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_funcs.h"
31 #include "BufferView.h"
35 #include "CutAndPaste.h"
37 #include "DispatchResult.h"
39 #include "ErrorList.h"
42 #include "FuncRequest.h"
43 #include "FuncStatus.h"
46 #include "InsetIterator.h"
51 #include "LyXAction.h"
56 #include "Paragraph.h"
57 #include "ParagraphParameters.h"
58 #include "ParIterator.h"
62 #include "TextClassList.h"
63 #include "ToolbarBackend.h"
66 #include "insets/InsetBox.h"
67 #include "insets/InsetBranch.h"
68 #include "insets/InsetCommand.h"
69 #include "insets/InsetERT.h"
70 #include "insets/InsetExternal.h"
71 #include "insets/InsetFloat.h"
72 #include "insets/InsetListings.h"
73 #include "insets/InsetGraphics.h"
74 #include "insets/InsetInclude.h"
75 #include "insets/InsetNote.h"
76 #include "insets/InsetTabular.h"
77 #include "insets/InsetVSpace.h"
78 #include "insets/InsetWrap.h"
80 #include "frontends/Application.h"
81 #include "frontends/alert.h"
82 #include "frontends/Dialogs.h"
83 #include "frontends/FileDialog.h"
84 #include "frontends/FontLoader.h"
85 #include "frontends/Gui.h"
86 #include "frontends/KeySymbol.h"
87 #include "frontends/LyXView.h"
88 #include "frontends/Selection.h"
89 #include "frontends/WorkArea.h"
91 #include "support/environment.h"
92 #include "support/FileFilterList.h"
93 #include "support/filetools.h"
94 #include "support/ForkedcallsController.h"
95 #include "support/fs_extras.h"
96 #include "support/lstrings.h"
97 #include "support/Path.h"
98 #include "support/Package.h"
99 #include "support/Systemcall.h"
100 #include "support/convert.h"
101 #include "support/os.h"
103 #include <boost/current_function.hpp>
104 #include <boost/filesystem/operations.hpp>
109 using std::make_pair;
112 using std::istringstream;
113 using std::ostringstream;
115 namespace fs = boost::filesystem;
119 using bv_funcs::freefont2string;
121 using frontend::LyXView;
123 using support::absolutePath;
124 using support::addName;
125 using support::addPath;
126 using support::bformat;
127 using support::changeExtension;
128 using support::contains;
129 using support::FileFilterList;
130 using support::FileName;
131 using support::fileSearch;
132 using support::ForkedcallsController;
133 using support::i18nLibFileSearch;
134 using support::isDirWriteable;
135 using support::isFileReadable;
136 using support::isStrInt;
137 using support::makeAbsPath;
138 using support::makeDisplayPath;
139 using support::package;
140 using support::quoteName;
141 using support::rtrim;
142 using support::split;
143 using support::subst;
144 using support::Systemcall;
145 using support::token;
147 using support::prefixIs;
149 namespace Alert = frontend::Alert;
154 bool getLocalStatus(Cursor cursor,
155 FuncRequest const & cmd, FuncStatus & status)
157 // Try to fix cursor in case it is broken.
158 cursor.fixIfBroken();
160 // This is, of course, a mess. Better create a new doc iterator and use
161 // this in Inset::getStatus. This might require an additional
162 // BufferView * arg, though (which should be avoided)
163 //Cursor safe = *this;
165 for ( ; cursor.depth(); cursor.pop()) {
166 //lyxerr << "\nCursor::getStatus: cmd: " << cmd << endl << *this << endl;
167 BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
168 BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
169 BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
171 // The inset's getStatus() will return 'true' if it made
172 // a definitive decision on whether it want to handle the
173 // request or not. The result of this decision is put into
174 // the 'status' parameter.
175 if (cursor.inset().getStatus(cursor, cmd, status)) {
184 /** Return the change status at cursor position, taking in account the
185 * status at each level of the document iterator (a table in a deleted
186 * footnote is deleted).
187 * When \param outer is true, the top slice is not looked at.
189 Change::Type lookupChangeType(DocIterator const & dit, bool outer = false)
191 size_t const depth = dit.depth() - (outer ? 1 : 0);
193 for (size_t i = 0 ; i < depth ; ++i) {
194 CursorSlice const & slice = dit[i];
195 if (!slice.inset().inMathed()
196 && slice.pos() < slice.paragraph().size()) {
197 Change::Type const ch = slice.paragraph().lookupChange(slice.pos()).type;
198 if (ch != Change::UNCHANGED)
202 return Change::UNCHANGED;
209 : lyx_view_(0), encoded_last_key(0), meta_fake_bit(key_modifier::none)
214 void LyXFunc::initKeySequences(KeyMap * kb)
216 keyseq = KeySequence(kb, kb);
217 cancel_meta_seq = KeySequence(kb, kb);
221 void LyXFunc::setLyXView(LyXView * lv)
223 if (!quitting && lyx_view_ && lyx_view_->view() && lyx_view_ != lv)
224 // save current selection to the selection buffer to allow
225 // middle-button paste in another window
226 cap::saveSelection(lyx_view_->view()->cursor());
231 void LyXFunc::handleKeyFunc(kb_action action)
233 char_type c = encoded_last_key;
238 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
239 lyx_view_->view()->getIntl().getTransManager().deadkey(
240 c, get_accent(action).accent, view()->cursor().innerText(), view()->cursor());
241 // Need to clear, in case the minibuffer calls these
244 // copied verbatim from do_accent_char
245 view()->cursor().resetAnchor();
250 void LyXFunc::gotoBookmark(unsigned int idx, bool openFile, bool switchToBuffer)
252 BOOST_ASSERT(lyx_view_);
253 if (!LyX::ref().session().bookmarks().isValid(idx))
255 BookmarksSection::Bookmark const & bm = LyX::ref().session().bookmarks().bookmark(idx);
256 BOOST_ASSERT(!bm.filename.empty());
257 string const file = bm.filename.absFilename();
258 // if the file is not opened, open it.
259 if (!theBufferList().exists(file)) {
261 dispatch(FuncRequest(LFUN_FILE_OPEN, file));
265 // open may fail, so we need to test it again
266 if (!theBufferList().exists(file))
269 // if the current buffer is not that one, switch to it.
270 if (lyx_view_->buffer()->fileName() != file) {
273 dispatch(FuncRequest(LFUN_BUFFER_SWITCH, file));
275 // moveToPosition try paragraph id first and then paragraph (pit, pos).
276 if (!view()->moveToPosition(bm.bottom_pit, bm.bottom_pos,
277 bm.top_id, bm.top_pos))
280 // Cursor jump succeeded!
281 Cursor const & cur = view()->cursor();
282 pit_type new_pit = cur.pit();
283 pos_type new_pos = cur.pos();
284 int new_id = cur.paragraph().id();
286 // if bottom_pit, bottom_pos or top_id has been changed, update bookmark
287 // see http://bugzilla.lyx.org/show_bug.cgi?id=3092
288 if (bm.bottom_pit != new_pit || bm.bottom_pos != new_pos
289 || bm.top_id != new_id) {
290 const_cast<BookmarksSection::Bookmark &>(bm).updatePos(
291 new_pit, new_pos, new_id);
296 void LyXFunc::processKeySym(KeySymbol const & keysym,
297 key_modifier::state state)
299 LYXERR(Debug::KEY) << "KeySym is " << keysym.getSymbolName() << endl;
301 // Do nothing if we have nothing (JMarc)
302 if (!keysym.isOK()) {
303 LYXERR(Debug::KEY) << "Empty kbd action (probably composing)"
308 if (keysym.isModifier()) {
309 LYXERR(Debug::KEY) << "isModifier true" << endl;
313 //Encoding const * encoding = view()->cursor().getEncoding();
314 //encoded_last_key = keysym.getISOEncoded(encoding ? encoding->name() : "");
315 // FIXME: encoded_last_key shadows the member variable of the same
316 // name. Is that intended?
317 char_type encoded_last_key = keysym.getUCSEncoded();
319 // Do a one-deep top-level lookup for
320 // cancel and meta-fake keys. RVDK_PATCH_5
321 cancel_meta_seq.reset();
323 FuncRequest func = cancel_meta_seq.addkey(keysym, state);
324 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
325 << " action first set to [" << func.action << ']'
328 // When not cancel or meta-fake, do the normal lookup.
329 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
330 // Mostly, meta_fake_bit = key_modifier::none. RVDK_PATCH_5.
331 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_PREFIX)) {
332 // remove Caps Lock and Mod2 as a modifiers
333 func = keyseq.addkey(keysym, (state | meta_fake_bit));
334 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
335 << "action now set to ["
336 << func.action << ']' << endl;
339 // Dont remove this unless you know what you are doing.
340 meta_fake_bit = key_modifier::none;
342 // Can this happen now ?
343 if (func.action == LFUN_NOACTION) {
344 func = FuncRequest(LFUN_COMMAND_PREFIX);
347 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
349 << func.action << "]["
350 << to_utf8(keyseq.print(false)) << ']'
353 // already here we know if it any point in going further
354 // why not return already here if action == -1 and
355 // num_bytes == 0? (Lgb)
357 if (keyseq.length() > 1) {
358 lyx_view_->message(keyseq.print(true));
362 // Maybe user can only reach the key via holding down shift.
363 // Let's see. But only if shift is the only modifier
364 if (func.action == LFUN_UNKNOWN_ACTION &&
365 state == key_modifier::shift) {
366 LYXERR(Debug::KEY) << "Trying without shift" << endl;
367 func = keyseq.addkey(keysym, key_modifier::none);
368 LYXERR(Debug::KEY) << "Action now " << func.action << endl;
371 if (func.action == LFUN_UNKNOWN_ACTION) {
372 // Hmm, we didn't match any of the keysequences. See
373 // if it's normal insertable text not already covered
375 if (keysym.isText() && keyseq.length() == 1) {
376 LYXERR(Debug::KEY) << "isText() is true, inserting." << endl;
377 func = FuncRequest(LFUN_SELF_INSERT,
378 FuncRequest::KEYBOARD);
380 LYXERR(Debug::KEY) << "Unknown, !isText() - giving up" << endl;
381 lyx_view_->message(_("Unknown function."));
386 if (func.action == LFUN_SELF_INSERT) {
387 if (encoded_last_key != 0) {
388 docstring const arg(1, encoded_last_key);
389 dispatch(FuncRequest(LFUN_SELF_INSERT, arg,
390 FuncRequest::KEYBOARD));
392 << "SelfInsert arg[`" << to_utf8(arg) << "']" << endl;
398 /* When we move around, or type, it's nice to be able to see
399 * the cursor immediately after the keypress.
401 if (lyx_view_ && lyx_view_->currentWorkArea())
402 lyx_view_->currentWorkArea()->startBlinkingCursor();
406 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
408 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
411 Cursor & cur = view()->cursor();
413 /* In LyX/Mac, when a dialog is open, the menus of the
414 application can still be accessed without giving focus to
415 the main window. In this case, we want to disable the menu
416 entries that are buffer-related.
418 Note that this code is not perfect, as bug 1941 attests:
419 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
421 Buffer * buf = lyx_view_? lyx_view_->buffer() : 0;
422 if (lyx_view_ && cmd.origin == FuncRequest::MENU && !lyx_view_->hasFocus())
425 if (cmd.action == LFUN_NOACTION) {
426 flag.message(from_utf8(N_("Nothing to do")));
431 switch (cmd.action) {
432 case LFUN_UNKNOWN_ACTION:
433 #ifndef HAVE_LIBAIKSAURUS
434 case LFUN_THESAURUS_ENTRY:
444 if (flag.unknown()) {
445 flag.message(from_utf8(N_("Unknown action")));
449 if (!flag.enabled()) {
450 if (flag.message().empty())
451 flag.message(from_utf8(N_("Command disabled")));
455 // Check whether we need a buffer
456 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
458 flag.message(from_utf8(N_("Command not allowed with"
459 "out any document open")));
464 // I would really like to avoid having this switch and rather try to
465 // encode this in the function itself.
466 // -- And I'd rather let an inset decide which LFUNs it is willing
467 // to handle (Andre')
469 switch (cmd.action) {
470 case LFUN_BUFFER_TOGGLE_READ_ONLY:
471 flag.setOnOff(buf->isReadonly());
474 case LFUN_BUFFER_SWITCH:
475 // toggle on the current buffer, but do not toggle off
476 // the other ones (is that a good idea?)
477 if (buf && to_utf8(cmd.argument()) == buf->fileName())
481 case LFUN_BUFFER_EXPORT:
482 enable = cmd.argument() == "custom"
483 || Exporter::isExportable(*buf, to_utf8(cmd.argument()));
486 case LFUN_BUFFER_CHKTEX:
487 enable = buf->isLatex() && !lyxrc.chktex_command.empty();
490 case LFUN_BUILD_PROGRAM:
491 enable = Exporter::isExportable(*buf, "program");
494 case LFUN_LAYOUT_TABULAR:
495 enable = cur.innerInsetOfType(Inset::TABULAR_CODE);
499 case LFUN_LAYOUT_PARAGRAPH:
500 enable = !cur.inset().forceDefaultParagraphs(cur.idx());
503 case LFUN_VC_REGISTER:
504 enable = !buf->lyxvc().inUse();
506 case LFUN_VC_CHECK_IN:
507 enable = buf->lyxvc().inUse() && !buf->isReadonly();
509 case LFUN_VC_CHECK_OUT:
510 enable = buf->lyxvc().inUse() && buf->isReadonly();
513 case LFUN_VC_UNDO_LAST:
514 enable = buf->lyxvc().inUse();
516 case LFUN_BUFFER_RELOAD:
517 enable = !buf->isUnnamed() && fs::exists(buf->fileName())
518 && (!buf->isClean() || buf->isExternallyModified(Buffer::timestamp_method));
521 case LFUN_INSET_SETTINGS: {
525 Inset::Code code = cur.inset().lyxCode();
527 case Inset::TABULAR_CODE:
528 enable = cmd.argument() == "tabular";
530 case Inset::ERT_CODE:
531 enable = cmd.argument() == "ert";
533 case Inset::FLOAT_CODE:
534 enable = cmd.argument() == "float";
536 case Inset::WRAP_CODE:
537 enable = cmd.argument() == "wrap";
539 case Inset::NOTE_CODE:
540 enable = cmd.argument() == "note";
542 case Inset::BRANCH_CODE:
543 enable = cmd.argument() == "branch";
545 case Inset::BOX_CODE:
546 enable = cmd.argument() == "box";
548 case Inset::LISTINGS_CODE:
549 enable = cmd.argument() == "listings";
557 case LFUN_INSET_APPLY: {
558 string const name = cmd.getArg(0);
559 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
561 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
563 if (!inset->getStatus(cur, fr, fs)) {
564 // Every inset is supposed to handle this
569 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
570 flag |= getStatus(fr);
572 enable = flag.enabled();
576 case LFUN_DIALOG_TOGGLE:
577 flag.setOnOff(lyx_view_->getDialogs().visible(cmd.getArg(0)));
578 // fall through to set "enable"
579 case LFUN_DIALOG_SHOW: {
580 string const name = cmd.getArg(0);
582 enable = name == "aboutlyx"
583 || name == "file" //FIXME: should be removed.
585 || name == "texinfo";
586 else if (name == "print")
587 enable = Exporter::isExportable(*buf, "dvi")
588 && lyxrc.print_command != "none";
589 else if (name == "character")
590 enable = cur.inset().lyxCode() != Inset::ERT_CODE &&
591 cur.inset().lyxCode() != Inset::LISTINGS_CODE;
592 else if (name == "latexlog")
593 enable = isFileReadable(FileName(buf->getLogName().second));
594 else if (name == "spellchecker")
595 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
596 enable = !buf->isReadonly();
600 else if (name == "vclog")
601 enable = buf->lyxvc().inUse();
605 case LFUN_DIALOG_SHOW_NEW_INSET:
606 enable = cur.inset().lyxCode() != Inset::ERT_CODE &&
607 cur.inset().lyxCode() != Inset::LISTINGS_CODE;
608 if (cur.inset().lyxCode() == Inset::CAPTION_CODE) {
610 if (cur.inset().getStatus(cur, cmd, flag))
615 case LFUN_DIALOG_UPDATE: {
616 string const name = cmd.getArg(0);
618 enable = name == "prefs";
622 case LFUN_CITATION_INSERT: {
623 FuncRequest fr(LFUN_INSET_INSERT, "citation");
624 enable = getStatus(fr).enabled();
628 case LFUN_BUFFER_WRITE: {
629 enable = lyx_view_->buffer()->isUnnamed()
630 || !lyx_view_->buffer()->isClean();
635 case LFUN_BUFFER_WRITE_ALL: {
636 // We enable the command only if there are some modified buffers
637 Buffer * first = theBufferList().first();
638 bool modified = false;
642 // We cannot use a for loop as the buffer list is a cycle.
648 b = theBufferList().next(b);
649 } while (b != first);
657 case LFUN_BOOKMARK_GOTO: {
658 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
659 enable = LyX::ref().session().bookmarks().isValid(num);
663 case LFUN_BOOKMARK_CLEAR:
664 enable = LyX::ref().session().bookmarks().size() > 0;
667 case LFUN_TOOLBAR_TOGGLE: {
668 bool const current = lyx_view_->isToolbarVisible(cmd.getArg(0));
669 flag.setOnOff(current);
672 case LFUN_WINDOW_CLOSE: {
673 enable = (theApp()->gui().viewIds().size() > 1);
677 // this one is difficult to get right. As a half-baked
678 // solution, we consider only the first action of the sequence
679 case LFUN_COMMAND_SEQUENCE: {
680 // argument contains ';'-terminated commands
681 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
682 FuncRequest func(lyxaction.lookupFunc(firstcmd));
683 func.origin = cmd.origin;
684 flag = getStatus(func);
687 case LFUN_BUFFER_NEW:
688 case LFUN_BUFFER_NEW_TEMPLATE:
689 case LFUN_WORD_FIND_FORWARD:
690 case LFUN_WORD_FIND_BACKWARD:
691 case LFUN_COMMAND_PREFIX:
692 case LFUN_COMMAND_EXECUTE:
694 case LFUN_META_PREFIX:
695 case LFUN_BUFFER_CLOSE:
696 case LFUN_BUFFER_WRITE_AS:
697 case LFUN_BUFFER_UPDATE:
698 case LFUN_BUFFER_VIEW:
699 case LFUN_MASTER_BUFFER_UPDATE:
700 case LFUN_MASTER_BUFFER_VIEW:
701 case LFUN_BUFFER_IMPORT:
702 case LFUN_BUFFER_AUTO_SAVE:
703 case LFUN_RECONFIGURE:
707 case LFUN_DROP_LAYOUTS_CHOICE:
709 case LFUN_SERVER_GET_NAME:
710 case LFUN_SERVER_NOTIFY:
711 case LFUN_SERVER_GOTO_FILE_ROW:
712 case LFUN_DIALOG_HIDE:
713 case LFUN_DIALOG_DISCONNECT_INSET:
714 case LFUN_BUFFER_CHILD_OPEN:
715 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
716 case LFUN_KEYMAP_OFF:
717 case LFUN_KEYMAP_PRIMARY:
718 case LFUN_KEYMAP_SECONDARY:
719 case LFUN_KEYMAP_TOGGLE:
721 case LFUN_BUFFER_EXPORT_CUSTOM:
722 case LFUN_BUFFER_PRINT:
723 case LFUN_PREFERENCES_SAVE:
724 case LFUN_SCREEN_FONT_UPDATE:
727 case LFUN_EXTERNAL_EDIT:
728 case LFUN_GRAPHICS_EDIT:
729 case LFUN_ALL_INSETS_TOGGLE:
730 case LFUN_BUFFER_LANGUAGE:
731 case LFUN_TEXTCLASS_APPLY:
732 case LFUN_TEXTCLASS_LOAD:
733 case LFUN_BUFFER_SAVE_AS_DEFAULT:
734 case LFUN_BUFFER_PARAMS_APPLY:
735 case LFUN_LAYOUT_MODULES_CLEAR:
736 case LFUN_LAYOUT_MODULE_ADD:
737 case LFUN_LAYOUT_RELOAD:
738 case LFUN_LYXRC_APPLY:
739 case LFUN_BUFFER_NEXT:
740 case LFUN_BUFFER_PREVIOUS:
741 case LFUN_WINDOW_NEW:
743 // these are handled in our dispatch()
747 if (!getLocalStatus(cur, cmd, flag))
748 flag = view()->getStatus(cmd);
754 // Can we use a readonly buffer?
755 if (buf && buf->isReadonly()
756 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
757 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
758 flag.message(from_utf8(N_("Document is read-only")));
762 // Are we in a DELETED change-tracking region?
763 if (buf && lookupChangeType(cur, true) == Change::DELETED
764 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
765 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
766 flag.message(from_utf8(N_("This portion of the document is deleted.")));
770 // the default error message if we disable the command
771 if (!flag.enabled() && flag.message().empty())
772 flag.message(from_utf8(N_("Command disabled")));
778 bool LyXFunc::ensureBufferClean(BufferView * bv)
780 Buffer & buf = bv->buffer();
784 docstring const file = makeDisplayPath(buf.fileName(), 30);
785 docstring text = bformat(_("The document %1$s has unsaved "
786 "changes.\n\nDo you want to save "
787 "the document?"), file);
788 int const ret = Alert::prompt(_("Save changed document?"),
789 text, 0, 1, _("&Save"),
793 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
795 return buf.isClean();
801 void showPrintError(string const & name)
803 docstring str = bformat(_("Could not print the document %1$s.\n"
804 "Check that your printer is set up correctly."),
805 makeDisplayPath(name, 50));
806 Alert::error(_("Print document failed"), str);
810 void loadTextClass(string const & name)
812 std::pair<bool, textclass_type> const tc_pair =
813 textclasslist.numberOfClass(name);
815 if (!tc_pair.first) {
816 lyxerr << "Document class \"" << name
817 << "\" does not exist."
822 textclass_type const tc = tc_pair.second;
824 if (!textclasslist[tc].load()) {
825 docstring s = bformat(_("The document class %1$s."
826 "could not be loaded."),
827 from_utf8(textclasslist[tc].name()));
828 Alert::error(_("Could not load class"), s);
833 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
838 void LyXFunc::dispatch(FuncRequest const & cmd)
840 string const argument = to_utf8(cmd.argument());
841 kb_action const action = cmd.action;
843 LYXERR(Debug::ACTION) << endl << "LyXFunc::dispatch: cmd: " << cmd << endl;
844 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
846 // we have not done anything wrong yet.
848 dispatch_buffer.erase();
850 // redraw the screen at the end (first of the two drawing steps).
851 //This is done unless explicitely requested otherwise
852 Update::flags updateFlags = Update::FitCursor;
854 FuncStatus const flag = getStatus(cmd);
855 if (!flag.enabled()) {
856 // We cannot use this function here
857 LYXERR(Debug::ACTION) << "LyXFunc::dispatch: "
858 << lyxaction.getActionName(action)
859 << " [" << action << "] is disabled at this location"
861 setErrorMessage(flag.message());
865 case LFUN_WORD_FIND_FORWARD:
866 case LFUN_WORD_FIND_BACKWARD: {
867 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
868 static docstring last_search;
869 docstring searched_string;
871 if (!cmd.argument().empty()) {
872 last_search = cmd.argument();
873 searched_string = cmd.argument();
875 searched_string = last_search;
878 if (searched_string.empty())
881 bool const fw = action == LFUN_WORD_FIND_FORWARD;
882 docstring const data =
883 find2string(searched_string, true, false, fw);
884 find(view(), FuncRequest(LFUN_WORD_FIND, data));
888 case LFUN_COMMAND_PREFIX:
889 BOOST_ASSERT(lyx_view_);
890 lyx_view_->message(keyseq.printOptions(true));
893 case LFUN_COMMAND_EXECUTE:
894 BOOST_ASSERT(lyx_view_);
895 lyx_view_->showMiniBuffer(true);
899 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
901 meta_fake_bit = key_modifier::none;
902 if (lyx_view_->buffer())
903 // cancel any selection
904 dispatch(FuncRequest(LFUN_MARK_OFF));
905 setMessage(from_ascii(N_("Cancel")));
908 case LFUN_META_PREFIX:
909 meta_fake_bit = key_modifier::alt;
910 setMessage(keyseq.print(true));
913 case LFUN_BUFFER_TOGGLE_READ_ONLY:
914 BOOST_ASSERT(lyx_view_ && lyx_view_->view() && lyx_view_->buffer());
915 if (lyx_view_->buffer()->lyxvc().inUse())
916 lyx_view_->buffer()->lyxvc().toggleReadOnly();
918 lyx_view_->buffer()->setReadonly(
919 !lyx_view_->buffer()->isReadonly());
922 // --- Menus -----------------------------------------------
923 case LFUN_BUFFER_NEW:
924 menuNew(argument, false);
925 updateFlags = Update::None;
928 case LFUN_BUFFER_NEW_TEMPLATE:
929 menuNew(argument, true);
930 updateFlags = Update::None;
933 case LFUN_BUFFER_CLOSE:
935 updateFlags = Update::None;
938 case LFUN_BUFFER_WRITE:
939 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
940 if (!lyx_view_->buffer()->isUnnamed()) {
941 docstring const str = bformat(_("Saving document %1$s..."),
942 makeDisplayPath(lyx_view_->buffer()->fileName()));
943 lyx_view_->message(str);
944 menuWrite(lyx_view_->buffer());
945 lyx_view_->message(str + _(" done."));
947 writeAs(lyx_view_->buffer());
949 updateFlags = Update::None;
952 case LFUN_BUFFER_WRITE_AS:
953 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
954 writeAs(lyx_view_->buffer(), argument);
955 updateFlags = Update::None;
958 case LFUN_BUFFER_WRITE_ALL: {
959 Buffer * first = theBufferList().first();
962 lyx_view_->message(_("Saving all documents..."));
964 // We cannot use a for loop as the buffer list cycles.
967 if (!b->isUnnamed()) {
969 lyxerr[Debug::ACTION] << "Saved " << b->fileName() << endl;
973 b = theBufferList().next(b);
974 } while (b != first);
975 lyx_view_->message(_("All documents saved."));
978 updateFlags = Update::None;
982 case LFUN_BUFFER_RELOAD: {
983 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
984 docstring const file = makeDisplayPath(lyx_view_->buffer()->fileName(), 20);
985 docstring text = bformat(_("Any changes will be lost. Are you sure "
986 "you want to revert to the saved version of the document %1$s?"), file);
987 int const ret = Alert::prompt(_("Revert to saved document?"),
988 text, 1, 1, _("&Revert"), _("&Cancel"));
995 case LFUN_BUFFER_UPDATE:
996 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
997 Exporter::Export(lyx_view_->buffer(), argument, true);
1000 case LFUN_BUFFER_VIEW:
1001 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1002 Exporter::preview(lyx_view_->buffer(), argument);
1005 case LFUN_MASTER_BUFFER_UPDATE:
1006 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->getMasterBuffer());
1007 Exporter::Export(lyx_view_->buffer()->getMasterBuffer(), argument, true);
1010 case LFUN_MASTER_BUFFER_VIEW:
1011 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->getMasterBuffer());
1012 Exporter::preview(lyx_view_->buffer()->getMasterBuffer(), argument);
1015 case LFUN_BUILD_PROGRAM:
1016 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1017 Exporter::Export(lyx_view_->buffer(), "program", true);
1020 case LFUN_BUFFER_CHKTEX:
1021 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1022 lyx_view_->buffer()->runChktex();
1025 case LFUN_BUFFER_EXPORT:
1026 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1027 if (argument == "custom")
1028 lyx_view_->getDialogs().show("sendto");
1030 Exporter::Export(lyx_view_->buffer(), argument, false);
1034 case LFUN_BUFFER_EXPORT_CUSTOM: {
1035 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1037 string command = split(argument, format_name, ' ');
1038 Format const * format = formats.getFormat(format_name);
1040 lyxerr << "Format \"" << format_name
1041 << "\" not recognized!"
1046 Buffer * buffer = lyx_view_->buffer();
1048 // The name of the file created by the conversion process
1051 // Output to filename
1052 if (format->name() == "lyx") {
1053 string const latexname =
1054 buffer->getLatexName(false);
1055 filename = changeExtension(latexname,
1056 format->extension());
1057 filename = addName(buffer->temppath(), filename);
1059 if (!buffer->writeFile(FileName(filename)))
1063 Exporter::Export(buffer, format_name, true, filename);
1066 // Substitute $$FName for filename
1067 if (!contains(command, "$$FName"))
1068 command = "( " + command + " ) < $$FName";
1069 command = subst(command, "$$FName", filename);
1071 // Execute the command in the background
1073 call.startscript(Systemcall::DontWait, command);
1077 case LFUN_BUFFER_PRINT: {
1078 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1079 // FIXME: cmd.getArg() might fail if one of the arguments
1080 // contains double quotes
1081 string target = cmd.getArg(0);
1082 string target_name = cmd.getArg(1);
1083 string command = cmd.getArg(2);
1086 || target_name.empty()
1087 || command.empty()) {
1088 lyxerr << "Unable to parse \""
1089 << argument << '"' << endl;
1092 if (target != "printer" && target != "file") {
1093 lyxerr << "Unrecognized target \""
1094 << target << '"' << endl;
1098 Buffer * buffer = lyx_view_->buffer();
1100 if (!Exporter::Export(buffer, "dvi", true)) {
1101 showPrintError(buffer->fileName());
1105 // Push directory path.
1106 string const path(buffer->temppath());
1107 // Prevent the compiler from optimizing away p
1109 support::Path p(pp);
1111 // there are three cases here:
1112 // 1. we print to a file
1113 // 2. we print directly to a printer
1114 // 3. we print using a spool command (print to file first)
1117 string const dviname =
1118 changeExtension(buffer->getLatexName(true),
1121 if (target == "printer") {
1122 if (!lyxrc.print_spool_command.empty()) {
1123 // case 3: print using a spool
1124 string const psname =
1125 changeExtension(dviname,".ps");
1126 command += ' ' + lyxrc.print_to_file
1129 + quoteName(dviname);
1132 lyxrc.print_spool_command + ' ';
1133 if (target_name != "default") {
1134 command2 += lyxrc.print_spool_printerprefix
1138 command2 += quoteName(psname);
1140 // If successful, then spool command
1141 res = one.startscript(
1146 res = one.startscript(
1147 Systemcall::DontWait,
1150 // case 2: print directly to a printer
1151 if (target_name != "default")
1152 command += ' ' + lyxrc.print_to_printer + target_name + ' ';
1153 res = one.startscript(
1154 Systemcall::DontWait,
1155 command + quoteName(dviname));
1159 // case 1: print to a file
1160 FileName const filename(makeAbsPath(target_name,
1161 lyx_view_->buffer()->filePath()));
1162 FileName const dvifile(makeAbsPath(dviname, path));
1163 if (fs::exists(filename.toFilesystemEncoding())) {
1164 docstring text = bformat(
1165 _("The file %1$s already exists.\n\n"
1166 "Do you want to overwrite that file?"),
1167 makeDisplayPath(filename.absFilename()));
1168 if (Alert::prompt(_("Overwrite file?"),
1169 text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
1172 command += ' ' + lyxrc.print_to_file
1173 + quoteName(filename.toFilesystemEncoding())
1175 + quoteName(dvifile.toFilesystemEncoding());
1176 res = one.startscript(Systemcall::DontWait,
1181 showPrintError(buffer->fileName());
1185 case LFUN_BUFFER_IMPORT:
1190 // quitting is triggered by the gui code
1191 // (leaving the event loop).
1192 lyx_view_->message(from_utf8(N_("Exiting.")));
1193 if (theBufferList().quitWriteAll())
1194 theApp()->gui().closeAllViews();
1197 case LFUN_BUFFER_AUTO_SAVE:
1201 case LFUN_RECONFIGURE:
1202 BOOST_ASSERT(lyx_view_);
1203 // argument is any additional parameter to the configure.py command
1204 reconfigure(*lyx_view_, argument);
1207 case LFUN_HELP_OPEN: {
1208 BOOST_ASSERT(lyx_view_);
1209 string const arg = argument;
1211 setErrorMessage(from_ascii(N_("Missing argument")));
1214 FileName const fname = i18nLibFileSearch("doc", arg, "lyx");
1215 if (fname.empty()) {
1216 lyxerr << "LyX: unable to find documentation file `"
1217 << arg << "'. Bad installation?" << endl;
1220 lyx_view_->message(bformat(_("Opening help file %1$s..."),
1221 makeDisplayPath(fname.absFilename())));
1222 Buffer * buf = lyx_view_->loadLyXFile(fname, false);
1225 lyx_view_->setBuffer(buf);
1226 lyx_view_->showErrorList("Parse");
1228 updateFlags = Update::None;
1232 // --- version control -------------------------------
1233 case LFUN_VC_REGISTER:
1234 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1235 if (!ensureBufferClean(view()))
1237 if (!lyx_view_->buffer()->lyxvc().inUse()) {
1238 lyx_view_->buffer()->lyxvc().registrer();
1241 updateFlags = Update::Force;
1244 case LFUN_VC_CHECK_IN:
1245 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1246 if (!ensureBufferClean(view()))
1248 if (lyx_view_->buffer()->lyxvc().inUse()
1249 && !lyx_view_->buffer()->isReadonly()) {
1250 lyx_view_->buffer()->lyxvc().checkIn();
1255 case LFUN_VC_CHECK_OUT:
1256 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1257 if (!ensureBufferClean(view()))
1259 if (lyx_view_->buffer()->lyxvc().inUse()
1260 && lyx_view_->buffer()->isReadonly()) {
1261 lyx_view_->buffer()->lyxvc().checkOut();
1266 case LFUN_VC_REVERT:
1267 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1268 lyx_view_->buffer()->lyxvc().revert();
1272 case LFUN_VC_UNDO_LAST:
1273 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1274 lyx_view_->buffer()->lyxvc().undoLast();
1278 // --- buffers ----------------------------------------
1279 case LFUN_BUFFER_SWITCH:
1280 BOOST_ASSERT(lyx_view_);
1281 lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1282 updateFlags = Update::None;
1285 case LFUN_BUFFER_NEXT:
1286 BOOST_ASSERT(lyx_view_);
1287 lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer()));
1288 updateFlags = Update::None;
1291 case LFUN_BUFFER_PREVIOUS:
1292 BOOST_ASSERT(lyx_view_);
1293 lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer()));
1294 updateFlags = Update::None;
1298 BOOST_ASSERT(lyx_view_);
1299 newFile(*lyx_view_, argument);
1300 updateFlags = Update::None;
1303 case LFUN_FILE_OPEN:
1304 BOOST_ASSERT(lyx_view_);
1306 updateFlags = Update::None;
1309 case LFUN_DROP_LAYOUTS_CHOICE:
1310 BOOST_ASSERT(lyx_view_);
1311 lyx_view_->openLayoutList();
1314 case LFUN_MENU_OPEN:
1315 BOOST_ASSERT(lyx_view_);
1316 lyx_view_->openMenu(from_utf8(argument));
1319 // --- lyxserver commands ----------------------------
1320 case LFUN_SERVER_GET_NAME:
1321 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1322 setMessage(from_utf8(lyx_view_->buffer()->fileName()));
1323 LYXERR(Debug::INFO) << "FNAME["
1324 << lyx_view_->buffer()->fileName()
1328 case LFUN_SERVER_NOTIFY:
1329 dispatch_buffer = keyseq.print(false);
1330 theServer().notifyClient(to_utf8(dispatch_buffer));
1333 case LFUN_SERVER_GOTO_FILE_ROW: {
1334 BOOST_ASSERT(lyx_view_);
1337 istringstream is(argument);
1338 is >> file_name >> row;
1340 bool loaded = false;
1341 if (prefixIs(file_name, package().temp_dir().absFilename()))
1342 // Needed by inverse dvi search. If it is a file
1343 // in tmpdir, call the apropriated function
1344 buf = theBufferList().getBufferFromTmp(file_name);
1346 // Must replace extension of the file to be .lyx
1347 // and get full path
1348 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1349 // Either change buffer or load the file
1350 if (theBufferList().exists(s.absFilename()))
1351 buf = theBufferList().getBuffer(s.absFilename());
1353 buf = lyx_view_->loadLyXFile(s);
1359 updateFlags = Update::None;
1364 lyx_view_->setBuffer(buf);
1365 view()->setCursorFromRow(row);
1367 lyx_view_->showErrorList("Parse");
1368 updateFlags = Update::FitCursor;
1372 case LFUN_DIALOG_SHOW: {
1373 BOOST_ASSERT(lyx_view_);
1374 string const name = cmd.getArg(0);
1375 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1377 if (name == "character") {
1378 data = freefont2string();
1380 lyx_view_->getDialogs().show("character", data);
1381 } else if (name == "latexlog") {
1382 pair<Buffer::LogType, string> const logfile =
1383 lyx_view_->buffer()->getLogName();
1384 switch (logfile.first) {
1385 case Buffer::latexlog:
1388 case Buffer::buildlog:
1392 data += Lexer::quoteString(logfile.second);
1393 lyx_view_->getDialogs().show("log", data);
1394 } else if (name == "vclog") {
1395 string const data = "vc " +
1396 Lexer::quoteString(lyx_view_->buffer()->lyxvc().getLogFile());
1397 lyx_view_->getDialogs().show("log", data);
1399 lyx_view_->getDialogs().show(name, data);
1403 case LFUN_DIALOG_SHOW_NEW_INSET: {
1404 BOOST_ASSERT(lyx_view_);
1405 string const name = cmd.getArg(0);
1406 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1407 if (name == "bibitem" ||
1411 name == "nomenclature" ||
1415 InsetCommandParams p(name);
1416 data = InsetCommandMailer::params2string(name, p);
1417 } else if (name == "include") {
1418 // data is the include type: one of "include",
1419 // "input", "verbatiminput" or "verbatiminput*"
1421 // default type is requested
1423 InsetCommandParams p(data);
1424 data = InsetIncludeMailer::params2string(p);
1425 } else if (name == "box") {
1426 // \c data == "Boxed" || "Frameless" etc
1427 InsetBoxParams p(data);
1428 data = InsetBoxMailer::params2string(p);
1429 } else if (name == "branch") {
1430 InsetBranchParams p;
1431 data = InsetBranchMailer::params2string(p);
1432 } else if (name == "citation") {
1433 InsetCommandParams p("cite");
1434 data = InsetCommandMailer::params2string(name, p);
1435 } else if (name == "ert") {
1436 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1437 } else if (name == "external") {
1438 InsetExternalParams p;
1439 Buffer const & buffer = *lyx_view_->buffer();
1440 data = InsetExternalMailer::params2string(p, buffer);
1441 } else if (name == "float") {
1443 data = InsetFloatMailer::params2string(p);
1444 } else if (name == "listings") {
1445 InsetListingsParams p;
1446 data = InsetListingsMailer::params2string(p);
1447 } else if (name == "graphics") {
1448 InsetGraphicsParams p;
1449 Buffer const & buffer = *lyx_view_->buffer();
1450 data = InsetGraphicsMailer::params2string(p, buffer);
1451 } else if (name == "note") {
1453 data = InsetNoteMailer::params2string(p);
1454 } else if (name == "vspace") {
1456 data = InsetVSpaceMailer::params2string(space);
1457 } else if (name == "wrap") {
1459 data = InsetWrapMailer::params2string(p);
1461 lyx_view_->getDialogs().show(name, data, 0);
1465 case LFUN_DIALOG_UPDATE: {
1466 BOOST_ASSERT(lyx_view_);
1467 string const & name = argument;
1468 // Can only update a dialog connected to an existing inset
1469 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1471 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1472 inset->dispatch(view()->cursor(), fr);
1473 } else if (name == "paragraph") {
1474 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1475 } else if (name == "prefs") {
1476 lyx_view_->getDialogs().update(name, string());
1481 case LFUN_DIALOG_HIDE:
1482 LyX::cref().hideDialogs(argument, 0);
1485 case LFUN_DIALOG_TOGGLE: {
1486 BOOST_ASSERT(lyx_view_);
1487 if (lyx_view_->getDialogs().visible(cmd.getArg(0)))
1488 dispatch(FuncRequest(LFUN_DIALOG_HIDE, argument));
1490 dispatch(FuncRequest(LFUN_DIALOG_SHOW, argument));
1494 case LFUN_DIALOG_DISCONNECT_INSET:
1495 BOOST_ASSERT(lyx_view_);
1496 lyx_view_->getDialogs().disconnect(argument);
1500 case LFUN_CITATION_INSERT: {
1501 BOOST_ASSERT(lyx_view_);
1502 if (!argument.empty()) {
1503 // we can have one optional argument, delimited by '|'
1504 // citation-insert <key>|<text_before>
1505 // this should be enhanced to also support text_after
1506 // and citation style
1507 string arg = argument;
1509 if (contains(argument, "|")) {
1510 arg = token(argument, '|', 0);
1511 opt1 = token(argument, '|', 1);
1513 InsetCommandParams icp("cite");
1514 icp["key"] = from_utf8(arg);
1516 icp["before"] = from_utf8(opt1);
1517 string icstr = InsetCommandMailer::params2string("citation", icp);
1518 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1521 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1525 case LFUN_BUFFER_CHILD_OPEN: {
1526 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1527 Buffer * parent = lyx_view_->buffer();
1528 FileName filename = makeAbsPath(argument, parent->filePath());
1529 view()->saveBookmark(false);
1531 bool parsed = false;
1532 if (theBufferList().exists(filename.absFilename())) {
1533 child = theBufferList().getBuffer(filename.absFilename());
1535 setMessage(bformat(_("Opening child document %1$s..."),
1536 makeDisplayPath(filename.absFilename())));
1537 child = lyx_view_->loadLyXFile(filename, true);
1541 // Set the parent name of the child document.
1542 // This makes insertion of citations and references in the child work,
1543 // when the target is in the parent or another child document.
1544 child->setParentName(parent->fileName());
1545 updateLabels(*child->getMasterBuffer());
1546 lyx_view_->setBuffer(child);
1548 lyx_view_->showErrorList("Parse");
1551 // If a screen update is required (in case where auto_open is false),
1552 // setBuffer() would have taken care of it already. Otherwise we shall
1553 // reset the update flag because it can cause a circular problem.
1555 updateFlags = Update::None;
1559 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1560 BOOST_ASSERT(lyx_view_);
1561 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1564 case LFUN_KEYMAP_OFF:
1565 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1566 lyx_view_->view()->getIntl().keyMapOn(false);
1569 case LFUN_KEYMAP_PRIMARY:
1570 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1571 lyx_view_->view()->getIntl().keyMapPrim();
1574 case LFUN_KEYMAP_SECONDARY:
1575 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1576 lyx_view_->view()->getIntl().keyMapSec();
1579 case LFUN_KEYMAP_TOGGLE:
1580 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1581 lyx_view_->view()->getIntl().toggleKeyMap();
1587 string rest = split(argument, countstr, ' ');
1588 istringstream is(countstr);
1591 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1592 for (int i = 0; i < count; ++i)
1593 dispatch(lyxaction.lookupFunc(rest));
1597 case LFUN_COMMAND_SEQUENCE: {
1598 // argument contains ';'-terminated commands
1599 string arg = argument;
1600 while (!arg.empty()) {
1602 arg = split(arg, first, ';');
1603 FuncRequest func(lyxaction.lookupFunc(first));
1604 func.origin = cmd.origin;
1610 case LFUN_PREFERENCES_SAVE: {
1611 lyxrc.write(makeAbsPath("preferences",
1612 package().user_support().absFilename()),
1617 case LFUN_SCREEN_FONT_UPDATE:
1618 BOOST_ASSERT(lyx_view_);
1619 // handle the screen font changes.
1620 theFontLoader().update();
1621 /// FIXME: only the current view will be updated. the Gui
1622 /// class is able to furnish the list of views.
1623 updateFlags = Update::Force;
1626 case LFUN_SET_COLOR: {
1628 string const x11_name = split(argument, lyx_name, ' ');
1629 if (lyx_name.empty() || x11_name.empty()) {
1630 setErrorMessage(from_ascii(N_(
1631 "Syntax: set-color <lyx_name>"
1636 bool const graphicsbg_changed =
1637 (lyx_name == lcolor.getLyXName(Color::graphicsbg) &&
1638 x11_name != lcolor.getX11Name(Color::graphicsbg));
1640 if (!lcolor.setColor(lyx_name, x11_name)) {
1642 bformat(_("Set-color \"%1$s\" failed "
1643 "- color is undefined or "
1644 "may not be redefined"),
1645 from_utf8(lyx_name)));
1649 theApp()->updateColor(lcolor.getFromLyXName(lyx_name));
1651 if (graphicsbg_changed) {
1652 // FIXME: The graphics cache no longer has a changeDisplay method.
1654 graphics::GCache::get().changeDisplay(true);
1661 BOOST_ASSERT(lyx_view_);
1662 lyx_view_->message(from_utf8(argument));
1665 case LFUN_EXTERNAL_EDIT: {
1666 BOOST_ASSERT(lyx_view_);
1667 FuncRequest fr(action, argument);
1668 InsetExternal().dispatch(view()->cursor(), fr);
1672 case LFUN_GRAPHICS_EDIT: {
1673 FuncRequest fr(action, argument);
1674 InsetGraphics().dispatch(view()->cursor(), fr);
1678 case LFUN_INSET_APPLY: {
1679 BOOST_ASSERT(lyx_view_);
1680 string const name = cmd.getArg(0);
1681 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1683 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1684 inset->dispatch(view()->cursor(), fr);
1686 FuncRequest fr(LFUN_INSET_INSERT, argument);
1689 // ideally, the update flag should be set by the insets,
1690 // but this is not possible currently
1691 updateFlags = Update::Force | Update::FitCursor;
1695 case LFUN_ALL_INSETS_TOGGLE: {
1696 BOOST_ASSERT(lyx_view_);
1698 string const name = split(argument, action, ' ');
1699 Inset::Code const inset_code =
1700 Inset::translate(name);
1702 Cursor & cur = view()->cursor();
1703 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1705 Inset & inset = lyx_view_->buffer()->inset();
1706 InsetIterator it = inset_iterator_begin(inset);
1707 InsetIterator const end = inset_iterator_end(inset);
1708 for (; it != end; ++it) {
1709 if (!it->asInsetMath()
1710 && (inset_code == Inset::NO_CODE
1711 || inset_code == it->lyxCode())) {
1712 Cursor tmpcur = cur;
1713 tmpcur.pushLeft(*it);
1714 it->dispatch(tmpcur, fr);
1717 updateFlags = Update::Force | Update::FitCursor;
1721 case LFUN_BUFFER_LANGUAGE: {
1722 BOOST_ASSERT(lyx_view_);
1723 Buffer & buffer = *lyx_view_->buffer();
1724 Language const * oldL = buffer.params().language;
1725 Language const * newL = languages.getLanguage(argument);
1726 if (!newL || oldL == newL)
1729 if (oldL->rightToLeft() == newL->rightToLeft()
1730 && !buffer.isMultiLingual())
1731 buffer.changeLanguage(oldL, newL);
1735 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1736 string const fname =
1737 addName(addPath(package().user_support().absFilename(), "templates/"),
1739 Buffer defaults(fname);
1741 istringstream ss(argument);
1744 int const unknown_tokens = defaults.readHeader(lex);
1746 if (unknown_tokens != 0) {
1747 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1748 << unknown_tokens << " unknown token"
1749 << (unknown_tokens == 1 ? "" : "s")
1753 if (defaults.writeFile(FileName(defaults.fileName())))
1754 setMessage(bformat(_("Document defaults saved in %1$s"),
1755 makeDisplayPath(fname)));
1757 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1761 case LFUN_BUFFER_PARAMS_APPLY: {
1762 BOOST_ASSERT(lyx_view_);
1763 biblio::CiteEngine const oldEngine =
1764 lyx_view_->buffer()->params().getEngine();
1766 Buffer * buffer = lyx_view_->buffer();
1768 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1769 recordUndoFullDocument(view());
1771 istringstream ss(argument);
1774 int const unknown_tokens = buffer->readHeader(lex);
1776 if (unknown_tokens != 0) {
1777 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1778 << unknown_tokens << " unknown token"
1779 << (unknown_tokens == 1 ? "" : "s")
1783 updateLayout(oldClass, buffer);
1785 biblio::CiteEngine const newEngine =
1786 lyx_view_->buffer()->params().getEngine();
1788 if (oldEngine != newEngine) {
1789 Cursor & cur = view()->cursor();
1790 FuncRequest fr(LFUN_INSET_REFRESH);
1792 Inset & inset = lyx_view_->buffer()->inset();
1793 InsetIterator it = inset_iterator_begin(inset);
1794 InsetIterator const end = inset_iterator_end(inset);
1795 for (; it != end; ++it)
1796 if (it->lyxCode() == Inset::CITE_CODE)
1797 it->dispatch(cur, fr);
1800 updateFlags = Update::Force | Update::FitCursor;
1804 case LFUN_LAYOUT_MODULES_CLEAR: {
1805 BOOST_ASSERT(lyx_view_);
1806 Buffer * buffer = lyx_view_->buffer();
1807 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1808 recordUndoFullDocument(view());
1809 buffer->params().clearLayoutModules();
1810 updateLayout(oldClass, buffer);
1811 updateFlags = Update::Force | Update::FitCursor;
1815 case LFUN_LAYOUT_MODULE_ADD: {
1816 BOOST_ASSERT(lyx_view_);
1817 Buffer * buffer = lyx_view_->buffer();
1818 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1819 recordUndoFullDocument(view());
1820 buffer->params().addLayoutModule(argument);
1821 updateLayout(oldClass, buffer);
1822 updateFlags = Update::Force | Update::FitCursor;
1826 case LFUN_TEXTCLASS_APPLY: {
1827 BOOST_ASSERT(lyx_view_);
1828 Buffer * buffer = lyx_view_->buffer();
1830 loadTextClass(argument);
1832 std::pair<bool, textclass_type> const tc_pair =
1833 textclasslist.numberOfClass(argument);
1838 textclass_type const old_class = buffer->params().getBaseClass();
1839 textclass_type const new_class = tc_pair.second;
1841 if (old_class == new_class)
1845 //Save the old, possibly modular, layout for use in conversion.
1846 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1847 recordUndoFullDocument(view());
1848 buffer->params().setBaseClass(new_class);
1849 updateLayout(oldClass, buffer);
1850 updateFlags = Update::Force | Update::FitCursor;
1854 case LFUN_LAYOUT_RELOAD: {
1855 BOOST_ASSERT(lyx_view_);
1856 Buffer * buffer = lyx_view_->buffer();
1857 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1858 textclass_type const tc = buffer->params().getBaseClass();
1859 textclasslist.reset(tc);
1860 buffer->params().setBaseClass(tc);
1861 updateLayout(oldClass, buffer);
1862 updateFlags = Update::Force | Update::FitCursor;
1866 case LFUN_TEXTCLASS_LOAD:
1867 loadTextClass(argument);
1870 case LFUN_LYXRC_APPLY: {
1871 LyXRC const lyxrc_orig = lyxrc;
1873 istringstream ss(argument);
1874 bool const success = lyxrc.read(ss) == 0;
1877 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1878 << "Unable to read lyxrc data"
1883 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1885 /// We force the redraw in any case because there might be
1886 /// some screen font changes.
1887 /// FIXME: only the current view will be updated. the Gui
1888 /// class is able to furnish the list of views.
1889 updateFlags = Update::Force;
1893 case LFUN_WINDOW_NEW:
1894 LyX::ref().newLyXView();
1897 case LFUN_WINDOW_CLOSE:
1898 BOOST_ASSERT(lyx_view_);
1899 BOOST_ASSERT(theApp());
1900 // update bookmark pit of the current buffer before window close
1901 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1902 gotoBookmark(i+1, false, false);
1903 // ask the user for saving changes or cancel quit
1904 if (!theBufferList().quitWriteAll())
1909 case LFUN_BOOKMARK_GOTO:
1910 // go to bookmark, open unopened file and switch to buffer if necessary
1911 gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
1914 case LFUN_BOOKMARK_CLEAR:
1915 LyX::ref().session().bookmarks().clear();
1918 case LFUN_TOOLBAR_TOGGLE: {
1919 BOOST_ASSERT(lyx_view_);
1920 string const name = cmd.getArg(0);
1921 bool const allowauto = cmd.getArg(1) == "allowauto";
1922 lyx_view_->toggleToolbarState(name, allowauto);
1923 ToolbarInfo * tbi = lyx_view_->getToolbarInfo(name);
1925 setMessage(bformat(_("Unknown toolbar \"%1$s\""),
1930 if (tbi->flags & ToolbarInfo::ON)
1932 else if (tbi->flags & ToolbarInfo::OFF)
1934 else if (tbi->flags & ToolbarInfo::AUTO)
1937 setMessage(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1938 _(tbi->gui_name), state));
1943 BOOST_ASSERT(lyx_view_);
1944 view()->cursor().dispatch(cmd);
1945 updateFlags = view()->cursor().result().update();
1946 if (!view()->cursor().result().dispatched())
1947 updateFlags = view()->dispatch(cmd);
1952 if (lyx_view_ && lyx_view_->buffer()) {
1953 // BufferView::update() updates the ViewMetricsInfo and
1954 // also initializes the position cache for all insets in
1955 // (at least partially) visible top-level paragraphs.
1956 // We will redraw the screen only if needed.
1957 if (view()->update(updateFlags)) {
1958 // Buffer::changed() signals that a repaint is needed.
1959 // The frontend (WorkArea) knows which area to repaint
1960 // thanks to the ViewMetricsInfo updated above.
1961 lyx_view_->buffer()->changed();
1964 lyx_view_->updateStatusBar();
1966 // if we executed a mutating lfun, mark the buffer as dirty
1968 && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
1969 && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
1970 lyx_view_->buffer()->markDirty();
1972 //Do we have a selection?
1973 theSelection().haveSelection(view()->cursor().selection());
1975 if (view()->cursor().inTexted()) {
1976 lyx_view_->updateLayoutChoice();
1980 if (!quitting && lyx_view_) {
1981 lyx_view_->updateToolbars();
1982 // Some messages may already be translated, so we cannot use _()
1983 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
1988 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
1990 const bool verbose = (cmd.origin == FuncRequest::MENU
1991 || cmd.origin == FuncRequest::TOOLBAR
1992 || cmd.origin == FuncRequest::COMMANDBUFFER);
1994 if (cmd.action == LFUN_SELF_INSERT || !verbose) {
1995 LYXERR(Debug::ACTION) << "dispatch msg is " << to_utf8(msg) << endl;
1997 lyx_view_->message(msg);
2001 docstring dispatch_msg = msg;
2002 if (!dispatch_msg.empty())
2003 dispatch_msg += ' ';
2005 docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
2007 bool argsadded = false;
2009 if (!cmd.argument().empty()) {
2010 if (cmd.action != LFUN_UNKNOWN_ACTION) {
2011 comname += ' ' + cmd.argument();
2016 docstring const shortcuts = theTopLevelKeymap().printbindings(cmd);
2018 if (!shortcuts.empty())
2019 comname += ": " + shortcuts;
2020 else if (!argsadded && !cmd.argument().empty())
2021 comname += ' ' + cmd.argument();
2023 if (!comname.empty()) {
2024 comname = rtrim(comname);
2025 dispatch_msg += '(' + rtrim(comname) + ')';
2028 LYXERR(Debug::ACTION) << "verbose dispatch msg "
2029 << to_utf8(dispatch_msg) << endl;
2030 if (!dispatch_msg.empty())
2031 lyx_view_->message(dispatch_msg);
2035 void LyXFunc::menuNew(string const & name, bool fromTemplate)
2037 // FIXME: initpath is not used. What to do?
2038 string initpath = lyxrc.document_path;
2039 string filename(name);
2041 if (lyx_view_->buffer()) {
2042 string const trypath = lyx_view_->buffer()->filePath();
2043 // If directory is writeable, use this as default.
2044 if (isDirWriteable(FileName(trypath)))
2048 static int newfile_number;
2050 if (filename.empty()) {
2051 filename = addName(lyxrc.document_path,
2052 "newfile" + convert<string>(++newfile_number) + ".lyx");
2053 while (theBufferList().exists(filename) ||
2054 fs::is_readable(FileName(filename).toFilesystemEncoding())) {
2056 filename = addName(lyxrc.document_path,
2057 "newfile" + convert<string>(newfile_number) +
2062 // The template stuff
2065 FileDialog fileDlg(_("Select template file"),
2066 LFUN_SELECT_FILE_SYNC,
2067 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2068 make_pair(_("Templates|#T#t"), from_utf8(lyxrc.template_path)));
2070 FileDialog::Result result =
2071 fileDlg.open(from_utf8(lyxrc.template_path),
2072 FileFilterList(_("LyX Documents (*.lyx)")),
2075 if (result.first == FileDialog::Later)
2077 if (result.second.empty())
2079 templname = to_utf8(result.second);
2082 Buffer * const b = newFile(filename, templname, !name.empty());
2084 lyx_view_->setBuffer(b);
2088 void LyXFunc::open(string const & fname)
2090 string initpath = lyxrc.document_path;
2092 if (lyx_view_->buffer()) {
2093 string const trypath = lyx_view_->buffer()->filePath();
2094 // If directory is writeable, use this as default.
2095 if (isDirWriteable(FileName(trypath)))
2101 if (fname.empty()) {
2102 FileDialog fileDlg(_("Select document to open"),
2104 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2105 make_pair(_("Examples|#E#e"), from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2107 FileDialog::Result result =
2108 fileDlg.open(from_utf8(initpath),
2109 FileFilterList(_("LyX Documents (*.lyx)")),
2112 if (result.first == FileDialog::Later)
2115 filename = to_utf8(result.second);
2117 // check selected filename
2118 if (filename.empty()) {
2119 lyx_view_->message(_("Canceled."));
2125 // get absolute path of file and add ".lyx" to the filename if
2127 FileName const fullname = fileSearch(string(), filename, "lyx");
2128 if (!fullname.empty())
2129 filename = fullname.absFilename();
2131 // if the file doesn't exist, let the user create one
2132 if (!fs::exists(fullname.toFilesystemEncoding())) {
2133 // the user specifically chose this name. Believe him.
2134 Buffer * const b = newFile(filename, string(), true);
2136 lyx_view_->setBuffer(b);
2140 docstring const disp_fn = makeDisplayPath(filename);
2141 lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
2144 Buffer * buf = lyx_view_->loadLyXFile(fullname);
2147 lyx_view_->setBuffer(buf);
2148 lyx_view_->showErrorList("Parse");
2149 str2 = bformat(_("Document %1$s opened."), disp_fn);
2151 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2153 lyx_view_->message(str2);
2157 void LyXFunc::doImport(string const & argument)
2160 string filename = split(argument, format, ' ');
2162 LYXERR(Debug::INFO) << "LyXFunc::doImport: " << format
2163 << " file: " << filename << endl;
2165 // need user interaction
2166 if (filename.empty()) {
2167 string initpath = lyxrc.document_path;
2169 if (lyx_view_->buffer()) {
2170 string const trypath = lyx_view_->buffer()->filePath();
2171 // If directory is writeable, use this as default.
2172 if (isDirWriteable(FileName(trypath)))
2176 docstring const text = bformat(_("Select %1$s file to import"),
2177 formats.prettyName(format));
2179 FileDialog fileDlg(text,
2181 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2182 make_pair(_("Examples|#E#e"),
2183 from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2185 docstring filter = formats.prettyName(format);
2188 filter += from_utf8(formats.extension(format));
2191 FileDialog::Result result =
2192 fileDlg.open(from_utf8(initpath),
2193 FileFilterList(filter),
2196 if (result.first == FileDialog::Later)
2199 filename = to_utf8(result.second);
2201 // check selected filename
2202 if (filename.empty())
2203 lyx_view_->message(_("Canceled."));
2206 if (filename.empty())
2209 // get absolute path of file
2210 FileName const fullname(makeAbsPath(filename));
2212 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
2214 // Check if the document already is open
2215 if (use_gui && theBufferList().exists(lyxfile.absFilename())) {
2216 if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) {
2217 lyx_view_->message(_("Canceled."));
2222 // if the file exists already, and we didn't do
2223 // -i lyx thefile.lyx, warn
2224 if (fs::exists(lyxfile.toFilesystemEncoding()) && fullname != lyxfile) {
2225 docstring const file = makeDisplayPath(lyxfile.absFilename(), 30);
2227 docstring text = bformat(_("The document %1$s already exists.\n\n"
2228 "Do you want to overwrite that document?"), file);
2229 int const ret = Alert::prompt(_("Overwrite document?"),
2230 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2233 lyx_view_->message(_("Canceled."));
2238 ErrorList errorList;
2239 Importer::Import(lyx_view_, fullname, format, errorList);
2240 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2244 void LyXFunc::closeBuffer()
2246 // goto bookmark to update bookmark pit.
2247 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2248 gotoBookmark(i+1, false, false);
2250 theBufferList().close(lyx_view_->buffer(), true);
2254 void LyXFunc::reloadBuffer()
2256 FileName filename(lyx_view_->buffer()->fileName());
2257 docstring const disp_fn = makeDisplayPath(filename.absFilename());
2260 Buffer * buf = lyx_view_->loadLyXFile(filename);
2263 lyx_view_->setBuffer(buf);
2264 lyx_view_->showErrorList("Parse");
2265 str = bformat(_("Document %1$s reloaded."), disp_fn);
2267 str = bformat(_("Could not reload document %1$s"), disp_fn);
2269 lyx_view_->message(str);
2272 // Each "lyx_view_" should have it's own message method. lyxview and
2273 // the minibuffer would use the minibuffer, but lyxserver would
2274 // send an ERROR signal to its client. Alejandro 970603
2275 // This function is bit problematic when it comes to NLS, to make the
2276 // lyx servers client be language indepenent we must not translate
2277 // strings sent to this func.
2278 void LyXFunc::setErrorMessage(docstring const & m) const
2280 dispatch_buffer = m;
2285 void LyXFunc::setMessage(docstring const & m) const
2287 dispatch_buffer = m;
2291 docstring const LyXFunc::viewStatusMessage()
2293 // When meta-fake key is pressed, show the key sequence so far + "M-".
2295 return keyseq.print(true) + "M-";
2297 // Else, when a non-complete key sequence is pressed,
2298 // show the available options.
2299 if (keyseq.length() > 0 && !keyseq.deleted())
2300 return keyseq.printOptions(true);
2302 BOOST_ASSERT(lyx_view_);
2303 if (!lyx_view_->buffer())
2304 return _("Welcome to LyX!");
2306 return view()->cursor().currentState();
2310 BufferView * LyXFunc::view() const
2312 BOOST_ASSERT(lyx_view_);
2313 return lyx_view_->view();
2317 bool LyXFunc::wasMetaKey() const
2319 return (meta_fake_bit != key_modifier::none);
2323 void LyXFunc::updateLayout(TextClassPtr const & oldlayout,
2326 lyx_view_->message(_("Converting document to new document class..."));
2328 StableDocIterator backcur(view()->cursor());
2329 ErrorList & el = buffer->errorList("Class Switch");
2330 cap::switchBetweenClasses(
2331 oldlayout, buffer->params().getTextClassPtr(),
2332 static_cast<InsetText &>(buffer->inset()), el);
2334 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
2336 buffer->errors("Class Switch");
2337 updateLabels(*buffer);
2343 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2345 // Why the switch you might ask. It is a trick to ensure that all
2346 // the elements in the LyXRCTags enum is handled. As you can see
2347 // there are no breaks at all. So it is just a huge fall-through.
2348 // The nice thing is that we will get a warning from the compiler
2349 // if we forget an element.
2350 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2352 case LyXRC::RC_ACCEPT_COMPOUND:
2353 case LyXRC::RC_ALT_LANG:
2354 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
2355 case LyXRC::RC_PLAINTEXT_LINELEN:
2356 case LyXRC::RC_AUTOREGIONDELETE:
2357 case LyXRC::RC_AUTORESET_OPTIONS:
2358 case LyXRC::RC_AUTOSAVE:
2359 case LyXRC::RC_AUTO_NUMBER:
2360 case LyXRC::RC_BACKUPDIR_PATH:
2361 case LyXRC::RC_BIBTEX_COMMAND:
2362 case LyXRC::RC_BINDFILE:
2363 case LyXRC::RC_CHECKLASTFILES:
2364 case LyXRC::RC_USELASTFILEPOS:
2365 case LyXRC::RC_LOADSESSION:
2366 case LyXRC::RC_CHKTEX_COMMAND:
2367 case LyXRC::RC_CONVERTER:
2368 case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
2369 case LyXRC::RC_COPIER:
2370 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2371 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2372 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2373 case LyXRC::RC_DATE_INSERT_FORMAT:
2374 case LyXRC::RC_DEFAULT_LANGUAGE:
2375 case LyXRC::RC_DEFAULT_PAPERSIZE:
2376 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2377 case LyXRC::RC_DISPLAY_GRAPHICS:
2378 case LyXRC::RC_DOCUMENTPATH:
2379 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2380 string const encoded = FileName(
2381 lyxrc_new.document_path).toFilesystemEncoding();
2382 if (fs::exists(encoded) && fs::is_directory(encoded))
2383 support::package().document_dir() = FileName(lyxrc.document_path);
2385 case LyXRC::RC_ESC_CHARS:
2386 case LyXRC::RC_FONT_ENCODING:
2387 case LyXRC::RC_FORMAT:
2388 case LyXRC::RC_INDEX_COMMAND:
2389 case LyXRC::RC_INPUT:
2390 case LyXRC::RC_KBMAP:
2391 case LyXRC::RC_KBMAP_PRIMARY:
2392 case LyXRC::RC_KBMAP_SECONDARY:
2393 case LyXRC::RC_LABEL_INIT_LENGTH:
2394 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2395 case LyXRC::RC_LANGUAGE_AUTO_END:
2396 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2397 case LyXRC::RC_LANGUAGE_COMMAND_END:
2398 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2399 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2400 case LyXRC::RC_LANGUAGE_PACKAGE:
2401 case LyXRC::RC_LANGUAGE_USE_BABEL:
2402 case LyXRC::RC_MAKE_BACKUP:
2403 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2404 case LyXRC::RC_NUMLASTFILES:
2405 case LyXRC::RC_PATH_PREFIX:
2406 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2407 support::prependEnvPath("PATH", lyxrc.path_prefix);
2409 case LyXRC::RC_PERS_DICT:
2410 case LyXRC::RC_PREVIEW:
2411 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2412 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2413 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2414 case LyXRC::RC_PRINTCOPIESFLAG:
2415 case LyXRC::RC_PRINTER:
2416 case LyXRC::RC_PRINTEVENPAGEFLAG:
2417 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2418 case LyXRC::RC_PRINTFILEEXTENSION:
2419 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2420 case LyXRC::RC_PRINTODDPAGEFLAG:
2421 case LyXRC::RC_PRINTPAGERANGEFLAG:
2422 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2423 case LyXRC::RC_PRINTPAPERFLAG:
2424 case LyXRC::RC_PRINTREVERSEFLAG:
2425 case LyXRC::RC_PRINTSPOOL_COMMAND:
2426 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2427 case LyXRC::RC_PRINTTOFILE:
2428 case LyXRC::RC_PRINTTOPRINTER:
2429 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2430 case LyXRC::RC_PRINT_COMMAND:
2431 case LyXRC::RC_RTL_SUPPORT:
2432 case LyXRC::RC_SCREEN_DPI:
2433 case LyXRC::RC_SCREEN_FONT_ROMAN:
2434 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2435 case LyXRC::RC_SCREEN_FONT_SANS:
2436 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2437 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2438 case LyXRC::RC_SCREEN_FONT_SIZES:
2439 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2440 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2441 case LyXRC::RC_SCREEN_GEOMETRY_HEIGHT:
2442 case LyXRC::RC_SCREEN_GEOMETRY_WIDTH:
2443 case LyXRC::RC_SCREEN_GEOMETRY_XYSAVED:
2444 case LyXRC::RC_SCREEN_ZOOM:
2445 case LyXRC::RC_SERVERPIPE:
2446 case LyXRC::RC_SET_COLOR:
2447 case LyXRC::RC_SHOW_BANNER:
2448 case LyXRC::RC_SPELL_COMMAND:
2449 case LyXRC::RC_TEMPDIRPATH:
2450 case LyXRC::RC_TEMPLATEPATH:
2451 case LyXRC::RC_TEX_ALLOWS_SPACES:
2452 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2453 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2454 support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2456 case LyXRC::RC_UIFILE:
2457 case LyXRC::RC_USER_EMAIL:
2458 case LyXRC::RC_USER_NAME:
2459 case LyXRC::RC_USETEMPDIR:
2460 case LyXRC::RC_USE_ALT_LANG:
2461 case LyXRC::RC_USE_CONVERTER_CACHE:
2462 case LyXRC::RC_USE_ESC_CHARS:
2463 case LyXRC::RC_USE_INP_ENC:
2464 case LyXRC::RC_USE_PERS_DICT:
2465 case LyXRC::RC_USE_SPELL_LIB:
2466 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2467 case LyXRC::RC_VIEWER:
2468 case LyXRC::RC_LAST: