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"
27 #include "buffer_funcs.h"
28 #include "BufferList.h"
29 #include "BufferParams.h"
30 #include "BufferView.h"
31 #include "bufferview_funcs.h"
33 #include "CutAndPaste.h"
35 #include "DispatchResult.h"
37 #include "ErrorList.h"
40 #include "FuncRequest.h"
41 #include "FuncStatus.h"
44 #include "InsetIterator.h"
52 #include "LyXAction.h"
58 #include "TextClassList.h"
60 #include "Paragraph.h"
61 #include "ParIterator.h"
62 #include "ParagraphParameters.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/Menubar.h"
88 #include "frontends/Toolbars.h"
89 #include "frontends/Selection.h"
91 #include "support/environment.h"
92 #include "support/FileFilterList.h"
93 #include "support/filetools.h"
94 #include "support/ForkedcallsController.h"
95 #include "support/fs_extras.h"
96 #include "support/lstrings.h"
97 #include "support/Path.h"
98 #include "support/Package.h"
99 #include "support/Systemcall.h"
100 #include "support/convert.h"
101 #include "support/os.h"
103 #include <boost/current_function.hpp>
104 #include <boost/filesystem/operations.hpp>
111 using bv_funcs::freefont2string;
113 using support::absolutePath;
114 using support::addName;
115 using support::addPath;
116 using support::bformat;
117 using support::changeExtension;
118 using support::contains;
119 using support::FileFilterList;
120 using support::FileName;
121 using support::fileSearch;
122 using support::ForkedcallsController;
123 using support::i18nLibFileSearch;
124 using support::isDirWriteable;
125 using support::isFileReadable;
126 using support::isStrInt;
127 using support::makeAbsPath;
128 using support::makeDisplayPath;
129 using support::package;
130 using support::quoteName;
131 using support::rtrim;
132 using support::split;
133 using support::subst;
134 using support::Systemcall;
135 using support::token;
137 using support::prefixIs;
140 using std::make_pair;
143 using std::istringstream;
144 using std::ostringstream;
146 namespace Alert = frontend::Alert;
147 namespace fs = boost::filesystem;
152 bool getLocalStatus(Cursor cursor,
153 FuncRequest const & cmd, FuncStatus & status)
155 // Try to fix cursor in case it is broken.
156 cursor.fixIfBroken();
158 // This is, of course, a mess. Better create a new doc iterator and use
159 // this in Inset::getStatus. This might require an additional
160 // BufferView * arg, though (which should be avoided)
161 //Cursor safe = *this;
163 for ( ; cursor.depth(); cursor.pop()) {
164 //lyxerr << "\nCursor::getStatus: cmd: " << cmd << endl << *this << endl;
165 BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
166 BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
167 BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
169 // The inset's getStatus() will return 'true' if it made
170 // a definitive decision on whether it want to handle the
171 // request or not. The result of this decision is put into
172 // the 'status' parameter.
173 if (cursor.inset().getStatus(cursor, cmd, status)) {
182 /** Return the change status at cursor position, taking in account the
183 * status at each level of the document iterator (a table in a deleted
184 * footnote is deleted).
185 * When \param outer is true, the top slice is not looked at.
187 Change::Type lookupChangeType(DocIterator const & dit, bool outer = false)
189 size_t const depth = dit.depth() - (outer ? 1 : 0);
191 for (size_t i = 0 ; i < depth ; ++i) {
192 CursorSlice const & slice = dit[i];
193 if (!slice.inset().inMathed()
194 && slice.pos() < slice.paragraph().size()) {
195 Change::Type const ch = slice.paragraph().lookupChange(slice.pos()).type;
196 if (ch != Change::UNCHANGED)
200 return Change::UNCHANGED;
208 meta_fake_bit(key_modifier::none)
213 void LyXFunc::initKeySequences(KeyMap * kb)
215 keyseq.reset(new KeySequence(kb, kb));
216 cancel_meta_seq.reset(new KeySequence(kb, kb));
220 void LyXFunc::setLyXView(LyXView * lv)
222 if (!quitting && lyx_view_ && lyx_view_ != lv)
223 // save current selection to the selection buffer to allow
224 // middle-button paste in another window
225 cap::saveSelection(lyx_view_->view()->cursor());
230 void LyXFunc::handleKeyFunc(kb_action action)
232 char_type c = encoded_last_key;
234 if (keyseq->length())
237 lyx_view_->view()->getIntl().getTransManager().deadkey(
238 c, get_accent(action).accent, view()->cursor().innerText(), view()->cursor());
239 // Need to clear, in case the minibuffer calls these
242 // copied verbatim from do_accent_char
243 view()->cursor().resetAnchor();
248 void LyXFunc::gotoBookmark(unsigned int idx, bool openFile, bool switchToBuffer)
250 BOOST_ASSERT(lyx_view_);
251 if (!LyX::ref().session().bookmarks().isValid(idx))
253 BookmarksSection::Bookmark const & bm = LyX::ref().session().bookmarks().bookmark(idx);
254 BOOST_ASSERT(!bm.filename.empty());
255 string const file = bm.filename.absFilename();
256 // if the file is not opened, open it.
257 if (!theBufferList().exists(file)) {
259 dispatch(FuncRequest(LFUN_FILE_OPEN, file));
263 // open may fail, so we need to test it again
264 if (theBufferList().exists(file)) {
265 // if the current buffer is not that one, switch to it.
266 if (lyx_view_->buffer()->fileName() != file) {
268 dispatch(FuncRequest(LFUN_BUFFER_SWITCH, file));
272 // moveToPosition use par_id, and par_pit and return new par_id.
276 boost::tie(new_pit, new_pos, new_id) = view()->moveToPosition(bm.bottom_pit, bm.bottom_pos, bm.top_id, bm.top_pos);
277 // if bottom_pit, bottom_pos or top_id has been changed, update bookmark
278 // see http://bugzilla.lyx.org/show_bug.cgi?id=3092
279 if (bm.bottom_pit != new_pit || bm.bottom_pos != new_pos || bm.top_id != new_id )
280 const_cast<BookmarksSection::Bookmark &>(bm).updatePos(new_pit, new_pos, new_id);
285 void LyXFunc::processKeySym(KeySymbolPtr keysym, key_modifier::state state)
287 LYXERR(Debug::KEY) << "KeySym is " << keysym->getSymbolName() << endl;
289 // Do nothing if we have nothing (JMarc)
290 if (!keysym->isOK()) {
291 LYXERR(Debug::KEY) << "Empty kbd action (probably composing)"
296 if (keysym->isModifier()) {
297 LYXERR(Debug::KEY) << "isModifier true" << endl;
301 //Encoding const * encoding = view()->cursor().getEncoding();
302 //encoded_last_key = keysym->getISOEncoded(encoding ? encoding->name() : "");
303 // FIXME: encoded_last_key shadows the member variable of the same
304 // name. Is that intended?
305 char_type encoded_last_key = keysym->getUCSEncoded();
307 // Do a one-deep top-level lookup for
308 // cancel and meta-fake keys. RVDK_PATCH_5
309 cancel_meta_seq->reset();
311 FuncRequest func = cancel_meta_seq->addkey(keysym, state);
312 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
313 << " action first set to [" << func.action << ']'
316 // When not cancel or meta-fake, do the normal lookup.
317 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
318 // Mostly, meta_fake_bit = key_modifier::none. RVDK_PATCH_5.
319 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_PREFIX)) {
320 // remove Caps Lock and Mod2 as a modifiers
321 func = keyseq->addkey(keysym, (state | meta_fake_bit));
322 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
323 << "action now set to ["
324 << func.action << ']' << endl;
327 // Dont remove this unless you know what you are doing.
328 meta_fake_bit = key_modifier::none;
330 // Can this happen now ?
331 if (func.action == LFUN_NOACTION) {
332 func = FuncRequest(LFUN_COMMAND_PREFIX);
335 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
337 << func.action << "]["
338 << to_utf8(keyseq->print(false)) << ']'
341 // already here we know if it any point in going further
342 // why not return already here if action == -1 and
343 // num_bytes == 0? (Lgb)
345 if (keyseq->length() > 1) {
346 lyx_view_->message(keyseq->print(true));
350 // Maybe user can only reach the key via holding down shift.
351 // Let's see. But only if shift is the only modifier
352 if (func.action == LFUN_UNKNOWN_ACTION &&
353 state == key_modifier::shift) {
354 LYXERR(Debug::KEY) << "Trying without shift" << endl;
355 func = keyseq->addkey(keysym, key_modifier::none);
356 LYXERR(Debug::KEY) << "Action now " << func.action << endl;
359 if (func.action == LFUN_UNKNOWN_ACTION) {
360 // Hmm, we didn't match any of the keysequences. See
361 // if it's normal insertable text not already covered
363 if (keysym->isText() && keyseq->length() == 1) {
364 LYXERR(Debug::KEY) << "isText() is true, inserting." << endl;
365 func = FuncRequest(LFUN_SELF_INSERT,
366 FuncRequest::KEYBOARD);
368 LYXERR(Debug::KEY) << "Unknown, !isText() - giving up" << endl;
369 lyx_view_->message(_("Unknown function."));
374 if (func.action == LFUN_SELF_INSERT) {
375 if (encoded_last_key != 0) {
376 docstring const arg(1, encoded_last_key);
377 dispatch(FuncRequest(LFUN_SELF_INSERT, arg,
378 FuncRequest::KEYBOARD));
380 << "SelfInsert arg[`" << to_utf8(arg) << "']" << endl;
388 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
390 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
393 Cursor & cur = view()->cursor();
395 /* In LyX/Mac, when a dialog is open, the menus of the
396 application can still be accessed without giving focus to
397 the main window. In this case, we want to disable the menu
398 entries that are buffer-related.
400 Note that this code is not perfect, as bug 1941 attests:
401 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
403 Buffer * buf = lyx_view_? lyx_view_->buffer() : 0;
404 if (lyx_view_ && cmd.origin == FuncRequest::MENU && !lyx_view_->hasFocus())
407 if (cmd.action == LFUN_NOACTION) {
408 flag.message(from_utf8(N_("Nothing to do")));
413 switch (cmd.action) {
414 case LFUN_UNKNOWN_ACTION:
415 #ifndef HAVE_LIBAIKSAURUS
416 case LFUN_THESAURUS_ENTRY:
426 if (flag.unknown()) {
427 flag.message(from_utf8(N_("Unknown action")));
431 if (!flag.enabled()) {
432 if (flag.message().empty())
433 flag.message(from_utf8(N_("Command disabled")));
437 // Check whether we need a buffer
438 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
440 flag.message(from_utf8(N_("Command not allowed with"
441 "out any document open")));
446 // I would really like to avoid having this switch and rather try to
447 // encode this in the function itself.
448 // -- And I'd rather let an inset decide which LFUNs it is willing
449 // to handle (Andre')
451 switch (cmd.action) {
452 case LFUN_BUFFER_TOGGLE_READ_ONLY:
453 flag.setOnOff(buf->isReadonly());
456 case LFUN_BUFFER_SWITCH:
457 // toggle on the current buffer, but do not toggle off
458 // the other ones (is that a good idea?)
459 if (to_utf8(cmd.argument()) == buf->fileName())
463 case LFUN_BUFFER_EXPORT:
464 enable = cmd.argument() == "custom"
465 || Exporter::isExportable(*buf, to_utf8(cmd.argument()));
468 case LFUN_BUFFER_CHKTEX:
469 enable = buf->isLatex() && !lyxrc.chktex_command.empty();
472 case LFUN_BUILD_PROGRAM:
473 enable = Exporter::isExportable(*buf, "program");
476 case LFUN_LAYOUT_TABULAR:
477 enable = cur.innerInsetOfType(Inset::TABULAR_CODE);
481 case LFUN_LAYOUT_PARAGRAPH:
482 enable = !cur.inset().forceDefaultParagraphs(cur.idx());
485 case LFUN_VC_REGISTER:
486 enable = !buf->lyxvc().inUse();
488 case LFUN_VC_CHECK_IN:
489 enable = buf->lyxvc().inUse() && !buf->isReadonly();
491 case LFUN_VC_CHECK_OUT:
492 enable = buf->lyxvc().inUse() && buf->isReadonly();
495 case LFUN_VC_UNDO_LAST:
496 enable = buf->lyxvc().inUse();
498 case LFUN_BUFFER_RELOAD:
499 enable = !buf->isUnnamed() && !buf->isClean();
502 case LFUN_INSET_SETTINGS: {
506 Inset::Code code = cur.inset().lyxCode();
508 case Inset::TABULAR_CODE:
509 enable = cmd.argument() == "tabular";
511 case Inset::ERT_CODE:
512 enable = cmd.argument() == "ert";
514 case Inset::FLOAT_CODE:
515 enable = cmd.argument() == "float";
517 case Inset::WRAP_CODE:
518 enable = cmd.argument() == "wrap";
520 case Inset::NOTE_CODE:
521 enable = cmd.argument() == "note";
523 case Inset::BRANCH_CODE:
524 enable = cmd.argument() == "branch";
526 case Inset::BOX_CODE:
527 enable = cmd.argument() == "box";
529 case Inset::LISTINGS_CODE:
530 enable = cmd.argument() == "listings";
538 case LFUN_INSET_APPLY: {
539 string const name = cmd.getArg(0);
540 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
542 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
544 if (!inset->getStatus(cur, fr, fs)) {
545 // Every inset is supposed to handle this
550 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
551 flag |= getStatus(fr);
553 enable = flag.enabled();
557 case LFUN_DIALOG_TOGGLE:
558 flag.setOnOff(lyx_view_->getDialogs().visible(cmd.getArg(0)));
559 // fall through to set "enable"
560 case LFUN_DIALOG_SHOW: {
561 string const name = cmd.getArg(0);
563 enable = name == "aboutlyx"
564 || name == "file" //FIXME: should be removed.
566 || name == "texinfo";
567 else if (name == "print")
568 enable = Exporter::isExportable(*buf, "dvi")
569 && lyxrc.print_command != "none";
570 else if (name == "character")
571 enable = cur.inset().lyxCode() != Inset::ERT_CODE &&
572 cur.inset().lyxCode() != Inset::LISTINGS_CODE;
573 else if (name == "latexlog")
574 enable = isFileReadable(FileName(buf->getLogName().second));
575 else if (name == "spellchecker")
576 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
577 enable = !buf->isReadonly();
581 else if (name == "vclog")
582 enable = buf->lyxvc().inUse();
586 case LFUN_DIALOG_SHOW_NEW_INSET:
587 enable = cur.inset().lyxCode() != Inset::ERT_CODE &&
588 cur.inset().lyxCode() != Inset::LISTINGS_CODE;
589 if (cur.inset().lyxCode() == Inset::CAPTION_CODE) {
591 if (cur.inset().getStatus(cur, cmd, flag))
596 case LFUN_DIALOG_UPDATE: {
597 string const name = cmd.getArg(0);
599 enable = name == "prefs";
603 case LFUN_CITATION_INSERT: {
604 FuncRequest fr(LFUN_INSET_INSERT, "citation");
605 enable = getStatus(fr).enabled();
609 case LFUN_BUFFER_WRITE: {
610 enable = view()->buffer()->isUnnamed()
611 || !view()->buffer()->isClean();
616 case LFUN_BUFFER_WRITE_ALL: {
617 // We enable the command only if there are some modified buffers
618 Buffer * first = theBufferList().first();
619 bool modified = false;
623 // We cannot use a for loop as the buffer list is a cycle.
629 b = theBufferList().next(b);
630 } while (b != first);
638 case LFUN_BOOKMARK_GOTO: {
639 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
640 enable = LyX::ref().session().bookmarks().isValid(num);
644 case LFUN_BOOKMARK_CLEAR:
645 enable = LyX::ref().session().bookmarks().size() > 0;
648 case LFUN_TOOLBAR_TOGGLE: {
649 bool const current = lyx_view_->getToolbars().visible(cmd.getArg(0));
650 flag.setOnOff(current);
653 case LFUN_WINDOW_CLOSE: {
654 enable = (theApp()->gui().viewIds().size() > 1);
658 // this one is difficult to get right. As a half-baked
659 // solution, we consider only the first action of the sequence
660 case LFUN_COMMAND_SEQUENCE: {
661 // argument contains ';'-terminated commands
662 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
663 FuncRequest func(lyxaction.lookupFunc(firstcmd));
664 func.origin = cmd.origin;
665 flag = getStatus(func);
668 case LFUN_BUFFER_NEW:
669 case LFUN_BUFFER_NEW_TEMPLATE:
670 case LFUN_WORD_FIND_FORWARD:
671 case LFUN_WORD_FIND_BACKWARD:
672 case LFUN_COMMAND_PREFIX:
673 case LFUN_COMMAND_EXECUTE:
675 case LFUN_META_PREFIX:
676 case LFUN_BUFFER_CLOSE:
677 case LFUN_BUFFER_WRITE_AS:
678 case LFUN_BUFFER_UPDATE:
679 case LFUN_BUFFER_VIEW:
680 case LFUN_BUFFER_IMPORT:
681 case LFUN_BUFFER_AUTO_SAVE:
682 case LFUN_RECONFIGURE:
686 case LFUN_DROP_LAYOUTS_CHOICE:
688 case LFUN_SERVER_GET_NAME:
689 case LFUN_SERVER_NOTIFY:
690 case LFUN_SERVER_GOTO_FILE_ROW:
691 case LFUN_DIALOG_HIDE:
692 case LFUN_DIALOG_DISCONNECT_INSET:
693 case LFUN_BUFFER_CHILD_OPEN:
694 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
695 case LFUN_KEYMAP_OFF:
696 case LFUN_KEYMAP_PRIMARY:
697 case LFUN_KEYMAP_SECONDARY:
698 case LFUN_KEYMAP_TOGGLE:
700 case LFUN_BUFFER_EXPORT_CUSTOM:
701 case LFUN_BUFFER_PRINT:
702 case LFUN_PREFERENCES_SAVE:
703 case LFUN_SCREEN_FONT_UPDATE:
706 case LFUN_EXTERNAL_EDIT:
707 case LFUN_GRAPHICS_EDIT:
708 case LFUN_ALL_INSETS_TOGGLE:
709 case LFUN_BUFFER_LANGUAGE:
710 case LFUN_TEXTCLASS_APPLY:
711 case LFUN_TEXTCLASS_LOAD:
712 case LFUN_BUFFER_SAVE_AS_DEFAULT:
713 case LFUN_BUFFER_PARAMS_APPLY:
714 case LFUN_LYXRC_APPLY:
715 case LFUN_BUFFER_NEXT:
716 case LFUN_BUFFER_PREVIOUS:
717 case LFUN_WINDOW_NEW:
719 // these are handled in our dispatch()
723 if (!getLocalStatus(cur, cmd, flag))
724 flag = view()->getStatus(cmd);
730 // Can we use a readonly buffer?
731 if (buf && buf->isReadonly()
732 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
733 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
734 flag.message(from_utf8(N_("Document is read-only")));
738 // Are we in a DELETED change-tracking region?
739 if (buf && lookupChangeType(cur, true) == Change::DELETED
740 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
741 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
742 flag.message(from_utf8(N_("This portion of the document is deleted.")));
746 // the default error message if we disable the command
747 if (!flag.enabled() && flag.message().empty())
748 flag.message(from_utf8(N_("Command disabled")));
754 bool LyXFunc::ensureBufferClean(BufferView * bv)
756 Buffer & buf = *bv->buffer();
760 docstring const file = makeDisplayPath(buf.fileName(), 30);
761 docstring text = bformat(_("The document %1$s has unsaved "
762 "changes.\n\nDo you want to save "
763 "the document?"), file);
764 int const ret = Alert::prompt(_("Save changed document?"),
765 text, 0, 1, _("&Save"),
769 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
771 return buf.isClean();
777 void showPrintError(string const & name)
779 docstring str = bformat(_("Could not print the document %1$s.\n"
780 "Check that your printer is set up correctly."),
781 makeDisplayPath(name, 50));
782 Alert::error(_("Print document failed"), str);
786 void loadTextclass(string const & name)
788 std::pair<bool, textclass_type> const tc_pair =
789 textclasslist.numberOfClass(name);
791 if (!tc_pair.first) {
792 lyxerr << "Document class \"" << name
793 << "\" does not exist."
798 textclass_type const tc = tc_pair.second;
800 if (!textclasslist[tc].load()) {
801 docstring s = bformat(_("The document could not be converted\n"
802 "into the document class %1$s."),
803 from_utf8(textclasslist[tc].name()));
804 Alert::error(_("Could not change class"), s);
809 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
814 void LyXFunc::dispatch(FuncRequest const & cmd)
816 string const argument = to_utf8(cmd.argument());
817 kb_action const action = cmd.action;
819 LYXERR(Debug::ACTION) << endl << "LyXFunc::dispatch: cmd: " << cmd << endl;
820 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
822 // we have not done anything wrong yet.
824 dispatch_buffer.erase();
826 // redraw the screen at the end (first of the two drawing steps).
827 //This is done unless explicitely requested otherwise
828 Update::flags updateFlags = Update::FitCursor;
830 FuncStatus const flag = getStatus(cmd);
831 if (!flag.enabled()) {
832 // We cannot use this function here
833 LYXERR(Debug::ACTION) << "LyXFunc::dispatch: "
834 << lyxaction.getActionName(action)
835 << " [" << action << "] is disabled at this location"
837 setErrorMessage(flag.message());
841 case LFUN_WORD_FIND_FORWARD:
842 case LFUN_WORD_FIND_BACKWARD: {
843 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
844 static docstring last_search;
845 docstring searched_string;
847 if (!cmd.argument().empty()) {
848 last_search = cmd.argument();
849 searched_string = cmd.argument();
851 searched_string = last_search;
854 if (searched_string.empty())
857 bool const fw = action == LFUN_WORD_FIND_FORWARD;
858 docstring const data =
859 find2string(searched_string, true, false, fw);
860 find(view(), FuncRequest(LFUN_WORD_FIND, data));
864 case LFUN_COMMAND_PREFIX:
865 BOOST_ASSERT(lyx_view_);
866 lyx_view_->message(keyseq->printOptions(true));
869 case LFUN_COMMAND_EXECUTE:
870 BOOST_ASSERT(lyx_view_);
871 lyx_view_->getToolbars().display("minibuffer", true);
872 lyx_view_->focus_command_buffer();
876 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
878 meta_fake_bit = key_modifier::none;
879 if (view()->buffer())
880 // cancel any selection
881 dispatch(FuncRequest(LFUN_MARK_OFF));
882 setMessage(from_ascii(N_("Cancel")));
885 case LFUN_META_PREFIX:
886 meta_fake_bit = key_modifier::alt;
887 setMessage(keyseq->print(true));
890 case LFUN_BUFFER_TOGGLE_READ_ONLY:
891 BOOST_ASSERT(lyx_view_ && lyx_view_->view() && lyx_view_->buffer());
892 if (lyx_view_->buffer()->lyxvc().inUse())
893 lyx_view_->buffer()->lyxvc().toggleReadOnly();
895 lyx_view_->buffer()->setReadonly(
896 !lyx_view_->buffer()->isReadonly());
899 // --- Menus -----------------------------------------------
900 case LFUN_BUFFER_NEW:
901 menuNew(argument, false);
904 case LFUN_BUFFER_NEW_TEMPLATE:
905 menuNew(argument, true);
908 case LFUN_BUFFER_CLOSE:
913 case LFUN_BUFFER_WRITE:
914 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
915 if (!lyx_view_->buffer()->isUnnamed()) {
916 docstring const str = bformat(_("Saving document %1$s..."),
917 makeDisplayPath(lyx_view_->buffer()->fileName()));
918 lyx_view_->message(str);
919 menuWrite(lyx_view_->buffer());
920 lyx_view_->message(str + _(" done."));
922 writeAs(lyx_view_->buffer());
924 updateFlags = Update::None;
927 case LFUN_BUFFER_WRITE_AS:
928 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
929 writeAs(lyx_view_->buffer(), argument);
930 updateFlags = Update::None;
933 case LFUN_BUFFER_WRITE_ALL: {
934 Buffer * first = theBufferList().first();
937 lyx_view_->message(_("Saving all documents..."));
939 // We cannot use a for loop as the buffer list cycles.
942 if (!b->isUnnamed()) {
944 lyxerr[Debug::ACTION] << "Saved " << b->fileName() << endl;
948 b = theBufferList().next(b);
949 } while (b != first);
950 lyx_view_->message(_("All documents saved."));
953 updateFlags = Update::None;
957 case LFUN_BUFFER_RELOAD: {
958 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
959 docstring const file = makeDisplayPath(view()->buffer()->fileName(), 20);
960 docstring text = bformat(_("Any changes will be lost. Are you sure "
961 "you want to revert to the saved version of the document %1$s?"), file);
962 int const ret = Alert::prompt(_("Revert to saved document?"),
963 text, 1, 1, _("&Revert"), _("&Cancel"));
970 case LFUN_BUFFER_UPDATE:
971 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
972 Exporter::Export(lyx_view_->buffer(), argument, true);
975 case LFUN_BUFFER_VIEW:
976 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
977 Exporter::preview(lyx_view_->buffer(), argument);
980 case LFUN_BUILD_PROGRAM:
981 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
982 Exporter::Export(lyx_view_->buffer(), "program", true);
985 case LFUN_BUFFER_CHKTEX:
986 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
987 lyx_view_->buffer()->runChktex();
990 case LFUN_BUFFER_EXPORT:
991 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
992 if (argument == "custom")
993 lyx_view_->getDialogs().show("sendto");
995 Exporter::Export(lyx_view_->buffer(), argument, false);
999 case LFUN_BUFFER_EXPORT_CUSTOM: {
1000 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1002 string command = split(argument, format_name, ' ');
1003 Format const * format = formats.getFormat(format_name);
1005 lyxerr << "Format \"" << format_name
1006 << "\" not recognized!"
1011 Buffer * buffer = lyx_view_->buffer();
1013 // The name of the file created by the conversion process
1016 // Output to filename
1017 if (format->name() == "lyx") {
1018 string const latexname =
1019 buffer->getLatexName(false);
1020 filename = changeExtension(latexname,
1021 format->extension());
1022 filename = addName(buffer->temppath(), filename);
1024 if (!buffer->writeFile(FileName(filename)))
1028 Exporter::Export(buffer, format_name, true, filename);
1031 // Substitute $$FName for filename
1032 if (!contains(command, "$$FName"))
1033 command = "( " + command + " ) < $$FName";
1034 command = subst(command, "$$FName", filename);
1036 // Execute the command in the background
1038 call.startscript(Systemcall::DontWait, command);
1042 case LFUN_BUFFER_PRINT: {
1043 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1044 // FIXME: cmd.getArg() might fail if one of the arguments
1045 // contains double quotes
1046 string target = cmd.getArg(0);
1047 string target_name = cmd.getArg(1);
1048 string command = cmd.getArg(2);
1051 || target_name.empty()
1052 || command.empty()) {
1053 lyxerr << "Unable to parse \""
1054 << argument << '"' << endl;
1057 if (target != "printer" && target != "file") {
1058 lyxerr << "Unrecognized target \""
1059 << target << '"' << endl;
1063 Buffer * buffer = lyx_view_->buffer();
1065 if (!Exporter::Export(buffer, "dvi", true)) {
1066 showPrintError(buffer->fileName());
1070 // Push directory path.
1071 string const path(buffer->temppath());
1072 // Prevent the compiler from optimizing away p
1074 support::Path p(pp);
1076 // there are three cases here:
1077 // 1. we print to a file
1078 // 2. we print directly to a printer
1079 // 3. we print using a spool command (print to file first)
1082 string const dviname =
1083 changeExtension(buffer->getLatexName(true),
1086 if (target == "printer") {
1087 if (!lyxrc.print_spool_command.empty()) {
1088 // case 3: print using a spool
1089 string const psname =
1090 changeExtension(dviname,".ps");
1091 command += ' ' + lyxrc.print_to_file
1094 + quoteName(dviname);
1097 lyxrc.print_spool_command + ' ';
1098 if (target_name != "default") {
1099 command2 += lyxrc.print_spool_printerprefix
1103 command2 += quoteName(psname);
1105 // If successful, then spool command
1106 res = one.startscript(
1111 res = one.startscript(
1112 Systemcall::DontWait,
1115 // case 2: print directly to a printer
1116 if (target_name != "default")
1117 command += ' ' + lyxrc.print_to_printer + target_name + ' ';
1118 res = one.startscript(
1119 Systemcall::DontWait,
1120 command + quoteName(dviname));
1124 // case 1: print to a file
1125 FileName const filename(makeAbsPath(target_name,
1126 lyx_view_->buffer()->filePath()));
1127 FileName const dvifile(makeAbsPath(dviname, path));
1128 if (fs::exists(filename.toFilesystemEncoding())) {
1129 docstring text = bformat(
1130 _("The file %1$s already exists.\n\n"
1131 "Do you want to overwrite that file?"),
1132 makeDisplayPath(filename.absFilename()));
1133 if (Alert::prompt(_("Overwrite file?"),
1134 text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
1137 command += ' ' + lyxrc.print_to_file
1138 + quoteName(filename.toFilesystemEncoding())
1140 + quoteName(dvifile.toFilesystemEncoding());
1141 res = one.startscript(Systemcall::DontWait,
1146 showPrintError(buffer->fileName());
1150 case LFUN_BUFFER_IMPORT:
1155 // quitting is triggered by the gui code
1156 // (leaving the event loop).
1157 lyx_view_->message(from_utf8(N_("Exiting.")));
1158 if (theBufferList().quitWriteAll())
1159 theApp()->gui().closeAllViews();
1162 case LFUN_BUFFER_AUTO_SAVE:
1166 case LFUN_RECONFIGURE:
1167 BOOST_ASSERT(lyx_view_);
1168 reconfigure(*lyx_view_);
1171 case LFUN_HELP_OPEN: {
1172 BOOST_ASSERT(lyx_view_);
1173 string const arg = argument;
1175 setErrorMessage(from_ascii(N_("Missing argument")));
1178 FileName const fname = i18nLibFileSearch("doc", arg, "lyx");
1179 if (fname.empty()) {
1180 lyxerr << "LyX: unable to find documentation file `"
1181 << arg << "'. Bad installation?" << endl;
1184 lyx_view_->message(bformat(_("Opening help file %1$s..."),
1185 makeDisplayPath(fname.absFilename())));
1186 lyx_view_->loadLyXFile(fname, false);
1190 // --- version control -------------------------------
1191 case LFUN_VC_REGISTER:
1192 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1193 if (!ensureBufferClean(view()))
1195 if (!lyx_view_->buffer()->lyxvc().inUse()) {
1196 lyx_view_->buffer()->lyxvc().registrer();
1199 updateFlags = Update::Force;
1202 case LFUN_VC_CHECK_IN:
1203 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1204 if (!ensureBufferClean(view()))
1206 if (lyx_view_->buffer()->lyxvc().inUse()
1207 && !lyx_view_->buffer()->isReadonly()) {
1208 lyx_view_->buffer()->lyxvc().checkIn();
1213 case LFUN_VC_CHECK_OUT:
1214 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1215 if (!ensureBufferClean(view()))
1217 if (lyx_view_->buffer()->lyxvc().inUse()
1218 && lyx_view_->buffer()->isReadonly()) {
1219 lyx_view_->buffer()->lyxvc().checkOut();
1224 case LFUN_VC_REVERT:
1225 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1226 lyx_view_->buffer()->lyxvc().revert();
1230 case LFUN_VC_UNDO_LAST:
1231 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1232 lyx_view_->buffer()->lyxvc().undoLast();
1236 // --- buffers ----------------------------------------
1237 case LFUN_BUFFER_SWITCH:
1238 BOOST_ASSERT(lyx_view_);
1239 lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1240 updateFlags = Update::Force;
1243 case LFUN_BUFFER_NEXT:
1244 BOOST_ASSERT(lyx_view_);
1245 lyx_view_->setBuffer(theBufferList().next(view()->buffer()));
1246 updateFlags = Update::Force;
1249 case LFUN_BUFFER_PREVIOUS:
1250 BOOST_ASSERT(lyx_view_);
1251 lyx_view_->setBuffer(theBufferList().previous(view()->buffer()));
1252 updateFlags = Update::Force;
1256 BOOST_ASSERT(lyx_view_);
1257 newFile(view(), argument);
1260 case LFUN_FILE_OPEN:
1261 BOOST_ASSERT(lyx_view_);
1265 case LFUN_DROP_LAYOUTS_CHOICE:
1266 BOOST_ASSERT(lyx_view_);
1267 lyx_view_->getToolbars().openLayoutList();
1270 case LFUN_MENU_OPEN:
1271 BOOST_ASSERT(lyx_view_);
1272 lyx_view_->getMenubar().openByName(from_utf8(argument));
1275 // --- lyxserver commands ----------------------------
1276 case LFUN_SERVER_GET_NAME:
1277 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1278 setMessage(from_utf8(lyx_view_->buffer()->fileName()));
1279 LYXERR(Debug::INFO) << "FNAME["
1280 << lyx_view_->buffer()->fileName()
1284 case LFUN_SERVER_NOTIFY:
1285 dispatch_buffer = keyseq->print(false);
1286 theServer().notifyClient(to_utf8(dispatch_buffer));
1289 case LFUN_SERVER_GOTO_FILE_ROW: {
1290 BOOST_ASSERT(lyx_view_);
1293 istringstream is(argument);
1294 is >> file_name >> row;
1295 if (prefixIs(file_name, package().temp_dir().absFilename())) {
1296 // Needed by inverse dvi search. If it is a file
1297 // in tmpdir, call the apropriated function
1298 lyx_view_->setBuffer(theBufferList().getBufferFromTmp(file_name));
1300 // Must replace extension of the file to be .lyx
1301 // and get full path
1302 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1303 // Either change buffer or load the file
1304 if (theBufferList().exists(s.absFilename())) {
1305 lyx_view_->setBuffer(theBufferList().getBuffer(s.absFilename()));
1307 lyx_view_->loadLyXFile(s);
1311 view()->setCursorFromRow(row);
1313 updateFlags = Update::FitCursor;
1317 case LFUN_DIALOG_SHOW: {
1318 BOOST_ASSERT(lyx_view_);
1319 string const name = cmd.getArg(0);
1320 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1322 if (name == "character") {
1323 data = freefont2string();
1325 lyx_view_->getDialogs().show("character", data);
1326 } else if (name == "latexlog") {
1327 pair<Buffer::LogType, string> const logfile =
1328 lyx_view_->buffer()->getLogName();
1329 switch (logfile.first) {
1330 case Buffer::latexlog:
1333 case Buffer::buildlog:
1337 data += Lexer::quoteString(logfile.second);
1338 lyx_view_->getDialogs().show("log", data);
1339 } else if (name == "vclog") {
1340 string const data = "vc " +
1341 Lexer::quoteString(lyx_view_->buffer()->lyxvc().getLogFile());
1342 lyx_view_->getDialogs().show("log", data);
1344 lyx_view_->getDialogs().show(name, data);
1348 case LFUN_DIALOG_SHOW_NEW_INSET: {
1349 BOOST_ASSERT(lyx_view_);
1350 string const name = cmd.getArg(0);
1351 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1352 if (name == "bibitem" ||
1356 name == "nomenclature" ||
1360 InsetCommandParams p(name);
1361 data = InsetCommandMailer::params2string(name, p);
1362 } else if (name == "include") {
1363 // data is the include type: one of "include",
1364 // "input", "verbatiminput" or "verbatiminput*"
1366 // default type is requested
1368 InsetCommandParams p(data);
1369 data = InsetIncludeMailer::params2string(p);
1370 } else if (name == "box") {
1371 // \c data == "Boxed" || "Frameless" etc
1372 InsetBoxParams p(data);
1373 data = InsetBoxMailer::params2string(p);
1374 } else if (name == "branch") {
1375 InsetBranchParams p;
1376 data = InsetBranchMailer::params2string(p);
1377 } else if (name == "citation") {
1378 InsetCommandParams p("cite");
1379 data = InsetCommandMailer::params2string(name, p);
1380 } else if (name == "ert") {
1381 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1382 } else if (name == "external") {
1383 InsetExternalParams p;
1384 Buffer const & buffer = *lyx_view_->buffer();
1385 data = InsetExternalMailer::params2string(p, buffer);
1386 } else if (name == "float") {
1388 data = InsetFloatMailer::params2string(p);
1389 } else if (name == "listings") {
1390 InsetListingsParams p;
1391 data = InsetListingsMailer::params2string(p);
1392 } else if (name == "graphics") {
1393 InsetGraphicsParams p;
1394 Buffer const & buffer = *lyx_view_->buffer();
1395 data = InsetGraphicsMailer::params2string(p, buffer);
1396 } else if (name == "note") {
1398 data = InsetNoteMailer::params2string(p);
1399 } else if (name == "vspace") {
1401 data = InsetVSpaceMailer::params2string(space);
1402 } else if (name == "wrap") {
1404 data = InsetWrapMailer::params2string(p);
1406 lyx_view_->getDialogs().show(name, data, 0);
1410 case LFUN_DIALOG_UPDATE: {
1411 BOOST_ASSERT(lyx_view_);
1412 string const & name = argument;
1413 // Can only update a dialog connected to an existing inset
1414 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1416 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1417 inset->dispatch(view()->cursor(), fr);
1418 } else if (name == "paragraph") {
1419 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1420 } else if (name == "prefs") {
1421 lyx_view_->getDialogs().update(name, string());
1426 case LFUN_DIALOG_HIDE:
1427 LyX::cref().hideDialogs(argument, 0);
1430 case LFUN_DIALOG_TOGGLE: {
1431 BOOST_ASSERT(lyx_view_);
1432 if (lyx_view_->getDialogs().visible(cmd.getArg(0)))
1433 dispatch(FuncRequest(LFUN_DIALOG_HIDE, argument));
1435 dispatch(FuncRequest(LFUN_DIALOG_SHOW, argument));
1439 case LFUN_DIALOG_DISCONNECT_INSET:
1440 BOOST_ASSERT(lyx_view_);
1441 lyx_view_->getDialogs().disconnect(argument);
1445 case LFUN_CITATION_INSERT: {
1446 BOOST_ASSERT(lyx_view_);
1447 if (!argument.empty()) {
1448 // we can have one optional argument, delimited by '|'
1449 // citation-insert <key>|<text_before>
1450 // this should be enhanced to also support text_after
1451 // and citation style
1452 string arg = argument;
1454 if (contains(argument, "|")) {
1455 arg = token(argument, '|', 0);
1456 opt1 = token(argument, '|', 1);
1458 InsetCommandParams icp("cite");
1459 icp["key"] = from_utf8(arg);
1461 icp["before"] = from_utf8(opt1);
1462 string icstr = InsetCommandMailer::params2string("citation", icp);
1463 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1466 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1470 case LFUN_BUFFER_CHILD_OPEN: {
1471 // takes an optional argument, "|bool", at the end
1472 // indicating whether this file is being opened automatically
1473 // by LyX itself, in which case we will not want to switch
1474 // buffers after opening. The default is false, so in practice
1475 // it is used only when true.
1476 BOOST_ASSERT(lyx_view_);
1477 int const arglength = argument.length();
1479 bool autoOpen = false;
1480 if (argument.substr(arglength - 5, 5) == "|true") {
1482 filename = makeAbsPath(argument.substr(0, arglength - 5),
1483 lyx_view_->buffer()->filePath());
1484 } else if (argument.substr(arglength - 6, 6) == "|false") {
1485 filename = makeAbsPath(argument.substr(0, arglength - 6),
1486 lyx_view_->buffer()->filePath());
1488 makeAbsPath(argument, lyx_view_->buffer()->filePath());
1489 view()->saveBookmark(false);
1490 if (theBufferList().exists(filename.absFilename())) {
1491 Buffer * buf = theBufferList().getBuffer(filename.absFilename());
1493 lyx_view_->setBuffer(buf, true);
1495 buf->setParentName(lyx_view_->buffer()->fileName());
1497 lyx_view_->loadLyXFile(filename, true, true, autoOpen);
1499 // If a screen update is required (in case where auto_open is false),
1500 // loadLyXFile() would have taken care of it already. Otherwise we shall
1501 // reset the update flag because it can cause a circular problem.
1503 updateFlags = Update::None;
1507 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1508 BOOST_ASSERT(lyx_view_);
1509 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1512 case LFUN_KEYMAP_OFF:
1513 BOOST_ASSERT(lyx_view_);
1514 lyx_view_->view()->getIntl().keyMapOn(false);
1517 case LFUN_KEYMAP_PRIMARY:
1518 BOOST_ASSERT(lyx_view_);
1519 lyx_view_->view()->getIntl().keyMapPrim();
1522 case LFUN_KEYMAP_SECONDARY:
1523 BOOST_ASSERT(lyx_view_);
1524 lyx_view_->view()->getIntl().keyMapSec();
1527 case LFUN_KEYMAP_TOGGLE:
1528 BOOST_ASSERT(lyx_view_);
1529 lyx_view_->view()->getIntl().toggleKeyMap();
1535 string rest = split(argument, countstr, ' ');
1536 istringstream is(countstr);
1539 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1540 for (int i = 0; i < count; ++i)
1541 dispatch(lyxaction.lookupFunc(rest));
1545 case LFUN_COMMAND_SEQUENCE: {
1546 // argument contains ';'-terminated commands
1547 string arg = argument;
1548 while (!arg.empty()) {
1550 arg = split(arg, first, ';');
1551 FuncRequest func(lyxaction.lookupFunc(first));
1552 func.origin = cmd.origin;
1558 case LFUN_PREFERENCES_SAVE: {
1559 lyxrc.write(makeAbsPath("preferences",
1560 package().user_support().absFilename()),
1565 case LFUN_SCREEN_FONT_UPDATE:
1566 BOOST_ASSERT(lyx_view_);
1567 // handle the screen font changes.
1568 theFontLoader().update();
1569 /// FIXME: only the current view will be updated. the Gui
1570 /// class is able to furnish the list of views.
1571 updateFlags = Update::Force;
1574 case LFUN_SET_COLOR: {
1576 string const x11_name = split(argument, lyx_name, ' ');
1577 if (lyx_name.empty() || x11_name.empty()) {
1578 setErrorMessage(from_ascii(N_(
1579 "Syntax: set-color <lyx_name>"
1584 bool const graphicsbg_changed =
1585 (lyx_name == lcolor.getLyXName(Color::graphicsbg) &&
1586 x11_name != lcolor.getX11Name(Color::graphicsbg));
1588 if (!lcolor.setColor(lyx_name, x11_name)) {
1590 bformat(_("Set-color \"%1$s\" failed "
1591 "- color is undefined or "
1592 "may not be redefined"),
1593 from_utf8(lyx_name)));
1597 theApp()->updateColor(lcolor.getFromLyXName(lyx_name));
1599 if (graphicsbg_changed) {
1600 #ifdef WITH_WARNINGS
1601 #warning FIXME!! The graphics cache no longer has a changeDisplay method.
1604 graphics::GCache::get().changeDisplay(true);
1611 BOOST_ASSERT(lyx_view_);
1612 lyx_view_->message(from_utf8(argument));
1615 case LFUN_EXTERNAL_EDIT: {
1616 BOOST_ASSERT(lyx_view_);
1617 FuncRequest fr(action, argument);
1618 InsetExternal().dispatch(view()->cursor(), fr);
1622 case LFUN_GRAPHICS_EDIT: {
1623 FuncRequest fr(action, argument);
1624 InsetGraphics().dispatch(view()->cursor(), fr);
1628 case LFUN_INSET_APPLY: {
1629 BOOST_ASSERT(lyx_view_);
1630 string const name = cmd.getArg(0);
1631 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1633 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1634 inset->dispatch(view()->cursor(), fr);
1636 FuncRequest fr(LFUN_INSET_INSERT, argument);
1639 // ideally, the update flag should be set by the insets,
1640 // but this is not possible currently
1641 updateFlags = Update::Force | Update::FitCursor;
1645 case LFUN_ALL_INSETS_TOGGLE: {
1646 BOOST_ASSERT(lyx_view_);
1648 string const name = split(argument, action, ' ');
1649 Inset::Code const inset_code =
1650 Inset::translate(name);
1652 Cursor & cur = view()->cursor();
1653 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1655 Inset & inset = lyx_view_->buffer()->inset();
1656 InsetIterator it = inset_iterator_begin(inset);
1657 InsetIterator const end = inset_iterator_end(inset);
1658 for (; it != end; ++it) {
1659 if (!it->asInsetMath()
1660 && (inset_code == Inset::NO_CODE
1661 || inset_code == it->lyxCode())) {
1662 Cursor tmpcur = cur;
1663 tmpcur.pushLeft(*it);
1664 it->dispatch(tmpcur, fr);
1667 updateFlags = Update::Force | Update::FitCursor;
1671 case LFUN_BUFFER_LANGUAGE: {
1672 BOOST_ASSERT(lyx_view_);
1673 Buffer & buffer = *lyx_view_->buffer();
1674 Language const * oldL = buffer.params().language;
1675 Language const * newL = languages.getLanguage(argument);
1676 if (!newL || oldL == newL)
1679 if (oldL->rightToLeft() == newL->rightToLeft()
1680 && !buffer.isMultiLingual())
1681 buffer.changeLanguage(oldL, newL);
1685 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1686 string const fname =
1687 addName(addPath(package().user_support().absFilename(), "templates/"),
1689 Buffer defaults(fname);
1691 istringstream ss(argument);
1694 int const unknown_tokens = defaults.readHeader(lex);
1696 if (unknown_tokens != 0) {
1697 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1698 << unknown_tokens << " unknown token"
1699 << (unknown_tokens == 1 ? "" : "s")
1703 if (defaults.writeFile(FileName(defaults.fileName())))
1704 setMessage(bformat(_("Document defaults saved in %1$s"),
1705 makeDisplayPath(fname)));
1707 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1711 case LFUN_BUFFER_PARAMS_APPLY: {
1712 BOOST_ASSERT(lyx_view_);
1713 biblio::CiteEngine const engine =
1714 lyx_view_->buffer()->params().getEngine();
1716 istringstream ss(argument);
1719 int const unknown_tokens =
1720 lyx_view_->buffer()->readHeader(lex);
1722 if (unknown_tokens != 0) {
1723 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1724 << unknown_tokens << " unknown token"
1725 << (unknown_tokens == 1 ? "" : "s")
1728 if (engine == lyx_view_->buffer()->params().getEngine())
1731 Cursor & cur = view()->cursor();
1732 FuncRequest fr(LFUN_INSET_REFRESH);
1734 Inset & inset = lyx_view_->buffer()->inset();
1735 InsetIterator it = inset_iterator_begin(inset);
1736 InsetIterator const end = inset_iterator_end(inset);
1737 for (; it != end; ++it)
1738 if (it->lyxCode() == Inset::CITE_CODE)
1739 it->dispatch(cur, fr);
1743 case LFUN_TEXTCLASS_APPLY: {
1744 BOOST_ASSERT(lyx_view_);
1745 Buffer * buffer = lyx_view_->buffer();
1747 textclass_type const old_class =
1748 buffer->params().textclass;
1750 loadTextclass(argument);
1752 std::pair<bool, textclass_type> const tc_pair =
1753 textclasslist.numberOfClass(argument);
1758 textclass_type const new_class = tc_pair.second;
1759 if (old_class == new_class)
1763 lyx_view_->message(_("Converting document to new document class..."));
1764 recordUndoFullDocument(view());
1765 buffer->params().textclass = new_class;
1766 StableDocIterator backcur(view()->cursor());
1767 ErrorList & el = buffer->errorList("Class Switch");
1768 cap::switchBetweenClasses(
1769 old_class, new_class,
1770 static_cast<InsetText &>(buffer->inset()), el);
1772 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
1774 buffer->errors("Class Switch");
1775 updateLabels(*buffer);
1776 updateFlags = Update::Force | Update::FitCursor;
1780 case LFUN_TEXTCLASS_LOAD:
1781 loadTextclass(argument);
1784 case LFUN_LYXRC_APPLY: {
1785 LyXRC const lyxrc_orig = lyxrc;
1787 istringstream ss(argument);
1788 bool const success = lyxrc.read(ss) == 0;
1791 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1792 << "Unable to read lyxrc data"
1797 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1799 /// We force the redraw in any case because there might be
1800 /// some screen font changes.
1801 /// FIXME: only the current view will be updated. the Gui
1802 /// class is able to furnish the list of views.
1803 updateFlags = Update::Force;
1807 case LFUN_WINDOW_NEW:
1808 LyX::ref().newLyXView();
1811 case LFUN_WINDOW_CLOSE:
1812 BOOST_ASSERT(lyx_view_);
1813 BOOST_ASSERT(theApp());
1814 // update bookmark pit of the current buffer before window close
1815 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1816 gotoBookmark(i+1, false, false);
1817 // ask the user for saving changes or cancel quit
1818 if (!theBufferList().quitWriteAll())
1823 case LFUN_BOOKMARK_GOTO:
1824 // go to bookmark, open unopened file and switch to buffer if necessary
1825 gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
1828 case LFUN_BOOKMARK_CLEAR:
1829 LyX::ref().session().bookmarks().clear();
1832 case LFUN_TOOLBAR_TOGGLE: {
1833 BOOST_ASSERT(lyx_view_);
1834 string const name = cmd.getArg(0);
1835 bool const allowauto = cmd.getArg(1) == "allowauto";
1836 lyx_view_->toggleToolbarState(name, allowauto);
1837 ToolbarInfo * tbi = lyx_view_->getToolbarInfo(name);
1839 setMessage(bformat(_("Unknown toolbar \"%1$s\""),
1844 if (tbi->flags & ToolbarInfo::ON)
1846 else if (tbi->flags & ToolbarInfo::OFF)
1848 else if (tbi->flags & ToolbarInfo::AUTO)
1851 setMessage(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1852 _(tbi->gui_name), state));
1857 BOOST_ASSERT(lyx_view_);
1858 view()->cursor().dispatch(cmd);
1859 updateFlags = view()->cursor().result().update();
1860 if (!view()->cursor().result().dispatched())
1861 updateFlags = view()->dispatch(cmd);
1866 if (lyx_view_ && view()->buffer()) {
1867 // BufferView::update() updates the ViewMetricsInfo and
1868 // also initializes the position cache for all insets in
1869 // (at least partially) visible top-level paragraphs.
1870 // We will redraw the screen only if needed.
1871 if (view()->update(updateFlags)) {
1872 // Buffer::changed() signals that a repaint is needed.
1873 // The frontend (WorkArea) knows which area to repaint
1874 // thanks to the ViewMetricsInfo updated above.
1875 view()->buffer()->changed();
1878 lyx_view_->updateStatusBar();
1880 // if we executed a mutating lfun, mark the buffer as dirty
1882 && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
1883 && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
1884 view()->buffer()->markDirty();
1886 //Do we have a selection?
1887 theSelection().haveSelection(view()->cursor().selection());
1889 if (view()->cursor().inTexted()) {
1890 lyx_view_->updateLayoutChoice();
1894 if (!quitting && lyx_view_) {
1895 lyx_view_->updateMenubar();
1896 lyx_view_->updateToolbars();
1897 // Some messages may already be translated, so we cannot use _()
1898 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
1903 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
1905 const bool verbose = (cmd.origin == FuncRequest::MENU
1906 || cmd.origin == FuncRequest::TOOLBAR
1907 || cmd.origin == FuncRequest::COMMANDBUFFER);
1909 if (cmd.action == LFUN_SELF_INSERT || !verbose) {
1910 LYXERR(Debug::ACTION) << "dispatch msg is " << to_utf8(msg) << endl;
1912 lyx_view_->message(msg);
1916 docstring dispatch_msg = msg;
1917 if (!dispatch_msg.empty())
1918 dispatch_msg += ' ';
1920 docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
1922 bool argsadded = false;
1924 if (!cmd.argument().empty()) {
1925 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1926 comname += ' ' + cmd.argument();
1931 docstring const shortcuts = theTopLevelKeymap().printbindings(cmd);
1933 if (!shortcuts.empty())
1934 comname += ": " + shortcuts;
1935 else if (!argsadded && !cmd.argument().empty())
1936 comname += ' ' + cmd.argument();
1938 if (!comname.empty()) {
1939 comname = rtrim(comname);
1940 dispatch_msg += '(' + rtrim(comname) + ')';
1943 LYXERR(Debug::ACTION) << "verbose dispatch msg "
1944 << to_utf8(dispatch_msg) << endl;
1945 if (!dispatch_msg.empty())
1946 lyx_view_->message(dispatch_msg);
1950 void LyXFunc::menuNew(string const & name, bool fromTemplate)
1952 // FIXME: initpath is not used. What to do?
1953 string initpath = lyxrc.document_path;
1954 string filename(name);
1956 if (view()->buffer()) {
1957 string const trypath = lyx_view_->buffer()->filePath();
1958 // If directory is writeable, use this as default.
1959 if (isDirWriteable(FileName(trypath)))
1963 static int newfile_number;
1965 if (filename.empty()) {
1966 filename = addName(lyxrc.document_path,
1967 "newfile" + convert<string>(++newfile_number) + ".lyx");
1968 while (theBufferList().exists(filename) ||
1969 fs::is_readable(FileName(filename).toFilesystemEncoding())) {
1971 filename = addName(lyxrc.document_path,
1972 "newfile" + convert<string>(newfile_number) +
1977 // The template stuff
1980 FileDialog fileDlg(_("Select template file"),
1981 LFUN_SELECT_FILE_SYNC,
1982 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
1983 make_pair(_("Templates|#T#t"), from_utf8(lyxrc.template_path)));
1985 FileDialog::Result result =
1986 fileDlg.open(from_utf8(lyxrc.template_path),
1987 FileFilterList(_("LyX Documents (*.lyx)")),
1990 if (result.first == FileDialog::Later)
1992 if (result.second.empty())
1994 templname = to_utf8(result.second);
1997 Buffer * const b = newFile(filename, templname, !name.empty());
2000 lyx_view_->setBuffer(b);
2005 void LyXFunc::open(string const & fname)
2007 string initpath = lyxrc.document_path;
2009 if (view()->buffer()) {
2010 string const trypath = lyx_view_->buffer()->filePath();
2011 // If directory is writeable, use this as default.
2012 if (isDirWriteable(FileName(trypath)))
2018 if (fname.empty()) {
2019 FileDialog fileDlg(_("Select document to open"),
2021 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2022 make_pair(_("Examples|#E#e"), from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2024 FileDialog::Result result =
2025 fileDlg.open(from_utf8(initpath),
2026 FileFilterList(_("LyX Documents (*.lyx)")),
2029 if (result.first == FileDialog::Later)
2032 filename = to_utf8(result.second);
2034 // check selected filename
2035 if (filename.empty()) {
2036 lyx_view_->message(_("Canceled."));
2042 // get absolute path of file and add ".lyx" to the filename if
2044 FileName const fullname = fileSearch(string(), filename, "lyx");
2045 if (!fullname.empty())
2046 filename = fullname.absFilename();
2048 // if the file doesn't exist, let the user create one
2049 if (!fs::exists(fullname.toFilesystemEncoding())) {
2050 // the user specifically chose this name. Believe him.
2051 Buffer * const b = newFile(filename, string(), true);
2053 lyx_view_->setBuffer(b);
2057 docstring const disp_fn = makeDisplayPath(filename);
2058 lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
2061 if (lyx_view_->loadLyXFile(fullname)) {
2062 str2 = bformat(_("Document %1$s opened."), disp_fn);
2064 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2066 lyx_view_->message(str2);
2070 void LyXFunc::doImport(string const & argument)
2073 string filename = split(argument, format, ' ');
2075 LYXERR(Debug::INFO) << "LyXFunc::doImport: " << format
2076 << " file: " << filename << endl;
2078 // need user interaction
2079 if (filename.empty()) {
2080 string initpath = lyxrc.document_path;
2082 if (view()->buffer()) {
2083 string const trypath = lyx_view_->buffer()->filePath();
2084 // If directory is writeable, use this as default.
2085 if (isDirWriteable(FileName(trypath)))
2089 docstring const text = bformat(_("Select %1$s file to import"),
2090 formats.prettyName(format));
2092 FileDialog fileDlg(text,
2094 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2095 make_pair(_("Examples|#E#e"),
2096 from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2098 docstring filter = formats.prettyName(format);
2101 filter += from_utf8(formats.extension(format));
2104 FileDialog::Result result =
2105 fileDlg.open(from_utf8(initpath),
2106 FileFilterList(filter),
2109 if (result.first == FileDialog::Later)
2112 filename = to_utf8(result.second);
2114 // check selected filename
2115 if (filename.empty())
2116 lyx_view_->message(_("Canceled."));
2119 if (filename.empty())
2122 // get absolute path of file
2123 FileName const fullname(makeAbsPath(filename));
2125 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
2127 // Check if the document already is open
2128 if (use_gui && theBufferList().exists(lyxfile.absFilename())) {
2129 if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) {
2130 lyx_view_->message(_("Canceled."));
2135 // if the file exists already, and we didn't do
2136 // -i lyx thefile.lyx, warn
2137 if (fs::exists(lyxfile.toFilesystemEncoding()) && fullname != lyxfile) {
2138 docstring const file = makeDisplayPath(lyxfile.absFilename(), 30);
2140 docstring text = bformat(_("The document %1$s already exists.\n\n"
2141 "Do you want to overwrite that document?"), file);
2142 int const ret = Alert::prompt(_("Overwrite document?"),
2143 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2146 lyx_view_->message(_("Canceled."));
2151 ErrorList errorList;
2152 Importer::Import(lyx_view_, fullname, format, errorList);
2153 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2157 void LyXFunc::closeBuffer()
2159 // goto bookmark to update bookmark pit.
2160 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2161 gotoBookmark(i+1, false, false);
2163 theBufferList().close(lyx_view_->buffer(), true);
2167 void LyXFunc::reloadBuffer()
2169 FileName filename(lyx_view_->buffer()->fileName());
2171 lyx_view_->loadLyXFile(filename);
2174 // Each "lyx_view_" should have it's own message method. lyxview and
2175 // the minibuffer would use the minibuffer, but lyxserver would
2176 // send an ERROR signal to its client. Alejandro 970603
2177 // This function is bit problematic when it comes to NLS, to make the
2178 // lyx servers client be language indepenent we must not translate
2179 // strings sent to this func.
2180 void LyXFunc::setErrorMessage(docstring const & m) const
2182 dispatch_buffer = m;
2187 void LyXFunc::setMessage(docstring const & m) const
2189 dispatch_buffer = m;
2193 docstring const LyXFunc::viewStatusMessage()
2195 // When meta-fake key is pressed, show the key sequence so far + "M-".
2197 return keyseq->print(true) + "M-";
2199 // Else, when a non-complete key sequence is pressed,
2200 // show the available options.
2201 if (keyseq->length() > 0 && !keyseq->deleted())
2202 return keyseq->printOptions(true);
2204 if (!view()->buffer())
2205 return _("Welcome to LyX!");
2207 return view()->cursor().currentState();
2211 BufferView * LyXFunc::view() const
2213 BOOST_ASSERT(lyx_view_);
2214 return lyx_view_->view();
2218 bool LyXFunc::wasMetaKey() const
2220 return (meta_fake_bit != key_modifier::none);
2226 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2228 // Why the switch you might ask. It is a trick to ensure that all
2229 // the elements in the LyXRCTags enum is handled. As you can see
2230 // there are no breaks at all. So it is just a huge fall-through.
2231 // The nice thing is that we will get a warning from the compiler
2232 // if we forget an element.
2233 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2235 case LyXRC::RC_ACCEPT_COMPOUND:
2236 case LyXRC::RC_ALT_LANG:
2237 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
2238 case LyXRC::RC_PLAINTEXT_LINELEN:
2239 case LyXRC::RC_AUTOREGIONDELETE:
2240 case LyXRC::RC_AUTORESET_OPTIONS:
2241 case LyXRC::RC_AUTOSAVE:
2242 case LyXRC::RC_AUTO_NUMBER:
2243 case LyXRC::RC_BACKUPDIR_PATH:
2244 case LyXRC::RC_BIBTEX_COMMAND:
2245 case LyXRC::RC_BINDFILE:
2246 case LyXRC::RC_CHECKLASTFILES:
2247 case LyXRC::RC_USELASTFILEPOS:
2248 case LyXRC::RC_LOADSESSION:
2249 case LyXRC::RC_CHKTEX_COMMAND:
2250 case LyXRC::RC_CONVERTER:
2251 case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
2252 case LyXRC::RC_COPIER:
2253 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2254 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2255 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2256 case LyXRC::RC_DATE_INSERT_FORMAT:
2257 case LyXRC::RC_DEFAULT_LANGUAGE:
2258 case LyXRC::RC_DEFAULT_PAPERSIZE:
2259 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2260 case LyXRC::RC_DISPLAY_GRAPHICS:
2261 case LyXRC::RC_DOCUMENTPATH:
2262 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2263 string const encoded = FileName(
2264 lyxrc_new.document_path).toFilesystemEncoding();
2265 if (fs::exists(encoded) && fs::is_directory(encoded))
2266 support::package().document_dir() = FileName(lyxrc.document_path);
2268 case LyXRC::RC_ESC_CHARS:
2269 case LyXRC::RC_FONT_ENCODING:
2270 case LyXRC::RC_FORMAT:
2271 case LyXRC::RC_INDEX_COMMAND:
2272 case LyXRC::RC_INPUT:
2273 case LyXRC::RC_KBMAP:
2274 case LyXRC::RC_KBMAP_PRIMARY:
2275 case LyXRC::RC_KBMAP_SECONDARY:
2276 case LyXRC::RC_LABEL_INIT_LENGTH:
2277 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2278 case LyXRC::RC_LANGUAGE_AUTO_END:
2279 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2280 case LyXRC::RC_LANGUAGE_COMMAND_END:
2281 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2282 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2283 case LyXRC::RC_LANGUAGE_PACKAGE:
2284 case LyXRC::RC_LANGUAGE_USE_BABEL:
2285 case LyXRC::RC_MAKE_BACKUP:
2286 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2287 case LyXRC::RC_NUMLASTFILES:
2288 case LyXRC::RC_PATH_PREFIX:
2289 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2290 support::prependEnvPath("PATH", lyxrc.path_prefix);
2292 case LyXRC::RC_PERS_DICT:
2293 case LyXRC::RC_PREVIEW:
2294 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2295 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2296 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2297 case LyXRC::RC_PRINTCOPIESFLAG:
2298 case LyXRC::RC_PRINTER:
2299 case LyXRC::RC_PRINTEVENPAGEFLAG:
2300 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2301 case LyXRC::RC_PRINTFILEEXTENSION:
2302 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2303 case LyXRC::RC_PRINTODDPAGEFLAG:
2304 case LyXRC::RC_PRINTPAGERANGEFLAG:
2305 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2306 case LyXRC::RC_PRINTPAPERFLAG:
2307 case LyXRC::RC_PRINTREVERSEFLAG:
2308 case LyXRC::RC_PRINTSPOOL_COMMAND:
2309 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2310 case LyXRC::RC_PRINTTOFILE:
2311 case LyXRC::RC_PRINTTOPRINTER:
2312 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2313 case LyXRC::RC_PRINT_COMMAND:
2314 case LyXRC::RC_RTL_SUPPORT:
2315 case LyXRC::RC_SCREEN_DPI:
2316 case LyXRC::RC_SCREEN_FONT_ROMAN:
2317 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2318 case LyXRC::RC_SCREEN_FONT_SANS:
2319 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2320 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2321 case LyXRC::RC_SCREEN_FONT_SIZES:
2322 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2323 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2324 case LyXRC::RC_SCREEN_GEOMETRY_HEIGHT:
2325 case LyXRC::RC_SCREEN_GEOMETRY_WIDTH:
2326 case LyXRC::RC_SCREEN_GEOMETRY_XYSAVED:
2327 case LyXRC::RC_SCREEN_ZOOM:
2328 case LyXRC::RC_SERVERPIPE:
2329 case LyXRC::RC_SET_COLOR:
2330 case LyXRC::RC_SHOW_BANNER:
2331 case LyXRC::RC_SPELL_COMMAND:
2332 case LyXRC::RC_TEMPDIRPATH:
2333 case LyXRC::RC_TEMPLATEPATH:
2334 case LyXRC::RC_TEX_ALLOWS_SPACES:
2335 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2336 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2337 support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2339 case LyXRC::RC_UIFILE:
2340 case LyXRC::RC_USER_EMAIL:
2341 case LyXRC::RC_USER_NAME:
2342 case LyXRC::RC_USETEMPDIR:
2343 case LyXRC::RC_USE_ALT_LANG:
2344 case LyXRC::RC_USE_CONVERTER_CACHE:
2345 case LyXRC::RC_USE_ESC_CHARS:
2346 case LyXRC::RC_USE_INP_ENC:
2347 case LyXRC::RC_USE_PERS_DICT:
2348 case LyXRC::RC_USE_SPELL_LIB:
2349 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2350 case LyXRC::RC_VIEWER:
2351 case LyXRC::RC_LAST: