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"
34 #include "CutAndPaste.h"
36 #include "DispatchResult.h"
38 #include "ErrorList.h"
41 #include "FuncRequest.h"
42 #include "FuncStatus.h"
45 #include "InsetIterator.h"
50 #include "LyXAction.h"
55 #include "Paragraph.h"
56 #include "ParagraphParameters.h"
57 #include "ParIterator.h"
61 #include "TextClassList.h"
62 #include "ToolbarBackend.h"
65 #include "insets/InsetBox.h"
66 #include "insets/InsetBranch.h"
67 #include "insets/InsetCommand.h"
68 #include "insets/InsetERT.h"
69 #include "insets/InsetExternal.h"
70 #include "insets/InsetFloat.h"
71 #include "insets/InsetListings.h"
72 #include "insets/InsetGraphics.h"
73 #include "insets/InsetInclude.h"
74 #include "insets/InsetNote.h"
75 #include "insets/InsetTabular.h"
76 #include "insets/InsetVSpace.h"
77 #include "insets/InsetWrap.h"
79 #include "frontends/Application.h"
80 #include "frontends/alert.h"
81 #include "frontends/Dialogs.h"
82 #include "frontends/FileDialog.h"
83 #include "frontends/FontLoader.h"
84 #include "frontends/Gui.h"
85 #include "frontends/KeySymbol.h"
86 #include "frontends/LyXView.h"
87 #include "frontends/Selection.h"
88 #include "frontends/WorkArea.h"
90 #include "support/environment.h"
91 #include "support/FileFilterList.h"
92 #include "support/filetools.h"
93 #include "support/ForkedcallsController.h"
94 #include "support/fs_extras.h"
95 #include "support/lstrings.h"
96 #include "support/Path.h"
97 #include "support/Package.h"
98 #include "support/Systemcall.h"
99 #include "support/convert.h"
100 #include "support/os.h"
102 #include <boost/current_function.hpp>
103 #include <boost/filesystem/operations.hpp>
108 using std::make_pair;
111 using std::istringstream;
112 using std::ostringstream;
114 namespace fs = boost::filesystem;
118 using frontend::LyXView;
120 using support::absolutePath;
121 using support::addName;
122 using support::addPath;
123 using support::bformat;
124 using support::changeExtension;
125 using support::contains;
126 using support::FileFilterList;
127 using support::FileName;
128 using support::fileSearch;
129 using support::ForkedcallsController;
130 using support::i18nLibFileSearch;
131 using support::isDirWriteable;
132 using support::isFileReadable;
133 using support::isStrInt;
134 using support::makeAbsPath;
135 using support::makeDisplayPath;
136 using support::package;
137 using support::quoteName;
138 using support::rtrim;
139 using support::split;
140 using support::subst;
141 using support::Systemcall;
142 using support::token;
144 using support::prefixIs;
146 namespace Alert = frontend::Alert;
151 bool getLocalStatus(Cursor cursor, FuncRequest const & cmd, FuncStatus & status)
153 // Try to fix cursor in case it is broken.
154 cursor.fixIfBroken();
156 // This is, of course, a mess. Better create a new doc iterator and use
157 // this in Inset::getStatus. This might require an additional
158 // BufferView * arg, though (which should be avoided)
159 //Cursor safe = *this;
161 for ( ; cursor.depth(); cursor.pop()) {
162 //lyxerr << "\nCursor::getStatus: cmd: " << cmd << endl << *this << endl;
163 BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
164 BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
165 BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
167 // The inset's getStatus() will return 'true' if it made
168 // a definitive decision on whether it want to handle the
169 // request or not. The result of this decision is put into
170 // the 'status' parameter.
171 if (cursor.inset().getStatus(cursor, cmd, status)) {
180 /** Return the change status at cursor position, taking in account the
181 * status at each level of the document iterator (a table in a deleted
182 * footnote is deleted).
183 * When \param outer is true, the top slice is not looked at.
185 Change::Type lookupChangeType(DocIterator const & dit, bool outer = false)
187 size_t const depth = dit.depth() - (outer ? 1 : 0);
189 for (size_t i = 0 ; i < depth ; ++i) {
190 CursorSlice const & slice = dit[i];
191 if (!slice.inset().inMathed()
192 && slice.pos() < slice.paragraph().size()) {
193 Change::Type const ch = slice.paragraph().lookupChange(slice.pos()).type;
194 if (ch != Change::UNCHANGED)
198 return Change::UNCHANGED;
205 : lyx_view_(0), encoded_last_key(0), meta_fake_bit(key_modifier::none)
210 void LyXFunc::initKeySequences(KeyMap * kb)
212 keyseq = KeySequence(kb, kb);
213 cancel_meta_seq = KeySequence(kb, kb);
217 void LyXFunc::setLyXView(LyXView * lv)
219 if (!quitting && lyx_view_ && lyx_view_->view() && lyx_view_ != lv)
220 // save current selection to the selection buffer to allow
221 // middle-button paste in another window
222 cap::saveSelection(lyx_view_->view()->cursor());
227 void LyXFunc::handleKeyFunc(kb_action action)
229 char_type c = encoded_last_key;
234 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
235 lyx_view_->view()->getIntl().getTransManager().deadkey(
236 c, get_accent(action).accent, view()->cursor().innerText(), view()->cursor());
237 // Need to clear, in case the minibuffer calls these
240 // copied verbatim from do_accent_char
241 view()->cursor().resetAnchor();
246 void LyXFunc::gotoBookmark(unsigned int idx, bool openFile, bool switchToBuffer)
248 BOOST_ASSERT(lyx_view_);
249 if (!LyX::ref().session().bookmarks().isValid(idx))
251 BookmarksSection::Bookmark const & bm = LyX::ref().session().bookmarks().bookmark(idx);
252 BOOST_ASSERT(!bm.filename.empty());
253 string const file = bm.filename.absFilename();
254 // if the file is not opened, open it.
255 if (!theBufferList().exists(file)) {
257 dispatch(FuncRequest(LFUN_FILE_OPEN, file));
261 // open may fail, so we need to test it again
262 if (!theBufferList().exists(file))
265 // if the current buffer is not that one, switch to it.
266 if (lyx_view_->buffer()->fileName() != file) {
269 dispatch(FuncRequest(LFUN_BUFFER_SWITCH, file));
271 // moveToPosition try paragraph id first and then paragraph (pit, pos).
272 if (!view()->moveToPosition(bm.bottom_pit, bm.bottom_pos,
273 bm.top_id, bm.top_pos))
276 // Cursor jump succeeded!
277 Cursor const & cur = view()->cursor();
278 pit_type new_pit = cur.pit();
279 pos_type new_pos = cur.pos();
280 int new_id = cur.paragraph().id();
282 // if bottom_pit, bottom_pos or top_id has been changed, update bookmark
283 // see http://bugzilla.lyx.org/show_bug.cgi?id=3092
284 if (bm.bottom_pit != new_pit || bm.bottom_pos != new_pos
285 || bm.top_id != new_id) {
286 const_cast<BookmarksSection::Bookmark &>(bm).updatePos(
287 new_pit, new_pos, new_id);
292 void LyXFunc::processKeySym(KeySymbol const & keysym,
293 key_modifier::state state)
295 LYXERR(Debug::KEY) << "KeySym is " << keysym.getSymbolName() << endl;
297 // Do nothing if we have nothing (JMarc)
298 if (!keysym.isOK()) {
299 LYXERR(Debug::KEY) << "Empty kbd action (probably composing)"
304 if (keysym.isModifier()) {
305 LYXERR(Debug::KEY) << "isModifier true" << endl;
309 //Encoding const * encoding = view()->cursor().getEncoding();
310 //encoded_last_key = keysym.getISOEncoded(encoding ? encoding->name() : "");
311 // FIXME: encoded_last_key shadows the member variable of the same
312 // name. Is that intended?
313 char_type encoded_last_key = keysym.getUCSEncoded();
315 // Do a one-deep top-level lookup for
316 // cancel and meta-fake keys. RVDK_PATCH_5
317 cancel_meta_seq.reset();
319 FuncRequest func = cancel_meta_seq.addkey(keysym, state);
320 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
321 << " action first set to [" << func.action << ']'
324 // When not cancel or meta-fake, do the normal lookup.
325 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
326 // Mostly, meta_fake_bit = key_modifier::none. RVDK_PATCH_5.
327 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_PREFIX)) {
328 // remove Caps Lock and Mod2 as a modifiers
329 func = keyseq.addkey(keysym, (state | meta_fake_bit));
330 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
331 << "action now set to ["
332 << func.action << ']' << endl;
335 // Dont remove this unless you know what you are doing.
336 meta_fake_bit = key_modifier::none;
338 // Can this happen now ?
339 if (func.action == LFUN_NOACTION) {
340 func = FuncRequest(LFUN_COMMAND_PREFIX);
343 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
345 << func.action << "]["
346 << to_utf8(keyseq.print(false)) << ']'
349 // already here we know if it any point in going further
350 // why not return already here if action == -1 and
351 // num_bytes == 0? (Lgb)
353 if (keyseq.length() > 1) {
354 lyx_view_->message(keyseq.print(true));
358 // Maybe user can only reach the key via holding down shift.
359 // Let's see. But only if shift is the only modifier
360 if (func.action == LFUN_UNKNOWN_ACTION &&
361 state == key_modifier::shift) {
362 LYXERR(Debug::KEY) << "Trying without shift" << endl;
363 func = keyseq.addkey(keysym, key_modifier::none);
364 LYXERR(Debug::KEY) << "Action now " << func.action << endl;
367 if (func.action == LFUN_UNKNOWN_ACTION) {
368 // Hmm, we didn't match any of the keysequences. See
369 // if it's normal insertable text not already covered
371 if (keysym.isText() && keyseq.length() == 1) {
372 LYXERR(Debug::KEY) << "isText() is true, inserting." << endl;
373 func = FuncRequest(LFUN_SELF_INSERT,
374 FuncRequest::KEYBOARD);
376 LYXERR(Debug::KEY) << "Unknown, !isText() - giving up" << endl;
377 lyx_view_->message(_("Unknown function."));
382 if (func.action == LFUN_SELF_INSERT) {
383 if (encoded_last_key != 0) {
384 docstring const arg(1, encoded_last_key);
385 dispatch(FuncRequest(LFUN_SELF_INSERT, arg,
386 FuncRequest::KEYBOARD));
388 << "SelfInsert arg[`" << to_utf8(arg) << "']" << endl;
394 /* When we move around, or type, it's nice to be able to see
395 * the cursor immediately after the keypress.
397 if (lyx_view_ && lyx_view_->currentWorkArea())
398 lyx_view_->currentWorkArea()->startBlinkingCursor();
402 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
404 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
407 Cursor & cur = view()->cursor();
409 /* In LyX/Mac, when a dialog is open, the menus of the
410 application can still be accessed without giving focus to
411 the main window. In this case, we want to disable the menu
412 entries that are buffer-related.
414 Note that this code is not perfect, as bug 1941 attests:
415 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
417 Buffer * buf = lyx_view_? lyx_view_->buffer() : 0;
418 if (lyx_view_ && cmd.origin == FuncRequest::MENU && !lyx_view_->hasFocus())
421 if (cmd.action == LFUN_NOACTION) {
422 flag.message(from_utf8(N_("Nothing to do")));
427 switch (cmd.action) {
428 case LFUN_UNKNOWN_ACTION:
429 #ifndef HAVE_LIBAIKSAURUS
430 case LFUN_THESAURUS_ENTRY:
440 if (flag.unknown()) {
441 flag.message(from_utf8(N_("Unknown action")));
445 if (!flag.enabled()) {
446 if (flag.message().empty())
447 flag.message(from_utf8(N_("Command disabled")));
451 // Check whether we need a buffer
452 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
454 flag.message(from_utf8(N_("Command not allowed with"
455 "out any document open")));
460 // I would really like to avoid having this switch and rather try to
461 // encode this in the function itself.
462 // -- And I'd rather let an inset decide which LFUNs it is willing
463 // to handle (Andre')
465 switch (cmd.action) {
466 case LFUN_BUFFER_TOGGLE_READ_ONLY:
467 flag.setOnOff(buf->isReadonly());
470 case LFUN_BUFFER_SWITCH:
471 // toggle on the current buffer, but do not toggle off
472 // the other ones (is that a good idea?)
473 if (buf && to_utf8(cmd.argument()) == buf->fileName())
477 case LFUN_BUFFER_EXPORT:
478 enable = cmd.argument() == "custom"
479 || Exporter::isExportable(*buf, to_utf8(cmd.argument()));
482 case LFUN_BUFFER_CHKTEX:
483 enable = buf->isLatex() && !lyxrc.chktex_command.empty();
486 case LFUN_BUILD_PROGRAM:
487 enable = Exporter::isExportable(*buf, "program");
490 case LFUN_LAYOUT_TABULAR:
491 enable = cur.innerInsetOfType(Inset::TABULAR_CODE);
495 case LFUN_LAYOUT_PARAGRAPH:
496 enable = !cur.inset().forceDefaultParagraphs(cur.idx());
499 case LFUN_VC_REGISTER:
500 enable = !buf->lyxvc().inUse();
502 case LFUN_VC_CHECK_IN:
503 enable = buf->lyxvc().inUse() && !buf->isReadonly();
505 case LFUN_VC_CHECK_OUT:
506 enable = buf->lyxvc().inUse() && buf->isReadonly();
509 case LFUN_VC_UNDO_LAST:
510 enable = buf->lyxvc().inUse();
512 case LFUN_BUFFER_RELOAD:
513 enable = !buf->isUnnamed() && fs::exists(buf->fileName())
514 && (!buf->isClean() || buf->isExternallyModified(Buffer::timestamp_method));
517 case LFUN_INSET_SETTINGS: {
521 Inset::Code code = cur.inset().lyxCode();
523 case Inset::TABULAR_CODE:
524 enable = cmd.argument() == "tabular";
526 case Inset::ERT_CODE:
527 enable = cmd.argument() == "ert";
529 case Inset::FLOAT_CODE:
530 enable = cmd.argument() == "float";
532 case Inset::WRAP_CODE:
533 enable = cmd.argument() == "wrap";
535 case Inset::NOTE_CODE:
536 enable = cmd.argument() == "note";
538 case Inset::BRANCH_CODE:
539 enable = cmd.argument() == "branch";
541 case Inset::BOX_CODE:
542 enable = cmd.argument() == "box";
544 case Inset::LISTINGS_CODE:
545 enable = cmd.argument() == "listings";
553 case LFUN_INSET_APPLY: {
554 string const name = cmd.getArg(0);
555 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
557 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
559 if (!inset->getStatus(cur, fr, fs)) {
560 // Every inset is supposed to handle this
565 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
566 flag |= getStatus(fr);
568 enable = flag.enabled();
572 case LFUN_DIALOG_TOGGLE:
573 flag.setOnOff(lyx_view_->getDialogs().visible(cmd.getArg(0)));
574 // fall through to set "enable"
575 case LFUN_DIALOG_SHOW: {
576 string const name = cmd.getArg(0);
578 enable = name == "aboutlyx"
579 || name == "file" //FIXME: should be removed.
581 || name == "texinfo";
582 else if (name == "print")
583 enable = Exporter::isExportable(*buf, "dvi")
584 && lyxrc.print_command != "none";
585 else if (name == "character")
586 enable = cur.inset().lyxCode() != Inset::ERT_CODE &&
587 cur.inset().lyxCode() != Inset::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_SHOW_NEW_INSET:
602 enable = cur.inset().lyxCode() != Inset::ERT_CODE &&
603 cur.inset().lyxCode() != Inset::LISTINGS_CODE;
604 if (cur.inset().lyxCode() == Inset::CAPTION_CODE) {
606 if (cur.inset().getStatus(cur, cmd, flag))
611 case LFUN_DIALOG_UPDATE: {
612 string const name = cmd.getArg(0);
614 enable = name == "prefs";
618 case LFUN_CITATION_INSERT: {
619 FuncRequest fr(LFUN_INSET_INSERT, "citation");
620 enable = getStatus(fr).enabled();
624 case LFUN_BUFFER_WRITE: {
625 enable = lyx_view_->buffer()->isUnnamed()
626 || !lyx_view_->buffer()->isClean();
631 case LFUN_BUFFER_WRITE_ALL: {
632 // We enable the command only if there are some modified buffers
633 Buffer * first = theBufferList().first();
634 bool modified = false;
638 // We cannot use a for loop as the buffer list is a cycle.
644 b = theBufferList().next(b);
645 } while (b != first);
653 case LFUN_BOOKMARK_GOTO: {
654 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
655 enable = LyX::ref().session().bookmarks().isValid(num);
659 case LFUN_BOOKMARK_CLEAR:
660 enable = LyX::ref().session().bookmarks().size() > 0;
663 case LFUN_TOOLBAR_TOGGLE: {
664 bool const current = lyx_view_->isToolbarVisible(cmd.getArg(0));
665 flag.setOnOff(current);
668 case LFUN_WINDOW_CLOSE: {
669 enable = (theApp()->gui().viewIds().size() > 1);
673 // this one is difficult to get right. As a half-baked
674 // solution, we consider only the first action of the sequence
675 case LFUN_COMMAND_SEQUENCE: {
676 // argument contains ';'-terminated commands
677 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
678 FuncRequest func(lyxaction.lookupFunc(firstcmd));
679 func.origin = cmd.origin;
680 flag = getStatus(func);
683 case LFUN_BUFFER_NEW:
684 case LFUN_BUFFER_NEW_TEMPLATE:
685 case LFUN_WORD_FIND_FORWARD:
686 case LFUN_WORD_FIND_BACKWARD:
687 case LFUN_COMMAND_PREFIX:
688 case LFUN_COMMAND_EXECUTE:
690 case LFUN_META_PREFIX:
691 case LFUN_BUFFER_CLOSE:
692 case LFUN_BUFFER_WRITE_AS:
693 case LFUN_BUFFER_UPDATE:
694 case LFUN_BUFFER_VIEW:
695 case LFUN_MASTER_BUFFER_UPDATE:
696 case LFUN_MASTER_BUFFER_VIEW:
697 case LFUN_BUFFER_IMPORT:
698 case LFUN_BUFFER_AUTO_SAVE:
699 case LFUN_RECONFIGURE:
703 case LFUN_DROP_LAYOUTS_CHOICE:
705 case LFUN_SERVER_GET_NAME:
706 case LFUN_SERVER_NOTIFY:
707 case LFUN_SERVER_GOTO_FILE_ROW:
708 case LFUN_DIALOG_HIDE:
709 case LFUN_DIALOG_DISCONNECT_INSET:
710 case LFUN_BUFFER_CHILD_OPEN:
711 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
712 case LFUN_KEYMAP_OFF:
713 case LFUN_KEYMAP_PRIMARY:
714 case LFUN_KEYMAP_SECONDARY:
715 case LFUN_KEYMAP_TOGGLE:
717 case LFUN_BUFFER_EXPORT_CUSTOM:
718 case LFUN_BUFFER_PRINT:
719 case LFUN_PREFERENCES_SAVE:
720 case LFUN_SCREEN_FONT_UPDATE:
723 case LFUN_EXTERNAL_EDIT:
724 case LFUN_GRAPHICS_EDIT:
725 case LFUN_ALL_INSETS_TOGGLE:
726 case LFUN_BUFFER_LANGUAGE:
727 case LFUN_TEXTCLASS_APPLY:
728 case LFUN_TEXTCLASS_LOAD:
729 case LFUN_BUFFER_SAVE_AS_DEFAULT:
730 case LFUN_BUFFER_PARAMS_APPLY:
731 case LFUN_LAYOUT_MODULES_CLEAR:
732 case LFUN_LAYOUT_MODULE_ADD:
733 case LFUN_LAYOUT_RELOAD:
734 case LFUN_LYXRC_APPLY:
735 case LFUN_BUFFER_NEXT:
736 case LFUN_BUFFER_PREVIOUS:
737 case LFUN_WINDOW_NEW:
739 // these are handled in our dispatch()
743 if (!getLocalStatus(cur, cmd, flag))
744 flag = view()->getStatus(cmd);
750 // Can we use a readonly buffer?
751 if (buf && buf->isReadonly()
752 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
753 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
754 flag.message(from_utf8(N_("Document is read-only")));
758 // Are we in a DELETED change-tracking region?
759 if (buf && lookupChangeType(cur, true) == Change::DELETED
760 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
761 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
762 flag.message(from_utf8(N_("This portion of the document is deleted.")));
766 // the default error message if we disable the command
767 if (!flag.enabled() && flag.message().empty())
768 flag.message(from_utf8(N_("Command disabled")));
774 bool LyXFunc::ensureBufferClean(BufferView * bv)
776 Buffer & buf = bv->buffer();
780 docstring const file = makeDisplayPath(buf.fileName(), 30);
781 docstring text = bformat(_("The document %1$s has unsaved "
782 "changes.\n\nDo you want to save "
783 "the document?"), file);
784 int const ret = Alert::prompt(_("Save changed document?"),
785 text, 0, 1, _("&Save"),
789 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
791 return buf.isClean();
797 void showPrintError(string const & name)
799 docstring str = bformat(_("Could not print the document %1$s.\n"
800 "Check that your printer is set up correctly."),
801 makeDisplayPath(name, 50));
802 Alert::error(_("Print document failed"), str);
806 void loadTextClass(string const & name)
808 std::pair<bool, textclass_type> const tc_pair =
809 textclasslist.numberOfClass(name);
811 if (!tc_pair.first) {
812 lyxerr << "Document class \"" << name
813 << "\" does not exist."
818 textclass_type const tc = tc_pair.second;
820 if (!textclasslist[tc].load()) {
821 docstring s = bformat(_("The document class %1$s."
822 "could not be loaded."),
823 from_utf8(textclasslist[tc].name()));
824 Alert::error(_("Could not load class"), s);
829 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
834 void LyXFunc::dispatch(FuncRequest const & cmd)
836 string const argument = to_utf8(cmd.argument());
837 kb_action const action = cmd.action;
839 LYXERR(Debug::ACTION) << endl << "LyXFunc::dispatch: cmd: " << cmd << endl;
840 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
842 // we have not done anything wrong yet.
844 dispatch_buffer.erase();
846 // redraw the screen at the end (first of the two drawing steps).
847 //This is done unless explicitely requested otherwise
848 Update::flags updateFlags = Update::FitCursor;
850 FuncStatus const flag = getStatus(cmd);
851 if (!flag.enabled()) {
852 // We cannot use this function here
853 LYXERR(Debug::ACTION) << "LyXFunc::dispatch: "
854 << lyxaction.getActionName(action)
855 << " [" << action << "] is disabled at this location"
857 setErrorMessage(flag.message());
861 case LFUN_WORD_FIND_FORWARD:
862 case LFUN_WORD_FIND_BACKWARD: {
863 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
864 static docstring last_search;
865 docstring searched_string;
867 if (!cmd.argument().empty()) {
868 last_search = cmd.argument();
869 searched_string = cmd.argument();
871 searched_string = last_search;
874 if (searched_string.empty())
877 bool const fw = action == LFUN_WORD_FIND_FORWARD;
878 docstring const data =
879 find2string(searched_string, true, false, fw);
880 find(view(), FuncRequest(LFUN_WORD_FIND, data));
884 case LFUN_COMMAND_PREFIX:
885 BOOST_ASSERT(lyx_view_);
886 lyx_view_->message(keyseq.printOptions(true));
889 case LFUN_COMMAND_EXECUTE:
890 BOOST_ASSERT(lyx_view_);
891 lyx_view_->showMiniBuffer(true);
895 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
897 meta_fake_bit = key_modifier::none;
898 if (lyx_view_->buffer())
899 // cancel any selection
900 dispatch(FuncRequest(LFUN_MARK_OFF));
901 setMessage(from_ascii(N_("Cancel")));
904 case LFUN_META_PREFIX:
905 meta_fake_bit = key_modifier::alt;
906 setMessage(keyseq.print(true));
909 case LFUN_BUFFER_TOGGLE_READ_ONLY:
910 BOOST_ASSERT(lyx_view_ && lyx_view_->view() && lyx_view_->buffer());
911 if (lyx_view_->buffer()->lyxvc().inUse())
912 lyx_view_->buffer()->lyxvc().toggleReadOnly();
914 lyx_view_->buffer()->setReadonly(
915 !lyx_view_->buffer()->isReadonly());
918 // --- Menus -----------------------------------------------
919 case LFUN_BUFFER_NEW:
920 menuNew(argument, false);
921 updateFlags = Update::None;
924 case LFUN_BUFFER_NEW_TEMPLATE:
925 menuNew(argument, true);
926 updateFlags = Update::None;
929 case LFUN_BUFFER_CLOSE:
931 updateFlags = Update::None;
934 case LFUN_BUFFER_WRITE:
935 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
936 if (!lyx_view_->buffer()->isUnnamed()) {
937 docstring const str = bformat(_("Saving document %1$s..."),
938 makeDisplayPath(lyx_view_->buffer()->fileName()));
939 lyx_view_->message(str);
940 menuWrite(lyx_view_->buffer());
941 lyx_view_->message(str + _(" done."));
943 writeAs(lyx_view_->buffer());
945 updateFlags = Update::None;
948 case LFUN_BUFFER_WRITE_AS:
949 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
950 writeAs(lyx_view_->buffer(), argument);
951 updateFlags = Update::None;
954 case LFUN_BUFFER_WRITE_ALL: {
955 Buffer * first = theBufferList().first();
958 lyx_view_->message(_("Saving all documents..."));
960 // We cannot use a for loop as the buffer list cycles.
963 if (!b->isUnnamed()) {
965 lyxerr[Debug::ACTION] << "Saved " << b->fileName() << endl;
969 b = theBufferList().next(b);
970 } while (b != first);
971 lyx_view_->message(_("All documents saved."));
974 updateFlags = Update::None;
978 case LFUN_BUFFER_RELOAD: {
979 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
980 docstring const file = makeDisplayPath(lyx_view_->buffer()->fileName(), 20);
981 docstring text = bformat(_("Any changes will be lost. Are you sure "
982 "you want to revert to the saved version of the document %1$s?"), file);
983 int const ret = Alert::prompt(_("Revert to saved document?"),
984 text, 1, 1, _("&Revert"), _("&Cancel"));
991 case LFUN_BUFFER_UPDATE:
992 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
993 Exporter::Export(lyx_view_->buffer(), argument, true);
996 case LFUN_BUFFER_VIEW:
997 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
998 Exporter::preview(lyx_view_->buffer(), argument);
1001 case LFUN_MASTER_BUFFER_UPDATE:
1002 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->getMasterBuffer());
1003 Exporter::Export(lyx_view_->buffer()->getMasterBuffer(), argument, true);
1006 case LFUN_MASTER_BUFFER_VIEW:
1007 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->getMasterBuffer());
1008 Exporter::preview(lyx_view_->buffer()->getMasterBuffer(), argument);
1011 case LFUN_BUILD_PROGRAM:
1012 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1013 Exporter::Export(lyx_view_->buffer(), "program", true);
1016 case LFUN_BUFFER_CHKTEX:
1017 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1018 lyx_view_->buffer()->runChktex();
1021 case LFUN_BUFFER_EXPORT:
1022 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1023 if (argument == "custom")
1024 lyx_view_->getDialogs().show("sendto");
1026 Exporter::Export(lyx_view_->buffer(), argument, false);
1030 case LFUN_BUFFER_EXPORT_CUSTOM: {
1031 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1033 string command = split(argument, format_name, ' ');
1034 Format const * format = formats.getFormat(format_name);
1036 lyxerr << "Format \"" << format_name
1037 << "\" not recognized!"
1042 Buffer * buffer = lyx_view_->buffer();
1044 // The name of the file created by the conversion process
1047 // Output to filename
1048 if (format->name() == "lyx") {
1049 string const latexname =
1050 buffer->getLatexName(false);
1051 filename = changeExtension(latexname,
1052 format->extension());
1053 filename = addName(buffer->temppath(), filename);
1055 if (!buffer->writeFile(FileName(filename)))
1059 Exporter::Export(buffer, format_name, true, filename);
1062 // Substitute $$FName for filename
1063 if (!contains(command, "$$FName"))
1064 command = "( " + command + " ) < $$FName";
1065 command = subst(command, "$$FName", filename);
1067 // Execute the command in the background
1069 call.startscript(Systemcall::DontWait, command);
1073 case LFUN_BUFFER_PRINT: {
1074 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1075 // FIXME: cmd.getArg() might fail if one of the arguments
1076 // contains double quotes
1077 string target = cmd.getArg(0);
1078 string target_name = cmd.getArg(1);
1079 string command = cmd.getArg(2);
1082 || target_name.empty()
1083 || command.empty()) {
1084 lyxerr << "Unable to parse \""
1085 << argument << '"' << endl;
1088 if (target != "printer" && target != "file") {
1089 lyxerr << "Unrecognized target \""
1090 << target << '"' << endl;
1094 Buffer * buffer = lyx_view_->buffer();
1096 if (!Exporter::Export(buffer, "dvi", true)) {
1097 showPrintError(buffer->fileName());
1101 // Push directory path.
1102 string const path(buffer->temppath());
1103 // Prevent the compiler from optimizing away p
1105 support::Path p(pp);
1107 // there are three cases here:
1108 // 1. we print to a file
1109 // 2. we print directly to a printer
1110 // 3. we print using a spool command (print to file first)
1113 string const dviname =
1114 changeExtension(buffer->getLatexName(true),
1117 if (target == "printer") {
1118 if (!lyxrc.print_spool_command.empty()) {
1119 // case 3: print using a spool
1120 string const psname =
1121 changeExtension(dviname,".ps");
1122 command += ' ' + lyxrc.print_to_file
1125 + quoteName(dviname);
1128 lyxrc.print_spool_command + ' ';
1129 if (target_name != "default") {
1130 command2 += lyxrc.print_spool_printerprefix
1134 command2 += quoteName(psname);
1136 // If successful, then spool command
1137 res = one.startscript(
1142 res = one.startscript(
1143 Systemcall::DontWait,
1146 // case 2: print directly to a printer
1147 if (target_name != "default")
1148 command += ' ' + lyxrc.print_to_printer + target_name + ' ';
1149 res = one.startscript(
1150 Systemcall::DontWait,
1151 command + quoteName(dviname));
1155 // case 1: print to a file
1156 FileName const filename(makeAbsPath(target_name,
1157 lyx_view_->buffer()->filePath()));
1158 FileName const dvifile(makeAbsPath(dviname, path));
1159 if (fs::exists(filename.toFilesystemEncoding())) {
1160 docstring text = bformat(
1161 _("The file %1$s already exists.\n\n"
1162 "Do you want to overwrite that file?"),
1163 makeDisplayPath(filename.absFilename()));
1164 if (Alert::prompt(_("Overwrite file?"),
1165 text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
1168 command += ' ' + lyxrc.print_to_file
1169 + quoteName(filename.toFilesystemEncoding())
1171 + quoteName(dvifile.toFilesystemEncoding());
1172 res = one.startscript(Systemcall::DontWait,
1177 showPrintError(buffer->fileName());
1181 case LFUN_BUFFER_IMPORT:
1186 // quitting is triggered by the gui code
1187 // (leaving the event loop).
1188 lyx_view_->message(from_utf8(N_("Exiting.")));
1189 if (theBufferList().quitWriteAll())
1190 theApp()->gui().closeAllViews();
1193 case LFUN_BUFFER_AUTO_SAVE:
1197 case LFUN_RECONFIGURE:
1198 BOOST_ASSERT(lyx_view_);
1199 // argument is any additional parameter to the configure.py command
1200 reconfigure(*lyx_view_, argument);
1203 case LFUN_HELP_OPEN: {
1204 BOOST_ASSERT(lyx_view_);
1205 string const arg = argument;
1207 setErrorMessage(from_ascii(N_("Missing argument")));
1210 FileName const fname = i18nLibFileSearch("doc", arg, "lyx");
1211 if (fname.empty()) {
1212 lyxerr << "LyX: unable to find documentation file `"
1213 << arg << "'. Bad installation?" << endl;
1216 lyx_view_->message(bformat(_("Opening help file %1$s..."),
1217 makeDisplayPath(fname.absFilename())));
1218 Buffer * buf = lyx_view_->loadLyXFile(fname, false);
1221 lyx_view_->setBuffer(buf);
1222 lyx_view_->showErrorList("Parse");
1224 updateFlags = Update::None;
1228 // --- version control -------------------------------
1229 case LFUN_VC_REGISTER:
1230 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1231 if (!ensureBufferClean(view()))
1233 if (!lyx_view_->buffer()->lyxvc().inUse()) {
1234 lyx_view_->buffer()->lyxvc().registrer();
1237 updateFlags = Update::Force;
1240 case LFUN_VC_CHECK_IN:
1241 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1242 if (!ensureBufferClean(view()))
1244 if (lyx_view_->buffer()->lyxvc().inUse()
1245 && !lyx_view_->buffer()->isReadonly()) {
1246 lyx_view_->buffer()->lyxvc().checkIn();
1251 case LFUN_VC_CHECK_OUT:
1252 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1253 if (!ensureBufferClean(view()))
1255 if (lyx_view_->buffer()->lyxvc().inUse()
1256 && lyx_view_->buffer()->isReadonly()) {
1257 lyx_view_->buffer()->lyxvc().checkOut();
1262 case LFUN_VC_REVERT:
1263 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1264 lyx_view_->buffer()->lyxvc().revert();
1268 case LFUN_VC_UNDO_LAST:
1269 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1270 lyx_view_->buffer()->lyxvc().undoLast();
1274 // --- buffers ----------------------------------------
1275 case LFUN_BUFFER_SWITCH:
1276 BOOST_ASSERT(lyx_view_);
1277 lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1278 updateFlags = Update::None;
1281 case LFUN_BUFFER_NEXT:
1282 BOOST_ASSERT(lyx_view_);
1283 lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer()));
1284 updateFlags = Update::None;
1287 case LFUN_BUFFER_PREVIOUS:
1288 BOOST_ASSERT(lyx_view_);
1289 lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer()));
1290 updateFlags = Update::None;
1294 BOOST_ASSERT(lyx_view_);
1295 newFile(*lyx_view_, argument);
1296 updateFlags = Update::None;
1299 case LFUN_FILE_OPEN:
1300 BOOST_ASSERT(lyx_view_);
1302 updateFlags = Update::None;
1305 case LFUN_DROP_LAYOUTS_CHOICE:
1306 BOOST_ASSERT(lyx_view_);
1307 lyx_view_->openLayoutList();
1310 case LFUN_MENU_OPEN:
1311 BOOST_ASSERT(lyx_view_);
1312 lyx_view_->openMenu(from_utf8(argument));
1315 // --- lyxserver commands ----------------------------
1316 case LFUN_SERVER_GET_NAME:
1317 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1318 setMessage(from_utf8(lyx_view_->buffer()->fileName()));
1319 LYXERR(Debug::INFO) << "FNAME["
1320 << lyx_view_->buffer()->fileName()
1324 case LFUN_SERVER_NOTIFY:
1325 dispatch_buffer = keyseq.print(false);
1326 theServer().notifyClient(to_utf8(dispatch_buffer));
1329 case LFUN_SERVER_GOTO_FILE_ROW: {
1330 BOOST_ASSERT(lyx_view_);
1333 istringstream is(argument);
1334 is >> file_name >> row;
1336 bool loaded = false;
1337 if (prefixIs(file_name, package().temp_dir().absFilename()))
1338 // Needed by inverse dvi search. If it is a file
1339 // in tmpdir, call the apropriated function
1340 buf = theBufferList().getBufferFromTmp(file_name);
1342 // Must replace extension of the file to be .lyx
1343 // and get full path
1344 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1345 // Either change buffer or load the file
1346 if (theBufferList().exists(s.absFilename()))
1347 buf = theBufferList().getBuffer(s.absFilename());
1349 buf = lyx_view_->loadLyXFile(s);
1355 updateFlags = Update::None;
1360 lyx_view_->setBuffer(buf);
1361 view()->setCursorFromRow(row);
1363 lyx_view_->showErrorList("Parse");
1364 updateFlags = Update::FitCursor;
1368 case LFUN_DIALOG_SHOW: {
1369 BOOST_ASSERT(lyx_view_);
1370 string const name = cmd.getArg(0);
1371 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1373 if (name == "character") {
1374 data = freefont2string();
1376 lyx_view_->getDialogs().show("character", data);
1377 } else if (name == "latexlog") {
1378 pair<Buffer::LogType, string> const logfile =
1379 lyx_view_->buffer()->getLogName();
1380 switch (logfile.first) {
1381 case Buffer::latexlog:
1384 case Buffer::buildlog:
1388 data += Lexer::quoteString(logfile.second);
1389 lyx_view_->getDialogs().show("log", data);
1390 } else if (name == "vclog") {
1391 string const data = "vc " +
1392 Lexer::quoteString(lyx_view_->buffer()->lyxvc().getLogFile());
1393 lyx_view_->getDialogs().show("log", data);
1395 lyx_view_->getDialogs().show(name, data);
1399 case LFUN_DIALOG_SHOW_NEW_INSET: {
1400 BOOST_ASSERT(lyx_view_);
1401 string const name = cmd.getArg(0);
1402 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1403 if (name == "bibitem" ||
1407 name == "nomenclature" ||
1411 InsetCommandParams p(name);
1412 data = InsetCommandMailer::params2string(name, p);
1413 } else if (name == "include") {
1414 // data is the include type: one of "include",
1415 // "input", "verbatiminput" or "verbatiminput*"
1417 // default type is requested
1419 InsetCommandParams p(data);
1420 data = InsetIncludeMailer::params2string(p);
1421 } else if (name == "box") {
1422 // \c data == "Boxed" || "Frameless" etc
1423 InsetBoxParams p(data);
1424 data = InsetBoxMailer::params2string(p);
1425 } else if (name == "branch") {
1426 InsetBranchParams p;
1427 data = InsetBranchMailer::params2string(p);
1428 } else if (name == "citation") {
1429 InsetCommandParams p("citation");
1430 data = InsetCommandMailer::params2string(name, p);
1431 } else if (name == "ert") {
1432 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1433 } else if (name == "external") {
1434 InsetExternalParams p;
1435 Buffer const & buffer = *lyx_view_->buffer();
1436 data = InsetExternalMailer::params2string(p, buffer);
1437 } else if (name == "float") {
1439 data = InsetFloatMailer::params2string(p);
1440 } else if (name == "listings") {
1441 InsetListingsParams p;
1442 data = InsetListingsMailer::params2string(p);
1443 } else if (name == "graphics") {
1444 InsetGraphicsParams p;
1445 Buffer const & buffer = *lyx_view_->buffer();
1446 data = InsetGraphicsMailer::params2string(p, buffer);
1447 } else if (name == "note") {
1449 data = InsetNoteMailer::params2string(p);
1450 } else if (name == "vspace") {
1452 data = InsetVSpaceMailer::params2string(space);
1453 } else if (name == "wrap") {
1455 data = InsetWrapMailer::params2string(p);
1457 lyx_view_->getDialogs().show(name, data, 0);
1461 case LFUN_DIALOG_UPDATE: {
1462 BOOST_ASSERT(lyx_view_);
1463 string const & name = argument;
1464 // Can only update a dialog connected to an existing inset
1465 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1467 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1468 inset->dispatch(view()->cursor(), fr);
1469 } else if (name == "paragraph") {
1470 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1471 } else if (name == "prefs") {
1472 lyx_view_->getDialogs().update(name, string());
1477 case LFUN_DIALOG_HIDE:
1478 LyX::cref().hideDialogs(argument, 0);
1481 case LFUN_DIALOG_TOGGLE: {
1482 BOOST_ASSERT(lyx_view_);
1483 if (lyx_view_->getDialogs().visible(cmd.getArg(0)))
1484 dispatch(FuncRequest(LFUN_DIALOG_HIDE, argument));
1486 dispatch(FuncRequest(LFUN_DIALOG_SHOW, argument));
1490 case LFUN_DIALOG_DISCONNECT_INSET:
1491 BOOST_ASSERT(lyx_view_);
1492 lyx_view_->getDialogs().disconnect(argument);
1496 case LFUN_CITATION_INSERT: {
1497 BOOST_ASSERT(lyx_view_);
1498 if (!argument.empty()) {
1499 // we can have one optional argument, delimited by '|'
1500 // citation-insert <key>|<text_before>
1501 // this should be enhanced to also support text_after
1502 // and citation style
1503 string arg = argument;
1505 if (contains(argument, "|")) {
1506 arg = token(argument, '|', 0);
1507 opt1 = token(argument, '|', 1);
1509 InsetCommandParams icp("citation");
1510 icp["key"] = from_utf8(arg);
1512 icp["before"] = from_utf8(opt1);
1513 string icstr = InsetCommandMailer::params2string("citation", icp);
1514 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1517 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1521 case LFUN_BUFFER_CHILD_OPEN: {
1522 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1523 Buffer * parent = lyx_view_->buffer();
1524 FileName filename = makeAbsPath(argument, parent->filePath());
1525 view()->saveBookmark(false);
1527 bool parsed = false;
1528 if (theBufferList().exists(filename.absFilename())) {
1529 child = theBufferList().getBuffer(filename.absFilename());
1531 setMessage(bformat(_("Opening child document %1$s..."),
1532 makeDisplayPath(filename.absFilename())));
1533 child = lyx_view_->loadLyXFile(filename, true);
1537 // Set the parent name of the child document.
1538 // This makes insertion of citations and references in the child work,
1539 // when the target is in the parent or another child document.
1540 child->setParentName(parent->fileName());
1541 updateLabels(*child->getMasterBuffer());
1542 lyx_view_->setBuffer(child);
1544 lyx_view_->showErrorList("Parse");
1547 // If a screen update is required (in case where auto_open is false),
1548 // setBuffer() would have taken care of it already. Otherwise we shall
1549 // reset the update flag because it can cause a circular problem.
1551 updateFlags = Update::None;
1555 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1556 BOOST_ASSERT(lyx_view_);
1557 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1560 case LFUN_KEYMAP_OFF:
1561 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1562 lyx_view_->view()->getIntl().keyMapOn(false);
1565 case LFUN_KEYMAP_PRIMARY:
1566 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1567 lyx_view_->view()->getIntl().keyMapPrim();
1570 case LFUN_KEYMAP_SECONDARY:
1571 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1572 lyx_view_->view()->getIntl().keyMapSec();
1575 case LFUN_KEYMAP_TOGGLE:
1576 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1577 lyx_view_->view()->getIntl().toggleKeyMap();
1583 string rest = split(argument, countstr, ' ');
1584 istringstream is(countstr);
1587 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1588 for (int i = 0; i < count; ++i)
1589 dispatch(lyxaction.lookupFunc(rest));
1593 case LFUN_COMMAND_SEQUENCE: {
1594 // argument contains ';'-terminated commands
1595 string arg = argument;
1596 while (!arg.empty()) {
1598 arg = split(arg, first, ';');
1599 FuncRequest func(lyxaction.lookupFunc(first));
1600 func.origin = cmd.origin;
1606 case LFUN_PREFERENCES_SAVE: {
1607 lyxrc.write(makeAbsPath("preferences",
1608 package().user_support().absFilename()),
1613 case LFUN_SCREEN_FONT_UPDATE:
1614 BOOST_ASSERT(lyx_view_);
1615 // handle the screen font changes.
1616 theFontLoader().update();
1617 /// FIXME: only the current view will be updated. the Gui
1618 /// class is able to furnish the list of views.
1619 updateFlags = Update::Force;
1622 case LFUN_SET_COLOR: {
1624 string const x11_name = split(argument, lyx_name, ' ');
1625 if (lyx_name.empty() || x11_name.empty()) {
1626 setErrorMessage(from_ascii(N_(
1627 "Syntax: set-color <lyx_name>"
1632 bool const graphicsbg_changed =
1633 (lyx_name == lcolor.getLyXName(Color::graphicsbg) &&
1634 x11_name != lcolor.getX11Name(Color::graphicsbg));
1636 if (!lcolor.setColor(lyx_name, x11_name)) {
1638 bformat(_("Set-color \"%1$s\" failed "
1639 "- color is undefined or "
1640 "may not be redefined"),
1641 from_utf8(lyx_name)));
1645 theApp()->updateColor(lcolor.getFromLyXName(lyx_name));
1647 if (graphicsbg_changed) {
1648 // FIXME: The graphics cache no longer has a changeDisplay method.
1650 graphics::GCache::get().changeDisplay(true);
1657 BOOST_ASSERT(lyx_view_);
1658 lyx_view_->message(from_utf8(argument));
1661 case LFUN_EXTERNAL_EDIT: {
1662 BOOST_ASSERT(lyx_view_);
1663 FuncRequest fr(action, argument);
1664 InsetExternal().dispatch(view()->cursor(), fr);
1668 case LFUN_GRAPHICS_EDIT: {
1669 FuncRequest fr(action, argument);
1670 InsetGraphics().dispatch(view()->cursor(), fr);
1674 case LFUN_INSET_APPLY: {
1675 BOOST_ASSERT(lyx_view_);
1676 string const name = cmd.getArg(0);
1677 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1679 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1680 inset->dispatch(view()->cursor(), fr);
1682 FuncRequest fr(LFUN_INSET_INSERT, argument);
1685 // ideally, the update flag should be set by the insets,
1686 // but this is not possible currently
1687 updateFlags = Update::Force | Update::FitCursor;
1691 case LFUN_ALL_INSETS_TOGGLE: {
1692 BOOST_ASSERT(lyx_view_);
1694 string const name = split(argument, action, ' ');
1695 Inset::Code const inset_code =
1696 Inset::translate(name);
1698 Cursor & cur = view()->cursor();
1699 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1701 Inset & inset = lyx_view_->buffer()->inset();
1702 InsetIterator it = inset_iterator_begin(inset);
1703 InsetIterator const end = inset_iterator_end(inset);
1704 for (; it != end; ++it) {
1705 if (!it->asInsetMath()
1706 && (inset_code == Inset::NO_CODE
1707 || inset_code == it->lyxCode())) {
1708 Cursor tmpcur = cur;
1709 tmpcur.pushLeft(*it);
1710 it->dispatch(tmpcur, fr);
1713 updateFlags = Update::Force | Update::FitCursor;
1717 case LFUN_BUFFER_LANGUAGE: {
1718 BOOST_ASSERT(lyx_view_);
1719 Buffer & buffer = *lyx_view_->buffer();
1720 Language const * oldL = buffer.params().language;
1721 Language const * newL = languages.getLanguage(argument);
1722 if (!newL || oldL == newL)
1725 if (oldL->rightToLeft() == newL->rightToLeft()
1726 && !buffer.isMultiLingual())
1727 buffer.changeLanguage(oldL, newL);
1731 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1732 string const fname =
1733 addName(addPath(package().user_support().absFilename(), "templates/"),
1735 Buffer defaults(fname);
1737 istringstream ss(argument);
1740 int const unknown_tokens = defaults.readHeader(lex);
1742 if (unknown_tokens != 0) {
1743 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1744 << unknown_tokens << " unknown token"
1745 << (unknown_tokens == 1 ? "" : "s")
1749 if (defaults.writeFile(FileName(defaults.fileName())))
1750 setMessage(bformat(_("Document defaults saved in %1$s"),
1751 makeDisplayPath(fname)));
1753 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1757 case LFUN_BUFFER_PARAMS_APPLY: {
1758 BOOST_ASSERT(lyx_view_);
1759 biblio::CiteEngine const oldEngine =
1760 lyx_view_->buffer()->params().getEngine();
1762 Buffer * buffer = lyx_view_->buffer();
1764 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1765 recordUndoFullDocument(view());
1767 istringstream ss(argument);
1770 int const unknown_tokens = buffer->readHeader(lex);
1772 if (unknown_tokens != 0) {
1773 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1774 << unknown_tokens << " unknown token"
1775 << (unknown_tokens == 1 ? "" : "s")
1779 updateLayout(oldClass, buffer);
1781 biblio::CiteEngine const newEngine =
1782 lyx_view_->buffer()->params().getEngine();
1784 if (oldEngine != newEngine) {
1785 Cursor & cur = view()->cursor();
1786 FuncRequest fr(LFUN_INSET_REFRESH);
1788 Inset & inset = lyx_view_->buffer()->inset();
1789 InsetIterator it = inset_iterator_begin(inset);
1790 InsetIterator const end = inset_iterator_end(inset);
1791 for (; it != end; ++it)
1792 if (it->lyxCode() == Inset::CITE_CODE)
1793 it->dispatch(cur, fr);
1796 updateFlags = Update::Force | Update::FitCursor;
1800 case LFUN_LAYOUT_MODULES_CLEAR: {
1801 BOOST_ASSERT(lyx_view_);
1802 Buffer * buffer = lyx_view_->buffer();
1803 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1804 recordUndoFullDocument(view());
1805 buffer->params().clearLayoutModules();
1806 updateLayout(oldClass, buffer);
1807 updateFlags = Update::Force | Update::FitCursor;
1811 case LFUN_LAYOUT_MODULE_ADD: {
1812 BOOST_ASSERT(lyx_view_);
1813 Buffer * buffer = lyx_view_->buffer();
1814 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1815 recordUndoFullDocument(view());
1816 buffer->params().addLayoutModule(argument);
1817 updateLayout(oldClass, buffer);
1818 updateFlags = Update::Force | Update::FitCursor;
1822 case LFUN_TEXTCLASS_APPLY: {
1823 BOOST_ASSERT(lyx_view_);
1824 Buffer * buffer = lyx_view_->buffer();
1826 loadTextClass(argument);
1828 std::pair<bool, textclass_type> const tc_pair =
1829 textclasslist.numberOfClass(argument);
1834 textclass_type const old_class = buffer->params().getBaseClass();
1835 textclass_type const new_class = tc_pair.second;
1837 if (old_class == new_class)
1841 //Save the old, possibly modular, layout for use in conversion.
1842 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1843 recordUndoFullDocument(view());
1844 buffer->params().setBaseClass(new_class);
1845 updateLayout(oldClass, buffer);
1846 updateFlags = Update::Force | Update::FitCursor;
1850 case LFUN_LAYOUT_RELOAD: {
1851 BOOST_ASSERT(lyx_view_);
1852 Buffer * buffer = lyx_view_->buffer();
1853 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1854 textclass_type const tc = buffer->params().getBaseClass();
1855 textclasslist.reset(tc);
1856 buffer->params().setBaseClass(tc);
1857 updateLayout(oldClass, buffer);
1858 updateFlags = Update::Force | Update::FitCursor;
1862 case LFUN_TEXTCLASS_LOAD:
1863 loadTextClass(argument);
1866 case LFUN_LYXRC_APPLY: {
1867 LyXRC const lyxrc_orig = lyxrc;
1869 istringstream ss(argument);
1870 bool const success = lyxrc.read(ss) == 0;
1873 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1874 << "Unable to read lyxrc data"
1879 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1881 /// We force the redraw in any case because there might be
1882 /// some screen font changes.
1883 /// FIXME: only the current view will be updated. the Gui
1884 /// class is able to furnish the list of views.
1885 updateFlags = Update::Force;
1889 case LFUN_WINDOW_NEW:
1890 LyX::ref().newLyXView();
1893 case LFUN_WINDOW_CLOSE:
1894 BOOST_ASSERT(lyx_view_);
1895 BOOST_ASSERT(theApp());
1896 // update bookmark pit of the current buffer before window close
1897 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1898 gotoBookmark(i+1, false, false);
1899 // ask the user for saving changes or cancel quit
1900 if (!theBufferList().quitWriteAll())
1905 case LFUN_BOOKMARK_GOTO:
1906 // go to bookmark, open unopened file and switch to buffer if necessary
1907 gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
1910 case LFUN_BOOKMARK_CLEAR:
1911 LyX::ref().session().bookmarks().clear();
1914 case LFUN_TOOLBAR_TOGGLE: {
1915 BOOST_ASSERT(lyx_view_);
1916 string const name = cmd.getArg(0);
1917 bool const allowauto = cmd.getArg(1) == "allowauto";
1918 lyx_view_->toggleToolbarState(name, allowauto);
1919 ToolbarInfo * tbi = lyx_view_->getToolbarInfo(name);
1921 setMessage(bformat(_("Unknown toolbar \"%1$s\""),
1926 if (tbi->flags & ToolbarInfo::ON)
1928 else if (tbi->flags & ToolbarInfo::OFF)
1930 else if (tbi->flags & ToolbarInfo::AUTO)
1933 setMessage(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1934 _(tbi->gui_name), state));
1939 BOOST_ASSERT(lyx_view_);
1940 view()->cursor().dispatch(cmd);
1941 updateFlags = view()->cursor().result().update();
1942 if (!view()->cursor().result().dispatched())
1943 updateFlags = view()->dispatch(cmd);
1948 if (lyx_view_ && lyx_view_->buffer()) {
1949 // BufferView::update() updates the ViewMetricsInfo and
1950 // also initializes the position cache for all insets in
1951 // (at least partially) visible top-level paragraphs.
1952 // We will redraw the screen only if needed.
1953 if (view()->update(updateFlags)) {
1954 // Buffer::changed() signals that a repaint is needed.
1955 // The frontend (WorkArea) knows which area to repaint
1956 // thanks to the ViewMetricsInfo updated above.
1957 lyx_view_->buffer()->changed();
1960 lyx_view_->updateStatusBar();
1962 // if we executed a mutating lfun, mark the buffer as dirty
1964 && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
1965 && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
1966 lyx_view_->buffer()->markDirty();
1968 //Do we have a selection?
1969 theSelection().haveSelection(view()->cursor().selection());
1971 if (view()->cursor().inTexted()) {
1972 lyx_view_->updateLayoutChoice();
1976 if (!quitting && lyx_view_) {
1977 lyx_view_->updateToolbars();
1978 // Some messages may already be translated, so we cannot use _()
1979 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
1984 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
1986 const bool verbose = (cmd.origin == FuncRequest::MENU
1987 || cmd.origin == FuncRequest::TOOLBAR
1988 || cmd.origin == FuncRequest::COMMANDBUFFER);
1990 if (cmd.action == LFUN_SELF_INSERT || !verbose) {
1991 LYXERR(Debug::ACTION) << "dispatch msg is " << to_utf8(msg) << endl;
1993 lyx_view_->message(msg);
1997 docstring dispatch_msg = msg;
1998 if (!dispatch_msg.empty())
1999 dispatch_msg += ' ';
2001 docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
2003 bool argsadded = false;
2005 if (!cmd.argument().empty()) {
2006 if (cmd.action != LFUN_UNKNOWN_ACTION) {
2007 comname += ' ' + cmd.argument();
2012 docstring const shortcuts = theTopLevelKeymap().printbindings(cmd);
2014 if (!shortcuts.empty())
2015 comname += ": " + shortcuts;
2016 else if (!argsadded && !cmd.argument().empty())
2017 comname += ' ' + cmd.argument();
2019 if (!comname.empty()) {
2020 comname = rtrim(comname);
2021 dispatch_msg += '(' + rtrim(comname) + ')';
2024 LYXERR(Debug::ACTION) << "verbose dispatch msg "
2025 << to_utf8(dispatch_msg) << endl;
2026 if (!dispatch_msg.empty())
2027 lyx_view_->message(dispatch_msg);
2031 void LyXFunc::menuNew(string const & name, bool fromTemplate)
2033 // FIXME: initpath is not used. What to do?
2034 string initpath = lyxrc.document_path;
2035 string filename(name);
2037 if (lyx_view_->buffer()) {
2038 string const trypath = lyx_view_->buffer()->filePath();
2039 // If directory is writeable, use this as default.
2040 if (isDirWriteable(FileName(trypath)))
2044 static int newfile_number;
2046 if (filename.empty()) {
2047 filename = addName(lyxrc.document_path,
2048 "newfile" + convert<string>(++newfile_number) + ".lyx");
2049 while (theBufferList().exists(filename) ||
2050 fs::is_readable(FileName(filename).toFilesystemEncoding())) {
2052 filename = addName(lyxrc.document_path,
2053 "newfile" + convert<string>(newfile_number) +
2058 // The template stuff
2061 FileDialog fileDlg(_("Select template file"),
2062 LFUN_SELECT_FILE_SYNC,
2063 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2064 make_pair(_("Templates|#T#t"), from_utf8(lyxrc.template_path)));
2066 FileDialog::Result result =
2067 fileDlg.open(from_utf8(lyxrc.template_path),
2068 FileFilterList(_("LyX Documents (*.lyx)")),
2071 if (result.first == FileDialog::Later)
2073 if (result.second.empty())
2075 templname = to_utf8(result.second);
2078 Buffer * const b = newFile(filename, templname, !name.empty());
2080 lyx_view_->setBuffer(b);
2084 void LyXFunc::open(string const & fname)
2086 string initpath = lyxrc.document_path;
2088 if (lyx_view_->buffer()) {
2089 string const trypath = lyx_view_->buffer()->filePath();
2090 // If directory is writeable, use this as default.
2091 if (isDirWriteable(FileName(trypath)))
2097 if (fname.empty()) {
2098 FileDialog fileDlg(_("Select document to open"),
2100 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2101 make_pair(_("Examples|#E#e"), from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2103 FileDialog::Result result =
2104 fileDlg.open(from_utf8(initpath),
2105 FileFilterList(_("LyX Documents (*.lyx)")),
2108 if (result.first == FileDialog::Later)
2111 filename = to_utf8(result.second);
2113 // check selected filename
2114 if (filename.empty()) {
2115 lyx_view_->message(_("Canceled."));
2121 // get absolute path of file and add ".lyx" to the filename if
2123 FileName const fullname = fileSearch(string(), filename, "lyx");
2124 if (!fullname.empty())
2125 filename = fullname.absFilename();
2127 // if the file doesn't exist, let the user create one
2128 if (!fs::exists(fullname.toFilesystemEncoding())) {
2129 // the user specifically chose this name. Believe him.
2130 Buffer * const b = newFile(filename, string(), true);
2132 lyx_view_->setBuffer(b);
2136 docstring const disp_fn = makeDisplayPath(filename);
2137 lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
2140 Buffer * buf = lyx_view_->loadLyXFile(fullname);
2143 lyx_view_->setBuffer(buf);
2144 lyx_view_->showErrorList("Parse");
2145 str2 = bformat(_("Document %1$s opened."), disp_fn);
2147 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2149 lyx_view_->message(str2);
2153 void LyXFunc::doImport(string const & argument)
2156 string filename = split(argument, format, ' ');
2158 LYXERR(Debug::INFO) << "LyXFunc::doImport: " << format
2159 << " file: " << filename << endl;
2161 // need user interaction
2162 if (filename.empty()) {
2163 string initpath = lyxrc.document_path;
2165 if (lyx_view_->buffer()) {
2166 string const trypath = lyx_view_->buffer()->filePath();
2167 // If directory is writeable, use this as default.
2168 if (isDirWriteable(FileName(trypath)))
2172 docstring const text = bformat(_("Select %1$s file to import"),
2173 formats.prettyName(format));
2175 FileDialog fileDlg(text,
2177 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2178 make_pair(_("Examples|#E#e"),
2179 from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2181 docstring filter = formats.prettyName(format);
2184 filter += from_utf8(formats.extension(format));
2187 FileDialog::Result result =
2188 fileDlg.open(from_utf8(initpath),
2189 FileFilterList(filter),
2192 if (result.first == FileDialog::Later)
2195 filename = to_utf8(result.second);
2197 // check selected filename
2198 if (filename.empty())
2199 lyx_view_->message(_("Canceled."));
2202 if (filename.empty())
2205 // get absolute path of file
2206 FileName const fullname(makeAbsPath(filename));
2208 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
2210 // Check if the document already is open
2211 if (use_gui && theBufferList().exists(lyxfile.absFilename())) {
2212 if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) {
2213 lyx_view_->message(_("Canceled."));
2218 // if the file exists already, and we didn't do
2219 // -i lyx thefile.lyx, warn
2220 if (fs::exists(lyxfile.toFilesystemEncoding()) && fullname != lyxfile) {
2221 docstring const file = makeDisplayPath(lyxfile.absFilename(), 30);
2223 docstring text = bformat(_("The document %1$s already exists.\n\n"
2224 "Do you want to overwrite that document?"), file);
2225 int const ret = Alert::prompt(_("Overwrite document?"),
2226 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2229 lyx_view_->message(_("Canceled."));
2234 ErrorList errorList;
2235 Importer::Import(lyx_view_, fullname, format, errorList);
2236 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2240 void LyXFunc::closeBuffer()
2242 // goto bookmark to update bookmark pit.
2243 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2244 gotoBookmark(i+1, false, false);
2246 theBufferList().close(lyx_view_->buffer(), true);
2250 void LyXFunc::reloadBuffer()
2252 FileName filename(lyx_view_->buffer()->fileName());
2253 docstring const disp_fn = makeDisplayPath(filename.absFilename());
2256 Buffer * buf = lyx_view_->loadLyXFile(filename);
2259 lyx_view_->setBuffer(buf);
2260 lyx_view_->showErrorList("Parse");
2261 str = bformat(_("Document %1$s reloaded."), disp_fn);
2263 str = bformat(_("Could not reload document %1$s"), disp_fn);
2265 lyx_view_->message(str);
2268 // Each "lyx_view_" should have it's own message method. lyxview and
2269 // the minibuffer would use the minibuffer, but lyxserver would
2270 // send an ERROR signal to its client. Alejandro 970603
2271 // This function is bit problematic when it comes to NLS, to make the
2272 // lyx servers client be language indepenent we must not translate
2273 // strings sent to this func.
2274 void LyXFunc::setErrorMessage(docstring const & m) const
2276 dispatch_buffer = m;
2281 void LyXFunc::setMessage(docstring const & m) const
2283 dispatch_buffer = m;
2287 docstring const LyXFunc::viewStatusMessage()
2289 // When meta-fake key is pressed, show the key sequence so far + "M-".
2291 return keyseq.print(true) + "M-";
2293 // Else, when a non-complete key sequence is pressed,
2294 // show the available options.
2295 if (keyseq.length() > 0 && !keyseq.deleted())
2296 return keyseq.printOptions(true);
2298 BOOST_ASSERT(lyx_view_);
2299 if (!lyx_view_->buffer())
2300 return _("Welcome to LyX!");
2302 return view()->cursor().currentState();
2306 BufferView * LyXFunc::view() const
2308 BOOST_ASSERT(lyx_view_);
2309 return lyx_view_->view();
2313 bool LyXFunc::wasMetaKey() const
2315 return (meta_fake_bit != key_modifier::none);
2319 void LyXFunc::updateLayout(TextClassPtr const & oldlayout,
2322 lyx_view_->message(_("Converting document to new document class..."));
2324 StableDocIterator backcur(view()->cursor());
2325 ErrorList & el = buffer->errorList("Class Switch");
2326 cap::switchBetweenClasses(
2327 oldlayout, buffer->params().getTextClassPtr(),
2328 static_cast<InsetText &>(buffer->inset()), el);
2330 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
2332 buffer->errors("Class Switch");
2333 updateLabels(*buffer);
2339 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2341 // Why the switch you might ask. It is a trick to ensure that all
2342 // the elements in the LyXRCTags enum is handled. As you can see
2343 // there are no breaks at all. So it is just a huge fall-through.
2344 // The nice thing is that we will get a warning from the compiler
2345 // if we forget an element.
2346 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2348 case LyXRC::RC_ACCEPT_COMPOUND:
2349 case LyXRC::RC_ALT_LANG:
2350 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
2351 case LyXRC::RC_PLAINTEXT_LINELEN:
2352 case LyXRC::RC_AUTOREGIONDELETE:
2353 case LyXRC::RC_AUTORESET_OPTIONS:
2354 case LyXRC::RC_AUTOSAVE:
2355 case LyXRC::RC_AUTO_NUMBER:
2356 case LyXRC::RC_BACKUPDIR_PATH:
2357 case LyXRC::RC_BIBTEX_COMMAND:
2358 case LyXRC::RC_BINDFILE:
2359 case LyXRC::RC_CHECKLASTFILES:
2360 case LyXRC::RC_USELASTFILEPOS:
2361 case LyXRC::RC_LOADSESSION:
2362 case LyXRC::RC_CHKTEX_COMMAND:
2363 case LyXRC::RC_CONVERTER:
2364 case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
2365 case LyXRC::RC_COPIER:
2366 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2367 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2368 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2369 case LyXRC::RC_DATE_INSERT_FORMAT:
2370 case LyXRC::RC_DEFAULT_LANGUAGE:
2371 case LyXRC::RC_DEFAULT_PAPERSIZE:
2372 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2373 case LyXRC::RC_DISPLAY_GRAPHICS:
2374 case LyXRC::RC_DOCUMENTPATH:
2375 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2376 string const encoded = FileName(
2377 lyxrc_new.document_path).toFilesystemEncoding();
2378 if (fs::exists(encoded) && fs::is_directory(encoded))
2379 support::package().document_dir() = FileName(lyxrc.document_path);
2381 case LyXRC::RC_ESC_CHARS:
2382 case LyXRC::RC_FONT_ENCODING:
2383 case LyXRC::RC_FORMAT:
2384 case LyXRC::RC_INDEX_COMMAND:
2385 case LyXRC::RC_INPUT:
2386 case LyXRC::RC_KBMAP:
2387 case LyXRC::RC_KBMAP_PRIMARY:
2388 case LyXRC::RC_KBMAP_SECONDARY:
2389 case LyXRC::RC_LABEL_INIT_LENGTH:
2390 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2391 case LyXRC::RC_LANGUAGE_AUTO_END:
2392 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2393 case LyXRC::RC_LANGUAGE_COMMAND_END:
2394 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2395 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2396 case LyXRC::RC_LANGUAGE_PACKAGE:
2397 case LyXRC::RC_LANGUAGE_USE_BABEL:
2398 case LyXRC::RC_MAKE_BACKUP:
2399 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2400 case LyXRC::RC_NUMLASTFILES:
2401 case LyXRC::RC_PATH_PREFIX:
2402 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2403 support::prependEnvPath("PATH", lyxrc.path_prefix);
2405 case LyXRC::RC_PERS_DICT:
2406 case LyXRC::RC_PREVIEW:
2407 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2408 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2409 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2410 case LyXRC::RC_PRINTCOPIESFLAG:
2411 case LyXRC::RC_PRINTER:
2412 case LyXRC::RC_PRINTEVENPAGEFLAG:
2413 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2414 case LyXRC::RC_PRINTFILEEXTENSION:
2415 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2416 case LyXRC::RC_PRINTODDPAGEFLAG:
2417 case LyXRC::RC_PRINTPAGERANGEFLAG:
2418 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2419 case LyXRC::RC_PRINTPAPERFLAG:
2420 case LyXRC::RC_PRINTREVERSEFLAG:
2421 case LyXRC::RC_PRINTSPOOL_COMMAND:
2422 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2423 case LyXRC::RC_PRINTTOFILE:
2424 case LyXRC::RC_PRINTTOPRINTER:
2425 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2426 case LyXRC::RC_PRINT_COMMAND:
2427 case LyXRC::RC_RTL_SUPPORT:
2428 case LyXRC::RC_SCREEN_DPI:
2429 case LyXRC::RC_SCREEN_FONT_ROMAN:
2430 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2431 case LyXRC::RC_SCREEN_FONT_SANS:
2432 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2433 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2434 case LyXRC::RC_SCREEN_FONT_SIZES:
2435 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2436 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2437 case LyXRC::RC_SCREEN_GEOMETRY_HEIGHT:
2438 case LyXRC::RC_SCREEN_GEOMETRY_WIDTH:
2439 case LyXRC::RC_SCREEN_GEOMETRY_XYSAVED:
2440 case LyXRC::RC_SCREEN_ZOOM:
2441 case LyXRC::RC_SERVERPIPE:
2442 case LyXRC::RC_SET_COLOR:
2443 case LyXRC::RC_SHOW_BANNER:
2444 case LyXRC::RC_SPELL_COMMAND:
2445 case LyXRC::RC_TEMPDIRPATH:
2446 case LyXRC::RC_TEMPLATEPATH:
2447 case LyXRC::RC_TEX_ALLOWS_SPACES:
2448 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2449 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2450 support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2452 case LyXRC::RC_UIFILE:
2453 case LyXRC::RC_USER_EMAIL:
2454 case LyXRC::RC_USER_NAME:
2455 case LyXRC::RC_USETEMPDIR:
2456 case LyXRC::RC_USE_ALT_LANG:
2457 case LyXRC::RC_USE_CONVERTER_CACHE:
2458 case LyXRC::RC_USE_ESC_CHARS:
2459 case LyXRC::RC_USE_INP_ENC:
2460 case LyXRC::RC_USE_PERS_DICT:
2461 case LyXRC::RC_USE_SPELL_LIB:
2462 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2463 case LyXRC::RC_VIEWER:
2464 case LyXRC::RC_LAST: