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 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();
169 Alert::information(_("System reconfigured"),
170 _("The system has been reconfigured.\n"
171 "You need to restart LyX to make use of any\n"
172 "updated document class specifications."));
176 bool getLocalStatus(Cursor cursor, FuncRequest const & cmd, FuncStatus & status)
178 // Try to fix cursor in case it is broken.
179 cursor.fixIfBroken();
181 // This is, of course, a mess. Better create a new doc iterator and use
182 // this in Inset::getStatus. This might require an additional
183 // BufferView * arg, though (which should be avoided)
184 //Cursor safe = *this;
186 for ( ; cursor.depth(); cursor.pop()) {
187 //lyxerr << "\nCursor::getStatus: cmd: " << cmd << endl << *this << endl;
188 BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
189 BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
190 BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
192 // The inset's getStatus() will return 'true' if it made
193 // a definitive decision on whether it want to handle the
194 // request or not. The result of this decision is put into
195 // the 'status' parameter.
196 if (cursor.inset().getStatus(cursor, cmd, status)) {
205 /** Return the change status at cursor position, taking in account the
206 * status at each level of the document iterator (a table in a deleted
207 * footnote is deleted).
208 * When \param outer is true, the top slice is not looked at.
210 Change::Type lookupChangeType(DocIterator const & dit, bool outer = false)
212 size_t const depth = dit.depth() - (outer ? 1 : 0);
214 for (size_t i = 0 ; i < depth ; ++i) {
215 CursorSlice const & slice = dit[i];
216 if (!slice.inset().inMathed()
217 && slice.pos() < slice.paragraph().size()) {
218 Change::Type const ch = slice.paragraph().lookupChange(slice.pos()).type;
219 if (ch != Change::UNCHANGED)
223 return Change::UNCHANGED;
230 : lyx_view_(0), encoded_last_key(0), meta_fake_bit(NoModifier)
235 void LyXFunc::initKeySequences(KeyMap * kb)
237 keyseq = KeySequence(kb, kb);
238 cancel_meta_seq = KeySequence(kb, kb);
242 void LyXFunc::setLyXView(LyXView * lv)
244 if (!quitting && lyx_view_ && lyx_view_->view() && lyx_view_ != lv)
245 // save current selection to the selection buffer to allow
246 // middle-button paste in another window
247 cap::saveSelection(lyx_view_->view()->cursor());
252 void LyXFunc::handleKeyFunc(kb_action action)
254 char_type c = encoded_last_key;
259 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
260 lyx_view_->view()->getIntl().getTransManager().deadkey(
261 c, get_accent(action).accent, view()->cursor().innerText(), view()->cursor());
262 // Need to clear, in case the minibuffer calls these
265 // copied verbatim from do_accent_char
266 view()->cursor().resetAnchor();
267 view()->processUpdateFlags(Update::FitCursor);
271 void LyXFunc::gotoBookmark(unsigned int idx, bool openFile, bool switchToBuffer)
273 BOOST_ASSERT(lyx_view_);
274 if (!LyX::ref().session().bookmarks().isValid(idx))
276 BookmarksSection::Bookmark const & bm = LyX::ref().session().bookmarks().bookmark(idx);
277 BOOST_ASSERT(!bm.filename.empty());
278 string const file = bm.filename.absFilename();
279 // if the file is not opened, open it.
280 if (!theBufferList().exists(file)) {
282 dispatch(FuncRequest(LFUN_FILE_OPEN, file));
286 // open may fail, so we need to test it again
287 if (!theBufferList().exists(file))
290 // if the current buffer is not that one, switch to it.
291 if (lyx_view_->buffer()->fileName() != file) {
294 dispatch(FuncRequest(LFUN_BUFFER_SWITCH, file));
296 // moveToPosition try paragraph id first and then paragraph (pit, pos).
297 if (!view()->moveToPosition(bm.bottom_pit, bm.bottom_pos,
298 bm.top_id, bm.top_pos))
301 // Cursor jump succeeded!
302 Cursor const & cur = view()->cursor();
303 pit_type new_pit = cur.pit();
304 pos_type new_pos = cur.pos();
305 int new_id = cur.paragraph().id();
307 // if bottom_pit, bottom_pos or top_id has been changed, update bookmark
308 // see http://bugzilla.lyx.org/show_bug.cgi?id=3092
309 if (bm.bottom_pit != new_pit || bm.bottom_pos != new_pos
310 || bm.top_id != new_id) {
311 const_cast<BookmarksSection::Bookmark &>(bm).updatePos(
312 new_pit, new_pos, new_id);
318 void restartCursor(LyXView * lv)
320 /* When we move around, or type, it's nice to be able to see
321 * the cursor immediately after the keypress.
323 if (lv && lv->currentWorkArea())
324 lv->currentWorkArea()->startBlinkingCursor();
328 void LyXFunc::processKeySym(KeySymbol const & keysym, KeyModifier state)
330 LYXERR(Debug::KEY) << "KeySym is " << keysym.getSymbolName() << endl;
332 // Do nothing if we have nothing (JMarc)
333 if (!keysym.isOK()) {
334 LYXERR(Debug::KEY) << "Empty kbd action (probably composing)"
336 restartCursor(lyx_view_);
340 if (keysym.isModifier()) {
341 LYXERR(Debug::KEY) << "isModifier true" << endl;
342 restartCursor(lyx_view_);
346 //Encoding const * encoding = view()->cursor().getEncoding();
347 //encoded_last_key = keysym.getISOEncoded(encoding ? encoding->name() : "");
348 // FIXME: encoded_last_key shadows the member variable of the same
349 // name. Is that intended?
350 char_type encoded_last_key = keysym.getUCSEncoded();
352 // Do a one-deep top-level lookup for
353 // cancel and meta-fake keys. RVDK_PATCH_5
354 cancel_meta_seq.reset();
356 FuncRequest func = cancel_meta_seq.addkey(keysym, state);
357 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
358 << " action first set to [" << func.action << ']'
361 // When not cancel or meta-fake, do the normal lookup.
362 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
363 // Mostly, meta_fake_bit = NoModifier. RVDK_PATCH_5.
364 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_PREFIX)) {
365 // remove Caps Lock and Mod2 as a modifiers
366 func = keyseq.addkey(keysym, (state | meta_fake_bit));
367 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
368 << "action now set to ["
369 << func.action << ']' << endl;
372 // Dont remove this unless you know what you are doing.
373 meta_fake_bit = NoModifier;
375 // Can this happen now ?
376 if (func.action == LFUN_NOACTION)
377 func = FuncRequest(LFUN_COMMAND_PREFIX);
379 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
381 << func.action << "]["
382 << to_utf8(keyseq.print(false)) << ']'
385 // already here we know if it any point in going further
386 // why not return already here if action == -1 and
387 // num_bytes == 0? (Lgb)
389 if (keyseq.length() > 1)
390 lyx_view_->message(keyseq.print(true));
393 // Maybe user can only reach the key via holding down shift.
394 // Let's see. But only if shift is the only modifier
395 if (func.action == LFUN_UNKNOWN_ACTION && state == ShiftModifier) {
396 LYXERR(Debug::KEY) << "Trying without shift" << endl;
397 func = keyseq.addkey(keysym, NoModifier);
398 LYXERR(Debug::KEY) << "Action now " << func.action << endl;
401 if (func.action == LFUN_UNKNOWN_ACTION) {
402 // Hmm, we didn't match any of the keysequences. See
403 // if it's normal insertable text not already covered
405 if (keysym.isText() && keyseq.length() == 1) {
406 LYXERR(Debug::KEY) << "isText() is true, inserting." << endl;
407 func = FuncRequest(LFUN_SELF_INSERT,
408 FuncRequest::KEYBOARD);
410 LYXERR(Debug::KEY) << "Unknown, !isText() - giving up" << endl;
411 lyx_view_->message(_("Unknown function."));
412 restartCursor(lyx_view_);
417 if (func.action == LFUN_SELF_INSERT) {
418 if (encoded_last_key != 0) {
419 docstring const arg(1, encoded_last_key);
420 dispatch(FuncRequest(LFUN_SELF_INSERT, arg,
421 FuncRequest::KEYBOARD));
423 << "SelfInsert arg[`" << to_utf8(arg) << "']" << endl;
429 restartCursor(lyx_view_);
433 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
435 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
438 /* In LyX/Mac, when a dialog is open, the menus of the
439 application can still be accessed without giving focus to
440 the main window. In this case, we want to disable the menu
441 entries that are buffer-related.
443 Note that this code is not perfect, as bug 1941 attests:
444 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
446 Buffer * buf = lyx_view_? lyx_view_->buffer() : 0;
447 if (lyx_view_ && cmd.origin == FuncRequest::MENU && !lyx_view_->hasFocus())
450 if (cmd.action == LFUN_NOACTION) {
451 flag.message(from_utf8(N_("Nothing to do")));
456 switch (cmd.action) {
457 case LFUN_UNKNOWN_ACTION:
458 #ifndef HAVE_LIBAIKSAURUS
459 case LFUN_THESAURUS_ENTRY:
469 if (flag.unknown()) {
470 flag.message(from_utf8(N_("Unknown action")));
474 if (!flag.enabled()) {
475 if (flag.message().empty())
476 flag.message(from_utf8(N_("Command disabled")));
480 // Check whether we need a buffer
481 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
483 flag.message(from_utf8(N_("Command not allowed with"
484 "out any document open")));
489 // I would really like to avoid having this switch and rather try to
490 // encode this in the function itself.
491 // -- And I'd rather let an inset decide which LFUNs it is willing
492 // to handle (Andre')
494 switch (cmd.action) {
495 case LFUN_BUFFER_TOGGLE_READ_ONLY:
496 flag.setOnOff(buf->isReadonly());
499 case LFUN_BUFFER_SWITCH:
500 // toggle on the current buffer, but do not toggle off
501 // the other ones (is that a good idea?)
502 if (buf && to_utf8(cmd.argument()) == buf->fileName())
506 case LFUN_BUFFER_EXPORT:
507 enable = cmd.argument() == "custom"
508 || Exporter::isExportable(*buf, to_utf8(cmd.argument()));
511 case LFUN_BUFFER_CHKTEX:
512 enable = buf->isLatex() && !lyxrc.chktex_command.empty();
515 case LFUN_BUILD_PROGRAM:
516 enable = Exporter::isExportable(*buf, "program");
519 case LFUN_VC_REGISTER:
520 enable = !buf->lyxvc().inUse();
522 case LFUN_VC_CHECK_IN:
523 enable = buf->lyxvc().inUse() && !buf->isReadonly();
525 case LFUN_VC_CHECK_OUT:
526 enable = buf->lyxvc().inUse() && buf->isReadonly();
529 case LFUN_VC_UNDO_LAST:
530 enable = buf->lyxvc().inUse();
532 case LFUN_BUFFER_RELOAD:
533 enable = !buf->isUnnamed() && fs::exists(buf->fileName())
534 && (!buf->isClean() || buf->isExternallyModified(Buffer::timestamp_method));
537 case LFUN_INSET_APPLY: {
542 string const name = cmd.getArg(0);
543 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
545 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
547 if (!inset->getStatus(view()->cursor(), fr, fs)) {
548 // Every inset is supposed to handle this
553 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
554 flag |= getStatus(fr);
556 enable = flag.enabled();
560 case LFUN_DIALOG_TOGGLE:
561 flag.setOnOff(lyx_view_->getDialogs().visible(cmd.getArg(0)));
562 // fall through to set "enable"
563 case LFUN_DIALOG_SHOW: {
564 string const name = cmd.getArg(0);
566 enable = name == "aboutlyx"
567 || name == "file" //FIXME: should be removed.
569 || name == "texinfo";
570 else if (name == "print")
571 enable = Exporter::isExportable(*buf, "dvi")
572 && lyxrc.print_command != "none";
573 else if (name == "character") {
577 InsetCode ic = view()->cursor().inset().lyxCode();
578 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
581 else if (name == "latexlog")
582 enable = isFileReadable(FileName(buf->getLogName().second));
583 else if (name == "spellchecker")
584 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
585 enable = !buf->isReadonly();
589 else if (name == "vclog")
590 enable = buf->lyxvc().inUse();
594 case LFUN_DIALOG_UPDATE: {
595 string const name = cmd.getArg(0);
597 enable = name == "prefs";
601 case LFUN_CITATION_INSERT: {
602 FuncRequest fr(LFUN_INSET_INSERT, "citation");
603 enable = getStatus(fr).enabled();
607 case LFUN_BUFFER_WRITE: {
608 enable = lyx_view_->buffer()->isUnnamed()
609 || !lyx_view_->buffer()->isClean();
614 case LFUN_BUFFER_WRITE_ALL: {
615 // We enable the command only if there are some modified buffers
616 Buffer * first = theBufferList().first();
617 bool modified = false;
621 // We cannot use a for loop as the buffer list is a cycle.
627 b = theBufferList().next(b);
628 } while (b != first);
636 case LFUN_BOOKMARK_GOTO: {
637 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
638 enable = LyX::ref().session().bookmarks().isValid(num);
642 case LFUN_BOOKMARK_CLEAR:
643 enable = LyX::ref().session().bookmarks().size() > 0;
646 case LFUN_TOOLBAR_TOGGLE: {
647 bool const current = lyx_view_->isToolbarVisible(cmd.getArg(0));
648 flag.setOnOff(current);
651 case LFUN_WINDOW_CLOSE: {
652 enable = (theApp()->gui().viewIds().size() > 1);
656 // this one is difficult to get right. As a half-baked
657 // solution, we consider only the first action of the sequence
658 case LFUN_COMMAND_SEQUENCE: {
659 // argument contains ';'-terminated commands
660 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
661 FuncRequest func(lyxaction.lookupFunc(firstcmd));
662 func.origin = cmd.origin;
663 flag = getStatus(func);
666 case LFUN_BUFFER_NEW:
667 case LFUN_BUFFER_NEW_TEMPLATE:
668 case LFUN_WORD_FIND_FORWARD:
669 case LFUN_WORD_FIND_BACKWARD:
670 case LFUN_COMMAND_PREFIX:
671 case LFUN_COMMAND_EXECUTE:
673 case LFUN_META_PREFIX:
674 case LFUN_BUFFER_CLOSE:
675 case LFUN_BUFFER_WRITE_AS:
676 case LFUN_BUFFER_UPDATE:
677 case LFUN_BUFFER_VIEW:
678 case LFUN_MASTER_BUFFER_UPDATE:
679 case LFUN_MASTER_BUFFER_VIEW:
680 case LFUN_BUFFER_IMPORT:
681 case LFUN_BUFFER_AUTO_SAVE:
682 case LFUN_RECONFIGURE:
686 case LFUN_DROP_LAYOUTS_CHOICE:
688 case LFUN_SERVER_GET_NAME:
689 case LFUN_SERVER_NOTIFY:
690 case LFUN_SERVER_GOTO_FILE_ROW:
691 case LFUN_DIALOG_HIDE:
692 case LFUN_DIALOG_DISCONNECT_INSET:
693 case LFUN_BUFFER_CHILD_OPEN:
694 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
695 case LFUN_KEYMAP_OFF:
696 case LFUN_KEYMAP_PRIMARY:
697 case LFUN_KEYMAP_SECONDARY:
698 case LFUN_KEYMAP_TOGGLE:
700 case LFUN_BUFFER_EXPORT_CUSTOM:
701 case LFUN_BUFFER_PRINT:
702 case LFUN_PREFERENCES_SAVE:
703 case LFUN_SCREEN_FONT_UPDATE:
706 case LFUN_EXTERNAL_EDIT:
707 case LFUN_GRAPHICS_EDIT:
708 case LFUN_ALL_INSETS_TOGGLE:
709 case LFUN_BUFFER_LANGUAGE:
710 case LFUN_TEXTCLASS_APPLY:
711 case LFUN_TEXTCLASS_LOAD:
712 case LFUN_BUFFER_SAVE_AS_DEFAULT:
713 case LFUN_BUFFER_PARAMS_APPLY:
714 case LFUN_LAYOUT_MODULES_CLEAR:
715 case LFUN_LAYOUT_MODULE_ADD:
716 case LFUN_LAYOUT_RELOAD:
717 case LFUN_LYXRC_APPLY:
718 case LFUN_BUFFER_NEXT:
719 case LFUN_BUFFER_PREVIOUS:
720 case LFUN_WINDOW_NEW:
722 // these are handled in our dispatch()
730 if (!getLocalStatus(view()->cursor(), cmd, flag))
731 flag = view()->getStatus(cmd);
737 // Can we use a readonly buffer?
738 if (buf && buf->isReadonly()
739 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
740 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
741 flag.message(from_utf8(N_("Document is read-only")));
745 // Are we in a DELETED change-tracking region?
747 && lookupChangeType(view()->cursor(), true) == Change::DELETED
748 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
749 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
750 flag.message(from_utf8(N_("This portion of the document is deleted.")));
754 // the default error message if we disable the command
755 if (!flag.enabled() && flag.message().empty())
756 flag.message(from_utf8(N_("Command disabled")));
762 bool LyXFunc::ensureBufferClean(BufferView * bv)
764 Buffer & buf = bv->buffer();
768 docstring const file = makeDisplayPath(buf.fileName(), 30);
769 docstring text = bformat(_("The document %1$s has unsaved "
770 "changes.\n\nDo you want to save "
771 "the document?"), file);
772 int const ret = Alert::prompt(_("Save changed document?"),
773 text, 0, 1, _("&Save"),
777 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
779 return buf.isClean();
785 void showPrintError(string const & name)
787 docstring str = bformat(_("Could not print the document %1$s.\n"
788 "Check that your printer is set up correctly."),
789 makeDisplayPath(name, 50));
790 Alert::error(_("Print document failed"), str);
794 void loadTextClass(string const & name)
796 std::pair<bool, textclass_type> const tc_pair =
797 textclasslist.numberOfClass(name);
799 if (!tc_pair.first) {
800 lyxerr << "Document class \"" << name
801 << "\" does not exist."
806 textclass_type const tc = tc_pair.second;
808 if (!textclasslist[tc].load()) {
809 docstring s = bformat(_("The document class %1$s."
810 "could not be loaded."),
811 from_utf8(textclasslist[tc].name()));
812 Alert::error(_("Could not load class"), s);
817 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
822 void LyXFunc::dispatch(FuncRequest const & cmd)
824 string const argument = to_utf8(cmd.argument());
825 kb_action const action = cmd.action;
827 LYXERR(Debug::ACTION) << endl << "LyXFunc::dispatch: cmd: " << cmd << endl;
828 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
830 // we have not done anything wrong yet.
832 dispatch_buffer.erase();
834 // redraw the screen at the end (first of the two drawing steps).
835 //This is done unless explicitely requested otherwise
836 Update::flags updateFlags = Update::FitCursor;
838 FuncStatus const flag = getStatus(cmd);
839 if (!flag.enabled()) {
840 // We cannot use this function here
841 LYXERR(Debug::ACTION) << "LyXFunc::dispatch: "
842 << lyxaction.getActionName(action)
843 << " [" << action << "] is disabled at this location"
845 setErrorMessage(flag.message());
849 case LFUN_WORD_FIND_FORWARD:
850 case LFUN_WORD_FIND_BACKWARD: {
851 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
852 static docstring last_search;
853 docstring searched_string;
855 if (!cmd.argument().empty()) {
856 last_search = cmd.argument();
857 searched_string = cmd.argument();
859 searched_string = last_search;
862 if (searched_string.empty())
865 bool const fw = action == LFUN_WORD_FIND_FORWARD;
866 docstring const data =
867 find2string(searched_string, true, false, fw);
868 find(view(), FuncRequest(LFUN_WORD_FIND, data));
872 case LFUN_COMMAND_PREFIX:
873 BOOST_ASSERT(lyx_view_);
874 lyx_view_->message(keyseq.printOptions(true));
877 case LFUN_COMMAND_EXECUTE:
878 BOOST_ASSERT(lyx_view_);
879 lyx_view_->showMiniBuffer(true);
883 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
885 meta_fake_bit = NoModifier;
886 if (lyx_view_->buffer())
887 // cancel any selection
888 dispatch(FuncRequest(LFUN_MARK_OFF));
889 setMessage(from_ascii(N_("Cancel")));
892 case LFUN_META_PREFIX:
893 meta_fake_bit = AltModifier;
894 setMessage(keyseq.print(true));
897 case LFUN_BUFFER_TOGGLE_READ_ONLY: {
898 BOOST_ASSERT(lyx_view_ && lyx_view_->view() && lyx_view_->buffer());
899 Buffer * buf = lyx_view_->buffer();
900 if (buf->lyxvc().inUse())
901 buf->lyxvc().toggleReadOnly();
903 buf->setReadonly(!lyx_view_->buffer()->isReadonly());
907 // --- Menus -----------------------------------------------
908 case LFUN_BUFFER_NEW:
909 menuNew(argument, false);
910 updateFlags = Update::None;
913 case LFUN_BUFFER_NEW_TEMPLATE:
914 menuNew(argument, true);
915 updateFlags = Update::None;
918 case LFUN_BUFFER_CLOSE:
920 updateFlags = Update::None;
923 case LFUN_BUFFER_WRITE:
924 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
925 if (!lyx_view_->buffer()->isUnnamed()) {
926 docstring const str = bformat(_("Saving document %1$s..."),
927 makeDisplayPath(lyx_view_->buffer()->fileName()));
928 lyx_view_->message(str);
929 lyx_view_->buffer()->menuWrite();
930 lyx_view_->message(str + _(" done."));
932 lyx_view_->buffer()->writeAs();
934 updateFlags = Update::None;
937 case LFUN_BUFFER_WRITE_AS:
938 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
939 lyx_view_->buffer()->writeAs(argument);
940 updateFlags = Update::None;
943 case LFUN_BUFFER_WRITE_ALL: {
944 Buffer * first = theBufferList().first();
947 lyx_view_->message(_("Saving all documents..."));
949 // We cannot use a for loop as the buffer list cycles.
952 if (!b->isUnnamed()) {
954 lyxerr[Debug::ACTION] << "Saved " << b->fileName() << endl;
958 b = theBufferList().next(b);
959 } while (b != first);
960 lyx_view_->message(_("All documents saved."));
963 updateFlags = Update::None;
967 case LFUN_BUFFER_RELOAD: {
968 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
969 docstring const file = makeDisplayPath(lyx_view_->buffer()->fileName(), 20);
970 docstring text = bformat(_("Any changes will be lost. Are you sure "
971 "you want to revert to the saved version of the document %1$s?"), file);
972 int const ret = Alert::prompt(_("Revert to saved document?"),
973 text, 1, 1, _("&Revert"), _("&Cancel"));
980 case LFUN_BUFFER_UPDATE:
981 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
982 Exporter::Export(lyx_view_->buffer(), argument, true);
985 case LFUN_BUFFER_VIEW:
986 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
987 Exporter::preview(lyx_view_->buffer(), argument);
990 case LFUN_MASTER_BUFFER_UPDATE:
991 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->getMasterBuffer());
992 Exporter::Export(lyx_view_->buffer()->getMasterBuffer(), argument, true);
995 case LFUN_MASTER_BUFFER_VIEW:
996 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->getMasterBuffer());
997 Exporter::preview(lyx_view_->buffer()->getMasterBuffer(), argument);
1000 case LFUN_BUILD_PROGRAM:
1001 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1002 Exporter::Export(lyx_view_->buffer(), "program", true);
1005 case LFUN_BUFFER_CHKTEX:
1006 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1007 lyx_view_->buffer()->runChktex();
1010 case LFUN_BUFFER_EXPORT:
1011 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1012 if (argument == "custom")
1013 lyx_view_->getDialogs().show("sendto");
1015 Exporter::Export(lyx_view_->buffer(), argument, false);
1019 case LFUN_BUFFER_EXPORT_CUSTOM: {
1020 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1022 string command = split(argument, format_name, ' ');
1023 Format const * format = formats.getFormat(format_name);
1025 lyxerr << "Format \"" << format_name
1026 << "\" not recognized!"
1031 Buffer * buffer = lyx_view_->buffer();
1033 // The name of the file created by the conversion process
1036 // Output to filename
1037 if (format->name() == "lyx") {
1038 string const latexname =
1039 buffer->getLatexName(false);
1040 filename = changeExtension(latexname,
1041 format->extension());
1042 filename = addName(buffer->temppath(), filename);
1044 if (!buffer->writeFile(FileName(filename)))
1048 Exporter::Export(buffer, format_name, true, filename);
1051 // Substitute $$FName for filename
1052 if (!contains(command, "$$FName"))
1053 command = "( " + command + " ) < $$FName";
1054 command = subst(command, "$$FName", filename);
1056 // Execute the command in the background
1058 call.startscript(Systemcall::DontWait, command);
1062 case LFUN_BUFFER_PRINT: {
1063 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1064 // FIXME: cmd.getArg() might fail if one of the arguments
1065 // contains double quotes
1066 string target = cmd.getArg(0);
1067 string target_name = cmd.getArg(1);
1068 string command = cmd.getArg(2);
1071 || target_name.empty()
1072 || command.empty()) {
1073 lyxerr << "Unable to parse \""
1074 << argument << '"' << endl;
1077 if (target != "printer" && target != "file") {
1078 lyxerr << "Unrecognized target \""
1079 << target << '"' << endl;
1083 Buffer * buffer = lyx_view_->buffer();
1085 if (!Exporter::Export(buffer, "dvi", true)) {
1086 showPrintError(buffer->fileName());
1090 // Push directory path.
1091 string const path = buffer->temppath();
1092 // Prevent the compiler from optimizing away p
1094 support::Path p(pp);
1096 // there are three cases here:
1097 // 1. we print to a file
1098 // 2. we print directly to a printer
1099 // 3. we print using a spool command (print to file first)
1102 string const dviname =
1103 changeExtension(buffer->getLatexName(true),
1106 if (target == "printer") {
1107 if (!lyxrc.print_spool_command.empty()) {
1108 // case 3: print using a spool
1109 string const psname =
1110 changeExtension(dviname,".ps");
1111 command += ' ' + lyxrc.print_to_file
1114 + quoteName(dviname);
1117 lyxrc.print_spool_command + ' ';
1118 if (target_name != "default") {
1119 command2 += lyxrc.print_spool_printerprefix
1123 command2 += quoteName(psname);
1125 // If successful, then spool command
1126 res = one.startscript(
1131 res = one.startscript(
1132 Systemcall::DontWait,
1135 // case 2: print directly to a printer
1136 if (target_name != "default")
1137 command += ' ' + lyxrc.print_to_printer + target_name + ' ';
1138 res = one.startscript(
1139 Systemcall::DontWait,
1140 command + quoteName(dviname));
1144 // case 1: print to a file
1145 FileName const filename(makeAbsPath(target_name,
1146 lyx_view_->buffer()->filePath()));
1147 FileName const dvifile(makeAbsPath(dviname, path));
1148 if (fs::exists(filename.toFilesystemEncoding())) {
1149 docstring text = bformat(
1150 _("The file %1$s already exists.\n\n"
1151 "Do you want to overwrite that file?"),
1152 makeDisplayPath(filename.absFilename()));
1153 if (Alert::prompt(_("Overwrite file?"),
1154 text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
1157 command += ' ' + lyxrc.print_to_file
1158 + quoteName(filename.toFilesystemEncoding())
1160 + quoteName(dvifile.toFilesystemEncoding());
1161 res = one.startscript(Systemcall::DontWait,
1166 showPrintError(buffer->fileName());
1170 case LFUN_BUFFER_IMPORT:
1175 // quitting is triggered by the gui code
1176 // (leaving the event loop).
1177 lyx_view_->message(from_utf8(N_("Exiting.")));
1178 if (theBufferList().quitWriteAll())
1179 theApp()->gui().closeAllViews();
1182 case LFUN_BUFFER_AUTO_SAVE:
1183 lyx_view_->buffer()->autoSave();
1186 case LFUN_RECONFIGURE:
1187 BOOST_ASSERT(lyx_view_);
1188 // argument is any additional parameter to the configure.py command
1189 reconfigure(*lyx_view_, argument);
1192 case LFUN_HELP_OPEN: {
1193 BOOST_ASSERT(lyx_view_);
1194 string const arg = argument;
1196 setErrorMessage(from_ascii(N_("Missing argument")));
1199 FileName const fname = i18nLibFileSearch("doc", arg, "lyx");
1200 if (fname.empty()) {
1201 lyxerr << "LyX: unable to find documentation file `"
1202 << arg << "'. Bad installation?" << endl;
1205 lyx_view_->message(bformat(_("Opening help file %1$s..."),
1206 makeDisplayPath(fname.absFilename())));
1207 Buffer * buf = lyx_view_->loadLyXFile(fname, false);
1210 lyx_view_->setBuffer(buf);
1211 lyx_view_->showErrorList("Parse");
1213 updateFlags = Update::None;
1217 // --- version control -------------------------------
1218 case LFUN_VC_REGISTER:
1219 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1220 if (!ensureBufferClean(view()))
1222 if (!lyx_view_->buffer()->lyxvc().inUse()) {
1223 lyx_view_->buffer()->lyxvc().registrer();
1226 updateFlags = Update::Force;
1229 case LFUN_VC_CHECK_IN:
1230 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1231 if (!ensureBufferClean(view()))
1233 if (lyx_view_->buffer()->lyxvc().inUse()
1234 && !lyx_view_->buffer()->isReadonly()) {
1235 lyx_view_->buffer()->lyxvc().checkIn();
1240 case LFUN_VC_CHECK_OUT:
1241 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1242 if (!ensureBufferClean(view()))
1244 if (lyx_view_->buffer()->lyxvc().inUse()
1245 && lyx_view_->buffer()->isReadonly()) {
1246 lyx_view_->buffer()->lyxvc().checkOut();
1251 case LFUN_VC_REVERT:
1252 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1253 lyx_view_->buffer()->lyxvc().revert();
1257 case LFUN_VC_UNDO_LAST:
1258 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1259 lyx_view_->buffer()->lyxvc().undoLast();
1263 // --- buffers ----------------------------------------
1264 case LFUN_BUFFER_SWITCH:
1265 BOOST_ASSERT(lyx_view_);
1266 lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1267 updateFlags = Update::None;
1270 case LFUN_BUFFER_NEXT:
1271 BOOST_ASSERT(lyx_view_);
1272 lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer()));
1273 updateFlags = Update::None;
1276 case LFUN_BUFFER_PREVIOUS:
1277 BOOST_ASSERT(lyx_view_);
1278 lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer()));
1279 updateFlags = Update::None;
1282 case LFUN_FILE_NEW: {
1283 BOOST_ASSERT(lyx_view_);
1285 string tmpname = split(argument, name, ':'); // Split filename
1286 Buffer * const b = newFile(name, tmpname);
1288 lyx_view_->setBuffer(b);
1289 updateFlags = Update::None;
1293 case LFUN_FILE_OPEN:
1294 BOOST_ASSERT(lyx_view_);
1296 updateFlags = Update::None;
1299 case LFUN_DROP_LAYOUTS_CHOICE:
1300 BOOST_ASSERT(lyx_view_);
1301 lyx_view_->openLayoutList();
1304 case LFUN_MENU_OPEN:
1305 BOOST_ASSERT(lyx_view_);
1306 lyx_view_->openMenu(from_utf8(argument));
1309 // --- lyxserver commands ----------------------------
1310 case LFUN_SERVER_GET_NAME:
1311 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1312 setMessage(from_utf8(lyx_view_->buffer()->fileName()));
1313 LYXERR(Debug::INFO) << "FNAME["
1314 << lyx_view_->buffer()->fileName()
1318 case LFUN_SERVER_NOTIFY:
1319 dispatch_buffer = keyseq.print(false);
1320 theServer().notifyClient(to_utf8(dispatch_buffer));
1323 case LFUN_SERVER_GOTO_FILE_ROW: {
1324 BOOST_ASSERT(lyx_view_);
1327 istringstream is(argument);
1328 is >> file_name >> row;
1330 bool loaded = false;
1331 if (prefixIs(file_name, package().temp_dir().absFilename()))
1332 // Needed by inverse dvi search. If it is a file
1333 // in tmpdir, call the apropriated function
1334 buf = theBufferList().getBufferFromTmp(file_name);
1336 // Must replace extension of the file to be .lyx
1337 // and get full path
1338 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1339 // Either change buffer or load the file
1340 if (theBufferList().exists(s.absFilename()))
1341 buf = theBufferList().getBuffer(s.absFilename());
1343 buf = lyx_view_->loadLyXFile(s);
1349 updateFlags = Update::None;
1354 lyx_view_->setBuffer(buf);
1355 view()->setCursorFromRow(row);
1357 lyx_view_->showErrorList("Parse");
1358 updateFlags = Update::FitCursor;
1362 case LFUN_DIALOG_SHOW: {
1363 BOOST_ASSERT(lyx_view_);
1364 string const name = cmd.getArg(0);
1365 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1367 if (name == "character") {
1368 data = freefont2string();
1370 lyx_view_->getDialogs().show("character", data);
1371 } else if (name == "latexlog") {
1372 pair<Buffer::LogType, string> const logfile =
1373 lyx_view_->buffer()->getLogName();
1374 switch (logfile.first) {
1375 case Buffer::latexlog:
1378 case Buffer::buildlog:
1382 data += Lexer::quoteString(logfile.second);
1383 lyx_view_->getDialogs().show("log", data);
1384 } else if (name == "vclog") {
1385 string const data = "vc " +
1386 Lexer::quoteString(lyx_view_->buffer()->lyxvc().getLogFile());
1387 lyx_view_->getDialogs().show("log", data);
1389 lyx_view_->getDialogs().show(name, data);
1393 case LFUN_DIALOG_SHOW_NEW_INSET: {
1394 BOOST_ASSERT(lyx_view_);
1395 string const name = cmd.getArg(0);
1396 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1397 if (name == "bibitem" ||
1401 name == "nomenclature" ||
1405 InsetCommandParams p(name);
1406 data = InsetCommandMailer::params2string(name, p);
1407 } else if (name == "include") {
1408 // data is the include type: one of "include",
1409 // "input", "verbatiminput" or "verbatiminput*"
1411 // default type is requested
1413 InsetCommandParams p(data);
1414 data = InsetIncludeMailer::params2string(p);
1415 } else if (name == "box") {
1416 // \c data == "Boxed" || "Frameless" etc
1417 InsetBoxParams p(data);
1418 data = InsetBoxMailer::params2string(p);
1419 } else if (name == "branch") {
1420 InsetBranchParams p;
1421 data = InsetBranchMailer::params2string(p);
1422 } else if (name == "citation") {
1423 InsetCommandParams p("citation");
1424 data = InsetCommandMailer::params2string(name, p);
1425 } else if (name == "ert") {
1426 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1427 } else if (name == "external") {
1428 InsetExternalParams p;
1429 Buffer const & buffer = *lyx_view_->buffer();
1430 data = InsetExternalMailer::params2string(p, buffer);
1431 } else if (name == "float") {
1433 data = InsetFloatMailer::params2string(p);
1434 } else if (name == "listings") {
1435 InsetListingsParams p;
1436 data = InsetListingsMailer::params2string(p);
1437 } else if (name == "graphics") {
1438 InsetGraphicsParams p;
1439 Buffer const & buffer = *lyx_view_->buffer();
1440 data = InsetGraphicsMailer::params2string(p, buffer);
1441 } else if (name == "note") {
1443 data = InsetNoteMailer::params2string(p);
1444 } else if (name == "vspace") {
1446 data = InsetVSpaceMailer::params2string(space);
1447 } else if (name == "wrap") {
1449 data = InsetWrapMailer::params2string(p);
1451 lyx_view_->getDialogs().show(name, data, 0);
1455 case LFUN_DIALOG_UPDATE: {
1456 BOOST_ASSERT(lyx_view_);
1457 string const & name = argument;
1458 // Can only update a dialog connected to an existing inset
1459 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1461 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1462 inset->dispatch(view()->cursor(), fr);
1463 } else if (name == "paragraph") {
1464 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1465 } else if (name == "prefs") {
1466 lyx_view_->getDialogs().update(name, string());
1471 case LFUN_DIALOG_HIDE:
1472 LyX::cref().hideDialogs(argument, 0);
1475 case LFUN_DIALOG_TOGGLE: {
1476 BOOST_ASSERT(lyx_view_);
1477 if (lyx_view_->getDialogs().visible(cmd.getArg(0)))
1478 dispatch(FuncRequest(LFUN_DIALOG_HIDE, argument));
1480 dispatch(FuncRequest(LFUN_DIALOG_SHOW, argument));
1484 case LFUN_DIALOG_DISCONNECT_INSET:
1485 BOOST_ASSERT(lyx_view_);
1486 lyx_view_->getDialogs().disconnect(argument);
1490 case LFUN_CITATION_INSERT: {
1491 BOOST_ASSERT(lyx_view_);
1492 if (!argument.empty()) {
1493 // we can have one optional argument, delimited by '|'
1494 // citation-insert <key>|<text_before>
1495 // this should be enhanced to also support text_after
1496 // and citation style
1497 string arg = argument;
1499 if (contains(argument, "|")) {
1500 arg = token(argument, '|', 0);
1501 opt1 = token(argument, '|', 1);
1503 InsetCommandParams icp("citation");
1504 icp["key"] = from_utf8(arg);
1506 icp["before"] = from_utf8(opt1);
1507 string icstr = InsetCommandMailer::params2string("citation", icp);
1508 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1511 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1515 case LFUN_BUFFER_CHILD_OPEN: {
1516 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1517 Buffer * parent = lyx_view_->buffer();
1518 FileName filename = makeAbsPath(argument, parent->filePath());
1519 view()->saveBookmark(false);
1521 bool parsed = false;
1522 if (theBufferList().exists(filename.absFilename())) {
1523 child = theBufferList().getBuffer(filename.absFilename());
1525 setMessage(bformat(_("Opening child document %1$s..."),
1526 makeDisplayPath(filename.absFilename())));
1527 child = lyx_view_->loadLyXFile(filename, true);
1531 // Set the parent name of the child document.
1532 // This makes insertion of citations and references in the child work,
1533 // when the target is in the parent or another child document.
1534 child->setParentName(parent->fileName());
1535 updateLabels(*child->getMasterBuffer());
1536 lyx_view_->setBuffer(child);
1538 lyx_view_->showErrorList("Parse");
1541 // If a screen update is required (in case where auto_open is false),
1542 // setBuffer() would have taken care of it already. Otherwise we shall
1543 // reset the update flag because it can cause a circular problem.
1545 updateFlags = Update::None;
1549 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1550 BOOST_ASSERT(lyx_view_);
1551 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1554 case LFUN_KEYMAP_OFF:
1555 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1556 lyx_view_->view()->getIntl().keyMapOn(false);
1559 case LFUN_KEYMAP_PRIMARY:
1560 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1561 lyx_view_->view()->getIntl().keyMapPrim();
1564 case LFUN_KEYMAP_SECONDARY:
1565 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1566 lyx_view_->view()->getIntl().keyMapSec();
1569 case LFUN_KEYMAP_TOGGLE:
1570 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1571 lyx_view_->view()->getIntl().toggleKeyMap();
1577 string rest = split(argument, countstr, ' ');
1578 istringstream is(countstr);
1581 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1582 for (int i = 0; i < count; ++i)
1583 dispatch(lyxaction.lookupFunc(rest));
1587 case LFUN_COMMAND_SEQUENCE: {
1588 // argument contains ';'-terminated commands
1589 string arg = argument;
1590 while (!arg.empty()) {
1592 arg = split(arg, first, ';');
1593 FuncRequest func(lyxaction.lookupFunc(first));
1594 func.origin = cmd.origin;
1600 case LFUN_PREFERENCES_SAVE: {
1601 lyxrc.write(makeAbsPath("preferences",
1602 package().user_support().absFilename()),
1607 case LFUN_SCREEN_FONT_UPDATE:
1608 BOOST_ASSERT(lyx_view_);
1609 // handle the screen font changes.
1610 theFontLoader().update();
1611 /// FIXME: only the current view will be updated. the Gui
1612 /// class is able to furnish the list of views.
1613 updateFlags = Update::Force;
1616 case LFUN_SET_COLOR: {
1618 string const x11_name = split(argument, lyx_name, ' ');
1619 if (lyx_name.empty() || x11_name.empty()) {
1620 setErrorMessage(from_ascii(N_(
1621 "Syntax: set-color <lyx_name>"
1626 bool const graphicsbg_changed =
1627 (lyx_name == lcolor.getLyXName(Color::graphicsbg) &&
1628 x11_name != lcolor.getX11Name(Color::graphicsbg));
1630 if (!lcolor.setColor(lyx_name, x11_name)) {
1632 bformat(_("Set-color \"%1$s\" failed "
1633 "- color is undefined or "
1634 "may not be redefined"),
1635 from_utf8(lyx_name)));
1639 theApp()->updateColor(lcolor.getFromLyXName(lyx_name));
1641 if (graphicsbg_changed) {
1642 // FIXME: The graphics cache no longer has a changeDisplay method.
1644 graphics::GCache::get().changeDisplay(true);
1651 BOOST_ASSERT(lyx_view_);
1652 lyx_view_->message(from_utf8(argument));
1655 case LFUN_EXTERNAL_EDIT: {
1656 BOOST_ASSERT(lyx_view_);
1657 FuncRequest fr(action, argument);
1658 InsetExternal().dispatch(view()->cursor(), fr);
1662 case LFUN_GRAPHICS_EDIT: {
1663 FuncRequest fr(action, argument);
1664 InsetGraphics().dispatch(view()->cursor(), fr);
1668 case LFUN_INSET_APPLY: {
1669 BOOST_ASSERT(lyx_view_);
1670 string const name = cmd.getArg(0);
1671 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1673 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1674 inset->dispatch(view()->cursor(), fr);
1676 FuncRequest fr(LFUN_INSET_INSERT, argument);
1679 // ideally, the update flag should be set by the insets,
1680 // but this is not possible currently
1681 updateFlags = Update::Force | Update::FitCursor;
1685 case LFUN_ALL_INSETS_TOGGLE: {
1686 BOOST_ASSERT(lyx_view_);
1688 string const name = split(argument, action, ' ');
1689 InsetCode const inset_code =
1692 Cursor & cur = view()->cursor();
1693 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1695 Inset & inset = lyx_view_->buffer()->inset();
1696 InsetIterator it = inset_iterator_begin(inset);
1697 InsetIterator const end = inset_iterator_end(inset);
1698 for (; it != end; ++it) {
1699 if (!it->asInsetMath()
1700 && (inset_code == NO_CODE
1701 || inset_code == it->lyxCode())) {
1702 Cursor tmpcur = cur;
1703 tmpcur.pushLeft(*it);
1704 it->dispatch(tmpcur, fr);
1707 updateFlags = Update::Force | Update::FitCursor;
1711 case LFUN_BUFFER_LANGUAGE: {
1712 BOOST_ASSERT(lyx_view_);
1713 Buffer & buffer = *lyx_view_->buffer();
1714 Language const * oldL = buffer.params().language;
1715 Language const * newL = languages.getLanguage(argument);
1716 if (!newL || oldL == newL)
1719 if (oldL->rightToLeft() == newL->rightToLeft()
1720 && !buffer.isMultiLingual())
1721 buffer.changeLanguage(oldL, newL);
1725 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1726 string const fname =
1727 addName(addPath(package().user_support().absFilename(), "templates/"),
1729 Buffer defaults(fname);
1731 istringstream ss(argument);
1734 int const unknown_tokens = defaults.readHeader(lex);
1736 if (unknown_tokens != 0) {
1737 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1738 << unknown_tokens << " unknown token"
1739 << (unknown_tokens == 1 ? "" : "s")
1743 if (defaults.writeFile(FileName(defaults.fileName())))
1744 setMessage(bformat(_("Document defaults saved in %1$s"),
1745 makeDisplayPath(fname)));
1747 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1751 case LFUN_BUFFER_PARAMS_APPLY: {
1752 BOOST_ASSERT(lyx_view_);
1753 biblio::CiteEngine const oldEngine =
1754 lyx_view_->buffer()->params().getEngine();
1756 Buffer * buffer = lyx_view_->buffer();
1758 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1759 recordUndoFullDocument(view());
1761 istringstream ss(argument);
1764 int const unknown_tokens = buffer->readHeader(lex);
1766 if (unknown_tokens != 0) {
1767 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1768 << unknown_tokens << " unknown token"
1769 << (unknown_tokens == 1 ? "" : "s")
1773 updateLayout(oldClass, buffer);
1775 biblio::CiteEngine const newEngine =
1776 lyx_view_->buffer()->params().getEngine();
1778 if (oldEngine != newEngine) {
1779 Cursor & cur = view()->cursor();
1780 FuncRequest fr(LFUN_INSET_REFRESH);
1782 Inset & inset = lyx_view_->buffer()->inset();
1783 InsetIterator it = inset_iterator_begin(inset);
1784 InsetIterator const end = inset_iterator_end(inset);
1785 for (; it != end; ++it)
1786 if (it->lyxCode() == CITE_CODE)
1787 it->dispatch(cur, fr);
1790 updateFlags = Update::Force | Update::FitCursor;
1794 case LFUN_LAYOUT_MODULES_CLEAR: {
1795 BOOST_ASSERT(lyx_view_);
1796 Buffer * buffer = lyx_view_->buffer();
1797 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1798 recordUndoFullDocument(view());
1799 buffer->params().clearLayoutModules();
1800 updateLayout(oldClass, buffer);
1801 updateFlags = Update::Force | Update::FitCursor;
1805 case LFUN_LAYOUT_MODULE_ADD: {
1806 BOOST_ASSERT(lyx_view_);
1807 Buffer * buffer = lyx_view_->buffer();
1808 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1809 recordUndoFullDocument(view());
1810 buffer->params().addLayoutModule(argument);
1811 updateLayout(oldClass, buffer);
1812 updateFlags = Update::Force | Update::FitCursor;
1816 case LFUN_TEXTCLASS_APPLY: {
1817 BOOST_ASSERT(lyx_view_);
1818 Buffer * buffer = lyx_view_->buffer();
1820 loadTextClass(argument);
1822 std::pair<bool, textclass_type> const tc_pair =
1823 textclasslist.numberOfClass(argument);
1828 textclass_type const old_class = buffer->params().getBaseClass();
1829 textclass_type const new_class = tc_pair.second;
1831 if (old_class == new_class)
1835 //Save the old, possibly modular, layout for use in conversion.
1836 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1837 recordUndoFullDocument(view());
1838 buffer->params().setBaseClass(new_class);
1839 updateLayout(oldClass, buffer);
1840 updateFlags = Update::Force | Update::FitCursor;
1844 case LFUN_LAYOUT_RELOAD: {
1845 BOOST_ASSERT(lyx_view_);
1846 Buffer * buffer = lyx_view_->buffer();
1847 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1848 textclass_type const tc = buffer->params().getBaseClass();
1849 textclasslist.reset(tc);
1850 buffer->params().setBaseClass(tc);
1851 updateLayout(oldClass, buffer);
1852 updateFlags = Update::Force | Update::FitCursor;
1856 case LFUN_TEXTCLASS_LOAD:
1857 loadTextClass(argument);
1860 case LFUN_LYXRC_APPLY: {
1861 LyXRC const lyxrc_orig = lyxrc;
1863 istringstream ss(argument);
1864 bool const success = lyxrc.read(ss) == 0;
1867 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1868 << "Unable to read lyxrc data"
1873 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1875 /// We force the redraw in any case because there might be
1876 /// some screen font changes.
1877 /// FIXME: only the current view will be updated. the Gui
1878 /// class is able to furnish the list of views.
1879 updateFlags = Update::Force;
1883 case LFUN_WINDOW_NEW:
1884 LyX::ref().newLyXView();
1887 case LFUN_WINDOW_CLOSE:
1888 BOOST_ASSERT(lyx_view_);
1889 BOOST_ASSERT(theApp());
1890 // update bookmark pit of the current buffer before window close
1891 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1892 gotoBookmark(i+1, false, false);
1893 // ask the user for saving changes or cancel quit
1894 if (!theBufferList().quitWriteAll())
1899 case LFUN_BOOKMARK_GOTO:
1900 // go to bookmark, open unopened file and switch to buffer if necessary
1901 gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
1904 case LFUN_BOOKMARK_CLEAR:
1905 LyX::ref().session().bookmarks().clear();
1908 case LFUN_TOOLBAR_TOGGLE: {
1909 BOOST_ASSERT(lyx_view_);
1910 string const name = cmd.getArg(0);
1911 bool const allowauto = cmd.getArg(1) == "allowauto";
1912 lyx_view_->toggleToolbarState(name, allowauto);
1913 ToolbarInfo * tbi = lyx_view_->getToolbarInfo(name);
1915 setMessage(bformat(_("Unknown toolbar \"%1$s\""),
1920 if (tbi->flags & ToolbarInfo::ON)
1922 else if (tbi->flags & ToolbarInfo::OFF)
1924 else if (tbi->flags & ToolbarInfo::AUTO)
1927 setMessage(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1928 _(tbi->gui_name), state));
1933 BOOST_ASSERT(lyx_view_);
1934 view()->cursor().dispatch(cmd);
1935 updateFlags = view()->cursor().result().update();
1936 if (!view()->cursor().result().dispatched())
1937 updateFlags = view()->dispatch(cmd);
1942 if (lyx_view_ && lyx_view_->buffer()) {
1943 // BufferView::update() updates the ViewMetricsInfo and
1944 // also initializes the position cache for all insets in
1945 // (at least partially) visible top-level paragraphs.
1946 // We will redraw the screen only if needed.
1947 view()->processUpdateFlags(updateFlags);
1948 lyx_view_->updateStatusBar();
1950 // if we executed a mutating lfun, mark the buffer as dirty
1952 && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
1953 && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
1954 lyx_view_->buffer()->markDirty();
1956 //Do we have a selection?
1957 theSelection().haveSelection(view()->cursor().selection());
1959 if (view()->cursor().inTexted()) {
1960 lyx_view_->updateLayoutChoice();
1964 if (!quitting && lyx_view_) {
1965 lyx_view_->updateToolbars();
1966 // Some messages may already be translated, so we cannot use _()
1967 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
1972 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
1974 const bool verbose = (cmd.origin == FuncRequest::MENU
1975 || cmd.origin == FuncRequest::TOOLBAR
1976 || cmd.origin == FuncRequest::COMMANDBUFFER);
1978 if (cmd.action == LFUN_SELF_INSERT || !verbose) {
1979 LYXERR(Debug::ACTION) << "dispatch msg is " << to_utf8(msg) << endl;
1981 lyx_view_->message(msg);
1985 docstring dispatch_msg = msg;
1986 if (!dispatch_msg.empty())
1987 dispatch_msg += ' ';
1989 docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
1991 bool argsadded = false;
1993 if (!cmd.argument().empty()) {
1994 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1995 comname += ' ' + cmd.argument();
2000 docstring const shortcuts = theTopLevelKeymap().printbindings(cmd);
2002 if (!shortcuts.empty())
2003 comname += ": " + shortcuts;
2004 else if (!argsadded && !cmd.argument().empty())
2005 comname += ' ' + cmd.argument();
2007 if (!comname.empty()) {
2008 comname = rtrim(comname);
2009 dispatch_msg += '(' + rtrim(comname) + ')';
2012 LYXERR(Debug::ACTION) << "verbose dispatch msg "
2013 << to_utf8(dispatch_msg) << endl;
2014 if (!dispatch_msg.empty())
2015 lyx_view_->message(dispatch_msg);
2019 void LyXFunc::menuNew(string const & name, bool fromTemplate)
2021 // FIXME: initpath is not used. What to do?
2022 string initpath = lyxrc.document_path;
2023 string filename(name);
2025 if (lyx_view_->buffer()) {
2026 string const trypath = lyx_view_->buffer()->filePath();
2027 // If directory is writeable, use this as default.
2028 if (isDirWriteable(FileName(trypath)))
2032 static int newfile_number;
2034 if (filename.empty()) {
2035 filename = addName(lyxrc.document_path,
2036 "newfile" + convert<string>(++newfile_number) + ".lyx");
2037 while (theBufferList().exists(filename) ||
2038 fs::is_readable(FileName(filename).toFilesystemEncoding())) {
2040 filename = addName(lyxrc.document_path,
2041 "newfile" + convert<string>(newfile_number) +
2046 // The template stuff
2049 FileDialog fileDlg(_("Select template file"),
2050 LFUN_SELECT_FILE_SYNC,
2051 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2052 make_pair(_("Templates|#T#t"), from_utf8(lyxrc.template_path)));
2054 FileDialog::Result result =
2055 fileDlg.open(from_utf8(lyxrc.template_path),
2056 FileFilterList(_("LyX Documents (*.lyx)")),
2059 if (result.first == FileDialog::Later)
2061 if (result.second.empty())
2063 templname = to_utf8(result.second);
2066 Buffer * const b = newFile(filename, templname, !name.empty());
2068 lyx_view_->setBuffer(b);
2072 void LyXFunc::open(string const & fname)
2074 string initpath = lyxrc.document_path;
2076 if (lyx_view_->buffer()) {
2077 string const trypath = lyx_view_->buffer()->filePath();
2078 // If directory is writeable, use this as default.
2079 if (isDirWriteable(FileName(trypath)))
2085 if (fname.empty()) {
2086 FileDialog fileDlg(_("Select document to open"),
2088 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2089 make_pair(_("Examples|#E#e"), from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2091 FileDialog::Result result =
2092 fileDlg.open(from_utf8(initpath),
2093 FileFilterList(_("LyX Documents (*.lyx)")),
2096 if (result.first == FileDialog::Later)
2099 filename = to_utf8(result.second);
2101 // check selected filename
2102 if (filename.empty()) {
2103 lyx_view_->message(_("Canceled."));
2109 // get absolute path of file and add ".lyx" to the filename if
2111 FileName const fullname = fileSearch(string(), filename, "lyx");
2112 if (!fullname.empty())
2113 filename = fullname.absFilename();
2115 // if the file doesn't exist, let the user create one
2116 if (!fs::exists(fullname.toFilesystemEncoding())) {
2117 // the user specifically chose this name. Believe him.
2118 Buffer * const b = newFile(filename, string(), true);
2120 lyx_view_->setBuffer(b);
2124 docstring const disp_fn = makeDisplayPath(filename);
2125 lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
2128 Buffer * buf = lyx_view_->loadLyXFile(fullname);
2131 lyx_view_->setBuffer(buf);
2132 lyx_view_->showErrorList("Parse");
2133 str2 = bformat(_("Document %1$s opened."), disp_fn);
2135 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2137 lyx_view_->message(str2);
2141 void LyXFunc::doImport(string const & argument)
2144 string filename = split(argument, format, ' ');
2146 LYXERR(Debug::INFO) << "LyXFunc::doImport: " << format
2147 << " file: " << filename << endl;
2149 // need user interaction
2150 if (filename.empty()) {
2151 string initpath = lyxrc.document_path;
2153 if (lyx_view_->buffer()) {
2154 string const trypath = lyx_view_->buffer()->filePath();
2155 // If directory is writeable, use this as default.
2156 if (isDirWriteable(FileName(trypath)))
2160 docstring const text = bformat(_("Select %1$s file to import"),
2161 formats.prettyName(format));
2163 FileDialog fileDlg(text,
2165 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2166 make_pair(_("Examples|#E#e"),
2167 from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2169 docstring filter = formats.prettyName(format);
2172 filter += from_utf8(formats.extension(format));
2175 FileDialog::Result result =
2176 fileDlg.open(from_utf8(initpath),
2177 FileFilterList(filter),
2180 if (result.first == FileDialog::Later)
2183 filename = to_utf8(result.second);
2185 // check selected filename
2186 if (filename.empty())
2187 lyx_view_->message(_("Canceled."));
2190 if (filename.empty())
2193 // get absolute path of file
2194 FileName const fullname(makeAbsPath(filename));
2196 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
2198 // Check if the document already is open
2199 if (use_gui && theBufferList().exists(lyxfile.absFilename())) {
2200 if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) {
2201 lyx_view_->message(_("Canceled."));
2206 // if the file exists already, and we didn't do
2207 // -i lyx thefile.lyx, warn
2208 if (fs::exists(lyxfile.toFilesystemEncoding()) && fullname != lyxfile) {
2209 docstring const file = makeDisplayPath(lyxfile.absFilename(), 30);
2211 docstring text = bformat(_("The document %1$s already exists.\n\n"
2212 "Do you want to overwrite that document?"), file);
2213 int const ret = Alert::prompt(_("Overwrite document?"),
2214 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2217 lyx_view_->message(_("Canceled."));
2222 ErrorList errorList;
2223 Importer::Import(lyx_view_, fullname, format, errorList);
2224 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2228 void LyXFunc::closeBuffer()
2230 // goto bookmark to update bookmark pit.
2231 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2232 gotoBookmark(i+1, false, false);
2234 theBufferList().close(lyx_view_->buffer(), true);
2238 void LyXFunc::reloadBuffer()
2240 FileName filename(lyx_view_->buffer()->fileName());
2241 docstring const disp_fn = makeDisplayPath(filename.absFilename());
2244 Buffer * buf = lyx_view_->loadLyXFile(filename);
2247 lyx_view_->setBuffer(buf);
2248 lyx_view_->showErrorList("Parse");
2249 str = bformat(_("Document %1$s reloaded."), disp_fn);
2251 str = bformat(_("Could not reload document %1$s"), disp_fn);
2253 lyx_view_->message(str);
2256 // Each "lyx_view_" should have it's own message method. lyxview and
2257 // the minibuffer would use the minibuffer, but lyxserver would
2258 // send an ERROR signal to its client. Alejandro 970603
2259 // This function is bit problematic when it comes to NLS, to make the
2260 // lyx servers client be language indepenent we must not translate
2261 // strings sent to this func.
2262 void LyXFunc::setErrorMessage(docstring const & m) const
2264 dispatch_buffer = m;
2269 void LyXFunc::setMessage(docstring const & m) const
2271 dispatch_buffer = m;
2275 docstring const LyXFunc::viewStatusMessage()
2277 // When meta-fake key is pressed, show the key sequence so far + "M-".
2279 return keyseq.print(true) + "M-";
2281 // Else, when a non-complete key sequence is pressed,
2282 // show the available options.
2283 if (keyseq.length() > 0 && !keyseq.deleted())
2284 return keyseq.printOptions(true);
2286 BOOST_ASSERT(lyx_view_);
2287 if (!lyx_view_->buffer())
2288 return _("Welcome to LyX!");
2290 return view()->cursor().currentState();
2294 BufferView * LyXFunc::view() const
2296 BOOST_ASSERT(lyx_view_);
2297 return lyx_view_->view();
2301 bool LyXFunc::wasMetaKey() const
2303 return (meta_fake_bit != NoModifier);
2307 void LyXFunc::updateLayout(TextClassPtr const & oldlayout,
2310 lyx_view_->message(_("Converting document to new document class..."));
2312 StableDocIterator backcur(view()->cursor());
2313 ErrorList & el = buffer->errorList("Class Switch");
2314 cap::switchBetweenClasses(
2315 oldlayout, buffer->params().getTextClassPtr(),
2316 static_cast<InsetText &>(buffer->inset()), el);
2318 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
2320 buffer->errors("Class Switch");
2321 updateLabels(*buffer);
2327 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2329 // Why the switch you might ask. It is a trick to ensure that all
2330 // the elements in the LyXRCTags enum is handled. As you can see
2331 // there are no breaks at all. So it is just a huge fall-through.
2332 // The nice thing is that we will get a warning from the compiler
2333 // if we forget an element.
2334 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2336 case LyXRC::RC_ACCEPT_COMPOUND:
2337 case LyXRC::RC_ALT_LANG:
2338 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
2339 case LyXRC::RC_PLAINTEXT_LINELEN:
2340 case LyXRC::RC_AUTOREGIONDELETE:
2341 case LyXRC::RC_AUTORESET_OPTIONS:
2342 case LyXRC::RC_AUTOSAVE:
2343 case LyXRC::RC_AUTO_NUMBER:
2344 case LyXRC::RC_BACKUPDIR_PATH:
2345 case LyXRC::RC_BIBTEX_COMMAND:
2346 case LyXRC::RC_BINDFILE:
2347 case LyXRC::RC_CHECKLASTFILES:
2348 case LyXRC::RC_USELASTFILEPOS:
2349 case LyXRC::RC_LOADSESSION:
2350 case LyXRC::RC_CHKTEX_COMMAND:
2351 case LyXRC::RC_CONVERTER:
2352 case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
2353 case LyXRC::RC_COPIER:
2354 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2355 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2356 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2357 case LyXRC::RC_DATE_INSERT_FORMAT:
2358 case LyXRC::RC_DEFAULT_LANGUAGE:
2359 case LyXRC::RC_DEFAULT_PAPERSIZE:
2360 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2361 case LyXRC::RC_DISPLAY_GRAPHICS:
2362 case LyXRC::RC_DOCUMENTPATH:
2363 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2364 string const encoded = FileName(
2365 lyxrc_new.document_path).toFilesystemEncoding();
2366 if (fs::exists(encoded) && fs::is_directory(encoded))
2367 support::package().document_dir() = FileName(lyxrc.document_path);
2369 case LyXRC::RC_ESC_CHARS:
2370 case LyXRC::RC_FONT_ENCODING:
2371 case LyXRC::RC_FORMAT:
2372 case LyXRC::RC_INDEX_COMMAND:
2373 case LyXRC::RC_INPUT:
2374 case LyXRC::RC_KBMAP:
2375 case LyXRC::RC_KBMAP_PRIMARY:
2376 case LyXRC::RC_KBMAP_SECONDARY:
2377 case LyXRC::RC_LABEL_INIT_LENGTH:
2378 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2379 case LyXRC::RC_LANGUAGE_AUTO_END:
2380 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2381 case LyXRC::RC_LANGUAGE_COMMAND_END:
2382 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2383 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2384 case LyXRC::RC_LANGUAGE_PACKAGE:
2385 case LyXRC::RC_LANGUAGE_USE_BABEL:
2386 case LyXRC::RC_MAKE_BACKUP:
2387 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2388 case LyXRC::RC_NUMLASTFILES:
2389 case LyXRC::RC_PATH_PREFIX:
2390 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2391 support::prependEnvPath("PATH", lyxrc.path_prefix);
2393 case LyXRC::RC_PERS_DICT:
2394 case LyXRC::RC_PREVIEW:
2395 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2396 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2397 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2398 case LyXRC::RC_PRINTCOPIESFLAG:
2399 case LyXRC::RC_PRINTER:
2400 case LyXRC::RC_PRINTEVENPAGEFLAG:
2401 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2402 case LyXRC::RC_PRINTFILEEXTENSION:
2403 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2404 case LyXRC::RC_PRINTODDPAGEFLAG:
2405 case LyXRC::RC_PRINTPAGERANGEFLAG:
2406 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2407 case LyXRC::RC_PRINTPAPERFLAG:
2408 case LyXRC::RC_PRINTREVERSEFLAG:
2409 case LyXRC::RC_PRINTSPOOL_COMMAND:
2410 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2411 case LyXRC::RC_PRINTTOFILE:
2412 case LyXRC::RC_PRINTTOPRINTER:
2413 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2414 case LyXRC::RC_PRINT_COMMAND:
2415 case LyXRC::RC_RTL_SUPPORT:
2416 case LyXRC::RC_SCREEN_DPI:
2417 case LyXRC::RC_SCREEN_FONT_ROMAN:
2418 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2419 case LyXRC::RC_SCREEN_FONT_SANS:
2420 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2421 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2422 case LyXRC::RC_SCREEN_FONT_SIZES:
2423 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2424 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2425 case LyXRC::RC_SCREEN_GEOMETRY_HEIGHT:
2426 case LyXRC::RC_SCREEN_GEOMETRY_WIDTH:
2427 case LyXRC::RC_SCREEN_GEOMETRY_XYSAVED:
2428 case LyXRC::RC_SCREEN_ZOOM:
2429 case LyXRC::RC_SERVERPIPE:
2430 case LyXRC::RC_SET_COLOR:
2431 case LyXRC::RC_SHOW_BANNER:
2432 case LyXRC::RC_SPELL_COMMAND:
2433 case LyXRC::RC_TEMPDIRPATH:
2434 case LyXRC::RC_TEMPLATEPATH:
2435 case LyXRC::RC_TEX_ALLOWS_SPACES:
2436 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2437 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2438 support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2440 case LyXRC::RC_UIFILE:
2441 case LyXRC::RC_USER_EMAIL:
2442 case LyXRC::RC_USER_NAME:
2443 case LyXRC::RC_USETEMPDIR:
2444 case LyXRC::RC_USE_ALT_LANG:
2445 case LyXRC::RC_USE_CONVERTER_CACHE:
2446 case LyXRC::RC_USE_ESC_CHARS:
2447 case LyXRC::RC_USE_INP_ENC:
2448 case LyXRC::RC_USE_PERS_DICT:
2449 case LyXRC::RC_USE_SPELL_LIB:
2450 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2451 case LyXRC::RC_VIEWER:
2452 case LyXRC::RC_LAST: