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.
25 #include "BranchList.h"
26 #include "buffer_funcs.h"
28 #include "BufferList.h"
29 #include "BufferParams.h"
30 #include "BufferView.h"
33 #include "CutAndPaste.h"
35 #include "DispatchResult.h"
37 #include "ErrorList.h"
40 #include "FuncRequest.h"
41 #include "FuncStatus.h"
44 #include "InsetIterator.h"
49 #include "LyXAction.h"
54 #include "Paragraph.h"
55 #include "ParagraphParameters.h"
56 #include "ParIterator.h"
60 #include "TextClassList.h"
61 #include "ToolbarBackend.h"
64 #include "insets/InsetBox.h"
65 #include "insets/InsetBranch.h"
66 #include "insets/InsetCommand.h"
67 #include "insets/InsetERT.h"
68 #include "insets/InsetExternal.h"
69 #include "insets/InsetFloat.h"
70 #include "insets/InsetListings.h"
71 #include "insets/InsetGraphics.h"
72 #include "insets/InsetInclude.h"
73 #include "insets/InsetNote.h"
74 #include "insets/InsetTabular.h"
75 #include "insets/InsetVSpace.h"
76 #include "insets/InsetWrap.h"
78 #include "frontends/Application.h"
79 #include "frontends/alert.h"
80 #include "frontends/Dialogs.h"
81 #include "frontends/FileDialog.h"
82 #include "frontends/FontLoader.h"
83 #include "frontends/Gui.h"
84 #include "frontends/KeySymbol.h"
85 #include "frontends/LyXView.h"
86 #include "frontends/Selection.h"
87 #include "frontends/WorkArea.h"
89 #include "support/environment.h"
90 #include "support/FileFilterList.h"
91 #include "support/filetools.h"
92 #include "support/fs_extras.h"
93 #include "support/lstrings.h"
94 #include "support/Path.h"
95 #include "support/Package.h"
96 #include "support/Systemcall.h"
97 #include "support/convert.h"
98 #include "support/os.h"
100 #include <boost/current_function.hpp>
101 #include <boost/filesystem/operations.hpp>
106 using std::make_pair;
109 using std::istringstream;
110 using std::ostringstream;
112 namespace fs = boost::filesystem;
116 using frontend::LyXView;
118 using support::absolutePath;
119 using support::addName;
120 using support::addPath;
121 using support::bformat;
122 using support::changeExtension;
123 using support::contains;
124 using support::FileFilterList;
125 using support::FileName;
126 using support::fileSearch;
127 using support::i18nLibFileSearch;
128 using support::isDirWriteable;
129 using support::isFileReadable;
130 using support::isStrInt;
131 using support::makeAbsPath;
132 using support::makeDisplayPath;
133 using support::package;
134 using support::quoteName;
135 using support::rtrim;
136 using support::split;
137 using support::subst;
138 using support::Systemcall;
139 using support::token;
141 using support::prefixIs;
143 namespace Alert = frontend::Alert;
145 extern bool quitting;
149 // This function runs "configure" and then rereads lyx.defaults to
150 // reconfigure the automatic settings.
151 void reconfigure(LyXView & lv, string const & option)
153 // emit message signal.
154 lv.message(_("Running configure..."));
156 // Run configure in user lyx directory
157 support::Path p(package().user_support());
158 string configure_command = package().configure_command();
159 configure_command += option;
161 int ret = one.startscript(Systemcall::Wait, configure_command);
163 // emit message signal.
164 lv.message(_("Reloading configuration..."));
165 lyxrc.read(support::libFileSearch(string(), "lyxrc.defaults"));
166 // Re-read packages.lst
167 LaTeXFeatures::getAvailable();
170 Alert::information(_("System reconfiguration failed"),
171 _("The system reconfiguration has failed.\n"
172 "Default textclass is used but LyX may "
173 "not be able to work properly.\n"
174 "Please reconfigure again if needed."));
177 Alert::information(_("System reconfigured"),
178 _("The system has been reconfigured.\n"
179 "You need to restart LyX to make use of any\n"
180 "updated document class specifications."));
184 bool getLocalStatus(Cursor cursor, FuncRequest const & cmd, FuncStatus & status)
186 // Try to fix cursor in case it is broken.
187 cursor.fixIfBroken();
189 // This is, of course, a mess. Better create a new doc iterator and use
190 // this in Inset::getStatus. This might require an additional
191 // BufferView * arg, though (which should be avoided)
192 //Cursor safe = *this;
194 for ( ; cursor.depth(); cursor.pop()) {
195 //lyxerr << "\nCursor::getStatus: cmd: " << cmd << endl << *this << endl;
196 BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
197 BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
198 BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
200 // The inset's getStatus() will return 'true' if it made
201 // a definitive decision on whether it want to handle the
202 // request or not. The result of this decision is put into
203 // the 'status' parameter.
204 if (cursor.inset().getStatus(cursor, cmd, status)) {
213 /** Return the change status at cursor position, taking in account the
214 * status at each level of the document iterator (a table in a deleted
215 * footnote is deleted).
216 * When \param outer is true, the top slice is not looked at.
218 Change::Type lookupChangeType(DocIterator const & dit, bool outer = false)
220 size_t const depth = dit.depth() - (outer ? 1 : 0);
222 for (size_t i = 0 ; i < depth ; ++i) {
223 CursorSlice const & slice = dit[i];
224 if (!slice.inset().inMathed()
225 && slice.pos() < slice.paragraph().size()) {
226 Change::Type const ch = slice.paragraph().lookupChange(slice.pos()).type;
227 if (ch != Change::UNCHANGED)
231 return Change::UNCHANGED;
238 : lyx_view_(0), encoded_last_key(0), meta_fake_bit(NoModifier)
243 void LyXFunc::initKeySequences(KeyMap * kb)
245 keyseq = KeySequence(kb, kb);
246 cancel_meta_seq = KeySequence(kb, kb);
250 void LyXFunc::setLyXView(LyXView * lv)
252 if (!quitting && lyx_view_ && lyx_view_->view() && lyx_view_ != lv)
253 // save current selection to the selection buffer to allow
254 // middle-button paste in another window
255 cap::saveSelection(lyx_view_->view()->cursor());
260 void LyXFunc::handleKeyFunc(kb_action action)
262 char_type c = encoded_last_key;
267 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
268 lyx_view_->view()->getIntl().getTransManager().deadkey(
269 c, get_accent(action).accent, view()->cursor().innerText(), view()->cursor());
270 // Need to clear, in case the minibuffer calls these
273 // copied verbatim from do_accent_char
274 view()->cursor().resetAnchor();
275 view()->processUpdateFlags(Update::FitCursor);
279 void LyXFunc::gotoBookmark(unsigned int idx, bool openFile, bool switchToBuffer)
281 BOOST_ASSERT(lyx_view_);
282 if (!LyX::ref().session().bookmarks().isValid(idx))
284 BookmarksSection::Bookmark const & bm = LyX::ref().session().bookmarks().bookmark(idx);
285 BOOST_ASSERT(!bm.filename.empty());
286 string const file = bm.filename.absFilename();
287 // if the file is not opened, open it.
288 if (!theBufferList().exists(file)) {
290 dispatch(FuncRequest(LFUN_FILE_OPEN, file));
294 // open may fail, so we need to test it again
295 if (!theBufferList().exists(file))
298 // if the current buffer is not that one, switch to it.
299 if (lyx_view_->buffer()->fileName() != file) {
302 dispatch(FuncRequest(LFUN_BUFFER_SWITCH, file));
304 // moveToPosition try paragraph id first and then paragraph (pit, pos).
305 if (!view()->moveToPosition(bm.bottom_pit, bm.bottom_pos,
306 bm.top_id, bm.top_pos))
309 // Cursor jump succeeded!
310 Cursor const & cur = view()->cursor();
311 pit_type new_pit = cur.pit();
312 pos_type new_pos = cur.pos();
313 int new_id = cur.paragraph().id();
315 // if bottom_pit, bottom_pos or top_id has been changed, update bookmark
316 // see http://bugzilla.lyx.org/show_bug.cgi?id=3092
317 if (bm.bottom_pit != new_pit || bm.bottom_pos != new_pos
318 || bm.top_id != new_id) {
319 const_cast<BookmarksSection::Bookmark &>(bm).updatePos(
320 new_pit, new_pos, new_id);
326 void restartCursor(LyXView * lv)
328 /* When we move around, or type, it's nice to be able to see
329 * the cursor immediately after the keypress.
331 if (lv && lv->currentWorkArea())
332 lv->currentWorkArea()->startBlinkingCursor();
336 void LyXFunc::processKeySym(KeySymbol const & keysym, KeyModifier state)
338 LYXERR(Debug::KEY) << "KeySym is " << keysym.getSymbolName() << endl;
340 // Do nothing if we have nothing (JMarc)
341 if (!keysym.isOK()) {
342 LYXERR(Debug::KEY) << "Empty kbd action (probably composing)"
344 restartCursor(lyx_view_);
348 if (keysym.isModifier()) {
349 LYXERR(Debug::KEY) << "isModifier true" << endl;
350 restartCursor(lyx_view_);
354 //Encoding const * encoding = view()->cursor().getEncoding();
355 //encoded_last_key = keysym.getISOEncoded(encoding ? encoding->name() : "");
356 // FIXME: encoded_last_key shadows the member variable of the same
357 // name. Is that intended?
358 char_type encoded_last_key = keysym.getUCSEncoded();
360 // Do a one-deep top-level lookup for
361 // cancel and meta-fake keys. RVDK_PATCH_5
362 cancel_meta_seq.reset();
364 FuncRequest func = cancel_meta_seq.addkey(keysym, state);
365 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
366 << " action first set to [" << func.action << ']'
369 // When not cancel or meta-fake, do the normal lookup.
370 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
371 // Mostly, meta_fake_bit = NoModifier. RVDK_PATCH_5.
372 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_PREFIX)) {
373 // remove Caps Lock and Mod2 as a modifiers
374 func = keyseq.addkey(keysym, (state | meta_fake_bit));
375 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
376 << "action now set to ["
377 << func.action << ']' << endl;
380 // Dont remove this unless you know what you are doing.
381 meta_fake_bit = NoModifier;
383 // Can this happen now ?
384 if (func.action == LFUN_NOACTION)
385 func = FuncRequest(LFUN_COMMAND_PREFIX);
387 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
389 << func.action << "]["
390 << to_utf8(keyseq.print(false)) << ']'
393 // already here we know if it any point in going further
394 // why not return already here if action == -1 and
395 // num_bytes == 0? (Lgb)
397 if (keyseq.length() > 1)
398 lyx_view_->message(keyseq.print(true));
401 // Maybe user can only reach the key via holding down shift.
402 // Let's see. But only if shift is the only modifier
403 if (func.action == LFUN_UNKNOWN_ACTION && state == ShiftModifier) {
404 LYXERR(Debug::KEY) << "Trying without shift" << endl;
405 func = keyseq.addkey(keysym, NoModifier);
406 LYXERR(Debug::KEY) << "Action now " << func.action << endl;
409 if (func.action == LFUN_UNKNOWN_ACTION) {
410 // Hmm, we didn't match any of the keysequences. See
411 // if it's normal insertable text not already covered
413 if (keysym.isText() && keyseq.length() == 1) {
414 LYXERR(Debug::KEY) << "isText() is true, inserting." << endl;
415 func = FuncRequest(LFUN_SELF_INSERT,
416 FuncRequest::KEYBOARD);
418 LYXERR(Debug::KEY) << "Unknown, !isText() - giving up" << endl;
419 lyx_view_->message(_("Unknown function."));
420 restartCursor(lyx_view_);
425 if (func.action == LFUN_SELF_INSERT) {
426 if (encoded_last_key != 0) {
427 docstring const arg(1, encoded_last_key);
428 dispatch(FuncRequest(LFUN_SELF_INSERT, arg,
429 FuncRequest::KEYBOARD));
431 << "SelfInsert arg[`" << to_utf8(arg) << "']" << endl;
437 restartCursor(lyx_view_);
441 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
443 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
446 /* In LyX/Mac, when a dialog is open, the menus of the
447 application can still be accessed without giving focus to
448 the main window. In this case, we want to disable the menu
449 entries that are buffer-related.
451 Note that this code is not perfect, as bug 1941 attests:
452 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
454 Buffer * buf = lyx_view_? lyx_view_->buffer() : 0;
455 if (lyx_view_ && cmd.origin == FuncRequest::MENU && !lyx_view_->hasFocus())
458 if (cmd.action == LFUN_NOACTION) {
459 flag.message(from_utf8(N_("Nothing to do")));
464 switch (cmd.action) {
465 case LFUN_UNKNOWN_ACTION:
466 #ifndef HAVE_LIBAIKSAURUS
467 case LFUN_THESAURUS_ENTRY:
477 if (flag.unknown()) {
478 flag.message(from_utf8(N_("Unknown action")));
482 if (!flag.enabled()) {
483 if (flag.message().empty())
484 flag.message(from_utf8(N_("Command disabled")));
488 // Check whether we need a buffer
489 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
491 flag.message(from_utf8(N_("Command not allowed with"
492 "out any document open")));
497 // I would really like to avoid having this switch and rather try to
498 // encode this in the function itself.
499 // -- And I'd rather let an inset decide which LFUNs it is willing
500 // to handle (Andre')
502 switch (cmd.action) {
503 case LFUN_BUFFER_TOGGLE_READ_ONLY:
504 flag.setOnOff(buf->isReadonly());
507 case LFUN_BUFFER_SWITCH:
508 // toggle on the current buffer, but do not toggle off
509 // the other ones (is that a good idea?)
510 if (buf && to_utf8(cmd.argument()) == buf->fileName())
514 case LFUN_BUFFER_EXPORT:
515 enable = cmd.argument() == "custom"
516 || Exporter::isExportable(*buf, to_utf8(cmd.argument()));
519 case LFUN_BUFFER_CHKTEX:
520 enable = buf->isLatex() && !lyxrc.chktex_command.empty();
523 case LFUN_BUILD_PROGRAM:
524 enable = Exporter::isExportable(*buf, "program");
527 case LFUN_VC_REGISTER:
528 enable = !buf->lyxvc().inUse();
530 case LFUN_VC_CHECK_IN:
531 enable = buf->lyxvc().inUse() && !buf->isReadonly();
533 case LFUN_VC_CHECK_OUT:
534 enable = buf->lyxvc().inUse() && buf->isReadonly();
537 case LFUN_VC_UNDO_LAST:
538 enable = buf->lyxvc().inUse();
540 case LFUN_BUFFER_RELOAD:
541 enable = !buf->isUnnamed() && fs::exists(buf->fileName())
542 && (!buf->isClean() || buf->isExternallyModified(Buffer::timestamp_method));
545 case LFUN_INSET_APPLY: {
550 string const name = cmd.getArg(0);
551 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
553 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
555 if (!inset->getStatus(view()->cursor(), fr, fs)) {
556 // Every inset is supposed to handle this
561 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
562 flag |= getStatus(fr);
564 enable = flag.enabled();
568 case LFUN_DIALOG_TOGGLE:
569 flag.setOnOff(lyx_view_->getDialogs().visible(cmd.getArg(0)));
570 // fall through to set "enable"
571 case LFUN_DIALOG_SHOW: {
572 string const name = cmd.getArg(0);
574 enable = name == "aboutlyx"
575 || name == "file" //FIXME: should be removed.
577 || name == "texinfo";
578 else if (name == "print")
579 enable = Exporter::isExportable(*buf, "dvi")
580 && lyxrc.print_command != "none";
581 else if (name == "character") {
585 InsetCode ic = view()->cursor().inset().lyxCode();
586 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
589 else if (name == "latexlog")
590 enable = isFileReadable(FileName(buf->getLogName().second));
591 else if (name == "spellchecker")
592 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
593 enable = !buf->isReadonly();
597 else if (name == "vclog")
598 enable = buf->lyxvc().inUse();
602 case LFUN_DIALOG_UPDATE: {
603 string const name = cmd.getArg(0);
605 enable = name == "prefs";
609 case LFUN_CITATION_INSERT: {
610 FuncRequest fr(LFUN_INSET_INSERT, "citation");
611 enable = getStatus(fr).enabled();
615 case LFUN_BUFFER_WRITE: {
616 enable = lyx_view_->buffer()->isUnnamed()
617 || !lyx_view_->buffer()->isClean();
622 case LFUN_BUFFER_WRITE_ALL: {
623 // We enable the command only if there are some modified buffers
624 Buffer * first = theBufferList().first();
625 bool modified = false;
629 // We cannot use a for loop as the buffer list is a cycle.
635 b = theBufferList().next(b);
636 } while (b != first);
644 case LFUN_BOOKMARK_GOTO: {
645 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
646 enable = LyX::ref().session().bookmarks().isValid(num);
650 case LFUN_BOOKMARK_CLEAR:
651 enable = LyX::ref().session().bookmarks().size() > 0;
654 case LFUN_TOOLBAR_TOGGLE: {
655 bool const current = lyx_view_->isToolbarVisible(cmd.getArg(0));
656 flag.setOnOff(current);
659 case LFUN_WINDOW_CLOSE: {
660 enable = (theApp()->gui().viewIds().size() > 1);
664 // this one is difficult to get right. As a half-baked
665 // solution, we consider only the first action of the sequence
666 case LFUN_COMMAND_SEQUENCE: {
667 // argument contains ';'-terminated commands
668 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
669 FuncRequest func(lyxaction.lookupFunc(firstcmd));
670 func.origin = cmd.origin;
671 flag = getStatus(func);
674 case LFUN_BUFFER_NEW:
675 case LFUN_BUFFER_NEW_TEMPLATE:
676 case LFUN_WORD_FIND_FORWARD:
677 case LFUN_WORD_FIND_BACKWARD:
678 case LFUN_COMMAND_PREFIX:
679 case LFUN_COMMAND_EXECUTE:
681 case LFUN_META_PREFIX:
682 case LFUN_BUFFER_CLOSE:
683 case LFUN_BUFFER_WRITE_AS:
684 case LFUN_BUFFER_UPDATE:
685 case LFUN_BUFFER_VIEW:
686 case LFUN_MASTER_BUFFER_UPDATE:
687 case LFUN_MASTER_BUFFER_VIEW:
688 case LFUN_BUFFER_IMPORT:
689 case LFUN_BUFFER_AUTO_SAVE:
690 case LFUN_RECONFIGURE:
694 case LFUN_DROP_LAYOUTS_CHOICE:
696 case LFUN_SERVER_GET_NAME:
697 case LFUN_SERVER_NOTIFY:
698 case LFUN_SERVER_GOTO_FILE_ROW:
699 case LFUN_DIALOG_HIDE:
700 case LFUN_DIALOG_DISCONNECT_INSET:
701 case LFUN_BUFFER_CHILD_OPEN:
702 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
703 case LFUN_KEYMAP_OFF:
704 case LFUN_KEYMAP_PRIMARY:
705 case LFUN_KEYMAP_SECONDARY:
706 case LFUN_KEYMAP_TOGGLE:
708 case LFUN_BUFFER_EXPORT_CUSTOM:
709 case LFUN_BUFFER_PRINT:
710 case LFUN_PREFERENCES_SAVE:
711 case LFUN_SCREEN_FONT_UPDATE:
714 case LFUN_EXTERNAL_EDIT:
715 case LFUN_GRAPHICS_EDIT:
716 case LFUN_ALL_INSETS_TOGGLE:
717 case LFUN_BUFFER_LANGUAGE:
718 case LFUN_TEXTCLASS_APPLY:
719 case LFUN_TEXTCLASS_LOAD:
720 case LFUN_BUFFER_SAVE_AS_DEFAULT:
721 case LFUN_BUFFER_PARAMS_APPLY:
722 case LFUN_LAYOUT_MODULES_CLEAR:
723 case LFUN_LAYOUT_MODULE_ADD:
724 case LFUN_LAYOUT_RELOAD:
725 case LFUN_LYXRC_APPLY:
726 case LFUN_BUFFER_NEXT:
727 case LFUN_BUFFER_PREVIOUS:
728 case LFUN_WINDOW_NEW:
730 // these are handled in our dispatch()
738 if (!getLocalStatus(view()->cursor(), cmd, flag))
739 flag = view()->getStatus(cmd);
745 // Can we use a readonly buffer?
746 if (buf && buf->isReadonly()
747 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
748 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
749 flag.message(from_utf8(N_("Document is read-only")));
753 // Are we in a DELETED change-tracking region?
755 && lookupChangeType(view()->cursor(), true) == Change::DELETED
756 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
757 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
758 flag.message(from_utf8(N_("This portion of the document is deleted.")));
762 // the default error message if we disable the command
763 if (!flag.enabled() && flag.message().empty())
764 flag.message(from_utf8(N_("Command disabled")));
770 bool LyXFunc::ensureBufferClean(BufferView * bv)
772 Buffer & buf = bv->buffer();
776 docstring const file = makeDisplayPath(buf.fileName(), 30);
777 docstring text = bformat(_("The document %1$s has unsaved "
778 "changes.\n\nDo you want to save "
779 "the document?"), file);
780 int const ret = Alert::prompt(_("Save changed document?"),
781 text, 0, 1, _("&Save"),
785 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
787 return buf.isClean();
793 void showPrintError(string const & name)
795 docstring str = bformat(_("Could not print the document %1$s.\n"
796 "Check that your printer is set up correctly."),
797 makeDisplayPath(name, 50));
798 Alert::error(_("Print document failed"), str);
802 void loadTextClass(string const & name)
804 std::pair<bool, textclass_type> const tc_pair =
805 textclasslist.numberOfClass(name);
807 if (!tc_pair.first) {
808 lyxerr << "Document class \"" << name
809 << "\" does not exist."
814 textclass_type const tc = tc_pair.second;
816 if (!textclasslist[tc].load()) {
817 docstring s = bformat(_("The document class %1$s."
818 "could not be loaded."),
819 from_utf8(textclasslist[tc].name()));
820 Alert::error(_("Could not load class"), s);
825 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
830 void LyXFunc::dispatch(FuncRequest const & cmd)
832 string const argument = to_utf8(cmd.argument());
833 kb_action const action = cmd.action;
835 LYXERR(Debug::ACTION) << endl << "LyXFunc::dispatch: cmd: " << cmd << endl;
836 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
838 // we have not done anything wrong yet.
840 dispatch_buffer.erase();
842 // redraw the screen at the end (first of the two drawing steps).
843 //This is done unless explicitely requested otherwise
844 Update::flags updateFlags = Update::FitCursor;
846 FuncStatus const flag = getStatus(cmd);
847 if (!flag.enabled()) {
848 // We cannot use this function here
849 LYXERR(Debug::ACTION) << "LyXFunc::dispatch: "
850 << lyxaction.getActionName(action)
851 << " [" << action << "] is disabled at this location"
853 setErrorMessage(flag.message());
857 case LFUN_WORD_FIND_FORWARD:
858 case LFUN_WORD_FIND_BACKWARD: {
859 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
860 static docstring last_search;
861 docstring searched_string;
863 if (!cmd.argument().empty()) {
864 last_search = cmd.argument();
865 searched_string = cmd.argument();
867 searched_string = last_search;
870 if (searched_string.empty())
873 bool const fw = action == LFUN_WORD_FIND_FORWARD;
874 docstring const data =
875 find2string(searched_string, true, false, fw);
876 find(view(), FuncRequest(LFUN_WORD_FIND, data));
880 case LFUN_COMMAND_PREFIX:
881 BOOST_ASSERT(lyx_view_);
882 lyx_view_->message(keyseq.printOptions(true));
885 case LFUN_COMMAND_EXECUTE:
886 BOOST_ASSERT(lyx_view_);
887 lyx_view_->showMiniBuffer(true);
891 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
893 meta_fake_bit = NoModifier;
894 if (lyx_view_->buffer())
895 // cancel any selection
896 dispatch(FuncRequest(LFUN_MARK_OFF));
897 setMessage(from_ascii(N_("Cancel")));
900 case LFUN_META_PREFIX:
901 meta_fake_bit = AltModifier;
902 setMessage(keyseq.print(true));
905 case LFUN_BUFFER_TOGGLE_READ_ONLY: {
906 BOOST_ASSERT(lyx_view_ && lyx_view_->view() && lyx_view_->buffer());
907 Buffer * buf = lyx_view_->buffer();
908 if (buf->lyxvc().inUse())
909 buf->lyxvc().toggleReadOnly();
911 buf->setReadonly(!lyx_view_->buffer()->isReadonly());
915 // --- Menus -----------------------------------------------
916 case LFUN_BUFFER_NEW:
917 menuNew(argument, false);
918 updateFlags = Update::None;
921 case LFUN_BUFFER_NEW_TEMPLATE:
922 menuNew(argument, true);
923 updateFlags = Update::None;
926 case LFUN_BUFFER_CLOSE:
928 updateFlags = Update::None;
931 case LFUN_BUFFER_WRITE:
932 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
933 if (!lyx_view_->buffer()->isUnnamed()) {
934 docstring const str = bformat(_("Saving document %1$s..."),
935 makeDisplayPath(lyx_view_->buffer()->fileName()));
936 lyx_view_->message(str);
937 lyx_view_->buffer()->menuWrite();
938 lyx_view_->message(str + _(" done."));
940 lyx_view_->buffer()->writeAs();
942 updateFlags = Update::None;
945 case LFUN_BUFFER_WRITE_AS:
946 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
947 lyx_view_->buffer()->writeAs(argument);
948 updateFlags = Update::None;
951 case LFUN_BUFFER_WRITE_ALL: {
952 Buffer * first = theBufferList().first();
955 lyx_view_->message(_("Saving all documents..."));
957 // We cannot use a for loop as the buffer list cycles.
960 if (!b->isUnnamed()) {
962 lyxerr[Debug::ACTION] << "Saved " << b->fileName() << endl;
966 b = theBufferList().next(b);
967 } while (b != first);
968 lyx_view_->message(_("All documents saved."));
971 updateFlags = Update::None;
975 case LFUN_BUFFER_RELOAD: {
976 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
977 docstring const file = makeDisplayPath(lyx_view_->buffer()->fileName(), 20);
978 docstring text = bformat(_("Any changes will be lost. Are you sure "
979 "you want to revert to the saved version of the document %1$s?"), file);
980 int const ret = Alert::prompt(_("Revert to saved document?"),
981 text, 1, 1, _("&Revert"), _("&Cancel"));
988 case LFUN_BUFFER_UPDATE:
989 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
990 Exporter::Export(lyx_view_->buffer(), argument, true);
993 case LFUN_BUFFER_VIEW:
994 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
995 Exporter::preview(lyx_view_->buffer(), argument);
998 case LFUN_MASTER_BUFFER_UPDATE:
999 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->getMasterBuffer());
1000 Exporter::Export(lyx_view_->buffer()->getMasterBuffer(), argument, true);
1003 case LFUN_MASTER_BUFFER_VIEW:
1004 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->getMasterBuffer());
1005 Exporter::preview(lyx_view_->buffer()->getMasterBuffer(), argument);
1008 case LFUN_BUILD_PROGRAM:
1009 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1010 Exporter::Export(lyx_view_->buffer(), "program", true);
1013 case LFUN_BUFFER_CHKTEX:
1014 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1015 lyx_view_->buffer()->runChktex();
1018 case LFUN_BUFFER_EXPORT:
1019 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1020 if (argument == "custom")
1021 lyx_view_->getDialogs().show("sendto");
1023 Exporter::Export(lyx_view_->buffer(), argument, false);
1027 case LFUN_BUFFER_EXPORT_CUSTOM: {
1028 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1030 string command = split(argument, format_name, ' ');
1031 Format const * format = formats.getFormat(format_name);
1033 lyxerr << "Format \"" << format_name
1034 << "\" not recognized!"
1039 Buffer * buffer = lyx_view_->buffer();
1041 // The name of the file created by the conversion process
1044 // Output to filename
1045 if (format->name() == "lyx") {
1046 string const latexname =
1047 buffer->getLatexName(false);
1048 filename = changeExtension(latexname,
1049 format->extension());
1050 filename = addName(buffer->temppath(), filename);
1052 if (!buffer->writeFile(FileName(filename)))
1056 Exporter::Export(buffer, format_name, true, filename);
1059 // Substitute $$FName for filename
1060 if (!contains(command, "$$FName"))
1061 command = "( " + command + " ) < $$FName";
1062 command = subst(command, "$$FName", filename);
1064 // Execute the command in the background
1066 call.startscript(Systemcall::DontWait, command);
1070 case LFUN_BUFFER_PRINT: {
1071 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1072 // FIXME: cmd.getArg() might fail if one of the arguments
1073 // contains double quotes
1074 string target = cmd.getArg(0);
1075 string target_name = cmd.getArg(1);
1076 string command = cmd.getArg(2);
1079 || target_name.empty()
1080 || command.empty()) {
1081 lyxerr << "Unable to parse \""
1082 << argument << '"' << endl;
1085 if (target != "printer" && target != "file") {
1086 lyxerr << "Unrecognized target \""
1087 << target << '"' << endl;
1091 Buffer * buffer = lyx_view_->buffer();
1093 if (!Exporter::Export(buffer, "dvi", true)) {
1094 showPrintError(buffer->fileName());
1098 // Push directory path.
1099 string const path = buffer->temppath();
1100 // Prevent the compiler from optimizing away p
1102 support::Path p(pp);
1104 // there are three cases here:
1105 // 1. we print to a file
1106 // 2. we print directly to a printer
1107 // 3. we print using a spool command (print to file first)
1110 string const dviname =
1111 changeExtension(buffer->getLatexName(true),
1114 if (target == "printer") {
1115 if (!lyxrc.print_spool_command.empty()) {
1116 // case 3: print using a spool
1117 string const psname =
1118 changeExtension(dviname,".ps");
1119 command += ' ' + lyxrc.print_to_file
1122 + quoteName(dviname);
1125 lyxrc.print_spool_command + ' ';
1126 if (target_name != "default") {
1127 command2 += lyxrc.print_spool_printerprefix
1131 command2 += quoteName(psname);
1133 // If successful, then spool command
1134 res = one.startscript(
1139 res = one.startscript(
1140 Systemcall::DontWait,
1143 // case 2: print directly to a printer
1144 if (target_name != "default")
1145 command += ' ' + lyxrc.print_to_printer + target_name + ' ';
1146 res = one.startscript(
1147 Systemcall::DontWait,
1148 command + quoteName(dviname));
1152 // case 1: print to a file
1153 FileName const filename(makeAbsPath(target_name,
1154 lyx_view_->buffer()->filePath()));
1155 FileName const dvifile(makeAbsPath(dviname, path));
1156 if (fs::exists(filename.toFilesystemEncoding())) {
1157 docstring text = bformat(
1158 _("The file %1$s already exists.\n\n"
1159 "Do you want to overwrite that file?"),
1160 makeDisplayPath(filename.absFilename()));
1161 if (Alert::prompt(_("Overwrite file?"),
1162 text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
1165 command += ' ' + lyxrc.print_to_file
1166 + quoteName(filename.toFilesystemEncoding())
1168 + quoteName(dvifile.toFilesystemEncoding());
1169 res = one.startscript(Systemcall::DontWait,
1174 showPrintError(buffer->fileName());
1178 case LFUN_BUFFER_IMPORT:
1183 // quitting is triggered by the gui code
1184 // (leaving the event loop).
1185 lyx_view_->message(from_utf8(N_("Exiting.")));
1186 if (theBufferList().quitWriteAll())
1187 theApp()->gui().closeAllViews();
1190 case LFUN_BUFFER_AUTO_SAVE:
1191 lyx_view_->buffer()->autoSave();
1194 case LFUN_RECONFIGURE:
1195 BOOST_ASSERT(lyx_view_);
1196 // argument is any additional parameter to the configure.py command
1197 reconfigure(*lyx_view_, argument);
1200 case LFUN_HELP_OPEN: {
1201 BOOST_ASSERT(lyx_view_);
1202 string const arg = argument;
1204 setErrorMessage(from_ascii(N_("Missing argument")));
1207 FileName const fname = i18nLibFileSearch("doc", arg, "lyx");
1208 if (fname.empty()) {
1209 lyxerr << "LyX: unable to find documentation file `"
1210 << arg << "'. Bad installation?" << endl;
1213 lyx_view_->message(bformat(_("Opening help file %1$s..."),
1214 makeDisplayPath(fname.absFilename())));
1215 Buffer * buf = lyx_view_->loadLyXFile(fname, false);
1218 lyx_view_->setBuffer(buf);
1219 lyx_view_->showErrorList("Parse");
1221 updateFlags = Update::None;
1225 // --- version control -------------------------------
1226 case LFUN_VC_REGISTER:
1227 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1228 if (!ensureBufferClean(view()))
1230 if (!lyx_view_->buffer()->lyxvc().inUse()) {
1231 lyx_view_->buffer()->lyxvc().registrer();
1234 updateFlags = Update::Force;
1237 case LFUN_VC_CHECK_IN:
1238 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1239 if (!ensureBufferClean(view()))
1241 if (lyx_view_->buffer()->lyxvc().inUse()
1242 && !lyx_view_->buffer()->isReadonly()) {
1243 lyx_view_->buffer()->lyxvc().checkIn();
1248 case LFUN_VC_CHECK_OUT:
1249 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1250 if (!ensureBufferClean(view()))
1252 if (lyx_view_->buffer()->lyxvc().inUse()
1253 && lyx_view_->buffer()->isReadonly()) {
1254 lyx_view_->buffer()->lyxvc().checkOut();
1259 case LFUN_VC_REVERT:
1260 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1261 lyx_view_->buffer()->lyxvc().revert();
1265 case LFUN_VC_UNDO_LAST:
1266 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1267 lyx_view_->buffer()->lyxvc().undoLast();
1271 // --- buffers ----------------------------------------
1272 case LFUN_BUFFER_SWITCH:
1273 BOOST_ASSERT(lyx_view_);
1274 lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1275 updateFlags = Update::None;
1278 case LFUN_BUFFER_NEXT:
1279 BOOST_ASSERT(lyx_view_);
1280 lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer()));
1281 updateFlags = Update::None;
1284 case LFUN_BUFFER_PREVIOUS:
1285 BOOST_ASSERT(lyx_view_);
1286 lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer()));
1287 updateFlags = Update::None;
1290 case LFUN_FILE_NEW: {
1291 BOOST_ASSERT(lyx_view_);
1293 string tmpname = split(argument, name, ':'); // Split filename
1294 Buffer * const b = newFile(name, tmpname);
1296 lyx_view_->setBuffer(b);
1297 updateFlags = Update::None;
1301 case LFUN_FILE_OPEN:
1302 BOOST_ASSERT(lyx_view_);
1304 updateFlags = Update::None;
1307 case LFUN_DROP_LAYOUTS_CHOICE:
1308 BOOST_ASSERT(lyx_view_);
1309 lyx_view_->openLayoutList();
1312 case LFUN_MENU_OPEN:
1313 BOOST_ASSERT(lyx_view_);
1314 lyx_view_->openMenu(from_utf8(argument));
1317 // --- lyxserver commands ----------------------------
1318 case LFUN_SERVER_GET_NAME:
1319 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1320 setMessage(from_utf8(lyx_view_->buffer()->fileName()));
1321 LYXERR(Debug::INFO) << "FNAME["
1322 << lyx_view_->buffer()->fileName()
1326 case LFUN_SERVER_NOTIFY:
1327 dispatch_buffer = keyseq.print(false);
1328 theServer().notifyClient(to_utf8(dispatch_buffer));
1331 case LFUN_SERVER_GOTO_FILE_ROW: {
1332 BOOST_ASSERT(lyx_view_);
1335 istringstream is(argument);
1336 is >> file_name >> row;
1338 bool loaded = false;
1339 if (prefixIs(file_name, package().temp_dir().absFilename()))
1340 // Needed by inverse dvi search. If it is a file
1341 // in tmpdir, call the apropriated function
1342 buf = theBufferList().getBufferFromTmp(file_name);
1344 // Must replace extension of the file to be .lyx
1345 // and get full path
1346 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1347 // Either change buffer or load the file
1348 if (theBufferList().exists(s.absFilename()))
1349 buf = theBufferList().getBuffer(s.absFilename());
1351 buf = lyx_view_->loadLyXFile(s);
1357 updateFlags = Update::None;
1362 lyx_view_->setBuffer(buf);
1363 view()->setCursorFromRow(row);
1365 lyx_view_->showErrorList("Parse");
1366 updateFlags = Update::FitCursor;
1370 case LFUN_DIALOG_SHOW: {
1371 BOOST_ASSERT(lyx_view_);
1372 string const name = cmd.getArg(0);
1373 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1375 if (name == "character") {
1376 data = freefont2string();
1378 lyx_view_->getDialogs().show("character", data);
1379 } else if (name == "latexlog") {
1380 pair<Buffer::LogType, string> const logfile =
1381 lyx_view_->buffer()->getLogName();
1382 switch (logfile.first) {
1383 case Buffer::latexlog:
1386 case Buffer::buildlog:
1390 data += Lexer::quoteString(logfile.second);
1391 lyx_view_->getDialogs().show("log", data);
1392 } else if (name == "vclog") {
1393 string const data = "vc " +
1394 Lexer::quoteString(lyx_view_->buffer()->lyxvc().getLogFile());
1395 lyx_view_->getDialogs().show("log", data);
1397 lyx_view_->getDialogs().show(name, data);
1401 case LFUN_DIALOG_SHOW_NEW_INSET: {
1402 BOOST_ASSERT(lyx_view_);
1403 string const name = cmd.getArg(0);
1404 InsetCode code = insetCode(name);
1405 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1406 bool insetCodeOK = true;
1415 case HYPERLINK_CODE: {
1416 InsetCommandParams p(name);
1417 data = InsetCommandMailer::params2string(name, p);
1420 case INCLUDE_CODE: {
1421 // data is the include type: one of "include",
1422 // "input", "verbatiminput" or "verbatiminput*"
1424 // default type is requested
1426 InsetCommandParams p("include", data);
1427 data = InsetIncludeMailer::params2string(p);
1431 // \c data == "Boxed" || "Frameless" etc
1432 InsetBoxParams p(data);
1433 data = InsetBoxMailer::params2string(p);
1437 InsetBranchParams p;
1438 data = InsetBranchMailer::params2string(p);
1442 InsetCommandParams p("cite");
1443 data = InsetCommandMailer::params2string(name, p);
1447 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1450 case EXTERNAL_CODE: {
1451 InsetExternalParams p;
1452 Buffer const & buffer = *lyx_view_->buffer();
1453 data = InsetExternalMailer::params2string(p, buffer);
1458 data = InsetFloatMailer::params2string(p);
1461 case LISTINGS_CODE: {
1462 InsetListingsParams p;
1463 data = InsetListingsMailer::params2string(p);
1466 case GRAPHICS_CODE: {
1467 InsetGraphicsParams p;
1468 Buffer const & buffer = *lyx_view_->buffer();
1469 data = InsetGraphicsMailer::params2string(p, buffer);
1474 data = InsetNoteMailer::params2string(p);
1479 data = InsetVSpaceMailer::params2string(space);
1484 data = InsetWrapMailer::params2string(p);
1488 lyxerr << "Inset type '" << name <<
1489 "' not recognized in LFUN_DIALOG_SHOW_NEW_INSET" << std:: endl;
1490 insetCodeOK = false;
1492 } // end switch(code)
1494 lyx_view_->getDialogs().show(name, data, 0);
1498 case LFUN_DIALOG_UPDATE: {
1499 BOOST_ASSERT(lyx_view_);
1500 string const & name = argument;
1501 // Can only update a dialog connected to an existing inset
1502 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1504 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1505 inset->dispatch(view()->cursor(), fr);
1506 } else if (name == "paragraph") {
1507 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1508 } else if (name == "prefs") {
1509 lyx_view_->getDialogs().update(name, string());
1514 case LFUN_DIALOG_HIDE:
1515 LyX::cref().hideDialogs(argument, 0);
1518 case LFUN_DIALOG_TOGGLE: {
1519 BOOST_ASSERT(lyx_view_);
1520 if (lyx_view_->getDialogs().visible(cmd.getArg(0)))
1521 dispatch(FuncRequest(LFUN_DIALOG_HIDE, argument));
1523 dispatch(FuncRequest(LFUN_DIALOG_SHOW, argument));
1527 case LFUN_DIALOG_DISCONNECT_INSET:
1528 BOOST_ASSERT(lyx_view_);
1529 lyx_view_->getDialogs().disconnect(argument);
1533 case LFUN_CITATION_INSERT: {
1534 BOOST_ASSERT(lyx_view_);
1535 if (!argument.empty()) {
1536 // we can have one optional argument, delimited by '|'
1537 // citation-insert <key>|<text_before>
1538 // this should be enhanced to also support text_after
1539 // and citation style
1540 string arg = argument;
1542 if (contains(argument, "|")) {
1543 arg = token(argument, '|', 0);
1544 opt1 = token(argument, '|', 1);
1546 InsetCommandParams icp("cite");
1547 icp["key"] = from_utf8(arg);
1549 icp["before"] = from_utf8(opt1);
1550 string icstr = InsetCommandMailer::params2string("citation", icp);
1551 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1554 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1558 case LFUN_BUFFER_CHILD_OPEN: {
1559 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1560 Buffer * parent = lyx_view_->buffer();
1561 FileName filename = makeAbsPath(argument, parent->filePath());
1562 view()->saveBookmark(false);
1564 bool parsed = false;
1565 if (theBufferList().exists(filename.absFilename())) {
1566 child = theBufferList().getBuffer(filename.absFilename());
1568 setMessage(bformat(_("Opening child document %1$s..."),
1569 makeDisplayPath(filename.absFilename())));
1570 child = lyx_view_->loadLyXFile(filename, true);
1574 // Set the parent name of the child document.
1575 // This makes insertion of citations and references in the child work,
1576 // when the target is in the parent or another child document.
1577 child->setParentName(parent->fileName());
1578 updateLabels(*child->getMasterBuffer());
1579 lyx_view_->setBuffer(child);
1581 lyx_view_->showErrorList("Parse");
1584 // If a screen update is required (in case where auto_open is false),
1585 // setBuffer() would have taken care of it already. Otherwise we shall
1586 // reset the update flag because it can cause a circular problem.
1588 updateFlags = Update::None;
1592 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1593 BOOST_ASSERT(lyx_view_);
1594 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1597 case LFUN_KEYMAP_OFF:
1598 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1599 lyx_view_->view()->getIntl().keyMapOn(false);
1602 case LFUN_KEYMAP_PRIMARY:
1603 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1604 lyx_view_->view()->getIntl().keyMapPrim();
1607 case LFUN_KEYMAP_SECONDARY:
1608 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1609 lyx_view_->view()->getIntl().keyMapSec();
1612 case LFUN_KEYMAP_TOGGLE:
1613 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1614 lyx_view_->view()->getIntl().toggleKeyMap();
1620 string rest = split(argument, countstr, ' ');
1621 istringstream is(countstr);
1624 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1625 for (int i = 0; i < count; ++i)
1626 dispatch(lyxaction.lookupFunc(rest));
1630 case LFUN_COMMAND_SEQUENCE: {
1631 // argument contains ';'-terminated commands
1632 string arg = argument;
1633 while (!arg.empty()) {
1635 arg = split(arg, first, ';');
1636 FuncRequest func(lyxaction.lookupFunc(first));
1637 func.origin = cmd.origin;
1643 case LFUN_PREFERENCES_SAVE: {
1644 lyxrc.write(makeAbsPath("preferences",
1645 package().user_support().absFilename()),
1650 case LFUN_SCREEN_FONT_UPDATE:
1651 BOOST_ASSERT(lyx_view_);
1652 // handle the screen font changes.
1653 theFontLoader().update();
1654 /// FIXME: only the current view will be updated. the Gui
1655 /// class is able to furnish the list of views.
1656 updateFlags = Update::Force;
1659 case LFUN_SET_COLOR: {
1661 string const x11_name = split(argument, lyx_name, ' ');
1662 if (lyx_name.empty() || x11_name.empty()) {
1663 setErrorMessage(from_ascii(N_(
1664 "Syntax: set-color <lyx_name>"
1669 bool const graphicsbg_changed =
1670 (lyx_name == lcolor.getLyXName(Color::graphicsbg) &&
1671 x11_name != lcolor.getX11Name(Color::graphicsbg));
1673 if (!lcolor.setColor(lyx_name, x11_name)) {
1675 bformat(_("Set-color \"%1$s\" failed "
1676 "- color is undefined or "
1677 "may not be redefined"),
1678 from_utf8(lyx_name)));
1682 theApp()->updateColor(lcolor.getFromLyXName(lyx_name));
1684 if (graphicsbg_changed) {
1685 // FIXME: The graphics cache no longer has a changeDisplay method.
1687 graphics::GCache::get().changeDisplay(true);
1694 BOOST_ASSERT(lyx_view_);
1695 lyx_view_->message(from_utf8(argument));
1698 case LFUN_EXTERNAL_EDIT: {
1699 BOOST_ASSERT(lyx_view_);
1700 FuncRequest fr(action, argument);
1701 InsetExternal().dispatch(view()->cursor(), fr);
1705 case LFUN_GRAPHICS_EDIT: {
1706 FuncRequest fr(action, argument);
1707 InsetGraphics().dispatch(view()->cursor(), fr);
1711 case LFUN_INSET_APPLY: {
1712 BOOST_ASSERT(lyx_view_);
1713 string const name = cmd.getArg(0);
1714 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1716 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1717 inset->dispatch(view()->cursor(), fr);
1719 FuncRequest fr(LFUN_INSET_INSERT, argument);
1722 // ideally, the update flag should be set by the insets,
1723 // but this is not possible currently
1724 updateFlags = Update::Force | Update::FitCursor;
1728 case LFUN_ALL_INSETS_TOGGLE: {
1729 BOOST_ASSERT(lyx_view_);
1731 string const name = split(argument, action, ' ');
1732 InsetCode const inset_code = insetCode(name);
1734 Cursor & cur = view()->cursor();
1735 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1737 Inset & inset = lyx_view_->buffer()->inset();
1738 InsetIterator it = inset_iterator_begin(inset);
1739 InsetIterator const end = inset_iterator_end(inset);
1740 for (; it != end; ++it) {
1741 if (!it->asInsetMath()
1742 && (inset_code == NO_CODE
1743 || inset_code == it->lyxCode())) {
1744 Cursor tmpcur = cur;
1745 tmpcur.pushLeft(*it);
1746 it->dispatch(tmpcur, fr);
1749 updateFlags = Update::Force | Update::FitCursor;
1753 case LFUN_BUFFER_LANGUAGE: {
1754 BOOST_ASSERT(lyx_view_);
1755 Buffer & buffer = *lyx_view_->buffer();
1756 Language const * oldL = buffer.params().language;
1757 Language const * newL = languages.getLanguage(argument);
1758 if (!newL || oldL == newL)
1761 if (oldL->rightToLeft() == newL->rightToLeft()
1762 && !buffer.isMultiLingual())
1763 buffer.changeLanguage(oldL, newL);
1767 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1768 string const fname =
1769 addName(addPath(package().user_support().absFilename(), "templates/"),
1771 Buffer defaults(fname);
1773 istringstream ss(argument);
1776 int const unknown_tokens = defaults.readHeader(lex);
1778 if (unknown_tokens != 0) {
1779 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1780 << unknown_tokens << " unknown token"
1781 << (unknown_tokens == 1 ? "" : "s")
1785 if (defaults.writeFile(FileName(defaults.fileName())))
1786 setMessage(bformat(_("Document defaults saved in %1$s"),
1787 makeDisplayPath(fname)));
1789 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1793 case LFUN_BUFFER_PARAMS_APPLY: {
1794 BOOST_ASSERT(lyx_view_);
1795 biblio::CiteEngine const oldEngine =
1796 lyx_view_->buffer()->params().getEngine();
1798 Buffer * buffer = lyx_view_->buffer();
1800 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1801 recordUndoFullDocument(view());
1803 istringstream ss(argument);
1806 int const unknown_tokens = buffer->readHeader(lex);
1808 if (unknown_tokens != 0) {
1809 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1810 << unknown_tokens << " unknown token"
1811 << (unknown_tokens == 1 ? "" : "s")
1815 updateLayout(oldClass, buffer);
1817 biblio::CiteEngine const newEngine =
1818 lyx_view_->buffer()->params().getEngine();
1820 if (oldEngine != newEngine) {
1821 Cursor & cur = view()->cursor();
1822 FuncRequest fr(LFUN_INSET_REFRESH);
1824 Inset & inset = lyx_view_->buffer()->inset();
1825 InsetIterator it = inset_iterator_begin(inset);
1826 InsetIterator const end = inset_iterator_end(inset);
1827 for (; it != end; ++it)
1828 if (it->lyxCode() == CITE_CODE)
1829 it->dispatch(cur, fr);
1832 updateFlags = Update::Force | Update::FitCursor;
1836 case LFUN_LAYOUT_MODULES_CLEAR: {
1837 BOOST_ASSERT(lyx_view_);
1838 Buffer * buffer = lyx_view_->buffer();
1839 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1840 recordUndoFullDocument(view());
1841 buffer->params().clearLayoutModules();
1842 updateLayout(oldClass, buffer);
1843 updateFlags = Update::Force | Update::FitCursor;
1847 case LFUN_LAYOUT_MODULE_ADD: {
1848 BOOST_ASSERT(lyx_view_);
1849 Buffer * buffer = lyx_view_->buffer();
1850 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1851 recordUndoFullDocument(view());
1852 buffer->params().addLayoutModule(argument);
1853 updateLayout(oldClass, buffer);
1854 updateFlags = Update::Force | Update::FitCursor;
1858 case LFUN_TEXTCLASS_APPLY: {
1859 BOOST_ASSERT(lyx_view_);
1860 Buffer * buffer = lyx_view_->buffer();
1862 loadTextClass(argument);
1864 std::pair<bool, textclass_type> const tc_pair =
1865 textclasslist.numberOfClass(argument);
1870 textclass_type const old_class = buffer->params().getBaseClass();
1871 textclass_type const new_class = tc_pair.second;
1873 if (old_class == new_class)
1877 //Save the old, possibly modular, layout for use in conversion.
1878 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1879 recordUndoFullDocument(view());
1880 buffer->params().setBaseClass(new_class);
1881 updateLayout(oldClass, buffer);
1882 updateFlags = Update::Force | Update::FitCursor;
1886 case LFUN_LAYOUT_RELOAD: {
1887 BOOST_ASSERT(lyx_view_);
1888 Buffer * buffer = lyx_view_->buffer();
1889 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1890 textclass_type const tc = buffer->params().getBaseClass();
1891 textclasslist.reset(tc);
1892 buffer->params().setBaseClass(tc);
1893 updateLayout(oldClass, buffer);
1894 updateFlags = Update::Force | Update::FitCursor;
1898 case LFUN_TEXTCLASS_LOAD:
1899 loadTextClass(argument);
1902 case LFUN_LYXRC_APPLY: {
1903 LyXRC const lyxrc_orig = lyxrc;
1905 istringstream ss(argument);
1906 bool const success = lyxrc.read(ss) == 0;
1909 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1910 << "Unable to read lyxrc data"
1915 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1917 /// We force the redraw in any case because there might be
1918 /// some screen font changes.
1919 /// FIXME: only the current view will be updated. the Gui
1920 /// class is able to furnish the list of views.
1921 updateFlags = Update::Force;
1925 case LFUN_WINDOW_NEW:
1926 LyX::ref().newLyXView();
1929 case LFUN_WINDOW_CLOSE:
1930 BOOST_ASSERT(lyx_view_);
1931 BOOST_ASSERT(theApp());
1932 // update bookmark pit of the current buffer before window close
1933 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1934 gotoBookmark(i+1, false, false);
1935 // ask the user for saving changes or cancel quit
1936 if (!theBufferList().quitWriteAll())
1941 case LFUN_BOOKMARK_GOTO:
1942 // go to bookmark, open unopened file and switch to buffer if necessary
1943 gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
1946 case LFUN_BOOKMARK_CLEAR:
1947 LyX::ref().session().bookmarks().clear();
1950 case LFUN_TOOLBAR_TOGGLE: {
1951 BOOST_ASSERT(lyx_view_);
1952 string const name = cmd.getArg(0);
1953 bool const allowauto = cmd.getArg(1) == "allowauto";
1954 lyx_view_->toggleToolbarState(name, allowauto);
1955 ToolbarInfo * tbi = lyx_view_->getToolbarInfo(name);
1957 setMessage(bformat(_("Unknown toolbar \"%1$s\""),
1962 if (tbi->flags & ToolbarInfo::ON)
1964 else if (tbi->flags & ToolbarInfo::OFF)
1966 else if (tbi->flags & ToolbarInfo::AUTO)
1969 setMessage(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1970 _(tbi->gui_name), state));
1975 BOOST_ASSERT(lyx_view_);
1976 view()->cursor().dispatch(cmd);
1977 updateFlags = view()->cursor().result().update();
1978 if (!view()->cursor().result().dispatched())
1979 updateFlags = view()->dispatch(cmd);
1984 if (lyx_view_ && lyx_view_->buffer()) {
1985 // BufferView::update() updates the ViewMetricsInfo and
1986 // also initializes the position cache for all insets in
1987 // (at least partially) visible top-level paragraphs.
1988 // We will redraw the screen only if needed.
1989 view()->processUpdateFlags(updateFlags);
1990 lyx_view_->updateStatusBar();
1992 // if we executed a mutating lfun, mark the buffer as dirty
1994 && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
1995 && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
1996 lyx_view_->buffer()->markDirty();
1998 //Do we have a selection?
1999 theSelection().haveSelection(view()->cursor().selection());
2001 if (view()->cursor().inTexted()) {
2002 lyx_view_->updateLayoutChoice();
2006 if (!quitting && lyx_view_) {
2007 lyx_view_->updateToolbars();
2008 // Some messages may already be translated, so we cannot use _()
2009 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
2014 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
2016 const bool verbose = (cmd.origin == FuncRequest::MENU
2017 || cmd.origin == FuncRequest::TOOLBAR
2018 || cmd.origin == FuncRequest::COMMANDBUFFER);
2020 if (cmd.action == LFUN_SELF_INSERT || !verbose) {
2021 LYXERR(Debug::ACTION) << "dispatch msg is " << to_utf8(msg) << endl;
2023 lyx_view_->message(msg);
2027 docstring dispatch_msg = msg;
2028 if (!dispatch_msg.empty())
2029 dispatch_msg += ' ';
2031 docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
2033 bool argsadded = false;
2035 if (!cmd.argument().empty()) {
2036 if (cmd.action != LFUN_UNKNOWN_ACTION) {
2037 comname += ' ' + cmd.argument();
2042 docstring const shortcuts = theTopLevelKeymap().printbindings(cmd);
2044 if (!shortcuts.empty())
2045 comname += ": " + shortcuts;
2046 else if (!argsadded && !cmd.argument().empty())
2047 comname += ' ' + cmd.argument();
2049 if (!comname.empty()) {
2050 comname = rtrim(comname);
2051 dispatch_msg += '(' + rtrim(comname) + ')';
2054 LYXERR(Debug::ACTION) << "verbose dispatch msg "
2055 << to_utf8(dispatch_msg) << endl;
2056 if (!dispatch_msg.empty())
2057 lyx_view_->message(dispatch_msg);
2061 void LyXFunc::menuNew(string const & name, bool fromTemplate)
2063 // FIXME: initpath is not used. What to do?
2064 string initpath = lyxrc.document_path;
2065 string filename(name);
2067 if (lyx_view_->buffer()) {
2068 string const trypath = lyx_view_->buffer()->filePath();
2069 // If directory is writeable, use this as default.
2070 if (isDirWriteable(FileName(trypath)))
2074 static int newfile_number;
2076 if (filename.empty()) {
2077 filename = addName(lyxrc.document_path,
2078 "newfile" + convert<string>(++newfile_number) + ".lyx");
2079 while (theBufferList().exists(filename) ||
2080 fs::is_readable(FileName(filename).toFilesystemEncoding())) {
2082 filename = addName(lyxrc.document_path,
2083 "newfile" + convert<string>(newfile_number) +
2088 // The template stuff
2091 FileDialog fileDlg(_("Select template file"),
2092 LFUN_SELECT_FILE_SYNC,
2093 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2094 make_pair(_("Templates|#T#t"), from_utf8(lyxrc.template_path)));
2096 FileDialog::Result result =
2097 fileDlg.open(from_utf8(lyxrc.template_path),
2098 FileFilterList(_("LyX Documents (*.lyx)")),
2101 if (result.first == FileDialog::Later)
2103 if (result.second.empty())
2105 templname = to_utf8(result.second);
2108 Buffer * const b = newFile(filename, templname, !name.empty());
2110 lyx_view_->setBuffer(b);
2114 void LyXFunc::open(string const & fname)
2116 string initpath = lyxrc.document_path;
2118 if (lyx_view_->buffer()) {
2119 string const trypath = lyx_view_->buffer()->filePath();
2120 // If directory is writeable, use this as default.
2121 if (isDirWriteable(FileName(trypath)))
2127 if (fname.empty()) {
2128 FileDialog fileDlg(_("Select document to open"),
2130 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2131 make_pair(_("Examples|#E#e"), from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2133 FileDialog::Result result =
2134 fileDlg.open(from_utf8(initpath),
2135 FileFilterList(_("LyX Documents (*.lyx)")),
2138 if (result.first == FileDialog::Later)
2141 filename = to_utf8(result.second);
2143 // check selected filename
2144 if (filename.empty()) {
2145 lyx_view_->message(_("Canceled."));
2151 // get absolute path of file and add ".lyx" to the filename if
2153 FileName const fullname = fileSearch(string(), filename, "lyx");
2154 if (!fullname.empty())
2155 filename = fullname.absFilename();
2157 // if the file doesn't exist, let the user create one
2158 if (!fs::exists(fullname.toFilesystemEncoding())) {
2159 // the user specifically chose this name. Believe him.
2160 Buffer * const b = newFile(filename, string(), true);
2162 lyx_view_->setBuffer(b);
2166 docstring const disp_fn = makeDisplayPath(filename);
2167 lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
2170 Buffer * buf = lyx_view_->loadLyXFile(fullname);
2173 lyx_view_->setBuffer(buf);
2174 lyx_view_->showErrorList("Parse");
2175 str2 = bformat(_("Document %1$s opened."), disp_fn);
2177 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2179 lyx_view_->message(str2);
2183 void LyXFunc::doImport(string const & argument)
2186 string filename = split(argument, format, ' ');
2188 LYXERR(Debug::INFO) << "LyXFunc::doImport: " << format
2189 << " file: " << filename << endl;
2191 // need user interaction
2192 if (filename.empty()) {
2193 string initpath = lyxrc.document_path;
2195 if (lyx_view_->buffer()) {
2196 string const trypath = lyx_view_->buffer()->filePath();
2197 // If directory is writeable, use this as default.
2198 if (isDirWriteable(FileName(trypath)))
2202 docstring const text = bformat(_("Select %1$s file to import"),
2203 formats.prettyName(format));
2205 FileDialog fileDlg(text,
2207 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2208 make_pair(_("Examples|#E#e"),
2209 from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2211 docstring filter = formats.prettyName(format);
2214 filter += from_utf8(formats.extension(format));
2217 FileDialog::Result result =
2218 fileDlg.open(from_utf8(initpath),
2219 FileFilterList(filter),
2222 if (result.first == FileDialog::Later)
2225 filename = to_utf8(result.second);
2227 // check selected filename
2228 if (filename.empty())
2229 lyx_view_->message(_("Canceled."));
2232 if (filename.empty())
2235 // get absolute path of file
2236 FileName const fullname(makeAbsPath(filename));
2238 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
2240 // Check if the document already is open
2241 if (use_gui && theBufferList().exists(lyxfile.absFilename())) {
2242 if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) {
2243 lyx_view_->message(_("Canceled."));
2248 // if the file exists already, and we didn't do
2249 // -i lyx thefile.lyx, warn
2250 if (fs::exists(lyxfile.toFilesystemEncoding()) && fullname != lyxfile) {
2251 docstring const file = makeDisplayPath(lyxfile.absFilename(), 30);
2253 docstring text = bformat(_("The document %1$s already exists.\n\n"
2254 "Do you want to overwrite that document?"), file);
2255 int const ret = Alert::prompt(_("Overwrite document?"),
2256 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2259 lyx_view_->message(_("Canceled."));
2264 ErrorList errorList;
2265 Importer::Import(lyx_view_, fullname, format, errorList);
2266 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2270 void LyXFunc::closeBuffer()
2272 // goto bookmark to update bookmark pit.
2273 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2274 gotoBookmark(i+1, false, false);
2276 theBufferList().close(lyx_view_->buffer(), true);
2280 void LyXFunc::reloadBuffer()
2282 FileName filename(lyx_view_->buffer()->fileName());
2283 docstring const disp_fn = makeDisplayPath(filename.absFilename());
2286 Buffer * buf = lyx_view_->loadLyXFile(filename);
2289 lyx_view_->setBuffer(buf);
2290 lyx_view_->showErrorList("Parse");
2291 str = bformat(_("Document %1$s reloaded."), disp_fn);
2293 str = bformat(_("Could not reload document %1$s"), disp_fn);
2295 lyx_view_->message(str);
2298 // Each "lyx_view_" should have it's own message method. lyxview and
2299 // the minibuffer would use the minibuffer, but lyxserver would
2300 // send an ERROR signal to its client. Alejandro 970603
2301 // This function is bit problematic when it comes to NLS, to make the
2302 // lyx servers client be language indepenent we must not translate
2303 // strings sent to this func.
2304 void LyXFunc::setErrorMessage(docstring const & m) const
2306 dispatch_buffer = m;
2311 void LyXFunc::setMessage(docstring const & m) const
2313 dispatch_buffer = m;
2317 docstring const LyXFunc::viewStatusMessage()
2319 // When meta-fake key is pressed, show the key sequence so far + "M-".
2321 return keyseq.print(true) + "M-";
2323 // Else, when a non-complete key sequence is pressed,
2324 // show the available options.
2325 if (keyseq.length() > 0 && !keyseq.deleted())
2326 return keyseq.printOptions(true);
2328 BOOST_ASSERT(lyx_view_);
2329 if (!lyx_view_->buffer())
2330 return _("Welcome to LyX!");
2332 return view()->cursor().currentState();
2336 BufferView * LyXFunc::view() const
2338 BOOST_ASSERT(lyx_view_);
2339 return lyx_view_->view();
2343 bool LyXFunc::wasMetaKey() const
2345 return (meta_fake_bit != NoModifier);
2349 void LyXFunc::updateLayout(TextClassPtr const & oldlayout,
2352 lyx_view_->message(_("Converting document to new document class..."));
2354 StableDocIterator backcur(view()->cursor());
2355 ErrorList & el = buffer->errorList("Class Switch");
2356 cap::switchBetweenClasses(
2357 oldlayout, buffer->params().getTextClassPtr(),
2358 static_cast<InsetText &>(buffer->inset()), el);
2360 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
2362 buffer->errors("Class Switch");
2363 updateLabels(*buffer);
2369 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2371 // Why the switch you might ask. It is a trick to ensure that all
2372 // the elements in the LyXRCTags enum is handled. As you can see
2373 // there are no breaks at all. So it is just a huge fall-through.
2374 // The nice thing is that we will get a warning from the compiler
2375 // if we forget an element.
2376 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2378 case LyXRC::RC_ACCEPT_COMPOUND:
2379 case LyXRC::RC_ALT_LANG:
2380 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
2381 case LyXRC::RC_PLAINTEXT_LINELEN:
2382 case LyXRC::RC_AUTOREGIONDELETE:
2383 case LyXRC::RC_AUTORESET_OPTIONS:
2384 case LyXRC::RC_AUTOSAVE:
2385 case LyXRC::RC_AUTO_NUMBER:
2386 case LyXRC::RC_BACKUPDIR_PATH:
2387 case LyXRC::RC_BIBTEX_COMMAND:
2388 case LyXRC::RC_BINDFILE:
2389 case LyXRC::RC_CHECKLASTFILES:
2390 case LyXRC::RC_USELASTFILEPOS:
2391 case LyXRC::RC_LOADSESSION:
2392 case LyXRC::RC_CHKTEX_COMMAND:
2393 case LyXRC::RC_CONVERTER:
2394 case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
2395 case LyXRC::RC_COPIER:
2396 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2397 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2398 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2399 case LyXRC::RC_DATE_INSERT_FORMAT:
2400 case LyXRC::RC_DEFAULT_LANGUAGE:
2401 case LyXRC::RC_DEFAULT_PAPERSIZE:
2402 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2403 case LyXRC::RC_DISPLAY_GRAPHICS:
2404 case LyXRC::RC_DOCUMENTPATH:
2405 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2406 string const encoded = FileName(
2407 lyxrc_new.document_path).toFilesystemEncoding();
2408 if (fs::exists(encoded) && fs::is_directory(encoded))
2409 support::package().document_dir() = FileName(lyxrc.document_path);
2411 case LyXRC::RC_ESC_CHARS:
2412 case LyXRC::RC_FONT_ENCODING:
2413 case LyXRC::RC_FORMAT:
2414 case LyXRC::RC_INDEX_COMMAND:
2415 case LyXRC::RC_INPUT:
2416 case LyXRC::RC_KBMAP:
2417 case LyXRC::RC_KBMAP_PRIMARY:
2418 case LyXRC::RC_KBMAP_SECONDARY:
2419 case LyXRC::RC_LABEL_INIT_LENGTH:
2420 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2421 case LyXRC::RC_LANGUAGE_AUTO_END:
2422 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2423 case LyXRC::RC_LANGUAGE_COMMAND_END:
2424 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2425 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2426 case LyXRC::RC_LANGUAGE_PACKAGE:
2427 case LyXRC::RC_LANGUAGE_USE_BABEL:
2428 case LyXRC::RC_MAKE_BACKUP:
2429 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2430 case LyXRC::RC_NUMLASTFILES:
2431 case LyXRC::RC_PATH_PREFIX:
2432 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2433 support::prependEnvPath("PATH", lyxrc.path_prefix);
2435 case LyXRC::RC_PERS_DICT:
2436 case LyXRC::RC_PREVIEW:
2437 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2438 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2439 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2440 case LyXRC::RC_PRINTCOPIESFLAG:
2441 case LyXRC::RC_PRINTER:
2442 case LyXRC::RC_PRINTEVENPAGEFLAG:
2443 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2444 case LyXRC::RC_PRINTFILEEXTENSION:
2445 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2446 case LyXRC::RC_PRINTODDPAGEFLAG:
2447 case LyXRC::RC_PRINTPAGERANGEFLAG:
2448 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2449 case LyXRC::RC_PRINTPAPERFLAG:
2450 case LyXRC::RC_PRINTREVERSEFLAG:
2451 case LyXRC::RC_PRINTSPOOL_COMMAND:
2452 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2453 case LyXRC::RC_PRINTTOFILE:
2454 case LyXRC::RC_PRINTTOPRINTER:
2455 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2456 case LyXRC::RC_PRINT_COMMAND:
2457 case LyXRC::RC_RTL_SUPPORT:
2458 case LyXRC::RC_SCREEN_DPI:
2459 case LyXRC::RC_SCREEN_FONT_ROMAN:
2460 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2461 case LyXRC::RC_SCREEN_FONT_SANS:
2462 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2463 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2464 case LyXRC::RC_SCREEN_FONT_SIZES:
2465 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2466 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2467 case LyXRC::RC_SCREEN_GEOMETRY_HEIGHT:
2468 case LyXRC::RC_SCREEN_GEOMETRY_WIDTH:
2469 case LyXRC::RC_SCREEN_GEOMETRY_XYSAVED:
2470 case LyXRC::RC_SCREEN_ZOOM:
2471 case LyXRC::RC_SERVERPIPE:
2472 case LyXRC::RC_SET_COLOR:
2473 case LyXRC::RC_SHOW_BANNER:
2474 case LyXRC::RC_SPELL_COMMAND:
2475 case LyXRC::RC_TEMPDIRPATH:
2476 case LyXRC::RC_TEMPLATEPATH:
2477 case LyXRC::RC_TEX_ALLOWS_SPACES:
2478 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2479 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2480 support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2482 case LyXRC::RC_UIFILE:
2483 case LyXRC::RC_USER_EMAIL:
2484 case LyXRC::RC_USER_NAME:
2485 case LyXRC::RC_USETEMPDIR:
2486 case LyXRC::RC_USE_ALT_LANG:
2487 case LyXRC::RC_USE_CONVERTER_CACHE:
2488 case LyXRC::RC_USE_ESC_CHARS:
2489 case LyXRC::RC_USE_INP_ENC:
2490 case LyXRC::RC_USE_PERS_DICT:
2491 case LyXRC::RC_USE_SPELL_LIB:
2492 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2493 case LyXRC::RC_VIEWER:
2494 case LyXRC::RC_LAST: