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(NoModifier)
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, KeyModifier state)
294 LYXERR(Debug::KEY) << "KeySym is " << keysym.getSymbolName() << endl;
296 // Do nothing if we have nothing (JMarc)
297 if (!keysym.isOK()) {
298 LYXERR(Debug::KEY) << "Empty kbd action (probably composing)"
303 if (keysym.isModifier()) {
304 LYXERR(Debug::KEY) << "isModifier true" << endl;
308 //Encoding const * encoding = view()->cursor().getEncoding();
309 //encoded_last_key = keysym.getISOEncoded(encoding ? encoding->name() : "");
310 // FIXME: encoded_last_key shadows the member variable of the same
311 // name. Is that intended?
312 char_type encoded_last_key = keysym.getUCSEncoded();
314 // Do a one-deep top-level lookup for
315 // cancel and meta-fake keys. RVDK_PATCH_5
316 cancel_meta_seq.reset();
318 FuncRequest func = cancel_meta_seq.addkey(keysym, state);
319 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
320 << " action first set to [" << func.action << ']'
323 // When not cancel or meta-fake, do the normal lookup.
324 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
325 // Mostly, meta_fake_bit = NoModifier. RVDK_PATCH_5.
326 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_PREFIX)) {
327 // remove Caps Lock and Mod2 as a modifiers
328 func = keyseq.addkey(keysym, (state | meta_fake_bit));
329 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
330 << "action now set to ["
331 << func.action << ']' << endl;
334 // Dont remove this unless you know what you are doing.
335 meta_fake_bit = NoModifier;
337 // Can this happen now ?
338 if (func.action == LFUN_NOACTION)
339 func = FuncRequest(LFUN_COMMAND_PREFIX);
341 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
343 << func.action << "]["
344 << to_utf8(keyseq.print(false)) << ']'
347 // already here we know if it any point in going further
348 // why not return already here if action == -1 and
349 // num_bytes == 0? (Lgb)
351 if (keyseq.length() > 1)
352 lyx_view_->message(keyseq.print(true));
355 // Maybe user can only reach the key via holding down shift.
356 // Let's see. But only if shift is the only modifier
357 if (func.action == LFUN_UNKNOWN_ACTION && state == ShiftModifier) {
358 LYXERR(Debug::KEY) << "Trying without shift" << endl;
359 func = keyseq.addkey(keysym, NoModifier);
360 LYXERR(Debug::KEY) << "Action now " << func.action << endl;
363 if (func.action == LFUN_UNKNOWN_ACTION) {
364 // Hmm, we didn't match any of the keysequences. See
365 // if it's normal insertable text not already covered
367 if (keysym.isText() && keyseq.length() == 1) {
368 LYXERR(Debug::KEY) << "isText() is true, inserting." << endl;
369 func = FuncRequest(LFUN_SELF_INSERT,
370 FuncRequest::KEYBOARD);
372 LYXERR(Debug::KEY) << "Unknown, !isText() - giving up" << endl;
373 lyx_view_->message(_("Unknown function."));
378 if (func.action == LFUN_SELF_INSERT) {
379 if (encoded_last_key != 0) {
380 docstring const arg(1, encoded_last_key);
381 dispatch(FuncRequest(LFUN_SELF_INSERT, arg,
382 FuncRequest::KEYBOARD));
384 << "SelfInsert arg[`" << to_utf8(arg) << "']" << endl;
390 /* When we move around, or type, it's nice to be able to see
391 * the cursor immediately after the keypress.
393 if (lyx_view_ && lyx_view_->currentWorkArea())
394 lyx_view_->currentWorkArea()->startBlinkingCursor();
398 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
400 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
403 Cursor & cur = view()->cursor();
405 /* In LyX/Mac, when a dialog is open, the menus of the
406 application can still be accessed without giving focus to
407 the main window. In this case, we want to disable the menu
408 entries that are buffer-related.
410 Note that this code is not perfect, as bug 1941 attests:
411 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
413 Buffer * buf = lyx_view_? lyx_view_->buffer() : 0;
414 if (lyx_view_ && cmd.origin == FuncRequest::MENU && !lyx_view_->hasFocus())
417 if (cmd.action == LFUN_NOACTION) {
418 flag.message(from_utf8(N_("Nothing to do")));
423 switch (cmd.action) {
424 case LFUN_UNKNOWN_ACTION:
425 #ifndef HAVE_LIBAIKSAURUS
426 case LFUN_THESAURUS_ENTRY:
436 if (flag.unknown()) {
437 flag.message(from_utf8(N_("Unknown action")));
441 if (!flag.enabled()) {
442 if (flag.message().empty())
443 flag.message(from_utf8(N_("Command disabled")));
447 // Check whether we need a buffer
448 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
450 flag.message(from_utf8(N_("Command not allowed with"
451 "out any document open")));
456 // I would really like to avoid having this switch and rather try to
457 // encode this in the function itself.
458 // -- And I'd rather let an inset decide which LFUNs it is willing
459 // to handle (Andre')
461 switch (cmd.action) {
462 case LFUN_BUFFER_TOGGLE_READ_ONLY:
463 flag.setOnOff(buf->isReadonly());
466 case LFUN_BUFFER_SWITCH:
467 // toggle on the current buffer, but do not toggle off
468 // the other ones (is that a good idea?)
469 if (buf && to_utf8(cmd.argument()) == buf->fileName())
473 case LFUN_BUFFER_EXPORT:
474 enable = cmd.argument() == "custom"
475 || Exporter::isExportable(*buf, to_utf8(cmd.argument()));
478 case LFUN_BUFFER_CHKTEX:
479 enable = buf->isLatex() && !lyxrc.chktex_command.empty();
482 case LFUN_BUILD_PROGRAM:
483 enable = Exporter::isExportable(*buf, "program");
486 case LFUN_LAYOUT_TABULAR:
487 enable = cur.innerInsetOfType(Inset::TABULAR_CODE);
491 case LFUN_LAYOUT_PARAGRAPH:
492 enable = !cur.inset().forceDefaultParagraphs(cur.idx());
495 case LFUN_VC_REGISTER:
496 enable = !buf->lyxvc().inUse();
498 case LFUN_VC_CHECK_IN:
499 enable = buf->lyxvc().inUse() && !buf->isReadonly();
501 case LFUN_VC_CHECK_OUT:
502 enable = buf->lyxvc().inUse() && buf->isReadonly();
505 case LFUN_VC_UNDO_LAST:
506 enable = buf->lyxvc().inUse();
508 case LFUN_BUFFER_RELOAD:
509 enable = !buf->isUnnamed() && fs::exists(buf->fileName())
510 && (!buf->isClean() || buf->isExternallyModified(Buffer::timestamp_method));
513 case LFUN_INSET_SETTINGS: {
517 Inset::Code code = cur.inset().lyxCode();
519 case Inset::TABULAR_CODE:
520 enable = cmd.argument() == "tabular";
522 case Inset::ERT_CODE:
523 enable = cmd.argument() == "ert";
525 case Inset::FLOAT_CODE:
526 enable = cmd.argument() == "float";
528 case Inset::WRAP_CODE:
529 enable = cmd.argument() == "wrap";
531 case Inset::NOTE_CODE:
532 enable = cmd.argument() == "note";
534 case Inset::BRANCH_CODE:
535 enable = cmd.argument() == "branch";
537 case Inset::BOX_CODE:
538 enable = cmd.argument() == "box";
540 case Inset::LISTINGS_CODE:
541 enable = cmd.argument() == "listings";
549 case LFUN_INSET_APPLY: {
550 string const name = cmd.getArg(0);
551 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
553 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
555 if (!inset->getStatus(cur, fr, fs)) {
556 // Every inset is supposed to handle this
561 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
562 flag |= getStatus(fr);
564 enable = flag.enabled();
568 case LFUN_DIALOG_TOGGLE:
569 flag.setOnOff(lyx_view_->getDialogs().visible(cmd.getArg(0)));
570 // fall through to set "enable"
571 case LFUN_DIALOG_SHOW: {
572 string const name = cmd.getArg(0);
574 enable = name == "aboutlyx"
575 || name == "file" //FIXME: should be removed.
577 || name == "texinfo";
578 else if (name == "print")
579 enable = Exporter::isExportable(*buf, "dvi")
580 && lyxrc.print_command != "none";
581 else if (name == "character")
582 enable = cur.inset().lyxCode() != Inset::ERT_CODE &&
583 cur.inset().lyxCode() != Inset::LISTINGS_CODE;
584 else if (name == "latexlog")
585 enable = isFileReadable(FileName(buf->getLogName().second));
586 else if (name == "spellchecker")
587 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
588 enable = !buf->isReadonly();
592 else if (name == "vclog")
593 enable = buf->lyxvc().inUse();
597 case LFUN_DIALOG_SHOW_NEW_INSET:
598 enable = cur.inset().lyxCode() != Inset::ERT_CODE &&
599 cur.inset().lyxCode() != Inset::LISTINGS_CODE;
600 if (cur.inset().lyxCode() == Inset::CAPTION_CODE) {
602 if (cur.inset().getStatus(cur, cmd, flag))
607 case LFUN_DIALOG_UPDATE: {
608 string const name = cmd.getArg(0);
610 enable = name == "prefs";
614 case LFUN_CITATION_INSERT: {
615 FuncRequest fr(LFUN_INSET_INSERT, "citation");
616 enable = getStatus(fr).enabled();
620 case LFUN_BUFFER_WRITE: {
621 enable = lyx_view_->buffer()->isUnnamed()
622 || !lyx_view_->buffer()->isClean();
627 case LFUN_BUFFER_WRITE_ALL: {
628 // We enable the command only if there are some modified buffers
629 Buffer * first = theBufferList().first();
630 bool modified = false;
634 // We cannot use a for loop as the buffer list is a cycle.
640 b = theBufferList().next(b);
641 } while (b != first);
649 case LFUN_BOOKMARK_GOTO: {
650 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
651 enable = LyX::ref().session().bookmarks().isValid(num);
655 case LFUN_BOOKMARK_CLEAR:
656 enable = LyX::ref().session().bookmarks().size() > 0;
659 case LFUN_TOOLBAR_TOGGLE: {
660 bool const current = lyx_view_->isToolbarVisible(cmd.getArg(0));
661 flag.setOnOff(current);
664 case LFUN_WINDOW_CLOSE: {
665 enable = (theApp()->gui().viewIds().size() > 1);
669 // this one is difficult to get right. As a half-baked
670 // solution, we consider only the first action of the sequence
671 case LFUN_COMMAND_SEQUENCE: {
672 // argument contains ';'-terminated commands
673 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
674 FuncRequest func(lyxaction.lookupFunc(firstcmd));
675 func.origin = cmd.origin;
676 flag = getStatus(func);
679 case LFUN_BUFFER_NEW:
680 case LFUN_BUFFER_NEW_TEMPLATE:
681 case LFUN_WORD_FIND_FORWARD:
682 case LFUN_WORD_FIND_BACKWARD:
683 case LFUN_COMMAND_PREFIX:
684 case LFUN_COMMAND_EXECUTE:
686 case LFUN_META_PREFIX:
687 case LFUN_BUFFER_CLOSE:
688 case LFUN_BUFFER_WRITE_AS:
689 case LFUN_BUFFER_UPDATE:
690 case LFUN_BUFFER_VIEW:
691 case LFUN_MASTER_BUFFER_UPDATE:
692 case LFUN_MASTER_BUFFER_VIEW:
693 case LFUN_BUFFER_IMPORT:
694 case LFUN_BUFFER_AUTO_SAVE:
695 case LFUN_RECONFIGURE:
699 case LFUN_DROP_LAYOUTS_CHOICE:
701 case LFUN_SERVER_GET_NAME:
702 case LFUN_SERVER_NOTIFY:
703 case LFUN_SERVER_GOTO_FILE_ROW:
704 case LFUN_DIALOG_HIDE:
705 case LFUN_DIALOG_DISCONNECT_INSET:
706 case LFUN_BUFFER_CHILD_OPEN:
707 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
708 case LFUN_KEYMAP_OFF:
709 case LFUN_KEYMAP_PRIMARY:
710 case LFUN_KEYMAP_SECONDARY:
711 case LFUN_KEYMAP_TOGGLE:
713 case LFUN_BUFFER_EXPORT_CUSTOM:
714 case LFUN_BUFFER_PRINT:
715 case LFUN_PREFERENCES_SAVE:
716 case LFUN_SCREEN_FONT_UPDATE:
719 case LFUN_EXTERNAL_EDIT:
720 case LFUN_GRAPHICS_EDIT:
721 case LFUN_ALL_INSETS_TOGGLE:
722 case LFUN_BUFFER_LANGUAGE:
723 case LFUN_TEXTCLASS_APPLY:
724 case LFUN_TEXTCLASS_LOAD:
725 case LFUN_BUFFER_SAVE_AS_DEFAULT:
726 case LFUN_BUFFER_PARAMS_APPLY:
727 case LFUN_LAYOUT_MODULES_CLEAR:
728 case LFUN_LAYOUT_MODULE_ADD:
729 case LFUN_LAYOUT_RELOAD:
730 case LFUN_LYXRC_APPLY:
731 case LFUN_BUFFER_NEXT:
732 case LFUN_BUFFER_PREVIOUS:
733 case LFUN_WINDOW_NEW:
735 // these are handled in our dispatch()
739 if (!getLocalStatus(cur, cmd, flag))
740 flag = view()->getStatus(cmd);
746 // Can we use a readonly buffer?
747 if (buf && buf->isReadonly()
748 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
749 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
750 flag.message(from_utf8(N_("Document is read-only")));
754 // Are we in a DELETED change-tracking region?
755 if (buf && lookupChangeType(cur, true) == Change::DELETED
756 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
757 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
758 flag.message(from_utf8(N_("This portion of the document is deleted.")));
762 // the default error message if we disable the command
763 if (!flag.enabled() && flag.message().empty())
764 flag.message(from_utf8(N_("Command disabled")));
770 bool LyXFunc::ensureBufferClean(BufferView * bv)
772 Buffer & buf = bv->buffer();
776 docstring const file = makeDisplayPath(buf.fileName(), 30);
777 docstring text = bformat(_("The document %1$s has unsaved "
778 "changes.\n\nDo you want to save "
779 "the document?"), file);
780 int const ret = Alert::prompt(_("Save changed document?"),
781 text, 0, 1, _("&Save"),
785 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
787 return buf.isClean();
793 void showPrintError(string const & name)
795 docstring str = bformat(_("Could not print the document %1$s.\n"
796 "Check that your printer is set up correctly."),
797 makeDisplayPath(name, 50));
798 Alert::error(_("Print document failed"), str);
802 void loadTextClass(string const & name)
804 std::pair<bool, textclass_type> const tc_pair =
805 textclasslist.numberOfClass(name);
807 if (!tc_pair.first) {
808 lyxerr << "Document class \"" << name
809 << "\" does not exist."
814 textclass_type const tc = tc_pair.second;
816 if (!textclasslist[tc].load()) {
817 docstring s = bformat(_("The document class %1$s."
818 "could not be loaded."),
819 from_utf8(textclasslist[tc].name()));
820 Alert::error(_("Could not load class"), s);
825 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
830 void LyXFunc::dispatch(FuncRequest const & cmd)
832 string const argument = to_utf8(cmd.argument());
833 kb_action const action = cmd.action;
835 LYXERR(Debug::ACTION) << endl << "LyXFunc::dispatch: cmd: " << cmd << endl;
836 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
838 // we have not done anything wrong yet.
840 dispatch_buffer.erase();
842 // redraw the screen at the end (first of the two drawing steps).
843 //This is done unless explicitely requested otherwise
844 Update::flags updateFlags = Update::FitCursor;
846 FuncStatus const flag = getStatus(cmd);
847 if (!flag.enabled()) {
848 // We cannot use this function here
849 LYXERR(Debug::ACTION) << "LyXFunc::dispatch: "
850 << lyxaction.getActionName(action)
851 << " [" << action << "] is disabled at this location"
853 setErrorMessage(flag.message());
857 case LFUN_WORD_FIND_FORWARD:
858 case LFUN_WORD_FIND_BACKWARD: {
859 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
860 static docstring last_search;
861 docstring searched_string;
863 if (!cmd.argument().empty()) {
864 last_search = cmd.argument();
865 searched_string = cmd.argument();
867 searched_string = last_search;
870 if (searched_string.empty())
873 bool const fw = action == LFUN_WORD_FIND_FORWARD;
874 docstring const data =
875 find2string(searched_string, true, false, fw);
876 find(view(), FuncRequest(LFUN_WORD_FIND, data));
880 case LFUN_COMMAND_PREFIX:
881 BOOST_ASSERT(lyx_view_);
882 lyx_view_->message(keyseq.printOptions(true));
885 case LFUN_COMMAND_EXECUTE:
886 BOOST_ASSERT(lyx_view_);
887 lyx_view_->showMiniBuffer(true);
891 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
893 meta_fake_bit = NoModifier;
894 if (lyx_view_->buffer())
895 // cancel any selection
896 dispatch(FuncRequest(LFUN_MARK_OFF));
897 setMessage(from_ascii(N_("Cancel")));
900 case LFUN_META_PREFIX:
901 meta_fake_bit = AltModifier;
902 setMessage(keyseq.print(true));
905 case LFUN_BUFFER_TOGGLE_READ_ONLY: {
906 BOOST_ASSERT(lyx_view_ && lyx_view_->view() && lyx_view_->buffer());
907 Buffer * buf = lyx_view_->buffer();
908 if (buf->lyxvc().inUse())
909 buf->lyxvc().toggleReadOnly();
911 buf->setReadonly(!lyx_view_->buffer()->isReadonly());
915 // --- Menus -----------------------------------------------
916 case LFUN_BUFFER_NEW:
917 menuNew(argument, false);
918 updateFlags = Update::None;
921 case LFUN_BUFFER_NEW_TEMPLATE:
922 menuNew(argument, true);
923 updateFlags = Update::None;
926 case LFUN_BUFFER_CLOSE:
928 updateFlags = Update::None;
931 case LFUN_BUFFER_WRITE:
932 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
933 if (!lyx_view_->buffer()->isUnnamed()) {
934 docstring const str = bformat(_("Saving document %1$s..."),
935 makeDisplayPath(lyx_view_->buffer()->fileName()));
936 lyx_view_->message(str);
937 menuWrite(lyx_view_->buffer());
938 lyx_view_->message(str + _(" done."));
940 writeAs(lyx_view_->buffer());
942 updateFlags = Update::None;
945 case LFUN_BUFFER_WRITE_AS:
946 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
947 writeAs(lyx_view_->buffer(), argument);
948 updateFlags = Update::None;
951 case LFUN_BUFFER_WRITE_ALL: {
952 Buffer * first = theBufferList().first();
955 lyx_view_->message(_("Saving all documents..."));
957 // We cannot use a for loop as the buffer list cycles.
960 if (!b->isUnnamed()) {
962 lyxerr[Debug::ACTION] << "Saved " << b->fileName() << endl;
966 b = theBufferList().next(b);
967 } while (b != first);
968 lyx_view_->message(_("All documents saved."));
971 updateFlags = Update::None;
975 case LFUN_BUFFER_RELOAD: {
976 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
977 docstring const file = makeDisplayPath(lyx_view_->buffer()->fileName(), 20);
978 docstring text = bformat(_("Any changes will be lost. Are you sure "
979 "you want to revert to the saved version of the document %1$s?"), file);
980 int const ret = Alert::prompt(_("Revert to saved document?"),
981 text, 1, 1, _("&Revert"), _("&Cancel"));
988 case LFUN_BUFFER_UPDATE:
989 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
990 Exporter::Export(lyx_view_->buffer(), argument, true);
993 case LFUN_BUFFER_VIEW:
994 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
995 Exporter::preview(lyx_view_->buffer(), argument);
998 case LFUN_MASTER_BUFFER_UPDATE:
999 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->getMasterBuffer());
1000 Exporter::Export(lyx_view_->buffer()->getMasterBuffer(), argument, true);
1003 case LFUN_MASTER_BUFFER_VIEW:
1004 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->getMasterBuffer());
1005 Exporter::preview(lyx_view_->buffer()->getMasterBuffer(), argument);
1008 case LFUN_BUILD_PROGRAM:
1009 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1010 Exporter::Export(lyx_view_->buffer(), "program", true);
1013 case LFUN_BUFFER_CHKTEX:
1014 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1015 lyx_view_->buffer()->runChktex();
1018 case LFUN_BUFFER_EXPORT:
1019 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1020 if (argument == "custom")
1021 lyx_view_->getDialogs().show("sendto");
1023 Exporter::Export(lyx_view_->buffer(), argument, false);
1027 case LFUN_BUFFER_EXPORT_CUSTOM: {
1028 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1030 string command = split(argument, format_name, ' ');
1031 Format const * format = formats.getFormat(format_name);
1033 lyxerr << "Format \"" << format_name
1034 << "\" not recognized!"
1039 Buffer * buffer = lyx_view_->buffer();
1041 // The name of the file created by the conversion process
1044 // Output to filename
1045 if (format->name() == "lyx") {
1046 string const latexname =
1047 buffer->getLatexName(false);
1048 filename = changeExtension(latexname,
1049 format->extension());
1050 filename = addName(buffer->temppath(), filename);
1052 if (!buffer->writeFile(FileName(filename)))
1056 Exporter::Export(buffer, format_name, true, filename);
1059 // Substitute $$FName for filename
1060 if (!contains(command, "$$FName"))
1061 command = "( " + command + " ) < $$FName";
1062 command = subst(command, "$$FName", filename);
1064 // Execute the command in the background
1066 call.startscript(Systemcall::DontWait, command);
1070 case LFUN_BUFFER_PRINT: {
1071 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1072 // FIXME: cmd.getArg() might fail if one of the arguments
1073 // contains double quotes
1074 string target = cmd.getArg(0);
1075 string target_name = cmd.getArg(1);
1076 string command = cmd.getArg(2);
1079 || target_name.empty()
1080 || command.empty()) {
1081 lyxerr << "Unable to parse \""
1082 << argument << '"' << endl;
1085 if (target != "printer" && target != "file") {
1086 lyxerr << "Unrecognized target \""
1087 << target << '"' << endl;
1091 Buffer * buffer = lyx_view_->buffer();
1093 if (!Exporter::Export(buffer, "dvi", true)) {
1094 showPrintError(buffer->fileName());
1098 // Push directory path.
1099 string const path(buffer->temppath());
1100 // Prevent the compiler from optimizing away p
1102 support::Path p(pp);
1104 // there are three cases here:
1105 // 1. we print to a file
1106 // 2. we print directly to a printer
1107 // 3. we print using a spool command (print to file first)
1110 string const dviname =
1111 changeExtension(buffer->getLatexName(true),
1114 if (target == "printer") {
1115 if (!lyxrc.print_spool_command.empty()) {
1116 // case 3: print using a spool
1117 string const psname =
1118 changeExtension(dviname,".ps");
1119 command += ' ' + lyxrc.print_to_file
1122 + quoteName(dviname);
1125 lyxrc.print_spool_command + ' ';
1126 if (target_name != "default") {
1127 command2 += lyxrc.print_spool_printerprefix
1131 command2 += quoteName(psname);
1133 // If successful, then spool command
1134 res = one.startscript(
1139 res = one.startscript(
1140 Systemcall::DontWait,
1143 // case 2: print directly to a printer
1144 if (target_name != "default")
1145 command += ' ' + lyxrc.print_to_printer + target_name + ' ';
1146 res = one.startscript(
1147 Systemcall::DontWait,
1148 command + quoteName(dviname));
1152 // case 1: print to a file
1153 FileName const filename(makeAbsPath(target_name,
1154 lyx_view_->buffer()->filePath()));
1155 FileName const dvifile(makeAbsPath(dviname, path));
1156 if (fs::exists(filename.toFilesystemEncoding())) {
1157 docstring text = bformat(
1158 _("The file %1$s already exists.\n\n"
1159 "Do you want to overwrite that file?"),
1160 makeDisplayPath(filename.absFilename()));
1161 if (Alert::prompt(_("Overwrite file?"),
1162 text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
1165 command += ' ' + lyxrc.print_to_file
1166 + quoteName(filename.toFilesystemEncoding())
1168 + quoteName(dvifile.toFilesystemEncoding());
1169 res = one.startscript(Systemcall::DontWait,
1174 showPrintError(buffer->fileName());
1178 case LFUN_BUFFER_IMPORT:
1183 // quitting is triggered by the gui code
1184 // (leaving the event loop).
1185 lyx_view_->message(from_utf8(N_("Exiting.")));
1186 if (theBufferList().quitWriteAll())
1187 theApp()->gui().closeAllViews();
1190 case LFUN_BUFFER_AUTO_SAVE:
1194 case LFUN_RECONFIGURE:
1195 BOOST_ASSERT(lyx_view_);
1196 // argument is any additional parameter to the configure.py command
1197 reconfigure(*lyx_view_, argument);
1200 case LFUN_HELP_OPEN: {
1201 BOOST_ASSERT(lyx_view_);
1202 string const arg = argument;
1204 setErrorMessage(from_ascii(N_("Missing argument")));
1207 FileName const fname = i18nLibFileSearch("doc", arg, "lyx");
1208 if (fname.empty()) {
1209 lyxerr << "LyX: unable to find documentation file `"
1210 << arg << "'. Bad installation?" << endl;
1213 lyx_view_->message(bformat(_("Opening help file %1$s..."),
1214 makeDisplayPath(fname.absFilename())));
1215 Buffer * buf = lyx_view_->loadLyXFile(fname, false);
1218 lyx_view_->setBuffer(buf);
1219 lyx_view_->showErrorList("Parse");
1221 updateFlags = Update::None;
1225 // --- version control -------------------------------
1226 case LFUN_VC_REGISTER:
1227 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1228 if (!ensureBufferClean(view()))
1230 if (!lyx_view_->buffer()->lyxvc().inUse()) {
1231 lyx_view_->buffer()->lyxvc().registrer();
1234 updateFlags = Update::Force;
1237 case LFUN_VC_CHECK_IN:
1238 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1239 if (!ensureBufferClean(view()))
1241 if (lyx_view_->buffer()->lyxvc().inUse()
1242 && !lyx_view_->buffer()->isReadonly()) {
1243 lyx_view_->buffer()->lyxvc().checkIn();
1248 case LFUN_VC_CHECK_OUT:
1249 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1250 if (!ensureBufferClean(view()))
1252 if (lyx_view_->buffer()->lyxvc().inUse()
1253 && lyx_view_->buffer()->isReadonly()) {
1254 lyx_view_->buffer()->lyxvc().checkOut();
1259 case LFUN_VC_REVERT:
1260 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1261 lyx_view_->buffer()->lyxvc().revert();
1265 case LFUN_VC_UNDO_LAST:
1266 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1267 lyx_view_->buffer()->lyxvc().undoLast();
1271 // --- buffers ----------------------------------------
1272 case LFUN_BUFFER_SWITCH:
1273 BOOST_ASSERT(lyx_view_);
1274 lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1275 updateFlags = Update::None;
1278 case LFUN_BUFFER_NEXT:
1279 BOOST_ASSERT(lyx_view_);
1280 lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer()));
1281 updateFlags = Update::None;
1284 case LFUN_BUFFER_PREVIOUS:
1285 BOOST_ASSERT(lyx_view_);
1286 lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer()));
1287 updateFlags = Update::None;
1291 BOOST_ASSERT(lyx_view_);
1292 newFile(*lyx_view_, argument);
1293 updateFlags = Update::None;
1296 case LFUN_FILE_OPEN:
1297 BOOST_ASSERT(lyx_view_);
1299 updateFlags = Update::None;
1302 case LFUN_DROP_LAYOUTS_CHOICE:
1303 BOOST_ASSERT(lyx_view_);
1304 lyx_view_->openLayoutList();
1307 case LFUN_MENU_OPEN:
1308 BOOST_ASSERT(lyx_view_);
1309 lyx_view_->openMenu(from_utf8(argument));
1312 // --- lyxserver commands ----------------------------
1313 case LFUN_SERVER_GET_NAME:
1314 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1315 setMessage(from_utf8(lyx_view_->buffer()->fileName()));
1316 LYXERR(Debug::INFO) << "FNAME["
1317 << lyx_view_->buffer()->fileName()
1321 case LFUN_SERVER_NOTIFY:
1322 dispatch_buffer = keyseq.print(false);
1323 theServer().notifyClient(to_utf8(dispatch_buffer));
1326 case LFUN_SERVER_GOTO_FILE_ROW: {
1327 BOOST_ASSERT(lyx_view_);
1330 istringstream is(argument);
1331 is >> file_name >> row;
1333 bool loaded = false;
1334 if (prefixIs(file_name, package().temp_dir().absFilename()))
1335 // Needed by inverse dvi search. If it is a file
1336 // in tmpdir, call the apropriated function
1337 buf = theBufferList().getBufferFromTmp(file_name);
1339 // Must replace extension of the file to be .lyx
1340 // and get full path
1341 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1342 // Either change buffer or load the file
1343 if (theBufferList().exists(s.absFilename()))
1344 buf = theBufferList().getBuffer(s.absFilename());
1346 buf = lyx_view_->loadLyXFile(s);
1352 updateFlags = Update::None;
1357 lyx_view_->setBuffer(buf);
1358 view()->setCursorFromRow(row);
1360 lyx_view_->showErrorList("Parse");
1361 updateFlags = Update::FitCursor;
1365 case LFUN_DIALOG_SHOW: {
1366 BOOST_ASSERT(lyx_view_);
1367 string const name = cmd.getArg(0);
1368 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1370 if (name == "character") {
1371 data = freefont2string();
1373 lyx_view_->getDialogs().show("character", data);
1374 } else if (name == "latexlog") {
1375 pair<Buffer::LogType, string> const logfile =
1376 lyx_view_->buffer()->getLogName();
1377 switch (logfile.first) {
1378 case Buffer::latexlog:
1381 case Buffer::buildlog:
1385 data += Lexer::quoteString(logfile.second);
1386 lyx_view_->getDialogs().show("log", data);
1387 } else if (name == "vclog") {
1388 string const data = "vc " +
1389 Lexer::quoteString(lyx_view_->buffer()->lyxvc().getLogFile());
1390 lyx_view_->getDialogs().show("log", data);
1392 lyx_view_->getDialogs().show(name, data);
1396 case LFUN_DIALOG_SHOW_NEW_INSET: {
1397 BOOST_ASSERT(lyx_view_);
1398 string const name = cmd.getArg(0);
1399 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1400 if (name == "bibitem" ||
1404 name == "nomenclature" ||
1408 InsetCommandParams p(name);
1409 data = InsetCommandMailer::params2string(name, p);
1410 } else if (name == "include") {
1411 // data is the include type: one of "include",
1412 // "input", "verbatiminput" or "verbatiminput*"
1414 // default type is requested
1416 InsetCommandParams p(data);
1417 data = InsetIncludeMailer::params2string(p);
1418 } else if (name == "box") {
1419 // \c data == "Boxed" || "Frameless" etc
1420 InsetBoxParams p(data);
1421 data = InsetBoxMailer::params2string(p);
1422 } else if (name == "branch") {
1423 InsetBranchParams p;
1424 data = InsetBranchMailer::params2string(p);
1425 } else if (name == "citation") {
1426 InsetCommandParams p("citation");
1427 data = InsetCommandMailer::params2string(name, p);
1428 } else if (name == "ert") {
1429 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1430 } else if (name == "external") {
1431 InsetExternalParams p;
1432 Buffer const & buffer = *lyx_view_->buffer();
1433 data = InsetExternalMailer::params2string(p, buffer);
1434 } else if (name == "float") {
1436 data = InsetFloatMailer::params2string(p);
1437 } else if (name == "listings") {
1438 InsetListingsParams p;
1439 data = InsetListingsMailer::params2string(p);
1440 } else if (name == "graphics") {
1441 InsetGraphicsParams p;
1442 Buffer const & buffer = *lyx_view_->buffer();
1443 data = InsetGraphicsMailer::params2string(p, buffer);
1444 } else if (name == "note") {
1446 data = InsetNoteMailer::params2string(p);
1447 } else if (name == "vspace") {
1449 data = InsetVSpaceMailer::params2string(space);
1450 } else if (name == "wrap") {
1452 data = InsetWrapMailer::params2string(p);
1454 lyx_view_->getDialogs().show(name, data, 0);
1458 case LFUN_DIALOG_UPDATE: {
1459 BOOST_ASSERT(lyx_view_);
1460 string const & name = argument;
1461 // Can only update a dialog connected to an existing inset
1462 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1464 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1465 inset->dispatch(view()->cursor(), fr);
1466 } else if (name == "paragraph") {
1467 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1468 } else if (name == "prefs") {
1469 lyx_view_->getDialogs().update(name, string());
1474 case LFUN_DIALOG_HIDE:
1475 LyX::cref().hideDialogs(argument, 0);
1478 case LFUN_DIALOG_TOGGLE: {
1479 BOOST_ASSERT(lyx_view_);
1480 if (lyx_view_->getDialogs().visible(cmd.getArg(0)))
1481 dispatch(FuncRequest(LFUN_DIALOG_HIDE, argument));
1483 dispatch(FuncRequest(LFUN_DIALOG_SHOW, argument));
1487 case LFUN_DIALOG_DISCONNECT_INSET:
1488 BOOST_ASSERT(lyx_view_);
1489 lyx_view_->getDialogs().disconnect(argument);
1493 case LFUN_CITATION_INSERT: {
1494 BOOST_ASSERT(lyx_view_);
1495 if (!argument.empty()) {
1496 // we can have one optional argument, delimited by '|'
1497 // citation-insert <key>|<text_before>
1498 // this should be enhanced to also support text_after
1499 // and citation style
1500 string arg = argument;
1502 if (contains(argument, "|")) {
1503 arg = token(argument, '|', 0);
1504 opt1 = token(argument, '|', 1);
1506 InsetCommandParams icp("citation");
1507 icp["key"] = from_utf8(arg);
1509 icp["before"] = from_utf8(opt1);
1510 string icstr = InsetCommandMailer::params2string("citation", icp);
1511 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1514 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1518 case LFUN_BUFFER_CHILD_OPEN: {
1519 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1520 Buffer * parent = lyx_view_->buffer();
1521 FileName filename = makeAbsPath(argument, parent->filePath());
1522 view()->saveBookmark(false);
1524 bool parsed = false;
1525 if (theBufferList().exists(filename.absFilename())) {
1526 child = theBufferList().getBuffer(filename.absFilename());
1528 setMessage(bformat(_("Opening child document %1$s..."),
1529 makeDisplayPath(filename.absFilename())));
1530 child = lyx_view_->loadLyXFile(filename, true);
1534 // Set the parent name of the child document.
1535 // This makes insertion of citations and references in the child work,
1536 // when the target is in the parent or another child document.
1537 child->setParentName(parent->fileName());
1538 updateLabels(*child->getMasterBuffer());
1539 lyx_view_->setBuffer(child);
1541 lyx_view_->showErrorList("Parse");
1544 // If a screen update is required (in case where auto_open is false),
1545 // setBuffer() would have taken care of it already. Otherwise we shall
1546 // reset the update flag because it can cause a circular problem.
1548 updateFlags = Update::None;
1552 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1553 BOOST_ASSERT(lyx_view_);
1554 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1557 case LFUN_KEYMAP_OFF:
1558 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1559 lyx_view_->view()->getIntl().keyMapOn(false);
1562 case LFUN_KEYMAP_PRIMARY:
1563 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1564 lyx_view_->view()->getIntl().keyMapPrim();
1567 case LFUN_KEYMAP_SECONDARY:
1568 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1569 lyx_view_->view()->getIntl().keyMapSec();
1572 case LFUN_KEYMAP_TOGGLE:
1573 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1574 lyx_view_->view()->getIntl().toggleKeyMap();
1580 string rest = split(argument, countstr, ' ');
1581 istringstream is(countstr);
1584 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1585 for (int i = 0; i < count; ++i)
1586 dispatch(lyxaction.lookupFunc(rest));
1590 case LFUN_COMMAND_SEQUENCE: {
1591 // argument contains ';'-terminated commands
1592 string arg = argument;
1593 while (!arg.empty()) {
1595 arg = split(arg, first, ';');
1596 FuncRequest func(lyxaction.lookupFunc(first));
1597 func.origin = cmd.origin;
1603 case LFUN_PREFERENCES_SAVE: {
1604 lyxrc.write(makeAbsPath("preferences",
1605 package().user_support().absFilename()),
1610 case LFUN_SCREEN_FONT_UPDATE:
1611 BOOST_ASSERT(lyx_view_);
1612 // handle the screen font changes.
1613 theFontLoader().update();
1614 /// FIXME: only the current view will be updated. the Gui
1615 /// class is able to furnish the list of views.
1616 updateFlags = Update::Force;
1619 case LFUN_SET_COLOR: {
1621 string const x11_name = split(argument, lyx_name, ' ');
1622 if (lyx_name.empty() || x11_name.empty()) {
1623 setErrorMessage(from_ascii(N_(
1624 "Syntax: set-color <lyx_name>"
1629 bool const graphicsbg_changed =
1630 (lyx_name == lcolor.getLyXName(Color::graphicsbg) &&
1631 x11_name != lcolor.getX11Name(Color::graphicsbg));
1633 if (!lcolor.setColor(lyx_name, x11_name)) {
1635 bformat(_("Set-color \"%1$s\" failed "
1636 "- color is undefined or "
1637 "may not be redefined"),
1638 from_utf8(lyx_name)));
1642 theApp()->updateColor(lcolor.getFromLyXName(lyx_name));
1644 if (graphicsbg_changed) {
1645 // FIXME: The graphics cache no longer has a changeDisplay method.
1647 graphics::GCache::get().changeDisplay(true);
1654 BOOST_ASSERT(lyx_view_);
1655 lyx_view_->message(from_utf8(argument));
1658 case LFUN_EXTERNAL_EDIT: {
1659 BOOST_ASSERT(lyx_view_);
1660 FuncRequest fr(action, argument);
1661 InsetExternal().dispatch(view()->cursor(), fr);
1665 case LFUN_GRAPHICS_EDIT: {
1666 FuncRequest fr(action, argument);
1667 InsetGraphics().dispatch(view()->cursor(), fr);
1671 case LFUN_INSET_APPLY: {
1672 BOOST_ASSERT(lyx_view_);
1673 string const name = cmd.getArg(0);
1674 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1676 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1677 inset->dispatch(view()->cursor(), fr);
1679 FuncRequest fr(LFUN_INSET_INSERT, argument);
1682 // ideally, the update flag should be set by the insets,
1683 // but this is not possible currently
1684 updateFlags = Update::Force | Update::FitCursor;
1688 case LFUN_ALL_INSETS_TOGGLE: {
1689 BOOST_ASSERT(lyx_view_);
1691 string const name = split(argument, action, ' ');
1692 Inset::Code const inset_code =
1693 Inset::translate(name);
1695 Cursor & cur = view()->cursor();
1696 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1698 Inset & inset = lyx_view_->buffer()->inset();
1699 InsetIterator it = inset_iterator_begin(inset);
1700 InsetIterator const end = inset_iterator_end(inset);
1701 for (; it != end; ++it) {
1702 if (!it->asInsetMath()
1703 && (inset_code == Inset::NO_CODE
1704 || inset_code == it->lyxCode())) {
1705 Cursor tmpcur = cur;
1706 tmpcur.pushLeft(*it);
1707 it->dispatch(tmpcur, fr);
1710 updateFlags = Update::Force | Update::FitCursor;
1714 case LFUN_BUFFER_LANGUAGE: {
1715 BOOST_ASSERT(lyx_view_);
1716 Buffer & buffer = *lyx_view_->buffer();
1717 Language const * oldL = buffer.params().language;
1718 Language const * newL = languages.getLanguage(argument);
1719 if (!newL || oldL == newL)
1722 if (oldL->rightToLeft() == newL->rightToLeft()
1723 && !buffer.isMultiLingual())
1724 buffer.changeLanguage(oldL, newL);
1728 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1729 string const fname =
1730 addName(addPath(package().user_support().absFilename(), "templates/"),
1732 Buffer defaults(fname);
1734 istringstream ss(argument);
1737 int const unknown_tokens = defaults.readHeader(lex);
1739 if (unknown_tokens != 0) {
1740 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1741 << unknown_tokens << " unknown token"
1742 << (unknown_tokens == 1 ? "" : "s")
1746 if (defaults.writeFile(FileName(defaults.fileName())))
1747 setMessage(bformat(_("Document defaults saved in %1$s"),
1748 makeDisplayPath(fname)));
1750 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1754 case LFUN_BUFFER_PARAMS_APPLY: {
1755 BOOST_ASSERT(lyx_view_);
1756 biblio::CiteEngine const oldEngine =
1757 lyx_view_->buffer()->params().getEngine();
1759 Buffer * buffer = lyx_view_->buffer();
1761 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1762 recordUndoFullDocument(view());
1764 istringstream ss(argument);
1767 int const unknown_tokens = buffer->readHeader(lex);
1769 if (unknown_tokens != 0) {
1770 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1771 << unknown_tokens << " unknown token"
1772 << (unknown_tokens == 1 ? "" : "s")
1776 updateLayout(oldClass, buffer);
1778 biblio::CiteEngine const newEngine =
1779 lyx_view_->buffer()->params().getEngine();
1781 if (oldEngine != newEngine) {
1782 Cursor & cur = view()->cursor();
1783 FuncRequest fr(LFUN_INSET_REFRESH);
1785 Inset & inset = lyx_view_->buffer()->inset();
1786 InsetIterator it = inset_iterator_begin(inset);
1787 InsetIterator const end = inset_iterator_end(inset);
1788 for (; it != end; ++it)
1789 if (it->lyxCode() == Inset::CITE_CODE)
1790 it->dispatch(cur, fr);
1793 updateFlags = Update::Force | Update::FitCursor;
1797 case LFUN_LAYOUT_MODULES_CLEAR: {
1798 BOOST_ASSERT(lyx_view_);
1799 Buffer * buffer = lyx_view_->buffer();
1800 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1801 recordUndoFullDocument(view());
1802 buffer->params().clearLayoutModules();
1803 updateLayout(oldClass, buffer);
1804 updateFlags = Update::Force | Update::FitCursor;
1808 case LFUN_LAYOUT_MODULE_ADD: {
1809 BOOST_ASSERT(lyx_view_);
1810 Buffer * buffer = lyx_view_->buffer();
1811 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1812 recordUndoFullDocument(view());
1813 buffer->params().addLayoutModule(argument);
1814 updateLayout(oldClass, buffer);
1815 updateFlags = Update::Force | Update::FitCursor;
1819 case LFUN_TEXTCLASS_APPLY: {
1820 BOOST_ASSERT(lyx_view_);
1821 Buffer * buffer = lyx_view_->buffer();
1823 loadTextClass(argument);
1825 std::pair<bool, textclass_type> const tc_pair =
1826 textclasslist.numberOfClass(argument);
1831 textclass_type const old_class = buffer->params().getBaseClass();
1832 textclass_type const new_class = tc_pair.second;
1834 if (old_class == new_class)
1838 //Save the old, possibly modular, layout for use in conversion.
1839 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1840 recordUndoFullDocument(view());
1841 buffer->params().setBaseClass(new_class);
1842 updateLayout(oldClass, buffer);
1843 updateFlags = Update::Force | Update::FitCursor;
1847 case LFUN_LAYOUT_RELOAD: {
1848 BOOST_ASSERT(lyx_view_);
1849 Buffer * buffer = lyx_view_->buffer();
1850 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1851 textclass_type const tc = buffer->params().getBaseClass();
1852 textclasslist.reset(tc);
1853 buffer->params().setBaseClass(tc);
1854 updateLayout(oldClass, buffer);
1855 updateFlags = Update::Force | Update::FitCursor;
1859 case LFUN_TEXTCLASS_LOAD:
1860 loadTextClass(argument);
1863 case LFUN_LYXRC_APPLY: {
1864 LyXRC const lyxrc_orig = lyxrc;
1866 istringstream ss(argument);
1867 bool const success = lyxrc.read(ss) == 0;
1870 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1871 << "Unable to read lyxrc data"
1876 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1878 /// We force the redraw in any case because there might be
1879 /// some screen font changes.
1880 /// FIXME: only the current view will be updated. the Gui
1881 /// class is able to furnish the list of views.
1882 updateFlags = Update::Force;
1886 case LFUN_WINDOW_NEW:
1887 LyX::ref().newLyXView();
1890 case LFUN_WINDOW_CLOSE:
1891 BOOST_ASSERT(lyx_view_);
1892 BOOST_ASSERT(theApp());
1893 // update bookmark pit of the current buffer before window close
1894 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1895 gotoBookmark(i+1, false, false);
1896 // ask the user for saving changes or cancel quit
1897 if (!theBufferList().quitWriteAll())
1902 case LFUN_BOOKMARK_GOTO:
1903 // go to bookmark, open unopened file and switch to buffer if necessary
1904 gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
1907 case LFUN_BOOKMARK_CLEAR:
1908 LyX::ref().session().bookmarks().clear();
1911 case LFUN_TOOLBAR_TOGGLE: {
1912 BOOST_ASSERT(lyx_view_);
1913 string const name = cmd.getArg(0);
1914 bool const allowauto = cmd.getArg(1) == "allowauto";
1915 lyx_view_->toggleToolbarState(name, allowauto);
1916 ToolbarInfo * tbi = lyx_view_->getToolbarInfo(name);
1918 setMessage(bformat(_("Unknown toolbar \"%1$s\""),
1923 if (tbi->flags & ToolbarInfo::ON)
1925 else if (tbi->flags & ToolbarInfo::OFF)
1927 else if (tbi->flags & ToolbarInfo::AUTO)
1930 setMessage(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1931 _(tbi->gui_name), state));
1936 BOOST_ASSERT(lyx_view_);
1937 view()->cursor().dispatch(cmd);
1938 updateFlags = view()->cursor().result().update();
1939 if (!view()->cursor().result().dispatched())
1940 updateFlags = view()->dispatch(cmd);
1945 if (lyx_view_ && lyx_view_->buffer()) {
1946 // BufferView::update() updates the ViewMetricsInfo and
1947 // also initializes the position cache for all insets in
1948 // (at least partially) visible top-level paragraphs.
1949 // We will redraw the screen only if needed.
1950 if (view()->update(updateFlags)) {
1951 // Buffer::changed() signals that a repaint is needed.
1952 // The frontend (WorkArea) knows which area to repaint
1953 // thanks to the ViewMetricsInfo updated above.
1954 lyx_view_->buffer()->changed();
1957 lyx_view_->updateStatusBar();
1959 // if we executed a mutating lfun, mark the buffer as dirty
1961 && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
1962 && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
1963 lyx_view_->buffer()->markDirty();
1965 //Do we have a selection?
1966 theSelection().haveSelection(view()->cursor().selection());
1968 if (view()->cursor().inTexted()) {
1969 lyx_view_->updateLayoutChoice();
1973 if (!quitting && lyx_view_) {
1974 lyx_view_->updateToolbars();
1975 // Some messages may already be translated, so we cannot use _()
1976 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
1981 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
1983 const bool verbose = (cmd.origin == FuncRequest::MENU
1984 || cmd.origin == FuncRequest::TOOLBAR
1985 || cmd.origin == FuncRequest::COMMANDBUFFER);
1987 if (cmd.action == LFUN_SELF_INSERT || !verbose) {
1988 LYXERR(Debug::ACTION) << "dispatch msg is " << to_utf8(msg) << endl;
1990 lyx_view_->message(msg);
1994 docstring dispatch_msg = msg;
1995 if (!dispatch_msg.empty())
1996 dispatch_msg += ' ';
1998 docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
2000 bool argsadded = false;
2002 if (!cmd.argument().empty()) {
2003 if (cmd.action != LFUN_UNKNOWN_ACTION) {
2004 comname += ' ' + cmd.argument();
2009 docstring const shortcuts = theTopLevelKeymap().printbindings(cmd);
2011 if (!shortcuts.empty())
2012 comname += ": " + shortcuts;
2013 else if (!argsadded && !cmd.argument().empty())
2014 comname += ' ' + cmd.argument();
2016 if (!comname.empty()) {
2017 comname = rtrim(comname);
2018 dispatch_msg += '(' + rtrim(comname) + ')';
2021 LYXERR(Debug::ACTION) << "verbose dispatch msg "
2022 << to_utf8(dispatch_msg) << endl;
2023 if (!dispatch_msg.empty())
2024 lyx_view_->message(dispatch_msg);
2028 void LyXFunc::menuNew(string const & name, bool fromTemplate)
2030 // FIXME: initpath is not used. What to do?
2031 string initpath = lyxrc.document_path;
2032 string filename(name);
2034 if (lyx_view_->buffer()) {
2035 string const trypath = lyx_view_->buffer()->filePath();
2036 // If directory is writeable, use this as default.
2037 if (isDirWriteable(FileName(trypath)))
2041 static int newfile_number;
2043 if (filename.empty()) {
2044 filename = addName(lyxrc.document_path,
2045 "newfile" + convert<string>(++newfile_number) + ".lyx");
2046 while (theBufferList().exists(filename) ||
2047 fs::is_readable(FileName(filename).toFilesystemEncoding())) {
2049 filename = addName(lyxrc.document_path,
2050 "newfile" + convert<string>(newfile_number) +
2055 // The template stuff
2058 FileDialog fileDlg(_("Select template file"),
2059 LFUN_SELECT_FILE_SYNC,
2060 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2061 make_pair(_("Templates|#T#t"), from_utf8(lyxrc.template_path)));
2063 FileDialog::Result result =
2064 fileDlg.open(from_utf8(lyxrc.template_path),
2065 FileFilterList(_("LyX Documents (*.lyx)")),
2068 if (result.first == FileDialog::Later)
2070 if (result.second.empty())
2072 templname = to_utf8(result.second);
2075 Buffer * const b = newFile(filename, templname, !name.empty());
2077 lyx_view_->setBuffer(b);
2081 void LyXFunc::open(string const & fname)
2083 string initpath = lyxrc.document_path;
2085 if (lyx_view_->buffer()) {
2086 string const trypath = lyx_view_->buffer()->filePath();
2087 // If directory is writeable, use this as default.
2088 if (isDirWriteable(FileName(trypath)))
2094 if (fname.empty()) {
2095 FileDialog fileDlg(_("Select document to open"),
2097 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2098 make_pair(_("Examples|#E#e"), from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2100 FileDialog::Result result =
2101 fileDlg.open(from_utf8(initpath),
2102 FileFilterList(_("LyX Documents (*.lyx)")),
2105 if (result.first == FileDialog::Later)
2108 filename = to_utf8(result.second);
2110 // check selected filename
2111 if (filename.empty()) {
2112 lyx_view_->message(_("Canceled."));
2118 // get absolute path of file and add ".lyx" to the filename if
2120 FileName const fullname = fileSearch(string(), filename, "lyx");
2121 if (!fullname.empty())
2122 filename = fullname.absFilename();
2124 // if the file doesn't exist, let the user create one
2125 if (!fs::exists(fullname.toFilesystemEncoding())) {
2126 // the user specifically chose this name. Believe him.
2127 Buffer * const b = newFile(filename, string(), true);
2129 lyx_view_->setBuffer(b);
2133 docstring const disp_fn = makeDisplayPath(filename);
2134 lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
2137 Buffer * buf = lyx_view_->loadLyXFile(fullname);
2140 lyx_view_->setBuffer(buf);
2141 lyx_view_->showErrorList("Parse");
2142 str2 = bformat(_("Document %1$s opened."), disp_fn);
2144 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2146 lyx_view_->message(str2);
2150 void LyXFunc::doImport(string const & argument)
2153 string filename = split(argument, format, ' ');
2155 LYXERR(Debug::INFO) << "LyXFunc::doImport: " << format
2156 << " file: " << filename << endl;
2158 // need user interaction
2159 if (filename.empty()) {
2160 string initpath = lyxrc.document_path;
2162 if (lyx_view_->buffer()) {
2163 string const trypath = lyx_view_->buffer()->filePath();
2164 // If directory is writeable, use this as default.
2165 if (isDirWriteable(FileName(trypath)))
2169 docstring const text = bformat(_("Select %1$s file to import"),
2170 formats.prettyName(format));
2172 FileDialog fileDlg(text,
2174 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2175 make_pair(_("Examples|#E#e"),
2176 from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2178 docstring filter = formats.prettyName(format);
2181 filter += from_utf8(formats.extension(format));
2184 FileDialog::Result result =
2185 fileDlg.open(from_utf8(initpath),
2186 FileFilterList(filter),
2189 if (result.first == FileDialog::Later)
2192 filename = to_utf8(result.second);
2194 // check selected filename
2195 if (filename.empty())
2196 lyx_view_->message(_("Canceled."));
2199 if (filename.empty())
2202 // get absolute path of file
2203 FileName const fullname(makeAbsPath(filename));
2205 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
2207 // Check if the document already is open
2208 if (use_gui && theBufferList().exists(lyxfile.absFilename())) {
2209 if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) {
2210 lyx_view_->message(_("Canceled."));
2215 // if the file exists already, and we didn't do
2216 // -i lyx thefile.lyx, warn
2217 if (fs::exists(lyxfile.toFilesystemEncoding()) && fullname != lyxfile) {
2218 docstring const file = makeDisplayPath(lyxfile.absFilename(), 30);
2220 docstring text = bformat(_("The document %1$s already exists.\n\n"
2221 "Do you want to overwrite that document?"), file);
2222 int const ret = Alert::prompt(_("Overwrite document?"),
2223 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2226 lyx_view_->message(_("Canceled."));
2231 ErrorList errorList;
2232 Importer::Import(lyx_view_, fullname, format, errorList);
2233 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2237 void LyXFunc::closeBuffer()
2239 // goto bookmark to update bookmark pit.
2240 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2241 gotoBookmark(i+1, false, false);
2243 theBufferList().close(lyx_view_->buffer(), true);
2247 void LyXFunc::reloadBuffer()
2249 FileName filename(lyx_view_->buffer()->fileName());
2250 docstring const disp_fn = makeDisplayPath(filename.absFilename());
2253 Buffer * buf = lyx_view_->loadLyXFile(filename);
2256 lyx_view_->setBuffer(buf);
2257 lyx_view_->showErrorList("Parse");
2258 str = bformat(_("Document %1$s reloaded."), disp_fn);
2260 str = bformat(_("Could not reload document %1$s"), disp_fn);
2262 lyx_view_->message(str);
2265 // Each "lyx_view_" should have it's own message method. lyxview and
2266 // the minibuffer would use the minibuffer, but lyxserver would
2267 // send an ERROR signal to its client. Alejandro 970603
2268 // This function is bit problematic when it comes to NLS, to make the
2269 // lyx servers client be language indepenent we must not translate
2270 // strings sent to this func.
2271 void LyXFunc::setErrorMessage(docstring const & m) const
2273 dispatch_buffer = m;
2278 void LyXFunc::setMessage(docstring const & m) const
2280 dispatch_buffer = m;
2284 docstring const LyXFunc::viewStatusMessage()
2286 // When meta-fake key is pressed, show the key sequence so far + "M-".
2288 return keyseq.print(true) + "M-";
2290 // Else, when a non-complete key sequence is pressed,
2291 // show the available options.
2292 if (keyseq.length() > 0 && !keyseq.deleted())
2293 return keyseq.printOptions(true);
2295 BOOST_ASSERT(lyx_view_);
2296 if (!lyx_view_->buffer())
2297 return _("Welcome to LyX!");
2299 return view()->cursor().currentState();
2303 BufferView * LyXFunc::view() const
2305 BOOST_ASSERT(lyx_view_);
2306 return lyx_view_->view();
2310 bool LyXFunc::wasMetaKey() const
2312 return (meta_fake_bit != NoModifier);
2316 void LyXFunc::updateLayout(TextClassPtr const & oldlayout,
2319 lyx_view_->message(_("Converting document to new document class..."));
2321 StableDocIterator backcur(view()->cursor());
2322 ErrorList & el = buffer->errorList("Class Switch");
2323 cap::switchBetweenClasses(
2324 oldlayout, buffer->params().getTextClassPtr(),
2325 static_cast<InsetText &>(buffer->inset()), el);
2327 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
2329 buffer->errors("Class Switch");
2330 updateLabels(*buffer);
2336 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2338 // Why the switch you might ask. It is a trick to ensure that all
2339 // the elements in the LyXRCTags enum is handled. As you can see
2340 // there are no breaks at all. So it is just a huge fall-through.
2341 // The nice thing is that we will get a warning from the compiler
2342 // if we forget an element.
2343 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2345 case LyXRC::RC_ACCEPT_COMPOUND:
2346 case LyXRC::RC_ALT_LANG:
2347 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
2348 case LyXRC::RC_PLAINTEXT_LINELEN:
2349 case LyXRC::RC_AUTOREGIONDELETE:
2350 case LyXRC::RC_AUTORESET_OPTIONS:
2351 case LyXRC::RC_AUTOSAVE:
2352 case LyXRC::RC_AUTO_NUMBER:
2353 case LyXRC::RC_BACKUPDIR_PATH:
2354 case LyXRC::RC_BIBTEX_COMMAND:
2355 case LyXRC::RC_BINDFILE:
2356 case LyXRC::RC_CHECKLASTFILES:
2357 case LyXRC::RC_USELASTFILEPOS:
2358 case LyXRC::RC_LOADSESSION:
2359 case LyXRC::RC_CHKTEX_COMMAND:
2360 case LyXRC::RC_CONVERTER:
2361 case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
2362 case LyXRC::RC_COPIER:
2363 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2364 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2365 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2366 case LyXRC::RC_DATE_INSERT_FORMAT:
2367 case LyXRC::RC_DEFAULT_LANGUAGE:
2368 case LyXRC::RC_DEFAULT_PAPERSIZE:
2369 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2370 case LyXRC::RC_DISPLAY_GRAPHICS:
2371 case LyXRC::RC_DOCUMENTPATH:
2372 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2373 string const encoded = FileName(
2374 lyxrc_new.document_path).toFilesystemEncoding();
2375 if (fs::exists(encoded) && fs::is_directory(encoded))
2376 support::package().document_dir() = FileName(lyxrc.document_path);
2378 case LyXRC::RC_ESC_CHARS:
2379 case LyXRC::RC_FONT_ENCODING:
2380 case LyXRC::RC_FORMAT:
2381 case LyXRC::RC_INDEX_COMMAND:
2382 case LyXRC::RC_INPUT:
2383 case LyXRC::RC_KBMAP:
2384 case LyXRC::RC_KBMAP_PRIMARY:
2385 case LyXRC::RC_KBMAP_SECONDARY:
2386 case LyXRC::RC_LABEL_INIT_LENGTH:
2387 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2388 case LyXRC::RC_LANGUAGE_AUTO_END:
2389 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2390 case LyXRC::RC_LANGUAGE_COMMAND_END:
2391 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2392 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2393 case LyXRC::RC_LANGUAGE_PACKAGE:
2394 case LyXRC::RC_LANGUAGE_USE_BABEL:
2395 case LyXRC::RC_MAKE_BACKUP:
2396 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2397 case LyXRC::RC_NUMLASTFILES:
2398 case LyXRC::RC_PATH_PREFIX:
2399 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2400 support::prependEnvPath("PATH", lyxrc.path_prefix);
2402 case LyXRC::RC_PERS_DICT:
2403 case LyXRC::RC_PREVIEW:
2404 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2405 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2406 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2407 case LyXRC::RC_PRINTCOPIESFLAG:
2408 case LyXRC::RC_PRINTER:
2409 case LyXRC::RC_PRINTEVENPAGEFLAG:
2410 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2411 case LyXRC::RC_PRINTFILEEXTENSION:
2412 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2413 case LyXRC::RC_PRINTODDPAGEFLAG:
2414 case LyXRC::RC_PRINTPAGERANGEFLAG:
2415 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2416 case LyXRC::RC_PRINTPAPERFLAG:
2417 case LyXRC::RC_PRINTREVERSEFLAG:
2418 case LyXRC::RC_PRINTSPOOL_COMMAND:
2419 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2420 case LyXRC::RC_PRINTTOFILE:
2421 case LyXRC::RC_PRINTTOPRINTER:
2422 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2423 case LyXRC::RC_PRINT_COMMAND:
2424 case LyXRC::RC_RTL_SUPPORT:
2425 case LyXRC::RC_SCREEN_DPI:
2426 case LyXRC::RC_SCREEN_FONT_ROMAN:
2427 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2428 case LyXRC::RC_SCREEN_FONT_SANS:
2429 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2430 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2431 case LyXRC::RC_SCREEN_FONT_SIZES:
2432 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2433 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2434 case LyXRC::RC_SCREEN_GEOMETRY_HEIGHT:
2435 case LyXRC::RC_SCREEN_GEOMETRY_WIDTH:
2436 case LyXRC::RC_SCREEN_GEOMETRY_XYSAVED:
2437 case LyXRC::RC_SCREEN_ZOOM:
2438 case LyXRC::RC_SERVERPIPE:
2439 case LyXRC::RC_SET_COLOR:
2440 case LyXRC::RC_SHOW_BANNER:
2441 case LyXRC::RC_SPELL_COMMAND:
2442 case LyXRC::RC_TEMPDIRPATH:
2443 case LyXRC::RC_TEMPLATEPATH:
2444 case LyXRC::RC_TEX_ALLOWS_SPACES:
2445 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2446 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2447 support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2449 case LyXRC::RC_UIFILE:
2450 case LyXRC::RC_USER_EMAIL:
2451 case LyXRC::RC_USER_NAME:
2452 case LyXRC::RC_USETEMPDIR:
2453 case LyXRC::RC_USE_ALT_LANG:
2454 case LyXRC::RC_USE_CONVERTER_CACHE:
2455 case LyXRC::RC_USE_ESC_CHARS:
2456 case LyXRC::RC_USE_INP_ENC:
2457 case LyXRC::RC_USE_PERS_DICT:
2458 case LyXRC::RC_USE_SPELL_LIB:
2459 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2460 case LyXRC::RC_VIEWER:
2461 case LyXRC::RC_LAST: