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"
63 #include "insets/InsetBox.h"
64 #include "insets/InsetBranch.h"
65 #include "insets/InsetCommand.h"
66 #include "insets/InsetERT.h"
67 #include "insets/InsetExternal.h"
68 #include "insets/InsetFloat.h"
69 #include "insets/InsetListings.h"
70 #include "insets/InsetGraphics.h"
71 #include "insets/InsetInclude.h"
72 #include "insets/InsetNote.h"
73 #include "insets/InsetTabular.h"
74 #include "insets/InsetVSpace.h"
75 #include "insets/InsetWrap.h"
77 #include "frontends/Application.h"
78 #include "frontends/alert.h"
79 #include "frontends/Dialogs.h"
80 #include "frontends/FileDialog.h"
81 #include "frontends/FontLoader.h"
82 #include "frontends/Gui.h"
83 #include "frontends/KeySymbol.h"
84 #include "frontends/LyXView.h"
85 #include "frontends/Selection.h"
86 #include "frontends/WorkArea.h"
88 #include "support/environment.h"
89 #include "support/FileFilterList.h"
90 #include "support/filetools.h"
91 #include "support/fs_extras.h"
92 #include "support/lstrings.h"
93 #include "support/Path.h"
94 #include "support/Package.h"
95 #include "support/Systemcall.h"
96 #include "support/convert.h"
97 #include "support/os.h"
99 #include <boost/current_function.hpp>
100 #include <boost/filesystem/operations.hpp>
105 using std::make_pair;
108 using std::istringstream;
109 using std::ostringstream;
111 namespace fs = boost::filesystem;
115 using frontend::LyXView;
117 using support::absolutePath;
118 using support::addName;
119 using support::addPath;
120 using support::bformat;
121 using support::changeExtension;
122 using support::contains;
123 using support::FileFilterList;
124 using support::FileName;
125 using support::fileSearch;
126 using support::i18nLibFileSearch;
127 using support::isDirWriteable;
128 using support::isFileReadable;
129 using support::isStrInt;
130 using support::makeAbsPath;
131 using support::makeDisplayPath;
132 using support::package;
133 using support::quoteName;
134 using support::rtrim;
135 using support::split;
136 using support::subst;
137 using support::Systemcall;
138 using support::token;
140 using support::prefixIs;
142 namespace Alert = frontend::Alert;
144 extern bool quitting;
148 // This function runs "configure" and then rereads lyx.defaults to
149 // reconfigure the automatic settings.
150 void reconfigure(LyXView & lv, string const & option)
152 // emit message signal.
153 lv.message(_("Running configure..."));
155 // Run configure in user lyx directory
156 support::Path p(package().user_support());
157 string configure_command = package().configure_command();
158 configure_command += option;
160 int ret = one.startscript(Systemcall::Wait, configure_command);
162 // emit message signal.
163 lv.message(_("Reloading configuration..."));
164 lyxrc.read(support::libFileSearch(string(), "lyxrc.defaults"));
165 // Re-read packages.lst
166 LaTeXFeatures::getAvailable();
169 Alert::information(_("System reconfiguration failed"),
170 _("The system reconfiguration has failed.\n"
171 "Default textclass is used but LyX may "
172 "not be able to work properly.\n"
173 "Please reconfigure again if needed."));
176 Alert::information(_("System reconfigured"),
177 _("The system has been reconfigured.\n"
178 "You need to restart LyX to make use of any\n"
179 "updated document class specifications."));
183 bool getLocalStatus(Cursor cursor, FuncRequest const & cmd, FuncStatus & status)
185 // Try to fix cursor in case it is broken.
186 cursor.fixIfBroken();
188 // This is, of course, a mess. Better create a new doc iterator and use
189 // this in Inset::getStatus. This might require an additional
190 // BufferView * arg, though (which should be avoided)
191 //Cursor safe = *this;
193 for ( ; cursor.depth(); cursor.pop()) {
194 //lyxerr << "\nCursor::getStatus: cmd: " << cmd << endl << *this << endl;
195 BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
196 BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
197 BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
199 // The inset's getStatus() will return 'true' if it made
200 // a definitive decision on whether it want to handle the
201 // request or not. The result of this decision is put into
202 // the 'status' parameter.
203 if (cursor.inset().getStatus(cursor, cmd, status)) {
212 /** Return the change status at cursor position, taking in account the
213 * status at each level of the document iterator (a table in a deleted
214 * footnote is deleted).
215 * When \param outer is true, the top slice is not looked at.
217 Change::Type lookupChangeType(DocIterator const & dit, bool outer = false)
219 size_t const depth = dit.depth() - (outer ? 1 : 0);
221 for (size_t i = 0 ; i < depth ; ++i) {
222 CursorSlice const & slice = dit[i];
223 if (!slice.inset().inMathed()
224 && slice.pos() < slice.paragraph().size()) {
225 Change::Type const ch = slice.paragraph().lookupChange(slice.pos()).type;
226 if (ch != Change::UNCHANGED)
230 return Change::UNCHANGED;
237 : lyx_view_(0), encoded_last_key(0), meta_fake_bit(NoModifier)
242 void LyXFunc::initKeySequences(KeyMap * kb)
244 keyseq = KeySequence(kb, kb);
245 cancel_meta_seq = KeySequence(kb, kb);
249 void LyXFunc::setLyXView(LyXView * lv)
251 if (!quitting && lyx_view_ && lyx_view_->view() && lyx_view_ != lv)
252 // save current selection to the selection buffer to allow
253 // middle-button paste in another window
254 cap::saveSelection(lyx_view_->view()->cursor());
259 void LyXFunc::handleKeyFunc(kb_action action)
261 char_type c = encoded_last_key;
266 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
267 lyx_view_->view()->getIntl().getTransManager().deadkey(
268 c, get_accent(action).accent, view()->cursor().innerText(), view()->cursor());
269 // Need to clear, in case the minibuffer calls these
272 // copied verbatim from do_accent_char
273 view()->cursor().resetAnchor();
274 view()->processUpdateFlags(Update::FitCursor);
278 void LyXFunc::gotoBookmark(unsigned int idx, bool openFile, bool switchToBuffer)
280 BOOST_ASSERT(lyx_view_);
281 if (!LyX::ref().session().bookmarks().isValid(idx))
283 BookmarksSection::Bookmark const & bm = LyX::ref().session().bookmarks().bookmark(idx);
284 BOOST_ASSERT(!bm.filename.empty());
285 string const file = bm.filename.absFilename();
286 // if the file is not opened, open it.
287 if (!theBufferList().exists(file)) {
289 dispatch(FuncRequest(LFUN_FILE_OPEN, file));
293 // open may fail, so we need to test it again
294 if (!theBufferList().exists(file))
297 // if the current buffer is not that one, switch to it.
298 if (lyx_view_->buffer()->fileName() != file) {
301 dispatch(FuncRequest(LFUN_BUFFER_SWITCH, file));
303 // moveToPosition try paragraph id first and then paragraph (pit, pos).
304 if (!view()->moveToPosition(bm.bottom_pit, bm.bottom_pos,
305 bm.top_id, bm.top_pos))
308 // Cursor jump succeeded!
309 Cursor const & cur = view()->cursor();
310 pit_type new_pit = cur.pit();
311 pos_type new_pos = cur.pos();
312 int new_id = cur.paragraph().id();
314 // if bottom_pit, bottom_pos or top_id has been changed, update bookmark
315 // see http://bugzilla.lyx.org/show_bug.cgi?id=3092
316 if (bm.bottom_pit != new_pit || bm.bottom_pos != new_pos
317 || bm.top_id != new_id) {
318 const_cast<BookmarksSection::Bookmark &>(bm).updatePos(
319 new_pit, new_pos, new_id);
325 void restartCursor(LyXView * lv)
327 /* When we move around, or type, it's nice to be able to see
328 * the cursor immediately after the keypress.
330 if (lv && lv->currentWorkArea())
331 lv->currentWorkArea()->startBlinkingCursor();
335 void LyXFunc::processKeySym(KeySymbol const & keysym, KeyModifier state)
337 LYXERR(Debug::KEY) << "KeySym is " << keysym.getSymbolName() << endl;
339 // Do nothing if we have nothing (JMarc)
340 if (!keysym.isOK()) {
341 LYXERR(Debug::KEY) << "Empty kbd action (probably composing)"
343 restartCursor(lyx_view_);
347 if (keysym.isModifier()) {
348 LYXERR(Debug::KEY) << "isModifier true" << endl;
349 restartCursor(lyx_view_);
353 //Encoding const * encoding = view()->cursor().getEncoding();
354 //encoded_last_key = keysym.getISOEncoded(encoding ? encoding->name() : "");
355 // FIXME: encoded_last_key shadows the member variable of the same
356 // name. Is that intended?
357 char_type encoded_last_key = keysym.getUCSEncoded();
359 // Do a one-deep top-level lookup for
360 // cancel and meta-fake keys. RVDK_PATCH_5
361 cancel_meta_seq.reset();
363 FuncRequest func = cancel_meta_seq.addkey(keysym, state);
364 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
365 << " action first set to [" << func.action << ']'
368 // When not cancel or meta-fake, do the normal lookup.
369 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
370 // Mostly, meta_fake_bit = NoModifier. RVDK_PATCH_5.
371 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_PREFIX)) {
372 // remove Caps Lock and Mod2 as a modifiers
373 func = keyseq.addkey(keysym, (state | meta_fake_bit));
374 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
375 << "action now set to ["
376 << func.action << ']' << endl;
379 // Dont remove this unless you know what you are doing.
380 meta_fake_bit = NoModifier;
382 // Can this happen now ?
383 if (func.action == LFUN_NOACTION)
384 func = FuncRequest(LFUN_COMMAND_PREFIX);
386 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
388 << func.action << "]["
389 << to_utf8(keyseq.print(false)) << ']'
392 // already here we know if it any point in going further
393 // why not return already here if action == -1 and
394 // num_bytes == 0? (Lgb)
396 if (keyseq.length() > 1)
397 lyx_view_->message(keyseq.print(true));
400 // Maybe user can only reach the key via holding down shift.
401 // Let's see. But only if shift is the only modifier
402 if (func.action == LFUN_UNKNOWN_ACTION && state == ShiftModifier) {
403 LYXERR(Debug::KEY) << "Trying without shift" << endl;
404 func = keyseq.addkey(keysym, NoModifier);
405 LYXERR(Debug::KEY) << "Action now " << func.action << endl;
408 if (func.action == LFUN_UNKNOWN_ACTION) {
409 // Hmm, we didn't match any of the keysequences. See
410 // if it's normal insertable text not already covered
412 if (keysym.isText() && keyseq.length() == 1) {
413 LYXERR(Debug::KEY) << "isText() is true, inserting." << endl;
414 func = FuncRequest(LFUN_SELF_INSERT,
415 FuncRequest::KEYBOARD);
417 LYXERR(Debug::KEY) << "Unknown, !isText() - giving up" << endl;
418 lyx_view_->message(_("Unknown function."));
419 restartCursor(lyx_view_);
424 if (func.action == LFUN_SELF_INSERT) {
425 if (encoded_last_key != 0) {
426 docstring const arg(1, encoded_last_key);
427 dispatch(FuncRequest(LFUN_SELF_INSERT, arg,
428 FuncRequest::KEYBOARD));
430 << "SelfInsert arg[`" << to_utf8(arg) << "']" << endl;
436 restartCursor(lyx_view_);
440 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
442 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
445 /* In LyX/Mac, when a dialog is open, the menus of the
446 application can still be accessed without giving focus to
447 the main window. In this case, we want to disable the menu
448 entries that are buffer-related.
450 Note that this code is not perfect, as bug 1941 attests:
451 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
453 Buffer * buf = lyx_view_? lyx_view_->buffer() : 0;
454 if (lyx_view_ && cmd.origin == FuncRequest::MENU && !lyx_view_->hasFocus())
457 if (cmd.action == LFUN_NOACTION) {
458 flag.message(from_utf8(N_("Nothing to do")));
463 switch (cmd.action) {
464 case LFUN_UNKNOWN_ACTION:
465 #ifndef HAVE_LIBAIKSAURUS
466 case LFUN_THESAURUS_ENTRY:
476 if (flag.unknown()) {
477 flag.message(from_utf8(N_("Unknown action")));
481 if (!flag.enabled()) {
482 if (flag.message().empty())
483 flag.message(from_utf8(N_("Command disabled")));
487 // Check whether we need a buffer
488 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
490 flag.message(from_utf8(N_("Command not allowed with"
491 "out any document open")));
496 // I would really like to avoid having this switch and rather try to
497 // encode this in the function itself.
498 // -- And I'd rather let an inset decide which LFUNs it is willing
499 // to handle (Andre')
501 switch (cmd.action) {
502 case LFUN_BUFFER_TOGGLE_READ_ONLY:
503 flag.setOnOff(buf->isReadonly());
506 case LFUN_BUFFER_SWITCH:
507 // toggle on the current buffer, but do not toggle off
508 // the other ones (is that a good idea?)
509 if (buf && to_utf8(cmd.argument()) == buf->fileName())
513 case LFUN_BUFFER_EXPORT:
514 enable = cmd.argument() == "custom"
515 || Exporter::isExportable(*buf, to_utf8(cmd.argument()));
518 case LFUN_BUFFER_CHKTEX:
519 enable = buf->isLatex() && !lyxrc.chktex_command.empty();
522 case LFUN_BUILD_PROGRAM:
523 enable = Exporter::isExportable(*buf, "program");
526 case LFUN_VC_REGISTER:
527 enable = !buf->lyxvc().inUse();
529 case LFUN_VC_CHECK_IN:
530 enable = buf->lyxvc().inUse() && !buf->isReadonly();
532 case LFUN_VC_CHECK_OUT:
533 enable = buf->lyxvc().inUse() && buf->isReadonly();
536 case LFUN_VC_UNDO_LAST:
537 enable = buf->lyxvc().inUse();
539 case LFUN_BUFFER_RELOAD:
540 enable = !buf->isUnnamed() && fs::exists(buf->fileName())
541 && (!buf->isClean() || buf->isExternallyModified(Buffer::timestamp_method));
544 case LFUN_INSET_APPLY: {
549 string const name = cmd.getArg(0);
550 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
552 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
554 if (!inset->getStatus(view()->cursor(), fr, fs)) {
555 // Every inset is supposed to handle this
560 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
561 flag |= getStatus(fr);
563 enable = flag.enabled();
567 case LFUN_DIALOG_TOGGLE:
568 flag.setOnOff(lyx_view_->getDialogs().visible(cmd.getArg(0)));
569 // fall through to set "enable"
570 case LFUN_DIALOG_SHOW: {
571 string const name = cmd.getArg(0);
573 enable = name == "aboutlyx"
574 || name == "file" //FIXME: should be removed.
576 || name == "texinfo";
577 else if (name == "print")
578 enable = Exporter::isExportable(*buf, "dvi")
579 && lyxrc.print_command != "none";
580 else if (name == "character") {
584 InsetCode ic = view()->cursor().inset().lyxCode();
585 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
588 else if (name == "latexlog")
589 enable = isFileReadable(FileName(buf->getLogName().second));
590 else if (name == "spellchecker")
591 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
592 enable = !buf->isReadonly();
596 else if (name == "vclog")
597 enable = buf->lyxvc().inUse();
601 case LFUN_DIALOG_UPDATE: {
602 string const name = cmd.getArg(0);
604 enable = name == "prefs";
608 case LFUN_CITATION_INSERT: {
609 FuncRequest fr(LFUN_INSET_INSERT, "citation");
610 enable = getStatus(fr).enabled();
614 case LFUN_BUFFER_WRITE: {
615 enable = lyx_view_->buffer()->isUnnamed()
616 || !lyx_view_->buffer()->isClean();
621 case LFUN_BUFFER_WRITE_ALL: {
622 // We enable the command only if there are some modified buffers
623 Buffer * first = theBufferList().first();
624 bool modified = false;
628 // We cannot use a for loop as the buffer list is a cycle.
634 b = theBufferList().next(b);
635 } while (b != first);
643 case LFUN_BOOKMARK_GOTO: {
644 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
645 enable = LyX::ref().session().bookmarks().isValid(num);
649 case LFUN_BOOKMARK_CLEAR:
650 enable = LyX::ref().session().bookmarks().size() > 0;
653 case LFUN_TOOLBAR_TOGGLE: {
654 bool const current = lyx_view_->isToolbarVisible(cmd.getArg(0));
655 flag.setOnOff(current);
658 case LFUN_WINDOW_CLOSE: {
659 enable = (theApp()->gui().viewIds().size() > 1);
663 // this one is difficult to get right. As a half-baked
664 // solution, we consider only the first action of the sequence
665 case LFUN_COMMAND_SEQUENCE: {
666 // argument contains ';'-terminated commands
667 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
668 FuncRequest func(lyxaction.lookupFunc(firstcmd));
669 func.origin = cmd.origin;
670 flag = getStatus(func);
673 case LFUN_BUFFER_NEW:
674 case LFUN_BUFFER_NEW_TEMPLATE:
675 case LFUN_WORD_FIND_FORWARD:
676 case LFUN_WORD_FIND_BACKWARD:
677 case LFUN_COMMAND_PREFIX:
678 case LFUN_COMMAND_EXECUTE:
680 case LFUN_META_PREFIX:
681 case LFUN_BUFFER_CLOSE:
682 case LFUN_BUFFER_WRITE_AS:
683 case LFUN_BUFFER_UPDATE:
684 case LFUN_BUFFER_VIEW:
685 case LFUN_MASTER_BUFFER_UPDATE:
686 case LFUN_MASTER_BUFFER_VIEW:
687 case LFUN_BUFFER_IMPORT:
688 case LFUN_BUFFER_AUTO_SAVE:
689 case LFUN_RECONFIGURE:
693 case LFUN_DROP_LAYOUTS_CHOICE:
695 case LFUN_SERVER_GET_NAME:
696 case LFUN_SERVER_NOTIFY:
697 case LFUN_SERVER_GOTO_FILE_ROW:
698 case LFUN_DIALOG_HIDE:
699 case LFUN_DIALOG_DISCONNECT_INSET:
700 case LFUN_BUFFER_CHILD_OPEN:
701 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
702 case LFUN_KEYMAP_OFF:
703 case LFUN_KEYMAP_PRIMARY:
704 case LFUN_KEYMAP_SECONDARY:
705 case LFUN_KEYMAP_TOGGLE:
707 case LFUN_BUFFER_EXPORT_CUSTOM:
708 case LFUN_BUFFER_PRINT:
709 case LFUN_PREFERENCES_SAVE:
710 case LFUN_SCREEN_FONT_UPDATE:
713 case LFUN_EXTERNAL_EDIT:
714 case LFUN_GRAPHICS_EDIT:
715 case LFUN_ALL_INSETS_TOGGLE:
716 case LFUN_BUFFER_LANGUAGE:
717 case LFUN_TEXTCLASS_APPLY:
718 case LFUN_TEXTCLASS_LOAD:
719 case LFUN_BUFFER_SAVE_AS_DEFAULT:
720 case LFUN_BUFFER_PARAMS_APPLY:
721 case LFUN_LAYOUT_MODULES_CLEAR:
722 case LFUN_LAYOUT_MODULE_ADD:
723 case LFUN_LAYOUT_RELOAD:
724 case LFUN_LYXRC_APPLY:
725 case LFUN_BUFFER_NEXT:
726 case LFUN_BUFFER_PREVIOUS:
727 case LFUN_WINDOW_NEW:
729 // these are handled in our dispatch()
737 if (!getLocalStatus(view()->cursor(), cmd, flag))
738 flag = view()->getStatus(cmd);
744 // Can we use a readonly buffer?
745 if (buf && buf->isReadonly()
746 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
747 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
748 flag.message(from_utf8(N_("Document is read-only")));
752 // Are we in a DELETED change-tracking region?
754 && lookupChangeType(view()->cursor(), true) == Change::DELETED
755 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
756 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
757 flag.message(from_utf8(N_("This portion of the document is deleted.")));
761 // the default error message if we disable the command
762 if (!flag.enabled() && flag.message().empty())
763 flag.message(from_utf8(N_("Command disabled")));
769 bool LyXFunc::ensureBufferClean(BufferView * bv)
771 Buffer & buf = bv->buffer();
775 docstring const file = makeDisplayPath(buf.fileName(), 30);
776 docstring text = bformat(_("The document %1$s has unsaved "
777 "changes.\n\nDo you want to save "
778 "the document?"), file);
779 int const ret = Alert::prompt(_("Save changed document?"),
780 text, 0, 1, _("&Save"),
784 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
786 return buf.isClean();
792 void showPrintError(string const & name)
794 docstring str = bformat(_("Could not print the document %1$s.\n"
795 "Check that your printer is set up correctly."),
796 makeDisplayPath(name, 50));
797 Alert::error(_("Print document failed"), str);
801 void loadTextClass(string const & name)
803 std::pair<bool, textclass_type> const tc_pair =
804 textclasslist.numberOfClass(name);
806 if (!tc_pair.first) {
807 lyxerr << "Document class \"" << name
808 << "\" does not exist."
813 textclass_type const tc = tc_pair.second;
815 if (!textclasslist[tc].load()) {
816 docstring s = bformat(_("The document class %1$s."
817 "could not be loaded."),
818 from_utf8(textclasslist[tc].name()));
819 Alert::error(_("Could not load class"), s);
824 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
829 void LyXFunc::dispatch(FuncRequest const & cmd)
831 string const argument = to_utf8(cmd.argument());
832 kb_action const action = cmd.action;
834 LYXERR(Debug::ACTION) << endl << "LyXFunc::dispatch: cmd: " << cmd << endl;
835 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
837 // we have not done anything wrong yet.
839 dispatch_buffer.erase();
841 // redraw the screen at the end (first of the two drawing steps).
842 //This is done unless explicitely requested otherwise
843 Update::flags updateFlags = Update::FitCursor;
845 FuncStatus const flag = getStatus(cmd);
846 if (!flag.enabled()) {
847 // We cannot use this function here
848 LYXERR(Debug::ACTION) << "LyXFunc::dispatch: "
849 << lyxaction.getActionName(action)
850 << " [" << action << "] is disabled at this location"
852 setErrorMessage(flag.message());
856 case LFUN_WORD_FIND_FORWARD:
857 case LFUN_WORD_FIND_BACKWARD: {
858 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
859 static docstring last_search;
860 docstring searched_string;
862 if (!cmd.argument().empty()) {
863 last_search = cmd.argument();
864 searched_string = cmd.argument();
866 searched_string = last_search;
869 if (searched_string.empty())
872 bool const fw = action == LFUN_WORD_FIND_FORWARD;
873 docstring const data =
874 find2string(searched_string, true, false, fw);
875 find(view(), FuncRequest(LFUN_WORD_FIND, data));
879 case LFUN_COMMAND_PREFIX:
880 BOOST_ASSERT(lyx_view_);
881 lyx_view_->message(keyseq.printOptions(true));
884 case LFUN_COMMAND_EXECUTE:
885 BOOST_ASSERT(lyx_view_);
886 lyx_view_->showMiniBuffer(true);
890 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
892 meta_fake_bit = NoModifier;
893 if (lyx_view_->buffer())
894 // cancel any selection
895 dispatch(FuncRequest(LFUN_MARK_OFF));
896 setMessage(from_ascii(N_("Cancel")));
899 case LFUN_META_PREFIX:
900 meta_fake_bit = AltModifier;
901 setMessage(keyseq.print(true));
904 case LFUN_BUFFER_TOGGLE_READ_ONLY: {
905 BOOST_ASSERT(lyx_view_ && lyx_view_->view() && lyx_view_->buffer());
906 Buffer * buf = lyx_view_->buffer();
907 if (buf->lyxvc().inUse())
908 buf->lyxvc().toggleReadOnly();
910 buf->setReadonly(!lyx_view_->buffer()->isReadonly());
914 // --- Menus -----------------------------------------------
915 case LFUN_BUFFER_NEW:
916 menuNew(argument, false);
917 updateFlags = Update::None;
920 case LFUN_BUFFER_NEW_TEMPLATE:
921 menuNew(argument, true);
922 updateFlags = Update::None;
925 case LFUN_BUFFER_CLOSE:
927 updateFlags = Update::None;
930 case LFUN_BUFFER_WRITE:
931 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
932 if (!lyx_view_->buffer()->isUnnamed()) {
933 docstring const str = bformat(_("Saving document %1$s..."),
934 makeDisplayPath(lyx_view_->buffer()->fileName()));
935 lyx_view_->message(str);
936 lyx_view_->buffer()->menuWrite();
937 lyx_view_->message(str + _(" done."));
939 lyx_view_->buffer()->writeAs();
941 updateFlags = Update::None;
944 case LFUN_BUFFER_WRITE_AS:
945 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
946 lyx_view_->buffer()->writeAs(argument);
947 updateFlags = Update::None;
950 case LFUN_BUFFER_WRITE_ALL: {
951 Buffer * first = theBufferList().first();
954 lyx_view_->message(_("Saving all documents..."));
956 // We cannot use a for loop as the buffer list cycles.
959 if (!b->isUnnamed()) {
961 lyxerr[Debug::ACTION] << "Saved " << b->fileName() << endl;
965 b = theBufferList().next(b);
966 } while (b != first);
967 lyx_view_->message(_("All documents saved."));
970 updateFlags = Update::None;
974 case LFUN_BUFFER_RELOAD: {
975 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
976 docstring const file = makeDisplayPath(lyx_view_->buffer()->fileName(), 20);
977 docstring text = bformat(_("Any changes will be lost. Are you sure "
978 "you want to revert to the saved version of the document %1$s?"), file);
979 int const ret = Alert::prompt(_("Revert to saved document?"),
980 text, 1, 1, _("&Revert"), _("&Cancel"));
987 case LFUN_BUFFER_UPDATE:
988 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
989 Exporter::Export(lyx_view_->buffer(), argument, true);
992 case LFUN_BUFFER_VIEW:
993 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
994 Exporter::preview(lyx_view_->buffer(), argument);
997 case LFUN_MASTER_BUFFER_UPDATE:
998 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->getMasterBuffer());
999 Exporter::Export(lyx_view_->buffer()->getMasterBuffer(), argument, true);
1002 case LFUN_MASTER_BUFFER_VIEW:
1003 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->getMasterBuffer());
1004 Exporter::preview(lyx_view_->buffer()->getMasterBuffer(), argument);
1007 case LFUN_BUILD_PROGRAM:
1008 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1009 Exporter::Export(lyx_view_->buffer(), "program", true);
1012 case LFUN_BUFFER_CHKTEX:
1013 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1014 lyx_view_->buffer()->runChktex();
1017 case LFUN_BUFFER_EXPORT:
1018 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1019 if (argument == "custom")
1020 lyx_view_->getDialogs().show("sendto");
1022 Exporter::Export(lyx_view_->buffer(), argument, false);
1026 case LFUN_BUFFER_EXPORT_CUSTOM: {
1027 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1029 string command = split(argument, format_name, ' ');
1030 Format const * format = formats.getFormat(format_name);
1032 lyxerr << "Format \"" << format_name
1033 << "\" not recognized!"
1038 Buffer * buffer = lyx_view_->buffer();
1040 // The name of the file created by the conversion process
1043 // Output to filename
1044 if (format->name() == "lyx") {
1045 string const latexname =
1046 buffer->getLatexName(false);
1047 filename = changeExtension(latexname,
1048 format->extension());
1049 filename = addName(buffer->temppath(), filename);
1051 if (!buffer->writeFile(FileName(filename)))
1055 Exporter::Export(buffer, format_name, true, filename);
1058 // Substitute $$FName for filename
1059 if (!contains(command, "$$FName"))
1060 command = "( " + command + " ) < $$FName";
1061 command = subst(command, "$$FName", filename);
1063 // Execute the command in the background
1065 call.startscript(Systemcall::DontWait, command);
1069 case LFUN_BUFFER_PRINT: {
1070 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1071 // FIXME: cmd.getArg() might fail if one of the arguments
1072 // contains double quotes
1073 string target = cmd.getArg(0);
1074 string target_name = cmd.getArg(1);
1075 string command = cmd.getArg(2);
1078 || target_name.empty()
1079 || command.empty()) {
1080 lyxerr << "Unable to parse \""
1081 << argument << '"' << endl;
1084 if (target != "printer" && target != "file") {
1085 lyxerr << "Unrecognized target \""
1086 << target << '"' << endl;
1090 Buffer * buffer = lyx_view_->buffer();
1092 if (!Exporter::Export(buffer, "dvi", true)) {
1093 showPrintError(buffer->fileName());
1097 // Push directory path.
1098 string const path = buffer->temppath();
1099 // Prevent the compiler from optimizing away p
1101 support::Path p(pp);
1103 // there are three cases here:
1104 // 1. we print to a file
1105 // 2. we print directly to a printer
1106 // 3. we print using a spool command (print to file first)
1109 string const dviname =
1110 changeExtension(buffer->getLatexName(true),
1113 if (target == "printer") {
1114 if (!lyxrc.print_spool_command.empty()) {
1115 // case 3: print using a spool
1116 string const psname =
1117 changeExtension(dviname,".ps");
1118 command += ' ' + lyxrc.print_to_file
1121 + quoteName(dviname);
1124 lyxrc.print_spool_command + ' ';
1125 if (target_name != "default") {
1126 command2 += lyxrc.print_spool_printerprefix
1130 command2 += quoteName(psname);
1132 // If successful, then spool command
1133 res = one.startscript(
1138 res = one.startscript(
1139 Systemcall::DontWait,
1142 // case 2: print directly to a printer
1143 if (target_name != "default")
1144 command += ' ' + lyxrc.print_to_printer + target_name + ' ';
1145 res = one.startscript(
1146 Systemcall::DontWait,
1147 command + quoteName(dviname));
1151 // case 1: print to a file
1152 FileName const filename(makeAbsPath(target_name,
1153 lyx_view_->buffer()->filePath()));
1154 FileName const dvifile(makeAbsPath(dviname, path));
1155 if (filename.exists()) {
1156 docstring text = bformat(
1157 _("The file %1$s already exists.\n\n"
1158 "Do you want to overwrite that file?"),
1159 makeDisplayPath(filename.absFilename()));
1160 if (Alert::prompt(_("Overwrite file?"),
1161 text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
1164 command += ' ' + lyxrc.print_to_file
1165 + quoteName(filename.toFilesystemEncoding())
1167 + quoteName(dvifile.toFilesystemEncoding());
1168 res = one.startscript(Systemcall::DontWait,
1173 showPrintError(buffer->fileName());
1177 case LFUN_BUFFER_IMPORT:
1182 // quitting is triggered by the gui code
1183 // (leaving the event loop).
1184 lyx_view_->message(from_utf8(N_("Exiting.")));
1185 if (theBufferList().quitWriteAll())
1186 theApp()->gui().closeAllViews();
1189 case LFUN_BUFFER_AUTO_SAVE:
1190 lyx_view_->buffer()->autoSave();
1193 case LFUN_RECONFIGURE:
1194 BOOST_ASSERT(lyx_view_);
1195 // argument is any additional parameter to the configure.py command
1196 reconfigure(*lyx_view_, argument);
1199 case LFUN_HELP_OPEN: {
1200 BOOST_ASSERT(lyx_view_);
1201 string const arg = argument;
1203 setErrorMessage(from_ascii(N_("Missing argument")));
1206 FileName const fname = i18nLibFileSearch("doc", arg, "lyx");
1207 if (fname.empty()) {
1208 lyxerr << "LyX: unable to find documentation file `"
1209 << arg << "'. Bad installation?" << endl;
1212 lyx_view_->message(bformat(_("Opening help file %1$s..."),
1213 makeDisplayPath(fname.absFilename())));
1214 Buffer * buf = lyx_view_->loadLyXFile(fname, false);
1217 lyx_view_->setBuffer(buf);
1218 lyx_view_->showErrorList("Parse");
1220 updateFlags = Update::None;
1224 // --- version control -------------------------------
1225 case LFUN_VC_REGISTER:
1226 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1227 if (!ensureBufferClean(view()))
1229 if (!lyx_view_->buffer()->lyxvc().inUse()) {
1230 lyx_view_->buffer()->lyxvc().registrer();
1233 updateFlags = Update::Force;
1236 case LFUN_VC_CHECK_IN:
1237 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1238 if (!ensureBufferClean(view()))
1240 if (lyx_view_->buffer()->lyxvc().inUse()
1241 && !lyx_view_->buffer()->isReadonly()) {
1242 lyx_view_->buffer()->lyxvc().checkIn();
1247 case LFUN_VC_CHECK_OUT:
1248 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1249 if (!ensureBufferClean(view()))
1251 if (lyx_view_->buffer()->lyxvc().inUse()
1252 && lyx_view_->buffer()->isReadonly()) {
1253 lyx_view_->buffer()->lyxvc().checkOut();
1258 case LFUN_VC_REVERT:
1259 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1260 lyx_view_->buffer()->lyxvc().revert();
1264 case LFUN_VC_UNDO_LAST:
1265 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1266 lyx_view_->buffer()->lyxvc().undoLast();
1270 // --- buffers ----------------------------------------
1271 case LFUN_BUFFER_SWITCH:
1272 BOOST_ASSERT(lyx_view_);
1273 lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1274 updateFlags = Update::None;
1277 case LFUN_BUFFER_NEXT:
1278 BOOST_ASSERT(lyx_view_);
1279 lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer()));
1280 updateFlags = Update::None;
1283 case LFUN_BUFFER_PREVIOUS:
1284 BOOST_ASSERT(lyx_view_);
1285 lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer()));
1286 updateFlags = Update::None;
1289 case LFUN_FILE_NEW: {
1290 BOOST_ASSERT(lyx_view_);
1292 string tmpname = split(argument, name, ':'); // Split filename
1293 Buffer * const b = newFile(name, tmpname);
1295 lyx_view_->setBuffer(b);
1296 updateFlags = Update::None;
1300 case LFUN_FILE_OPEN:
1301 BOOST_ASSERT(lyx_view_);
1303 updateFlags = Update::None;
1306 case LFUN_DROP_LAYOUTS_CHOICE:
1307 BOOST_ASSERT(lyx_view_);
1308 lyx_view_->openLayoutList();
1311 case LFUN_MENU_OPEN:
1312 BOOST_ASSERT(lyx_view_);
1313 lyx_view_->openMenu(from_utf8(argument));
1316 // --- lyxserver commands ----------------------------
1317 case LFUN_SERVER_GET_NAME:
1318 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1319 setMessage(from_utf8(lyx_view_->buffer()->fileName()));
1320 LYXERR(Debug::INFO) << "FNAME["
1321 << lyx_view_->buffer()->fileName()
1325 case LFUN_SERVER_NOTIFY:
1326 dispatch_buffer = keyseq.print(false);
1327 theServer().notifyClient(to_utf8(dispatch_buffer));
1330 case LFUN_SERVER_GOTO_FILE_ROW: {
1331 BOOST_ASSERT(lyx_view_);
1334 istringstream is(argument);
1335 is >> file_name >> row;
1337 bool loaded = false;
1338 if (prefixIs(file_name, package().temp_dir().absFilename()))
1339 // Needed by inverse dvi search. If it is a file
1340 // in tmpdir, call the apropriated function
1341 buf = theBufferList().getBufferFromTmp(file_name);
1343 // Must replace extension of the file to be .lyx
1344 // and get full path
1345 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1346 // Either change buffer or load the file
1347 if (theBufferList().exists(s.absFilename()))
1348 buf = theBufferList().getBuffer(s.absFilename());
1350 buf = lyx_view_->loadLyXFile(s);
1356 updateFlags = Update::None;
1361 lyx_view_->setBuffer(buf);
1362 view()->setCursorFromRow(row);
1364 lyx_view_->showErrorList("Parse");
1365 updateFlags = Update::FitCursor;
1369 case LFUN_DIALOG_SHOW: {
1370 BOOST_ASSERT(lyx_view_);
1371 string const name = cmd.getArg(0);
1372 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1374 if (name == "character") {
1375 data = freefont2string();
1377 lyx_view_->getDialogs().show("character", data);
1378 } else if (name == "latexlog") {
1379 pair<Buffer::LogType, string> const logfile =
1380 lyx_view_->buffer()->getLogName();
1381 switch (logfile.first) {
1382 case Buffer::latexlog:
1385 case Buffer::buildlog:
1389 data += Lexer::quoteString(logfile.second);
1390 lyx_view_->getDialogs().show("log", data);
1391 } else if (name == "vclog") {
1392 string const data = "vc " +
1393 Lexer::quoteString(lyx_view_->buffer()->lyxvc().getLogFile());
1394 lyx_view_->getDialogs().show("log", data);
1396 lyx_view_->getDialogs().show(name, data);
1400 case LFUN_DIALOG_SHOW_NEW_INSET: {
1401 BOOST_ASSERT(lyx_view_);
1402 string const name = cmd.getArg(0);
1403 InsetCode code = insetCode(name);
1404 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1405 bool insetCodeOK = true;
1414 case HYPERLINK_CODE: {
1415 InsetCommandParams p(name);
1416 data = InsetCommandMailer::params2string(name, p);
1419 case INCLUDE_CODE: {
1420 // data is the include type: one of "include",
1421 // "input", "verbatiminput" or "verbatiminput*"
1423 // default type is requested
1425 InsetCommandParams p("include", data);
1426 data = InsetIncludeMailer::params2string(p);
1430 // \c data == "Boxed" || "Frameless" etc
1431 InsetBoxParams p(data);
1432 data = InsetBoxMailer::params2string(p);
1436 InsetBranchParams p;
1437 data = InsetBranchMailer::params2string(p);
1441 InsetCommandParams p("cite");
1442 data = InsetCommandMailer::params2string(name, p);
1446 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1449 case EXTERNAL_CODE: {
1450 InsetExternalParams p;
1451 Buffer const & buffer = *lyx_view_->buffer();
1452 data = InsetExternalMailer::params2string(p, buffer);
1457 data = InsetFloatMailer::params2string(p);
1460 case LISTINGS_CODE: {
1461 InsetListingsParams p;
1462 data = InsetListingsMailer::params2string(p);
1465 case GRAPHICS_CODE: {
1466 InsetGraphicsParams p;
1467 Buffer const & buffer = *lyx_view_->buffer();
1468 data = InsetGraphicsMailer::params2string(p, buffer);
1473 data = InsetNoteMailer::params2string(p);
1478 data = InsetVSpaceMailer::params2string(space);
1483 data = InsetWrapMailer::params2string(p);
1487 lyxerr << "Inset type '" << name <<
1488 "' not recognized in LFUN_DIALOG_SHOW_NEW_INSET" << std:: endl;
1489 insetCodeOK = false;
1491 } // end switch(code)
1493 lyx_view_->getDialogs().show(name, data, 0);
1497 case LFUN_DIALOG_UPDATE: {
1498 BOOST_ASSERT(lyx_view_);
1499 string const & name = argument;
1500 // Can only update a dialog connected to an existing inset
1501 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1503 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1504 inset->dispatch(view()->cursor(), fr);
1505 } else if (name == "paragraph") {
1506 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1507 } else if (name == "prefs") {
1508 lyx_view_->getDialogs().update(name, string());
1513 case LFUN_DIALOG_HIDE:
1514 LyX::cref().hideDialogs(argument, 0);
1517 case LFUN_DIALOG_TOGGLE: {
1518 BOOST_ASSERT(lyx_view_);
1519 if (lyx_view_->getDialogs().visible(cmd.getArg(0)))
1520 dispatch(FuncRequest(LFUN_DIALOG_HIDE, argument));
1522 dispatch(FuncRequest(LFUN_DIALOG_SHOW, argument));
1526 case LFUN_DIALOG_DISCONNECT_INSET:
1527 BOOST_ASSERT(lyx_view_);
1528 lyx_view_->getDialogs().disconnect(argument);
1532 case LFUN_CITATION_INSERT: {
1533 BOOST_ASSERT(lyx_view_);
1534 if (!argument.empty()) {
1535 // we can have one optional argument, delimited by '|'
1536 // citation-insert <key>|<text_before>
1537 // this should be enhanced to also support text_after
1538 // and citation style
1539 string arg = argument;
1541 if (contains(argument, "|")) {
1542 arg = token(argument, '|', 0);
1543 opt1 = token(argument, '|', 1);
1545 InsetCommandParams icp("cite");
1546 icp["key"] = from_utf8(arg);
1548 icp["before"] = from_utf8(opt1);
1549 string icstr = InsetCommandMailer::params2string("citation", icp);
1550 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1553 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1557 case LFUN_BUFFER_CHILD_OPEN: {
1558 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1559 Buffer * parent = lyx_view_->buffer();
1560 FileName filename = makeAbsPath(argument, parent->filePath());
1561 view()->saveBookmark(false);
1563 bool parsed = false;
1564 if (theBufferList().exists(filename.absFilename())) {
1565 child = theBufferList().getBuffer(filename.absFilename());
1567 setMessage(bformat(_("Opening child document %1$s..."),
1568 makeDisplayPath(filename.absFilename())));
1569 child = lyx_view_->loadLyXFile(filename, true);
1573 // Set the parent name of the child document.
1574 // This makes insertion of citations and references in the child work,
1575 // when the target is in the parent or another child document.
1576 child->setParentName(parent->fileName());
1577 updateLabels(*child->getMasterBuffer());
1578 lyx_view_->setBuffer(child);
1580 lyx_view_->showErrorList("Parse");
1583 // If a screen update is required (in case where auto_open is false),
1584 // setBuffer() would have taken care of it already. Otherwise we shall
1585 // reset the update flag because it can cause a circular problem.
1587 updateFlags = Update::None;
1591 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1592 BOOST_ASSERT(lyx_view_);
1593 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1596 case LFUN_KEYMAP_OFF:
1597 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1598 lyx_view_->view()->getIntl().keyMapOn(false);
1601 case LFUN_KEYMAP_PRIMARY:
1602 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1603 lyx_view_->view()->getIntl().keyMapPrim();
1606 case LFUN_KEYMAP_SECONDARY:
1607 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1608 lyx_view_->view()->getIntl().keyMapSec();
1611 case LFUN_KEYMAP_TOGGLE:
1612 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1613 lyx_view_->view()->getIntl().toggleKeyMap();
1619 string rest = split(argument, countstr, ' ');
1620 istringstream is(countstr);
1623 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1624 for (int i = 0; i < count; ++i)
1625 dispatch(lyxaction.lookupFunc(rest));
1629 case LFUN_COMMAND_SEQUENCE: {
1630 // argument contains ';'-terminated commands
1631 string arg = argument;
1632 while (!arg.empty()) {
1634 arg = split(arg, first, ';');
1635 FuncRequest func(lyxaction.lookupFunc(first));
1636 func.origin = cmd.origin;
1642 case LFUN_PREFERENCES_SAVE: {
1643 lyxrc.write(makeAbsPath("preferences",
1644 package().user_support().absFilename()),
1649 case LFUN_SCREEN_FONT_UPDATE:
1650 BOOST_ASSERT(lyx_view_);
1651 // handle the screen font changes.
1652 theFontLoader().update();
1653 /// FIXME: only the current view will be updated. the Gui
1654 /// class is able to furnish the list of views.
1655 updateFlags = Update::Force;
1658 case LFUN_SET_COLOR: {
1660 string const x11_name = split(argument, lyx_name, ' ');
1661 if (lyx_name.empty() || x11_name.empty()) {
1662 setErrorMessage(from_ascii(N_(
1663 "Syntax: set-color <lyx_name>"
1668 bool const graphicsbg_changed =
1669 (lyx_name == lcolor.getLyXName(Color::graphicsbg) &&
1670 x11_name != lcolor.getX11Name(Color::graphicsbg));
1672 if (!lcolor.setColor(lyx_name, x11_name)) {
1674 bformat(_("Set-color \"%1$s\" failed "
1675 "- color is undefined or "
1676 "may not be redefined"),
1677 from_utf8(lyx_name)));
1681 theApp()->updateColor(lcolor.getFromLyXName(lyx_name));
1683 if (graphicsbg_changed) {
1684 // FIXME: The graphics cache no longer has a changeDisplay method.
1686 graphics::GCache::get().changeDisplay(true);
1693 BOOST_ASSERT(lyx_view_);
1694 lyx_view_->message(from_utf8(argument));
1697 case LFUN_EXTERNAL_EDIT: {
1698 BOOST_ASSERT(lyx_view_);
1699 FuncRequest fr(action, argument);
1700 InsetExternal().dispatch(view()->cursor(), fr);
1704 case LFUN_GRAPHICS_EDIT: {
1705 FuncRequest fr(action, argument);
1706 InsetGraphics().dispatch(view()->cursor(), fr);
1710 case LFUN_INSET_APPLY: {
1711 BOOST_ASSERT(lyx_view_);
1712 string const name = cmd.getArg(0);
1713 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1715 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1716 inset->dispatch(view()->cursor(), fr);
1718 FuncRequest fr(LFUN_INSET_INSERT, argument);
1721 // ideally, the update flag should be set by the insets,
1722 // but this is not possible currently
1723 updateFlags = Update::Force | Update::FitCursor;
1727 case LFUN_ALL_INSETS_TOGGLE: {
1728 BOOST_ASSERT(lyx_view_);
1730 string const name = split(argument, action, ' ');
1731 InsetCode const inset_code = insetCode(name);
1733 Cursor & cur = view()->cursor();
1734 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1736 Inset & inset = lyx_view_->buffer()->inset();
1737 InsetIterator it = inset_iterator_begin(inset);
1738 InsetIterator const end = inset_iterator_end(inset);
1739 for (; it != end; ++it) {
1740 if (!it->asInsetMath()
1741 && (inset_code == NO_CODE
1742 || inset_code == it->lyxCode())) {
1743 Cursor tmpcur = cur;
1744 tmpcur.pushLeft(*it);
1745 it->dispatch(tmpcur, fr);
1748 updateFlags = Update::Force | Update::FitCursor;
1752 case LFUN_BUFFER_LANGUAGE: {
1753 BOOST_ASSERT(lyx_view_);
1754 Buffer & buffer = *lyx_view_->buffer();
1755 Language const * oldL = buffer.params().language;
1756 Language const * newL = languages.getLanguage(argument);
1757 if (!newL || oldL == newL)
1760 if (oldL->rightToLeft() == newL->rightToLeft()
1761 && !buffer.isMultiLingual())
1762 buffer.changeLanguage(oldL, newL);
1766 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1767 string const fname =
1768 addName(addPath(package().user_support().absFilename(), "templates/"),
1770 Buffer defaults(fname);
1772 istringstream ss(argument);
1775 int const unknown_tokens = defaults.readHeader(lex);
1777 if (unknown_tokens != 0) {
1778 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1779 << unknown_tokens << " unknown token"
1780 << (unknown_tokens == 1 ? "" : "s")
1784 if (defaults.writeFile(FileName(defaults.fileName())))
1785 setMessage(bformat(_("Document defaults saved in %1$s"),
1786 makeDisplayPath(fname)));
1788 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1792 case LFUN_BUFFER_PARAMS_APPLY: {
1793 BOOST_ASSERT(lyx_view_);
1794 biblio::CiteEngine const oldEngine =
1795 lyx_view_->buffer()->params().getEngine();
1797 Buffer * buffer = lyx_view_->buffer();
1799 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1801 Cursor & cur = view()->cursor();
1802 cur.recordUndoFullDocument();
1804 istringstream ss(argument);
1807 int const unknown_tokens = buffer->readHeader(lex);
1809 if (unknown_tokens != 0) {
1810 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1811 << unknown_tokens << " unknown token"
1812 << (unknown_tokens == 1 ? "" : "s")
1816 updateLayout(oldClass, buffer);
1818 biblio::CiteEngine const newEngine =
1819 lyx_view_->buffer()->params().getEngine();
1821 if (oldEngine != newEngine) {
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 view()->cursor().recordUndoFullDocument();
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 view()->cursor().recordUndoFullDocument();
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 view()->cursor().recordUndoFullDocument();
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 FileName(filename).isReadable()) {
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 (!fullname.exists()) {
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 (lyxfile.exists() && 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 FileName path(lyxrc_new.document_path);
2407 if (path.exists() && path.isDirectory())
2408 support::package().document_dir() = FileName(lyxrc.document_path);
2410 case LyXRC::RC_ESC_CHARS:
2411 case LyXRC::RC_FONT_ENCODING:
2412 case LyXRC::RC_FORMAT:
2413 case LyXRC::RC_INDEX_COMMAND:
2414 case LyXRC::RC_INPUT:
2415 case LyXRC::RC_KBMAP:
2416 case LyXRC::RC_KBMAP_PRIMARY:
2417 case LyXRC::RC_KBMAP_SECONDARY:
2418 case LyXRC::RC_LABEL_INIT_LENGTH:
2419 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2420 case LyXRC::RC_LANGUAGE_AUTO_END:
2421 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2422 case LyXRC::RC_LANGUAGE_COMMAND_END:
2423 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2424 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2425 case LyXRC::RC_LANGUAGE_PACKAGE:
2426 case LyXRC::RC_LANGUAGE_USE_BABEL:
2427 case LyXRC::RC_MAKE_BACKUP:
2428 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2429 case LyXRC::RC_NUMLASTFILES:
2430 case LyXRC::RC_PATH_PREFIX:
2431 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2432 support::prependEnvPath("PATH", lyxrc.path_prefix);
2434 case LyXRC::RC_PERS_DICT:
2435 case LyXRC::RC_PREVIEW:
2436 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2437 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2438 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2439 case LyXRC::RC_PRINTCOPIESFLAG:
2440 case LyXRC::RC_PRINTER:
2441 case LyXRC::RC_PRINTEVENPAGEFLAG:
2442 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2443 case LyXRC::RC_PRINTFILEEXTENSION:
2444 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2445 case LyXRC::RC_PRINTODDPAGEFLAG:
2446 case LyXRC::RC_PRINTPAGERANGEFLAG:
2447 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2448 case LyXRC::RC_PRINTPAPERFLAG:
2449 case LyXRC::RC_PRINTREVERSEFLAG:
2450 case LyXRC::RC_PRINTSPOOL_COMMAND:
2451 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2452 case LyXRC::RC_PRINTTOFILE:
2453 case LyXRC::RC_PRINTTOPRINTER:
2454 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2455 case LyXRC::RC_PRINT_COMMAND:
2456 case LyXRC::RC_RTL_SUPPORT:
2457 case LyXRC::RC_SCREEN_DPI:
2458 case LyXRC::RC_SCREEN_FONT_ROMAN:
2459 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2460 case LyXRC::RC_SCREEN_FONT_SANS:
2461 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2462 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2463 case LyXRC::RC_SCREEN_FONT_SIZES:
2464 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2465 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2466 case LyXRC::RC_SCREEN_GEOMETRY_HEIGHT:
2467 case LyXRC::RC_SCREEN_GEOMETRY_WIDTH:
2468 case LyXRC::RC_SCREEN_GEOMETRY_XYSAVED:
2469 case LyXRC::RC_SCREEN_ZOOM:
2470 case LyXRC::RC_SERVERPIPE:
2471 case LyXRC::RC_SET_COLOR:
2472 case LyXRC::RC_SHOW_BANNER:
2473 case LyXRC::RC_SPELL_COMMAND:
2474 case LyXRC::RC_TEMPDIRPATH:
2475 case LyXRC::RC_TEMPLATEPATH:
2476 case LyXRC::RC_TEX_ALLOWS_SPACES:
2477 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2478 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2479 support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2481 case LyXRC::RC_UIFILE:
2482 case LyXRC::RC_USER_EMAIL:
2483 case LyXRC::RC_USER_NAME:
2484 case LyXRC::RC_USETEMPDIR:
2485 case LyXRC::RC_USE_ALT_LANG:
2486 case LyXRC::RC_USE_CONVERTER_CACHE:
2487 case LyXRC::RC_USE_ESC_CHARS:
2488 case LyXRC::RC_USE_INP_ENC:
2489 case LyXRC::RC_USE_PERS_DICT:
2490 case LyXRC::RC_USE_SPELL_LIB:
2491 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2492 case LyXRC::RC_VIEWER:
2493 case LyXRC::RC_LAST: