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.size(); 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] << "action first set to [" << func.action << ']' << endl;
252 // When not cancel or meta-fake, do the normal lookup.
253 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
254 // Mostly, meta_fake_bit = key_modifier::none. RVDK_PATCH_5.
255 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_FAKE)) {
256 // remove Caps Lock and Mod2 as a modifiers
257 func = keyseq.addkey(keysym, (state | meta_fake_bit));
258 lyxerr[Debug::KEY] << "action now set to ["
259 << func.action << ']' << endl;
262 // Dont remove this unless you know what you are doing.
263 meta_fake_bit = key_modifier::none;
265 // can this happen now ?
266 if (func.action == LFUN_NOACTION) {
267 func = FuncRequest(LFUN_PREFIX);
270 if (lyxerr.debugging(Debug::KEY)) {
271 lyxerr << "Key [action="
272 << func.action << "]["
273 << keyseq.print() << ']'
277 // already here we know if it any point in going further
278 // why not return already here if action == -1 and
279 // num_bytes == 0? (Lgb)
281 if (keyseq.length() > 1) {
282 owner->message(keyseq.print());
286 // Maybe user can only reach the key via holding down shift.
287 // Let's see. But only if shift is the only modifier
288 if (func.action == LFUN_UNKNOWN_ACTION &&
289 state == key_modifier::shift) {
290 lyxerr[Debug::KEY] << "Trying without shift" << endl;
291 func = keyseq.addkey(keysym, key_modifier::none);
292 lyxerr[Debug::KEY] << "Action now " << func.action << endl;
295 if (func.action == LFUN_UNKNOWN_ACTION) {
296 // Hmm, we didn't match any of the keysequences. See
297 // if it's normal insertable text not already covered
299 if (keysym->isText() && keyseq.length() == 1) {
300 lyxerr[Debug::KEY] << "isText() is true, inserting." << endl;
301 func = FuncRequest(LFUN_SELFINSERT);
303 lyxerr[Debug::KEY] << "Unknown, !isText() - giving up" << endl;
304 owner->message(_("Unknown function."));
309 if (func.action == LFUN_SELFINSERT) {
310 if (encoded_last_key != 0) {
311 string arg(1, encoded_last_key);
312 dispatch(FuncRequest(LFUN_SELFINSERT, arg));
314 << "SelfInsert arg[`" << arg << "']" << endl;
322 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
324 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
326 LCursor & cur = view()->cursor();
328 /* In LyX/Mac, when a dialog is open, the menus of the
329 application can still be accessed without giving focus to
330 the main window. In this case, we want to disable the menu
331 entries that are buffer-related.
334 if (cmd.origin == FuncRequest::UI && !owner->hasFocus())
337 buf = owner->buffer();
339 if (cmd.action == LFUN_NOACTION) {
340 flag.message(N_("Nothing to do"));
345 switch (cmd.action) {
346 case LFUN_UNKNOWN_ACTION:
347 #ifndef HAVE_LIBAIKSAURUS
348 case LFUN_THESAURUS_ENTRY:
354 flag |= lyx_gui::getStatus(cmd);
357 if (flag.unknown()) {
358 flag.message(N_("Unknown action"));
362 if (!flag.enabled()) {
363 if (flag.message().empty())
364 flag.message(N_("Command disabled"));
368 // Check whether we need a buffer
369 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
371 flag.message(N_("Command not allowed with"
372 "out any document open"));
377 // I would really like to avoid having this switch and rather try to
378 // encode this in the function itself.
379 // -- And I'd rather let an inset decide which LFUNs it is willing
380 // to handle (Andre')
382 switch (cmd.action) {
383 case LFUN_TOOLTIPS_TOGGLE:
384 flag.setOnOff(owner->getDialogs().tooltipsEnabled());
387 case LFUN_READ_ONLY_TOGGLE:
388 flag.setOnOff(buf->isReadonly());
391 case LFUN_SWITCHBUFFER:
392 // toggle on the current buffer, but do not toggle off
393 // the other ones (is that a good idea?)
394 if (cmd.argument == buf->fileName())
399 enable = cmd.argument == "custom"
400 || Exporter::IsExportable(*buf, cmd.argument);
404 enable = cur.selection();
408 enable = buf->isLatex() && lyxrc.chktex_command != "none";
412 enable = Exporter::IsExportable(*buf, "program");
415 case LFUN_LAYOUT_TABULAR:
416 enable = cur.innerInsetOfType(InsetBase::TABULAR_CODE);
420 case LFUN_LAYOUT_PARAGRAPH:
421 enable = !cur.inset().forceDefaultParagraphs(&cur.inset());
424 case LFUN_VC_REGISTER:
425 enable = !buf->lyxvc().inUse();
427 case LFUN_VC_CHECKIN:
428 enable = buf->lyxvc().inUse() && !buf->isReadonly();
430 case LFUN_VC_CHECKOUT:
431 enable = buf->lyxvc().inUse() && buf->isReadonly();
435 enable = buf->lyxvc().inUse();
437 case LFUN_MENURELOAD:
438 enable = !buf->isUnnamed() && !buf->isClean();
442 case LFUN_INSET_SETTINGS: {
446 UpdatableInset * inset = cur.inset().asUpdatableInset();
447 lyxerr << "inset: " << inset << endl;
451 InsetBase::Code code = inset->lyxCode();
453 case InsetBase::TABULAR_CODE:
454 enable = cmd.argument == "tabular";
456 case InsetBase::ERT_CODE:
457 enable = cmd.argument == "ert";
459 case InsetBase::FLOAT_CODE:
460 enable = cmd.argument == "float";
462 case InsetBase::WRAP_CODE:
463 enable = cmd.argument == "wrap";
465 case InsetBase::NOTE_CODE:
466 enable = cmd.argument == "note";
468 case InsetBase::BRANCH_CODE:
469 enable = cmd.argument == "branch";
471 case InsetBase::BOX_CODE:
472 enable = cmd.argument == "box";
480 case LFUN_DIALOG_SHOW: {
481 string const name = cmd.getArg(0);
483 enable = name == "aboutlyx"
487 || name == "texinfo";
488 else if (name == "print")
489 enable = Exporter::IsExportable(*buf, "dvi")
490 && lyxrc.print_command != "none";
491 else if (name == "character" || name == "mathpanel")
492 enable = cur.inset().lyxCode() != InsetBase::ERT_CODE;
493 else if (name == "vclog")
494 enable = buf->lyxvc().inUse();
495 else if (name == "latexlog")
496 enable = IsFileReadable(buf->getLogName().second);
500 case LFUN_DIALOG_SHOW_NEW_INSET:
501 enable = cur.inset().lyxCode() != InsetBase::ERT_CODE;
504 case LFUN_DIALOG_UPDATE: {
505 string const name = cmd.getArg(0);
507 enable = name == "prefs";
511 // this one is difficult to get right. As a half-baked
512 // solution, we consider only the first action of the sequence
513 case LFUN_SEQUENCE: {
514 // argument contains ';'-terminated commands
515 string const firstcmd = token(cmd.argument, ';', 0);
516 FuncRequest func(lyxaction.lookupFunc(firstcmd));
517 func.origin = cmd.origin;
518 flag = getStatus(func);
522 case LFUN_MENUNEWTMPLT:
523 case LFUN_WORDFINDFORWARD:
524 case LFUN_WORDFINDBACKWARD:
526 case LFUN_EXEC_COMMAND:
529 case LFUN_CLOSEBUFFER:
538 case LFUN_RECONFIGURE:
542 case LFUN_DROP_LAYOUTS_CHOICE:
543 case LFUN_MENU_OPEN_BY_NAME:
546 case LFUN_GOTOFILEROW:
547 case LFUN_GOTO_PARAGRAPH:
548 case LFUN_DIALOG_SHOW_NEXT_INSET:
549 case LFUN_DIALOG_HIDE:
550 case LFUN_DIALOG_DISCONNECT_INSET:
552 case LFUN_TOGGLECURSORFOLLOW:
556 case LFUN_KMAP_TOGGLE:
558 case LFUN_EXPORT_CUSTOM:
560 case LFUN_SAVEPREFERENCES:
561 case LFUN_SCREEN_FONT_UPDATE:
564 case LFUN_EXTERNAL_EDIT:
565 case LFUN_GRAPHICS_EDIT:
566 case LFUN_ALL_INSETS_TOGGLE:
567 case LFUN_LANGUAGE_BUFFER:
568 case LFUN_TEXTCLASS_APPLY:
569 case LFUN_TEXTCLASS_LOAD:
570 case LFUN_SAVE_AS_DEFAULT:
571 case LFUN_BUFFERPARAMS_APPLY:
572 case LFUN_LYXRC_APPLY:
573 case LFUN_NEXTBUFFER:
574 case LFUN_PREVIOUSBUFFER:
575 // these are handled in our dispatch()
580 if (!::getStatus(cur, cmd, flag))
581 flag = view()->getStatus(cmd);
587 // Can we use a readonly buffer?
588 if (buf && buf->isReadonly()
589 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
590 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
591 flag.message(N_("Document is read-only"));
595 // the default error message if we disable the command
596 if (!flag.enabled() && flag.message().empty())
597 flag.message(N_("Command disabled"));
605 bool ensureBufferClean(BufferView * bv)
607 Buffer & buf = *bv->buffer();
611 string const file = MakeDisplayPath(buf.fileName(), 30);
612 string text = bformat(_("The document %1$s has unsaved "
613 "changes.\n\nDo you want to save "
614 "the document?"), file);
615 int const ret = Alert::prompt(_("Save changed document?"),
616 text, 0, 1, _("&Save"),
620 bv->owner()->dispatch(FuncRequest(LFUN_MENUWRITE));
622 return buf.isClean();
626 void showPrintError(string const & name)
628 string str = bformat(_("Could not print the document %1$s.\n"
629 "Check that your printer is set up correctly."),
630 MakeDisplayPath(name, 50));
631 Alert::error(_("Print document failed"), str);
635 void loadTextclass(string const & name)
637 std::pair<bool, lyx::textclass_type> const tc_pair =
638 textclasslist.NumberOfClass(name);
640 if (!tc_pair.first) {
641 lyxerr << "Document class \"" << name
642 << "\" does not exist."
647 lyx::textclass_type const tc = tc_pair.second;
649 if (!textclasslist[tc].load()) {
650 string s = bformat(_("The document could not be converted\n"
651 "into the document class %1$s."),
652 textclasslist[tc].name());
653 Alert::error(_("Could not change class"), s);
658 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
663 void LyXFunc::dispatch(FuncRequest const & cmd)
665 BOOST_ASSERT(view());
666 string const argument = cmd.argument;
667 kb_action const action = cmd.action;
669 lyxerr[Debug::ACTION] << "LyXFunc::dispatch: cmd: " << cmd << endl;
670 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
672 // we have not done anything wrong yet.
674 dispatch_buffer.erase();
678 FuncStatus const flag = getStatus(cmd);
679 if (!flag.enabled()) {
680 // We cannot use this function here
681 lyxerr[Debug::ACTION] << "LyXFunc::dispatch: "
682 << lyxaction.getActionName(action)
683 << " [" << action << "] is disabled at this location"
685 setErrorMessage(flag.message());
688 if (view()->available())
689 view()->hideCursor();
693 case LFUN_WORDFINDFORWARD:
694 case LFUN_WORDFINDBACKWARD: {
695 static string last_search;
696 string searched_string;
698 if (!argument.empty()) {
699 last_search = argument;
700 searched_string = argument;
702 searched_string = last_search;
705 if (searched_string.empty())
708 bool const fw = action == LFUN_WORDFINDFORWARD;
710 lyx::find::find2string(searched_string, true, false, fw);
711 lyx::find::find(view(), FuncRequest(LFUN_WORD_FIND, data));
716 owner->message(keyseq.printOptions());
719 case LFUN_EXEC_COMMAND:
720 owner->getToolbars().display("minibuffer", true);
721 owner->focus_command_buffer();
726 meta_fake_bit = key_modifier::none;
727 if (view()->available())
728 // cancel any selection
729 dispatch(FuncRequest(LFUN_MARK_OFF));
730 setMessage(N_("Cancel"));
734 meta_fake_bit = key_modifier::alt;
735 setMessage(keyseq.print());
738 case LFUN_READ_ONLY_TOGGLE:
739 if (owner->buffer()->lyxvc().inUse())
740 owner->buffer()->lyxvc().toggleReadOnly();
742 owner->buffer()->setReadonly(
743 !owner->buffer()->isReadonly());
746 // --- Menus -----------------------------------------------
748 menuNew(argument, false);
751 case LFUN_MENUNEWTMPLT:
752 menuNew(argument, true);
755 case LFUN_CLOSEBUFFER:
760 if (!owner->buffer()->isUnnamed()) {
761 string const str = bformat(_("Saving document %1$s..."),
762 MakeDisplayPath(owner->buffer()->fileName()));
764 MenuWrite(owner->buffer());
765 owner->message(str + _(" done."));
767 WriteAs(owner->buffer());
771 WriteAs(owner->buffer(), argument);
774 case LFUN_MENURELOAD: {
775 string const file = MakeDisplayPath(view()->buffer()->fileName(), 20);
776 string text = bformat(_("Any changes will be lost. Are you sure "
777 "you want to revert to the saved version of the document %1$s?"), file);
778 int const ret = Alert::prompt(_("Revert to saved document?"),
779 text, 0, 1, _("&Revert"), _("&Cancel"));
787 Exporter::Export(owner->buffer(), argument, true);
788 view()->showErrorList(BufferFormat(*owner->buffer()));
792 Exporter::Preview(owner->buffer(), argument);
793 view()->showErrorList(BufferFormat(*owner->buffer()));
797 Exporter::Export(owner->buffer(), "program", true);
798 view()->showErrorList(_("Build"));
802 owner->buffer()->runChktex();
803 view()->showErrorList(_("ChkTeX"));
807 if (argument == "custom")
808 owner->getDialogs().show("sendto");
810 Exporter::Export(owner->buffer(), argument, false);
811 view()->showErrorList(BufferFormat(*owner->buffer()));
815 case LFUN_EXPORT_CUSTOM: {
817 string command = split(argument, format_name, ' ');
818 Format const * format = formats.getFormat(format_name);
820 lyxerr << "Format \"" << format_name
821 << "\" not recognized!"
826 Buffer * buffer = owner->buffer();
828 // The name of the file created by the conversion process
831 // Output to filename
832 if (format->name() == "lyx") {
833 string const latexname =
834 buffer->getLatexName(false);
835 filename = ChangeExtension(latexname,
836 format->extension());
837 filename = AddName(buffer->temppath(), filename);
839 if (!buffer->writeFile(filename))
843 Exporter::Export(buffer, format_name, true,
847 // Substitute $$FName for filename
848 if (!contains(command, "$$FName"))
849 command = "( " + command + " ) < $$FName";
850 command = subst(command, "$$FName", filename);
852 // Execute the command in the background
854 call.startscript(Systemcall::DontWait, command);
861 string command = split(split(argument, target, ' '),
865 || target_name.empty()
866 || command.empty()) {
867 lyxerr << "Unable to parse \""
868 << argument << '"' << std::endl;
871 if (target != "printer" && target != "file") {
872 lyxerr << "Unrecognized target \""
873 << target << '"' << std::endl;
877 Buffer * buffer = owner->buffer();
879 if (!Exporter::Export(buffer, "dvi", true)) {
880 showPrintError(buffer->fileName());
884 // Push directory path.
885 string const path = buffer->temppath();
888 // there are three cases here:
889 // 1. we print to a file
890 // 2. we print directly to a printer
891 // 3. we print using a spool command (print to file first)
894 string const dviname =
895 ChangeExtension(buffer->getLatexName(true),
898 if (target == "printer") {
899 if (!lyxrc.print_spool_command.empty()) {
900 // case 3: print using a spool
901 string const psname =
902 ChangeExtension(dviname,".ps");
903 command += lyxrc.print_to_file
906 + QuoteName(dviname);
909 lyxrc.print_spool_command +' ';
910 if (target_name != "default") {
911 command2 += lyxrc.print_spool_printerprefix
915 command2 += QuoteName(psname);
917 // If successful, then spool command
918 res = one.startscript(
923 res = one.startscript(
924 Systemcall::DontWait,
927 // case 2: print directly to a printer
928 res = one.startscript(
929 Systemcall::DontWait,
930 command + QuoteName(dviname));
934 // case 1: print to a file
935 command += lyxrc.print_to_file
936 + QuoteName(MakeAbsPath(target_name,
939 + QuoteName(dviname);
940 res = one.startscript(Systemcall::DontWait,
945 showPrintError(buffer->fileName());
958 InsetCommandParams p("tableofcontents");
959 string const data = InsetCommandMailer::params2string("toc", p);
960 owner->getDialogs().show("toc", data, 0);
968 case LFUN_RECONFIGURE:
972 case LFUN_HELP_OPEN: {
973 string const arg = argument;
975 setErrorMessage(N_("Missing argument"));
978 string const fname = i18nLibFileSearch("doc", arg, "lyx");
980 lyxerr << "LyX: unable to find documentation file `"
981 << arg << "'. Bad installation?" << endl;
984 owner->message(bformat(_("Opening help file %1$s..."),
985 MakeDisplayPath(fname)));
986 view()->loadLyXFile(fname, false);
990 // --- version control -------------------------------
991 case LFUN_VC_REGISTER:
992 if (!ensureBufferClean(view()))
994 if (!owner->buffer()->lyxvc().inUse()) {
995 owner->buffer()->lyxvc().registrer();
1000 case LFUN_VC_CHECKIN:
1001 if (!ensureBufferClean(view()))
1003 if (owner->buffer()->lyxvc().inUse()
1004 && !owner->buffer()->isReadonly()) {
1005 owner->buffer()->lyxvc().checkIn();
1010 case LFUN_VC_CHECKOUT:
1011 if (!ensureBufferClean(view()))
1013 if (owner->buffer()->lyxvc().inUse()
1014 && owner->buffer()->isReadonly()) {
1015 owner->buffer()->lyxvc().checkOut();
1020 case LFUN_VC_REVERT:
1021 owner->buffer()->lyxvc().revert();
1026 owner->buffer()->lyxvc().undoLast();
1030 // --- buffers ----------------------------------------
1031 case LFUN_SWITCHBUFFER:
1032 view()->setBuffer(bufferlist.getBuffer(argument));
1035 case LFUN_NEXTBUFFER:
1036 view()->setBuffer(bufferlist.next(view()->buffer()));
1039 case LFUN_PREVIOUSBUFFER:
1040 view()->setBuffer(bufferlist.previous(view()->buffer()));
1044 NewFile(view(), argument);
1047 case LFUN_FILE_OPEN:
1051 case LFUN_DROP_LAYOUTS_CHOICE:
1052 owner->getToolbars().openLayoutList();
1055 case LFUN_MENU_OPEN_BY_NAME:
1056 owner->getMenubar().openByName(argument);
1059 // --- lyxserver commands ----------------------------
1061 setMessage(owner->buffer()->fileName());
1062 lyxerr[Debug::INFO] << "FNAME["
1063 << owner->buffer()->fileName()
1068 dispatch_buffer = keyseq.print();
1069 lyxserver->notifyClient(dispatch_buffer);
1072 case LFUN_GOTOFILEROW: {
1075 istringstream is(argument);
1076 is >> file_name >> row;
1077 if (prefixIs(file_name, package().temp_dir())) {
1078 // Needed by inverse dvi search. If it is a file
1079 // in tmpdir, call the apropriated function
1080 view()->setBuffer(bufferlist.getBufferFromTmp(file_name));
1082 // Must replace extension of the file to be .lyx
1083 // and get full path
1084 string const s = ChangeExtension(file_name, ".lyx");
1085 // Either change buffer or load the file
1086 if (bufferlist.exists(s)) {
1087 view()->setBuffer(bufferlist.getBuffer(s));
1089 view()->loadLyXFile(s);
1093 view()->setCursorFromRow(row);
1096 // see BufferView_pimpl::center()
1097 view()->updateScrollbar();
1101 case LFUN_GOTO_PARAGRAPH: {
1102 istringstream is(argument);
1105 ParIterator par = owner->buffer()->getParFromID(id);
1106 if (par == owner->buffer()->par_iterator_end()) {
1107 lyxerr[Debug::INFO] << "No matching paragraph found! ["
1108 << id << ']' << endl;
1111 lyxerr[Debug::INFO] << "Paragraph " << par->id()
1112 << " found." << endl;
1116 view()->setCursor(par, 0);
1118 view()->switchKeyMap();
1119 owner->view_state_changed();
1122 // see BufferView_pimpl::center()
1123 view()->updateScrollbar();
1127 case LFUN_DIALOG_SHOW: {
1128 string const name = cmd.getArg(0);
1129 string data = trim(cmd.argument.substr(name.size()));
1131 if (name == "character") {
1132 data = freefont2string();
1134 owner->getDialogs().show("character", data);
1137 else if (name == "latexlog") {
1138 pair<Buffer::LogType, string> const logfile =
1139 owner->buffer()->getLogName();
1140 switch (logfile.first) {
1141 case Buffer::latexlog:
1144 case Buffer::buildlog:
1148 data += logfile.second;
1149 owner->getDialogs().show("log", data);
1151 else if (name == "vclog") {
1152 string const data = "vc " +
1153 owner->buffer()->lyxvc().getLogFile();
1154 owner->getDialogs().show("log", data);
1157 owner->getDialogs().show(name, data);
1161 case LFUN_DIALOG_SHOW_NEW_INSET: {
1162 string const name = cmd.getArg(0);
1163 string data = trim(cmd.argument.substr(name.size()));
1164 if (name == "bibitem" ||
1166 name == "include" ||
1172 InsetCommandParams p(name);
1173 data = InsetCommandMailer::params2string(name, p);
1174 } else if (name == "box") {
1175 // \c data == "Boxed" || "Frameless" etc
1176 InsetBoxParams p(data);
1177 data = InsetBoxMailer::params2string(p);
1178 } else if (name == "branch") {
1179 InsetBranchParams p;
1180 data = InsetBranchMailer::params2string(p);
1181 } else if (name == "citation") {
1182 InsetCommandParams p("cite");
1183 data = InsetCommandMailer::params2string(name, p);
1184 } else if (name == "ert") {
1185 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1186 } else if (name == "external") {
1187 InsetExternalParams p;
1188 Buffer const & buffer = *owner->buffer();
1189 data = InsetExternalMailer::params2string(p, buffer);
1190 } else if (name == "float") {
1192 data = InsetFloatMailer::params2string(p);
1193 } else if (name == "graphics") {
1194 InsetGraphicsParams p;
1195 Buffer const & buffer = *owner->buffer();
1196 data = InsetGraphicsMailer::params2string(p, buffer);
1197 } else if (name == "note") {
1199 data = InsetNoteMailer::params2string(p);
1200 } else if (name == "vspace") {
1202 data = InsetVSpaceMailer::params2string(space);
1203 } else if (name == "wrap") {
1205 data = InsetWrapMailer::params2string(p);
1207 owner->getDialogs().show(name, data, 0);
1211 case LFUN_DIALOG_SHOW_NEXT_INSET:
1214 case LFUN_DIALOG_UPDATE: {
1215 string const & name = argument;
1216 // Can only update a dialog connected to an existing inset
1217 InsetBase * inset = owner->getDialogs().getOpenInset(name);
1219 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument);
1220 inset->dispatch(view()->cursor(), fr);
1221 } else if (name == "paragraph") {
1222 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1223 } else if (name == "prefs") {
1224 owner->getDialogs().update(name, string());
1229 case LFUN_DIALOG_HIDE:
1230 Dialogs::hide(argument, 0);
1233 case LFUN_DIALOG_DISCONNECT_INSET:
1234 owner->getDialogs().disconnect(argument);
1237 case LFUN_CHILDOPEN: {
1238 string const filename =
1239 MakeAbsPath(argument, owner->buffer()->filePath());
1240 setMessage(N_("Opening child document ") +
1241 MakeDisplayPath(filename) + "...");
1242 view()->savePosition(0);
1243 string const parentfilename = owner->buffer()->fileName();
1244 if (bufferlist.exists(filename))
1245 view()->setBuffer(bufferlist.getBuffer(filename));
1247 view()->loadLyXFile(filename);
1248 // Set the parent name of the child document.
1249 // This makes insertion of citations and references in the child work,
1250 // when the target is in the parent or another child document.
1251 owner->buffer()->setParentName(parentfilename);
1255 case LFUN_TOGGLECURSORFOLLOW:
1256 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1260 owner->getIntl().KeyMapOn(false);
1263 case LFUN_KMAP_PRIM:
1264 owner->getIntl().KeyMapPrim();
1268 owner->getIntl().KeyMapSec();
1271 case LFUN_KMAP_TOGGLE:
1272 owner->getIntl().ToggleKeyMap();
1278 string rest = split(argument, countstr, ' ');
1279 istringstream is(countstr);
1282 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1283 for (int i = 0; i < count; ++i)
1284 dispatch(lyxaction.lookupFunc(rest));
1288 case LFUN_SEQUENCE: {
1289 // argument contains ';'-terminated commands
1290 string arg = argument;
1291 while (!arg.empty()) {
1293 arg = split(arg, first, ';');
1294 FuncRequest func(lyxaction.lookupFunc(first));
1295 func.origin = cmd.origin;
1301 case LFUN_SAVEPREFERENCES: {
1302 Path p(package().user_support());
1303 lyxrc.write("preferences", false);
1307 case LFUN_SCREEN_FONT_UPDATE:
1308 // handle the screen font changes.
1309 lyxrc.set_font_norm_type();
1310 lyx_gui::update_fonts();
1311 // All visible buffers will need resize
1315 case LFUN_SET_COLOR: {
1317 string const x11_name = split(argument, lyx_name, ' ');
1318 if (lyx_name.empty() || x11_name.empty()) {
1319 setErrorMessage(N_("Syntax: set-color <lyx_name>"
1324 bool const graphicsbg_changed =
1325 (lyx_name == lcolor.getLyXName(LColor::graphicsbg) &&
1326 x11_name != lcolor.getX11Name(LColor::graphicsbg));
1328 if (!lcolor.setColor(lyx_name, x11_name)) {
1330 bformat(_("Set-color \"%1$s\" failed "
1331 "- color is undefined or "
1332 "may not be redefined"), lyx_name));
1336 lyx_gui::update_color(lcolor.getFromLyXName(lyx_name));
1338 if (graphicsbg_changed) {
1339 #ifdef WITH_WARNINGS
1340 #warning FIXME!! The graphics cache no longer has a changeDisplay method.
1343 lyx::graphics::GCache::get().changeDisplay(true);
1350 owner->message(argument);
1353 case LFUN_TOOLTIPS_TOGGLE:
1354 owner->getDialogs().toggleTooltips();
1357 case LFUN_EXTERNAL_EDIT: {
1358 FuncRequest fr(action, argument);
1359 InsetExternal().dispatch(view()->cursor(), fr);
1363 case LFUN_GRAPHICS_EDIT: {
1364 FuncRequest fr(action, argument);
1365 InsetGraphics().dispatch(view()->cursor(), fr);
1369 case LFUN_ALL_INSETS_TOGGLE: {
1371 string const name = split(argument, action, ' ');
1372 InsetBase::Code const inset_code =
1373 InsetBase::translate(name);
1375 LCursor & cur = view()->cursor();
1376 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1378 InsetBase & inset = owner->buffer()->inset();
1379 InsetIterator it = inset_iterator_begin(inset);
1380 InsetIterator const end = inset_iterator_end(inset);
1381 for (; it != end; ++it) {
1382 if (inset_code == InsetBase::NO_CODE
1383 || inset_code == it->lyxCode())
1384 it->dispatch(cur, fr);
1389 case LFUN_LANGUAGE_BUFFER: {
1390 Buffer & buffer = *owner->buffer();
1391 Language const * oldL = buffer.params().language;
1392 Language const * newL = languages.getLanguage(argument);
1393 if (!newL || oldL == newL)
1396 if (oldL->RightToLeft() == newL->RightToLeft()
1397 && !buffer.isMultiLingual())
1398 buffer.changeLanguage(oldL, newL);
1400 buffer.updateDocLang(newL);
1404 case LFUN_SAVE_AS_DEFAULT: {
1405 string const fname =
1406 AddName(AddPath(package().user_support(), "templates/"),
1408 Buffer defaults(fname);
1410 istringstream ss(argument);
1413 int const unknown_tokens = defaults.readHeader(lex);
1415 if (unknown_tokens != 0) {
1416 lyxerr << "Warning in LFUN_SAVE_AS_DEFAULT!\n"
1417 << unknown_tokens << " unknown token"
1418 << (unknown_tokens == 1 ? "" : "s")
1422 if (defaults.writeFile(defaults.fileName()))
1423 setMessage(_("Document defaults saved in ")
1424 + MakeDisplayPath(fname));
1426 setErrorMessage(_("Unable to save document defaults"));
1430 case LFUN_BUFFERPARAMS_APPLY: {
1431 biblio::CiteEngine const engine =
1432 owner->buffer()->params().cite_engine;
1434 istringstream ss(argument);
1437 int const unknown_tokens =
1438 owner->buffer()->readHeader(lex);
1440 if (unknown_tokens != 0) {
1441 lyxerr << "Warning in LFUN_BUFFERPARAMS_APPLY!\n"
1442 << unknown_tokens << " unknown token"
1443 << (unknown_tokens == 1 ? "" : "s")
1446 if (engine == owner->buffer()->params().cite_engine)
1449 LCursor & cur = view()->cursor();
1450 FuncRequest fr(LFUN_INSET_REFRESH);
1452 InsetBase & inset = owner->buffer()->inset();
1453 InsetIterator it = inset_iterator_begin(inset);
1454 InsetIterator const end = inset_iterator_end(inset);
1455 for (; it != end; ++it)
1456 if (it->lyxCode() == InsetBase::CITE_CODE)
1457 it->dispatch(cur, fr);
1461 case LFUN_TEXTCLASS_APPLY: {
1462 Buffer * buffer = owner->buffer();
1464 lyx::textclass_type const old_class =
1465 buffer->params().textclass;
1467 loadTextclass(argument);
1469 std::pair<bool, lyx::textclass_type> const tc_pair =
1470 textclasslist.NumberOfClass(argument);
1475 lyx::textclass_type const new_class = tc_pair.second;
1476 if (old_class == new_class)
1480 owner->message(_("Converting document to new document class..."));
1482 lyx::cap::SwitchLayoutsBetweenClasses(
1483 old_class, new_class,
1484 buffer->paragraphs(), el);
1486 bufferErrors(*buffer, el);
1487 view()->showErrorList(_("Class switch"));
1491 case LFUN_TEXTCLASS_LOAD:
1492 loadTextclass(argument);
1495 case LFUN_LYXRC_APPLY: {
1496 LyXRC const lyxrc_orig = lyxrc;
1498 istringstream ss(argument);
1499 bool const success = lyxrc.read(ss) == 0;
1502 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1503 << "Unable to read lyxrc data"
1508 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1514 view()->cursor().dispatch(cmd);
1515 if (view()->cursor().result().dispatched())
1516 update |= view()->cursor().result().update();
1518 update |= view()->dispatch(cmd);
1523 if (view()->available()) {
1524 // Redraw screen unless explicitly told otherwise.
1525 // This also initializes the position cache for all insets
1526 // in (at least partially) visible top-level paragraphs.
1527 view()->update(true, update);
1529 // if we executed a mutating lfun, mark the buffer as dirty
1530 if (getStatus(cmd).enabled()
1531 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)
1532 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly))
1533 view()->buffer()->markDirty();
1536 if (view()->cursor().inTexted()) {
1537 view()->owner()->updateLayoutChoice();
1540 sendDispatchMessage(getMessage(), cmd);
1544 void LyXFunc::sendDispatchMessage(string const & msg, FuncRequest const & cmd)
1546 owner->updateMenubar();
1547 owner->updateToolbars();
1549 const bool verbose = (cmd.origin == FuncRequest::UI
1550 || cmd.origin == FuncRequest::COMMANDBUFFER);
1552 if (cmd.action == LFUN_SELFINSERT || !verbose) {
1553 lyxerr[Debug::ACTION] << "dispatch msg is " << msg << endl;
1555 owner->message(msg);
1559 string dispatch_msg = msg;
1560 if (!dispatch_msg.empty())
1561 dispatch_msg += ' ';
1563 string comname = lyxaction.getActionName(cmd.action);
1565 bool argsadded = false;
1567 if (!cmd.argument.empty()) {
1568 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1569 comname += ' ' + cmd.argument;
1574 string const shortcuts = toplevel_keymap->printbindings(cmd);
1576 if (!shortcuts.empty()) {
1577 comname += ": " + shortcuts;
1578 } else if (!argsadded && !cmd.argument.empty()) {
1579 comname += ' ' + cmd.argument;
1582 if (!comname.empty()) {
1583 comname = rtrim(comname);
1584 dispatch_msg += '(' + comname + ')';
1587 lyxerr[Debug::ACTION] << "verbose dispatch msg " << dispatch_msg << endl;
1588 if (!dispatch_msg.empty())
1589 owner->message(dispatch_msg);
1593 void LyXFunc::setupLocalKeymap()
1595 keyseq.stdmap = toplevel_keymap.get();
1596 keyseq.curmap = toplevel_keymap.get();
1597 cancel_meta_seq.stdmap = toplevel_keymap.get();
1598 cancel_meta_seq.curmap = toplevel_keymap.get();
1602 void LyXFunc::menuNew(string const & name, bool fromTemplate)
1604 string initpath = lyxrc.document_path;
1605 string filename(name);
1607 if (view()->available()) {
1608 string const trypath = owner->buffer()->filePath();
1609 // If directory is writeable, use this as default.
1610 if (IsDirWriteable(trypath))
1614 static int newfile_number;
1616 if (filename.empty()) {
1617 filename = AddName(lyxrc.document_path,
1618 "newfile" + convert<string>(++newfile_number) + ".lyx");
1619 while (bufferlist.exists(filename) || fs::is_readable(filename)) {
1621 filename = AddName(lyxrc.document_path,
1622 "newfile" + convert<string>(newfile_number) +
1627 // The template stuff
1630 FileDialog fileDlg(_("Select template file"),
1631 LFUN_SELECT_FILE_SYNC,
1632 make_pair(string(_("Documents|#o#O")),
1633 string(lyxrc.document_path)),
1634 make_pair(string(_("Templates|#T#t")),
1635 string(lyxrc.template_path)));
1637 FileDialog::Result result =
1638 fileDlg.open(lyxrc.template_path,
1639 FileFilterList(_("LyX Documents (*.lyx)")),
1642 if (result.first == FileDialog::Later)
1644 if (result.second.empty())
1646 templname = result.second;
1649 view()->newFile(filename, templname, !name.empty());
1653 void LyXFunc::open(string const & fname)
1655 string initpath = lyxrc.document_path;
1657 if (view()->available()) {
1658 string const trypath = owner->buffer()->filePath();
1659 // If directory is writeable, use this as default.
1660 if (IsDirWriteable(trypath))
1666 if (fname.empty()) {
1667 FileDialog fileDlg(_("Select document to open"),
1669 make_pair(string(_("Documents|#o#O")),
1670 string(lyxrc.document_path)),
1671 make_pair(string(_("Examples|#E#e")),
1672 string(AddPath(package().system_support(), "examples"))));
1674 FileDialog::Result result =
1675 fileDlg.open(initpath,
1676 FileFilterList(_("LyX Documents (*.lyx)")),
1679 if (result.first == FileDialog::Later)
1682 filename = result.second;
1684 // check selected filename
1685 if (filename.empty()) {
1686 owner->message(_("Canceled."));
1692 // get absolute path of file and add ".lyx" to the filename if
1694 string const fullpath = FileSearch(string(), filename, "lyx");
1695 if (!fullpath.empty()) {
1696 filename = fullpath;
1699 string const disp_fn(MakeDisplayPath(filename));
1701 // if the file doesn't exist, let the user create one
1702 if (!fs::exists(filename)) {
1703 // the user specifically chose this name. Believe them.
1704 view()->newFile(filename, "", true);
1708 owner->message(bformat(_("Opening document %1$s..."), disp_fn));
1711 if (view()->loadLyXFile(filename)) {
1712 str2 = bformat(_("Document %1$s opened."), disp_fn);
1714 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1716 owner->message(str2);
1720 void LyXFunc::doImport(string const & argument)
1723 string filename = split(argument, format, ' ');
1725 lyxerr[Debug::INFO] << "LyXFunc::doImport: " << format
1726 << " file: " << filename << endl;
1728 // need user interaction
1729 if (filename.empty()) {
1730 string initpath = lyxrc.document_path;
1732 if (view()->available()) {
1733 string const trypath = owner->buffer()->filePath();
1734 // If directory is writeable, use this as default.
1735 if (IsDirWriteable(trypath))
1739 string const text = bformat(_("Select %1$s file to import"),
1740 formats.prettyName(format));
1742 FileDialog fileDlg(text,
1744 make_pair(string(_("Documents|#o#O")),
1745 string(lyxrc.document_path)),
1746 make_pair(string(_("Examples|#E#e")),
1747 string(AddPath(package().system_support(), "examples"))));
1749 string const filter = formats.prettyName(format)
1750 + " (*." + formats.extension(format) + ')';
1752 FileDialog::Result result =
1753 fileDlg.open(initpath,
1754 FileFilterList(filter),
1757 if (result.first == FileDialog::Later)
1760 filename = result.second;
1762 // check selected filename
1763 if (filename.empty())
1764 owner->message(_("Canceled."));
1767 if (filename.empty())
1770 // get absolute path of file
1771 filename = MakeAbsPath(filename);
1773 string const lyxfile = ChangeExtension(filename, ".lyx");
1775 // Check if the document already is open
1776 if (lyx_gui::use_gui && bufferlist.exists(lyxfile)) {
1777 if (!bufferlist.close(bufferlist.getBuffer(lyxfile), true)) {
1778 owner->message(_("Canceled."));
1783 // if the file exists already, and we didn't do
1784 // -i lyx thefile.lyx, warn
1785 if (fs::exists(lyxfile) && filename != lyxfile) {
1786 string const file = MakeDisplayPath(lyxfile, 30);
1788 string text = bformat(_("The document %1$s already exists.\n\n"
1789 "Do you want to over-write that document?"), file);
1790 int const ret = Alert::prompt(_("Over-write document?"),
1791 text, 0, 1, _("&Over-write"), _("&Cancel"));
1794 owner->message(_("Canceled."));
1799 Importer::Import(owner, filename, format);
1803 void LyXFunc::closeBuffer()
1805 if (bufferlist.close(owner->buffer(), true) && !quitting) {
1806 if (bufferlist.empty()) {
1807 // need this otherwise SEGV may occur while
1808 // trying to set variables that don't exist
1809 // since there's no current buffer
1810 owner->getDialogs().hideBufferDependent();
1812 view()->setBuffer(bufferlist.first());
1818 // Each "owner" should have it's own message method. lyxview and
1819 // the minibuffer would use the minibuffer, but lyxserver would
1820 // send an ERROR signal to its client. Alejandro 970603
1821 // This function is bit problematic when it comes to NLS, to make the
1822 // lyx servers client be language indepenent we must not translate
1823 // strings sent to this func.
1824 void LyXFunc::setErrorMessage(string const & m) const
1826 dispatch_buffer = m;
1831 void LyXFunc::setMessage(string const & m) const
1833 dispatch_buffer = m;
1837 string const LyXFunc::viewStatusMessage()
1839 // When meta-fake key is pressed, show the key sequence so far + "M-".
1841 return keyseq.print() + "M-";
1843 // Else, when a non-complete key sequence is pressed,
1844 // show the available options.
1845 if (keyseq.length() > 0 && !keyseq.deleted())
1846 return keyseq.printOptions();
1848 if (!view()->available())
1849 return _("Welcome to LyX!");
1851 return view()->cursor().currentState();
1855 BufferView * LyXFunc::view() const
1857 BOOST_ASSERT(owner);
1858 return owner->view().get();
1862 bool LyXFunc::wasMetaKey() const
1864 return (meta_fake_bit != key_modifier::none);
1870 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
1872 // Why the switch you might ask. It is a trick to ensure that all
1873 // the elements in the LyXRCTags enum is handled. As you can see
1874 // there are no breaks at all. So it is just a huge fall-through.
1875 // The nice thing is that we will get a warning from the compiler
1876 // if we forget an element.
1877 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
1879 case LyXRC::RC_ACCEPT_COMPOUND:
1880 case LyXRC::RC_ALT_LANG:
1881 case LyXRC::RC_ASCIIROFF_COMMAND:
1882 case LyXRC::RC_ASCII_LINELEN:
1883 case LyXRC::RC_AUTOREGIONDELETE:
1884 case LyXRC::RC_AUTORESET_OPTIONS:
1885 case LyXRC::RC_AUTOSAVE:
1886 case LyXRC::RC_AUTO_NUMBER:
1887 case LyXRC::RC_BACKUPDIR_PATH:
1888 case LyXRC::RC_BIBTEX_COMMAND:
1889 case LyXRC::RC_BINDFILE:
1890 case LyXRC::RC_CHECKLASTFILES:
1891 case LyXRC::RC_CHKTEX_COMMAND:
1892 case LyXRC::RC_CONVERTER:
1893 case LyXRC::RC_COPIER:
1894 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
1895 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
1896 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
1897 case LyXRC::RC_CYGWIN_PATH_FIX:
1898 if (lyxrc_orig.cygwin_path_fix != lyxrc_new.cygwin_path_fix) {
1899 namespace os = lyx::support::os;
1900 os::cygwin_path_fix(lyxrc_new.cygwin_path_fix);
1902 case LyXRC::RC_DATE_INSERT_FORMAT:
1903 case LyXRC::RC_DEFAULT_LANGUAGE:
1904 case LyXRC::RC_DEFAULT_PAPERSIZE:
1905 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
1906 case LyXRC::RC_DISPLAY_GRAPHICS:
1907 case LyXRC::RC_DOCUMENTPATH:
1908 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
1909 if (fs::exists(lyxrc_new.document_path) &&
1910 fs::is_directory(lyxrc_new.document_path)) {
1911 using lyx::support::package;
1912 package().document_dir() = lyxrc.document_path;
1915 case LyXRC::RC_ESC_CHARS:
1916 case LyXRC::RC_FONT_ENCODING:
1917 case LyXRC::RC_FORMAT:
1918 case LyXRC::RC_INDEX_COMMAND:
1919 case LyXRC::RC_INPUT:
1920 case LyXRC::RC_KBMAP:
1921 case LyXRC::RC_KBMAP_PRIMARY:
1922 case LyXRC::RC_KBMAP_SECONDARY:
1923 case LyXRC::RC_LABEL_INIT_LENGTH:
1924 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
1925 case LyXRC::RC_LANGUAGE_AUTO_END:
1926 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
1927 case LyXRC::RC_LANGUAGE_COMMAND_END:
1928 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
1929 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
1930 case LyXRC::RC_LANGUAGE_PACKAGE:
1931 case LyXRC::RC_LANGUAGE_USE_BABEL:
1932 case LyXRC::RC_LASTFILES:
1933 case LyXRC::RC_MAKE_BACKUP:
1934 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
1935 case LyXRC::RC_NUMLASTFILES:
1936 case LyXRC::RC_PATH_PREFIX:
1937 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
1938 using lyx::support::prependEnvPath;
1939 prependEnvPath("PATH", lyxrc.path_prefix);
1941 case LyXRC::RC_PERS_DICT:
1942 case LyXRC::RC_POPUP_BOLD_FONT:
1943 case LyXRC::RC_POPUP_FONT_ENCODING:
1944 case LyXRC::RC_POPUP_NORMAL_FONT:
1945 case LyXRC::RC_PREVIEW:
1946 case LyXRC::RC_PREVIEW_HASHED_LABELS:
1947 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
1948 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
1949 case LyXRC::RC_PRINTCOPIESFLAG:
1950 case LyXRC::RC_PRINTER:
1951 case LyXRC::RC_PRINTEVENPAGEFLAG:
1952 case LyXRC::RC_PRINTEXSTRAOPTIONS:
1953 case LyXRC::RC_PRINTFILEEXTENSION:
1954 case LyXRC::RC_PRINTLANDSCAPEFLAG:
1955 case LyXRC::RC_PRINTODDPAGEFLAG:
1956 case LyXRC::RC_PRINTPAGERANGEFLAG:
1957 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
1958 case LyXRC::RC_PRINTPAPERFLAG:
1959 case LyXRC::RC_PRINTREVERSEFLAG:
1960 case LyXRC::RC_PRINTSPOOL_COMMAND:
1961 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
1962 case LyXRC::RC_PRINTTOFILE:
1963 case LyXRC::RC_PRINTTOPRINTER:
1964 case LyXRC::RC_PRINT_ADAPTOUTPUT:
1965 case LyXRC::RC_PRINT_COMMAND:
1966 case LyXRC::RC_RTL_SUPPORT:
1967 case LyXRC::RC_SCREEN_DPI:
1968 case LyXRC::RC_SCREEN_FONT_ENCODING:
1969 case LyXRC::RC_SCREEN_FONT_ROMAN:
1970 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
1971 case LyXRC::RC_SCREEN_FONT_SANS:
1972 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
1973 case LyXRC::RC_SCREEN_FONT_SCALABLE:
1974 case LyXRC::RC_SCREEN_FONT_SIZES:
1975 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
1976 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
1977 case LyXRC::RC_SCREEN_ZOOM:
1978 case LyXRC::RC_SERVERPIPE:
1979 case LyXRC::RC_SET_COLOR:
1980 case LyXRC::RC_SHOW_BANNER:
1981 case LyXRC::RC_SPELL_COMMAND:
1982 case LyXRC::RC_TEMPDIRPATH:
1983 case LyXRC::RC_TEMPLATEPATH:
1984 case LyXRC::RC_UIFILE:
1985 case LyXRC::RC_USER_EMAIL:
1986 case LyXRC::RC_USER_NAME:
1987 case LyXRC::RC_USETEMPDIR:
1988 case LyXRC::RC_USE_ALT_LANG:
1989 case LyXRC::RC_USE_ESC_CHARS:
1990 case LyXRC::RC_USE_INP_ENC:
1991 case LyXRC::RC_USE_PERS_DICT:
1992 case LyXRC::RC_USE_SPELL_LIB:
1993 case LyXRC::RC_VIEWDVI_PAPEROPTION:
1994 case LyXRC::RC_VIEWER:
1995 case LyXRC::RC_WHEEL_JUMP:
1996 case LyXRC::RC_LAST: