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() && fs::exists(buf->fileName())
500 && (!buf->isClean() || buf->isExternallyModified(Buffer::timestamp_method));
503 case LFUN_INSET_SETTINGS: {
507 Inset::Code code = cur.inset().lyxCode();
509 case Inset::TABULAR_CODE:
510 enable = cmd.argument() == "tabular";
512 case Inset::ERT_CODE:
513 enable = cmd.argument() == "ert";
515 case Inset::FLOAT_CODE:
516 enable = cmd.argument() == "float";
518 case Inset::WRAP_CODE:
519 enable = cmd.argument() == "wrap";
521 case Inset::NOTE_CODE:
522 enable = cmd.argument() == "note";
524 case Inset::BRANCH_CODE:
525 enable = cmd.argument() == "branch";
527 case Inset::BOX_CODE:
528 enable = cmd.argument() == "box";
530 case Inset::LISTINGS_CODE:
531 enable = cmd.argument() == "listings";
539 case LFUN_INSET_APPLY: {
540 string const name = cmd.getArg(0);
541 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
543 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
545 if (!inset->getStatus(cur, fr, fs)) {
546 // Every inset is supposed to handle this
551 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
552 flag |= getStatus(fr);
554 enable = flag.enabled();
558 case LFUN_DIALOG_TOGGLE:
559 flag.setOnOff(lyx_view_->getDialogs().visible(cmd.getArg(0)));
560 // fall through to set "enable"
561 case LFUN_DIALOG_SHOW: {
562 string const name = cmd.getArg(0);
564 enable = name == "aboutlyx"
565 || name == "file" //FIXME: should be removed.
567 || name == "texinfo";
568 else if (name == "print")
569 enable = Exporter::isExportable(*buf, "dvi")
570 && lyxrc.print_command != "none";
571 else if (name == "character")
572 enable = cur.inset().lyxCode() != Inset::ERT_CODE &&
573 cur.inset().lyxCode() != Inset::LISTINGS_CODE;
574 else if (name == "latexlog")
575 enable = isFileReadable(FileName(buf->getLogName().second));
576 else if (name == "spellchecker")
577 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
578 enable = !buf->isReadonly();
582 else if (name == "vclog")
583 enable = buf->lyxvc().inUse();
587 case LFUN_DIALOG_SHOW_NEW_INSET:
588 enable = cur.inset().lyxCode() != Inset::ERT_CODE &&
589 cur.inset().lyxCode() != Inset::LISTINGS_CODE;
590 if (cur.inset().lyxCode() == Inset::CAPTION_CODE) {
592 if (cur.inset().getStatus(cur, cmd, flag))
597 case LFUN_DIALOG_UPDATE: {
598 string const name = cmd.getArg(0);
600 enable = name == "prefs";
604 case LFUN_CITATION_INSERT: {
605 FuncRequest fr(LFUN_INSET_INSERT, "citation");
606 enable = getStatus(fr).enabled();
610 case LFUN_BUFFER_WRITE: {
611 enable = view()->buffer()->isUnnamed()
612 || !view()->buffer()->isClean();
617 case LFUN_BUFFER_WRITE_ALL: {
618 // We enable the command only if there are some modified buffers
619 Buffer * first = theBufferList().first();
620 bool modified = false;
624 // We cannot use a for loop as the buffer list is a cycle.
630 b = theBufferList().next(b);
631 } while (b != first);
639 case LFUN_BOOKMARK_GOTO: {
640 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
641 enable = LyX::ref().session().bookmarks().isValid(num);
645 case LFUN_BOOKMARK_CLEAR:
646 enable = LyX::ref().session().bookmarks().size() > 0;
649 case LFUN_TOOLBAR_TOGGLE: {
650 bool const current = lyx_view_->getToolbars().visible(cmd.getArg(0));
651 flag.setOnOff(current);
654 case LFUN_WINDOW_CLOSE: {
655 enable = (theApp()->gui().viewIds().size() > 1);
659 // this one is difficult to get right. As a half-baked
660 // solution, we consider only the first action of the sequence
661 case LFUN_COMMAND_SEQUENCE: {
662 // argument contains ';'-terminated commands
663 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
664 FuncRequest func(lyxaction.lookupFunc(firstcmd));
665 func.origin = cmd.origin;
666 flag = getStatus(func);
669 case LFUN_BUFFER_NEW:
670 case LFUN_BUFFER_NEW_TEMPLATE:
671 case LFUN_WORD_FIND_FORWARD:
672 case LFUN_WORD_FIND_BACKWARD:
673 case LFUN_COMMAND_PREFIX:
674 case LFUN_COMMAND_EXECUTE:
676 case LFUN_META_PREFIX:
677 case LFUN_BUFFER_CLOSE:
678 case LFUN_BUFFER_WRITE_AS:
679 case LFUN_BUFFER_UPDATE:
680 case LFUN_BUFFER_VIEW:
681 case LFUN_BUFFER_IMPORT:
682 case LFUN_BUFFER_AUTO_SAVE:
683 case LFUN_RECONFIGURE:
687 case LFUN_DROP_LAYOUTS_CHOICE:
689 case LFUN_SERVER_GET_NAME:
690 case LFUN_SERVER_NOTIFY:
691 case LFUN_SERVER_GOTO_FILE_ROW:
692 case LFUN_DIALOG_HIDE:
693 case LFUN_DIALOG_DISCONNECT_INSET:
694 case LFUN_BUFFER_CHILD_OPEN:
695 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
696 case LFUN_KEYMAP_OFF:
697 case LFUN_KEYMAP_PRIMARY:
698 case LFUN_KEYMAP_SECONDARY:
699 case LFUN_KEYMAP_TOGGLE:
701 case LFUN_BUFFER_EXPORT_CUSTOM:
702 case LFUN_BUFFER_PRINT:
703 case LFUN_PREFERENCES_SAVE:
704 case LFUN_SCREEN_FONT_UPDATE:
707 case LFUN_EXTERNAL_EDIT:
708 case LFUN_GRAPHICS_EDIT:
709 case LFUN_ALL_INSETS_TOGGLE:
710 case LFUN_BUFFER_LANGUAGE:
711 case LFUN_TEXTCLASS_APPLY:
712 case LFUN_TEXTCLASS_LOAD:
713 case LFUN_BUFFER_SAVE_AS_DEFAULT:
714 case LFUN_BUFFER_PARAMS_APPLY:
715 case LFUN_LYXRC_APPLY:
716 case LFUN_BUFFER_NEXT:
717 case LFUN_BUFFER_PREVIOUS:
718 case LFUN_WINDOW_NEW:
720 // these are handled in our dispatch()
724 if (!getLocalStatus(cur, cmd, flag))
725 flag = view()->getStatus(cmd);
731 // Can we use a readonly buffer?
732 if (buf && buf->isReadonly()
733 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
734 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
735 flag.message(from_utf8(N_("Document is read-only")));
739 // Are we in a DELETED change-tracking region?
740 if (buf && lookupChangeType(cur, true) == Change::DELETED
741 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
742 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
743 flag.message(from_utf8(N_("This portion of the document is deleted.")));
747 // the default error message if we disable the command
748 if (!flag.enabled() && flag.message().empty())
749 flag.message(from_utf8(N_("Command disabled")));
755 bool LyXFunc::ensureBufferClean(BufferView * bv)
757 Buffer & buf = *bv->buffer();
761 docstring const file = makeDisplayPath(buf.fileName(), 30);
762 docstring text = bformat(_("The document %1$s has unsaved "
763 "changes.\n\nDo you want to save "
764 "the document?"), file);
765 int const ret = Alert::prompt(_("Save changed document?"),
766 text, 0, 1, _("&Save"),
770 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
772 return buf.isClean();
778 void showPrintError(string const & name)
780 docstring str = bformat(_("Could not print the document %1$s.\n"
781 "Check that your printer is set up correctly."),
782 makeDisplayPath(name, 50));
783 Alert::error(_("Print document failed"), str);
787 void loadTextclass(string const & name)
789 std::pair<bool, textclass_type> const tc_pair =
790 textclasslist.numberOfClass(name);
792 if (!tc_pair.first) {
793 lyxerr << "Document class \"" << name
794 << "\" does not exist."
799 textclass_type const tc = tc_pair.second;
801 if (!textclasslist[tc].load()) {
802 docstring s = bformat(_("The document could not be converted\n"
803 "into the document class %1$s."),
804 from_utf8(textclasslist[tc].name()));
805 Alert::error(_("Could not change class"), s);
810 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
815 void LyXFunc::dispatch(FuncRequest const & cmd)
817 string const argument = to_utf8(cmd.argument());
818 kb_action const action = cmd.action;
820 LYXERR(Debug::ACTION) << endl << "LyXFunc::dispatch: cmd: " << cmd << endl;
821 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
823 // we have not done anything wrong yet.
825 dispatch_buffer.erase();
827 // redraw the screen at the end (first of the two drawing steps).
828 //This is done unless explicitely requested otherwise
829 Update::flags updateFlags = Update::FitCursor;
831 FuncStatus const flag = getStatus(cmd);
832 if (!flag.enabled()) {
833 // We cannot use this function here
834 LYXERR(Debug::ACTION) << "LyXFunc::dispatch: "
835 << lyxaction.getActionName(action)
836 << " [" << action << "] is disabled at this location"
838 setErrorMessage(flag.message());
842 case LFUN_WORD_FIND_FORWARD:
843 case LFUN_WORD_FIND_BACKWARD: {
844 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
845 static docstring last_search;
846 docstring searched_string;
848 if (!cmd.argument().empty()) {
849 last_search = cmd.argument();
850 searched_string = cmd.argument();
852 searched_string = last_search;
855 if (searched_string.empty())
858 bool const fw = action == LFUN_WORD_FIND_FORWARD;
859 docstring const data =
860 find2string(searched_string, true, false, fw);
861 find(view(), FuncRequest(LFUN_WORD_FIND, data));
865 case LFUN_COMMAND_PREFIX:
866 BOOST_ASSERT(lyx_view_);
867 lyx_view_->message(keyseq->printOptions(true));
870 case LFUN_COMMAND_EXECUTE:
871 BOOST_ASSERT(lyx_view_);
872 lyx_view_->getToolbars().display("minibuffer", true);
873 lyx_view_->focus_command_buffer();
877 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
879 meta_fake_bit = key_modifier::none;
880 if (view()->buffer())
881 // cancel any selection
882 dispatch(FuncRequest(LFUN_MARK_OFF));
883 setMessage(from_ascii(N_("Cancel")));
886 case LFUN_META_PREFIX:
887 meta_fake_bit = key_modifier::alt;
888 setMessage(keyseq->print(true));
891 case LFUN_BUFFER_TOGGLE_READ_ONLY:
892 BOOST_ASSERT(lyx_view_ && lyx_view_->view() && lyx_view_->buffer());
893 if (lyx_view_->buffer()->lyxvc().inUse())
894 lyx_view_->buffer()->lyxvc().toggleReadOnly();
896 lyx_view_->buffer()->setReadonly(
897 !lyx_view_->buffer()->isReadonly());
900 // --- Menus -----------------------------------------------
901 case LFUN_BUFFER_NEW:
902 menuNew(argument, false);
905 case LFUN_BUFFER_NEW_TEMPLATE:
906 menuNew(argument, true);
909 case LFUN_BUFFER_CLOSE:
914 case LFUN_BUFFER_WRITE:
915 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
916 if (!lyx_view_->buffer()->isUnnamed()) {
917 docstring const str = bformat(_("Saving document %1$s..."),
918 makeDisplayPath(lyx_view_->buffer()->fileName()));
919 lyx_view_->message(str);
920 menuWrite(lyx_view_->buffer());
921 lyx_view_->message(str + _(" done."));
923 writeAs(lyx_view_->buffer());
925 updateFlags = Update::None;
928 case LFUN_BUFFER_WRITE_AS:
929 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
930 writeAs(lyx_view_->buffer(), argument);
931 updateFlags = Update::None;
934 case LFUN_BUFFER_WRITE_ALL: {
935 Buffer * first = theBufferList().first();
938 lyx_view_->message(_("Saving all documents..."));
940 // We cannot use a for loop as the buffer list cycles.
943 if (!b->isUnnamed()) {
945 lyxerr[Debug::ACTION] << "Saved " << b->fileName() << endl;
949 b = theBufferList().next(b);
950 } while (b != first);
951 lyx_view_->message(_("All documents saved."));
954 updateFlags = Update::None;
958 case LFUN_BUFFER_RELOAD: {
959 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
960 docstring const file = makeDisplayPath(view()->buffer()->fileName(), 20);
961 docstring text = bformat(_("Any changes will be lost. Are you sure "
962 "you want to revert to the saved version of the document %1$s?"), file);
963 int const ret = Alert::prompt(_("Revert to saved document?"),
964 text, 1, 1, _("&Revert"), _("&Cancel"));
971 case LFUN_BUFFER_UPDATE:
972 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
973 Exporter::Export(lyx_view_->buffer(), argument, true);
976 case LFUN_BUFFER_VIEW:
977 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
978 Exporter::preview(lyx_view_->buffer(), argument);
981 case LFUN_BUILD_PROGRAM:
982 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
983 Exporter::Export(lyx_view_->buffer(), "program", true);
986 case LFUN_BUFFER_CHKTEX:
987 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
988 lyx_view_->buffer()->runChktex();
991 case LFUN_BUFFER_EXPORT:
992 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
993 if (argument == "custom")
994 lyx_view_->getDialogs().show("sendto");
996 Exporter::Export(lyx_view_->buffer(), argument, false);
1000 case LFUN_BUFFER_EXPORT_CUSTOM: {
1001 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1003 string command = split(argument, format_name, ' ');
1004 Format const * format = formats.getFormat(format_name);
1006 lyxerr << "Format \"" << format_name
1007 << "\" not recognized!"
1012 Buffer * buffer = lyx_view_->buffer();
1014 // The name of the file created by the conversion process
1017 // Output to filename
1018 if (format->name() == "lyx") {
1019 string const latexname =
1020 buffer->getLatexName(false);
1021 filename = changeExtension(latexname,
1022 format->extension());
1023 filename = addName(buffer->temppath(), filename);
1025 if (!buffer->writeFile(FileName(filename)))
1029 Exporter::Export(buffer, format_name, true, filename);
1032 // Substitute $$FName for filename
1033 if (!contains(command, "$$FName"))
1034 command = "( " + command + " ) < $$FName";
1035 command = subst(command, "$$FName", filename);
1037 // Execute the command in the background
1039 call.startscript(Systemcall::DontWait, command);
1043 case LFUN_BUFFER_PRINT: {
1044 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1045 // FIXME: cmd.getArg() might fail if one of the arguments
1046 // contains double quotes
1047 string target = cmd.getArg(0);
1048 string target_name = cmd.getArg(1);
1049 string command = cmd.getArg(2);
1052 || target_name.empty()
1053 || command.empty()) {
1054 lyxerr << "Unable to parse \""
1055 << argument << '"' << endl;
1058 if (target != "printer" && target != "file") {
1059 lyxerr << "Unrecognized target \""
1060 << target << '"' << endl;
1064 Buffer * buffer = lyx_view_->buffer();
1066 if (!Exporter::Export(buffer, "dvi", true)) {
1067 showPrintError(buffer->fileName());
1071 // Push directory path.
1072 string const path(buffer->temppath());
1073 // Prevent the compiler from optimizing away p
1075 support::Path p(pp);
1077 // there are three cases here:
1078 // 1. we print to a file
1079 // 2. we print directly to a printer
1080 // 3. we print using a spool command (print to file first)
1083 string const dviname =
1084 changeExtension(buffer->getLatexName(true),
1087 if (target == "printer") {
1088 if (!lyxrc.print_spool_command.empty()) {
1089 // case 3: print using a spool
1090 string const psname =
1091 changeExtension(dviname,".ps");
1092 command += ' ' + lyxrc.print_to_file
1095 + quoteName(dviname);
1098 lyxrc.print_spool_command + ' ';
1099 if (target_name != "default") {
1100 command2 += lyxrc.print_spool_printerprefix
1104 command2 += quoteName(psname);
1106 // If successful, then spool command
1107 res = one.startscript(
1112 res = one.startscript(
1113 Systemcall::DontWait,
1116 // case 2: print directly to a printer
1117 if (target_name != "default")
1118 command += ' ' + lyxrc.print_to_printer + target_name + ' ';
1119 res = one.startscript(
1120 Systemcall::DontWait,
1121 command + quoteName(dviname));
1125 // case 1: print to a file
1126 FileName const filename(makeAbsPath(target_name,
1127 lyx_view_->buffer()->filePath()));
1128 FileName const dvifile(makeAbsPath(dviname, path));
1129 if (fs::exists(filename.toFilesystemEncoding())) {
1130 docstring text = bformat(
1131 _("The file %1$s already exists.\n\n"
1132 "Do you want to overwrite that file?"),
1133 makeDisplayPath(filename.absFilename()));
1134 if (Alert::prompt(_("Overwrite file?"),
1135 text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
1138 command += ' ' + lyxrc.print_to_file
1139 + quoteName(filename.toFilesystemEncoding())
1141 + quoteName(dvifile.toFilesystemEncoding());
1142 res = one.startscript(Systemcall::DontWait,
1147 showPrintError(buffer->fileName());
1151 case LFUN_BUFFER_IMPORT:
1156 // quitting is triggered by the gui code
1157 // (leaving the event loop).
1158 lyx_view_->message(from_utf8(N_("Exiting.")));
1159 if (theBufferList().quitWriteAll())
1160 theApp()->gui().closeAllViews();
1163 case LFUN_BUFFER_AUTO_SAVE:
1167 case LFUN_RECONFIGURE:
1168 BOOST_ASSERT(lyx_view_);
1169 reconfigure(*lyx_view_);
1172 case LFUN_HELP_OPEN: {
1173 BOOST_ASSERT(lyx_view_);
1174 string const arg = argument;
1176 setErrorMessage(from_ascii(N_("Missing argument")));
1179 FileName const fname = i18nLibFileSearch("doc", arg, "lyx");
1180 if (fname.empty()) {
1181 lyxerr << "LyX: unable to find documentation file `"
1182 << arg << "'. Bad installation?" << endl;
1185 lyx_view_->message(bformat(_("Opening help file %1$s..."),
1186 makeDisplayPath(fname.absFilename())));
1187 lyx_view_->loadLyXFile(fname, false);
1191 // --- version control -------------------------------
1192 case LFUN_VC_REGISTER:
1193 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1194 if (!ensureBufferClean(view()))
1196 if (!lyx_view_->buffer()->lyxvc().inUse()) {
1197 lyx_view_->buffer()->lyxvc().registrer();
1200 updateFlags = Update::Force;
1203 case LFUN_VC_CHECK_IN:
1204 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1205 if (!ensureBufferClean(view()))
1207 if (lyx_view_->buffer()->lyxvc().inUse()
1208 && !lyx_view_->buffer()->isReadonly()) {
1209 lyx_view_->buffer()->lyxvc().checkIn();
1214 case LFUN_VC_CHECK_OUT:
1215 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1216 if (!ensureBufferClean(view()))
1218 if (lyx_view_->buffer()->lyxvc().inUse()
1219 && lyx_view_->buffer()->isReadonly()) {
1220 lyx_view_->buffer()->lyxvc().checkOut();
1225 case LFUN_VC_REVERT:
1226 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1227 lyx_view_->buffer()->lyxvc().revert();
1231 case LFUN_VC_UNDO_LAST:
1232 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1233 lyx_view_->buffer()->lyxvc().undoLast();
1237 // --- buffers ----------------------------------------
1238 case LFUN_BUFFER_SWITCH:
1239 BOOST_ASSERT(lyx_view_);
1240 lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1241 updateFlags = Update::Force;
1244 case LFUN_BUFFER_NEXT:
1245 BOOST_ASSERT(lyx_view_);
1246 lyx_view_->setBuffer(theBufferList().next(view()->buffer()));
1247 updateFlags = Update::Force;
1250 case LFUN_BUFFER_PREVIOUS:
1251 BOOST_ASSERT(lyx_view_);
1252 lyx_view_->setBuffer(theBufferList().previous(view()->buffer()));
1253 updateFlags = Update::Force;
1257 BOOST_ASSERT(lyx_view_);
1258 newFile(view(), argument);
1261 case LFUN_FILE_OPEN:
1262 BOOST_ASSERT(lyx_view_);
1266 case LFUN_DROP_LAYOUTS_CHOICE:
1267 BOOST_ASSERT(lyx_view_);
1268 lyx_view_->getToolbars().openLayoutList();
1271 case LFUN_MENU_OPEN:
1272 BOOST_ASSERT(lyx_view_);
1273 lyx_view_->getMenubar().openByName(from_utf8(argument));
1276 // --- lyxserver commands ----------------------------
1277 case LFUN_SERVER_GET_NAME:
1278 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1279 setMessage(from_utf8(lyx_view_->buffer()->fileName()));
1280 LYXERR(Debug::INFO) << "FNAME["
1281 << lyx_view_->buffer()->fileName()
1285 case LFUN_SERVER_NOTIFY:
1286 dispatch_buffer = keyseq->print(false);
1287 theServer().notifyClient(to_utf8(dispatch_buffer));
1290 case LFUN_SERVER_GOTO_FILE_ROW: {
1291 BOOST_ASSERT(lyx_view_);
1294 istringstream is(argument);
1295 is >> file_name >> row;
1296 if (prefixIs(file_name, package().temp_dir().absFilename())) {
1297 // Needed by inverse dvi search. If it is a file
1298 // in tmpdir, call the apropriated function
1299 lyx_view_->setBuffer(theBufferList().getBufferFromTmp(file_name));
1301 // Must replace extension of the file to be .lyx
1302 // and get full path
1303 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1304 // Either change buffer or load the file
1305 if (theBufferList().exists(s.absFilename())) {
1306 lyx_view_->setBuffer(theBufferList().getBuffer(s.absFilename()));
1308 lyx_view_->loadLyXFile(s);
1312 view()->setCursorFromRow(row);
1314 updateFlags = Update::FitCursor;
1318 case LFUN_DIALOG_SHOW: {
1319 BOOST_ASSERT(lyx_view_);
1320 string const name = cmd.getArg(0);
1321 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1323 if (name == "character") {
1324 data = freefont2string();
1326 lyx_view_->getDialogs().show("character", data);
1327 } else if (name == "latexlog") {
1328 pair<Buffer::LogType, string> const logfile =
1329 lyx_view_->buffer()->getLogName();
1330 switch (logfile.first) {
1331 case Buffer::latexlog:
1334 case Buffer::buildlog:
1338 data += Lexer::quoteString(logfile.second);
1339 lyx_view_->getDialogs().show("log", data);
1340 } else if (name == "vclog") {
1341 string const data = "vc " +
1342 Lexer::quoteString(lyx_view_->buffer()->lyxvc().getLogFile());
1343 lyx_view_->getDialogs().show("log", data);
1345 lyx_view_->getDialogs().show(name, data);
1349 case LFUN_DIALOG_SHOW_NEW_INSET: {
1350 BOOST_ASSERT(lyx_view_);
1351 string const name = cmd.getArg(0);
1352 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1353 if (name == "bibitem" ||
1357 name == "nomenclature" ||
1361 InsetCommandParams p(name);
1362 data = InsetCommandMailer::params2string(name, p);
1363 } else if (name == "include") {
1364 // data is the include type: one of "include",
1365 // "input", "verbatiminput" or "verbatiminput*"
1367 // default type is requested
1369 InsetCommandParams p(data);
1370 data = InsetIncludeMailer::params2string(p);
1371 } else if (name == "box") {
1372 // \c data == "Boxed" || "Frameless" etc
1373 InsetBoxParams p(data);
1374 data = InsetBoxMailer::params2string(p);
1375 } else if (name == "branch") {
1376 InsetBranchParams p;
1377 data = InsetBranchMailer::params2string(p);
1378 } else if (name == "citation") {
1379 InsetCommandParams p("cite");
1380 data = InsetCommandMailer::params2string(name, p);
1381 } else if (name == "ert") {
1382 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1383 } else if (name == "external") {
1384 InsetExternalParams p;
1385 Buffer const & buffer = *lyx_view_->buffer();
1386 data = InsetExternalMailer::params2string(p, buffer);
1387 } else if (name == "float") {
1389 data = InsetFloatMailer::params2string(p);
1390 } else if (name == "listings") {
1391 InsetListingsParams p;
1392 data = InsetListingsMailer::params2string(p);
1393 } else if (name == "graphics") {
1394 InsetGraphicsParams p;
1395 Buffer const & buffer = *lyx_view_->buffer();
1396 data = InsetGraphicsMailer::params2string(p, buffer);
1397 } else if (name == "note") {
1399 data = InsetNoteMailer::params2string(p);
1400 } else if (name == "vspace") {
1402 data = InsetVSpaceMailer::params2string(space);
1403 } else if (name == "wrap") {
1405 data = InsetWrapMailer::params2string(p);
1407 lyx_view_->getDialogs().show(name, data, 0);
1411 case LFUN_DIALOG_UPDATE: {
1412 BOOST_ASSERT(lyx_view_);
1413 string const & name = argument;
1414 // Can only update a dialog connected to an existing inset
1415 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1417 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1418 inset->dispatch(view()->cursor(), fr);
1419 } else if (name == "paragraph") {
1420 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1421 } else if (name == "prefs") {
1422 lyx_view_->getDialogs().update(name, string());
1427 case LFUN_DIALOG_HIDE:
1428 LyX::cref().hideDialogs(argument, 0);
1431 case LFUN_DIALOG_TOGGLE: {
1432 BOOST_ASSERT(lyx_view_);
1433 if (lyx_view_->getDialogs().visible(cmd.getArg(0)))
1434 dispatch(FuncRequest(LFUN_DIALOG_HIDE, argument));
1436 dispatch(FuncRequest(LFUN_DIALOG_SHOW, argument));
1440 case LFUN_DIALOG_DISCONNECT_INSET:
1441 BOOST_ASSERT(lyx_view_);
1442 lyx_view_->getDialogs().disconnect(argument);
1446 case LFUN_CITATION_INSERT: {
1447 BOOST_ASSERT(lyx_view_);
1448 if (!argument.empty()) {
1449 // we can have one optional argument, delimited by '|'
1450 // citation-insert <key>|<text_before>
1451 // this should be enhanced to also support text_after
1452 // and citation style
1453 string arg = argument;
1455 if (contains(argument, "|")) {
1456 arg = token(argument, '|', 0);
1457 opt1 = token(argument, '|', 1);
1459 InsetCommandParams icp("cite");
1460 icp["key"] = from_utf8(arg);
1462 icp["before"] = from_utf8(opt1);
1463 string icstr = InsetCommandMailer::params2string("citation", icp);
1464 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1467 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1471 case LFUN_BUFFER_CHILD_OPEN: {
1472 // takes an optional argument, "|bool", at the end
1473 // indicating whether this file is being opened automatically
1474 // by LyX itself, in which case we will not want to switch
1475 // buffers after opening. The default is false, so in practice
1476 // it is used only when true.
1477 BOOST_ASSERT(lyx_view_);
1478 int const arglength = argument.length();
1480 bool autoOpen = false;
1481 if (argument.substr(arglength - 5, 5) == "|true") {
1483 filename = makeAbsPath(argument.substr(0, arglength - 5),
1484 lyx_view_->buffer()->filePath());
1485 } else if (argument.substr(arglength - 6, 6) == "|false") {
1486 filename = makeAbsPath(argument.substr(0, arglength - 6),
1487 lyx_view_->buffer()->filePath());
1489 makeAbsPath(argument, lyx_view_->buffer()->filePath());
1490 view()->saveBookmark(false);
1491 if (theBufferList().exists(filename.absFilename())) {
1492 Buffer * buf = theBufferList().getBuffer(filename.absFilename());
1494 lyx_view_->setBuffer(buf, true);
1496 buf->setParentName(lyx_view_->buffer()->fileName());
1498 lyx_view_->loadLyXFile(filename, true, true, autoOpen);
1500 // If a screen update is required (in case where auto_open is false),
1501 // loadLyXFile() would have taken care of it already. Otherwise we shall
1502 // reset the update flag because it can cause a circular problem.
1504 updateFlags = Update::None;
1508 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1509 BOOST_ASSERT(lyx_view_);
1510 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1513 case LFUN_KEYMAP_OFF:
1514 BOOST_ASSERT(lyx_view_);
1515 lyx_view_->view()->getIntl().keyMapOn(false);
1518 case LFUN_KEYMAP_PRIMARY:
1519 BOOST_ASSERT(lyx_view_);
1520 lyx_view_->view()->getIntl().keyMapPrim();
1523 case LFUN_KEYMAP_SECONDARY:
1524 BOOST_ASSERT(lyx_view_);
1525 lyx_view_->view()->getIntl().keyMapSec();
1528 case LFUN_KEYMAP_TOGGLE:
1529 BOOST_ASSERT(lyx_view_);
1530 lyx_view_->view()->getIntl().toggleKeyMap();
1536 string rest = split(argument, countstr, ' ');
1537 istringstream is(countstr);
1540 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1541 for (int i = 0; i < count; ++i)
1542 dispatch(lyxaction.lookupFunc(rest));
1546 case LFUN_COMMAND_SEQUENCE: {
1547 // argument contains ';'-terminated commands
1548 string arg = argument;
1549 while (!arg.empty()) {
1551 arg = split(arg, first, ';');
1552 FuncRequest func(lyxaction.lookupFunc(first));
1553 func.origin = cmd.origin;
1559 case LFUN_PREFERENCES_SAVE: {
1560 lyxrc.write(makeAbsPath("preferences",
1561 package().user_support().absFilename()),
1566 case LFUN_SCREEN_FONT_UPDATE:
1567 BOOST_ASSERT(lyx_view_);
1568 // handle the screen font changes.
1569 theFontLoader().update();
1570 /// FIXME: only the current view will be updated. the Gui
1571 /// class is able to furnish the list of views.
1572 updateFlags = Update::Force;
1575 case LFUN_SET_COLOR: {
1577 string const x11_name = split(argument, lyx_name, ' ');
1578 if (lyx_name.empty() || x11_name.empty()) {
1579 setErrorMessage(from_ascii(N_(
1580 "Syntax: set-color <lyx_name>"
1585 bool const graphicsbg_changed =
1586 (lyx_name == lcolor.getLyXName(Color::graphicsbg) &&
1587 x11_name != lcolor.getX11Name(Color::graphicsbg));
1589 if (!lcolor.setColor(lyx_name, x11_name)) {
1591 bformat(_("Set-color \"%1$s\" failed "
1592 "- color is undefined or "
1593 "may not be redefined"),
1594 from_utf8(lyx_name)));
1598 theApp()->updateColor(lcolor.getFromLyXName(lyx_name));
1600 if (graphicsbg_changed) {
1601 // FIXME: The graphics cache no longer has a changeDisplay method.
1603 graphics::GCache::get().changeDisplay(true);
1610 BOOST_ASSERT(lyx_view_);
1611 lyx_view_->message(from_utf8(argument));
1614 case LFUN_EXTERNAL_EDIT: {
1615 BOOST_ASSERT(lyx_view_);
1616 FuncRequest fr(action, argument);
1617 InsetExternal().dispatch(view()->cursor(), fr);
1621 case LFUN_GRAPHICS_EDIT: {
1622 FuncRequest fr(action, argument);
1623 InsetGraphics().dispatch(view()->cursor(), fr);
1627 case LFUN_INSET_APPLY: {
1628 BOOST_ASSERT(lyx_view_);
1629 string const name = cmd.getArg(0);
1630 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1632 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1633 inset->dispatch(view()->cursor(), fr);
1635 FuncRequest fr(LFUN_INSET_INSERT, argument);
1638 // ideally, the update flag should be set by the insets,
1639 // but this is not possible currently
1640 updateFlags = Update::Force | Update::FitCursor;
1644 case LFUN_ALL_INSETS_TOGGLE: {
1645 BOOST_ASSERT(lyx_view_);
1647 string const name = split(argument, action, ' ');
1648 Inset::Code const inset_code =
1649 Inset::translate(name);
1651 Cursor & cur = view()->cursor();
1652 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1654 Inset & inset = lyx_view_->buffer()->inset();
1655 InsetIterator it = inset_iterator_begin(inset);
1656 InsetIterator const end = inset_iterator_end(inset);
1657 for (; it != end; ++it) {
1658 if (!it->asInsetMath()
1659 && (inset_code == Inset::NO_CODE
1660 || inset_code == it->lyxCode())) {
1661 Cursor tmpcur = cur;
1662 tmpcur.pushLeft(*it);
1663 it->dispatch(tmpcur, fr);
1666 updateFlags = Update::Force | Update::FitCursor;
1670 case LFUN_BUFFER_LANGUAGE: {
1671 BOOST_ASSERT(lyx_view_);
1672 Buffer & buffer = *lyx_view_->buffer();
1673 Language const * oldL = buffer.params().language;
1674 Language const * newL = languages.getLanguage(argument);
1675 if (!newL || oldL == newL)
1678 if (oldL->rightToLeft() == newL->rightToLeft()
1679 && !buffer.isMultiLingual())
1680 buffer.changeLanguage(oldL, newL);
1684 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1685 string const fname =
1686 addName(addPath(package().user_support().absFilename(), "templates/"),
1688 Buffer defaults(fname);
1690 istringstream ss(argument);
1693 int const unknown_tokens = defaults.readHeader(lex);
1695 if (unknown_tokens != 0) {
1696 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1697 << unknown_tokens << " unknown token"
1698 << (unknown_tokens == 1 ? "" : "s")
1702 if (defaults.writeFile(FileName(defaults.fileName())))
1703 setMessage(bformat(_("Document defaults saved in %1$s"),
1704 makeDisplayPath(fname)));
1706 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1710 case LFUN_BUFFER_PARAMS_APPLY: {
1711 BOOST_ASSERT(lyx_view_);
1712 biblio::CiteEngine const engine =
1713 lyx_view_->buffer()->params().getEngine();
1715 istringstream ss(argument);
1718 int const unknown_tokens =
1719 lyx_view_->buffer()->readHeader(lex);
1721 if (unknown_tokens != 0) {
1722 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1723 << unknown_tokens << " unknown token"
1724 << (unknown_tokens == 1 ? "" : "s")
1727 if (engine == lyx_view_->buffer()->params().getEngine())
1730 Cursor & cur = view()->cursor();
1731 FuncRequest fr(LFUN_INSET_REFRESH);
1733 Inset & inset = lyx_view_->buffer()->inset();
1734 InsetIterator it = inset_iterator_begin(inset);
1735 InsetIterator const end = inset_iterator_end(inset);
1736 for (; it != end; ++it)
1737 if (it->lyxCode() == Inset::CITE_CODE)
1738 it->dispatch(cur, fr);
1742 case LFUN_TEXTCLASS_APPLY: {
1743 BOOST_ASSERT(lyx_view_);
1744 Buffer * buffer = lyx_view_->buffer();
1746 textclass_type const old_class =
1747 buffer->params().textclass;
1749 loadTextclass(argument);
1751 std::pair<bool, textclass_type> const tc_pair =
1752 textclasslist.numberOfClass(argument);
1757 textclass_type const new_class = tc_pair.second;
1758 if (old_class == new_class)
1762 lyx_view_->message(_("Converting document to new document class..."));
1763 recordUndoFullDocument(view());
1764 buffer->params().textclass = new_class;
1765 StableDocIterator backcur(view()->cursor());
1766 ErrorList & el = buffer->errorList("Class Switch");
1767 cap::switchBetweenClasses(
1768 old_class, new_class,
1769 static_cast<InsetText &>(buffer->inset()), el);
1771 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
1773 buffer->errors("Class Switch");
1774 updateLabels(*buffer);
1775 updateFlags = Update::Force | Update::FitCursor;
1779 case LFUN_TEXTCLASS_LOAD:
1780 loadTextclass(argument);
1783 case LFUN_LYXRC_APPLY: {
1784 LyXRC const lyxrc_orig = lyxrc;
1786 istringstream ss(argument);
1787 bool const success = lyxrc.read(ss) == 0;
1790 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1791 << "Unable to read lyxrc data"
1796 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1798 /// We force the redraw in any case because there might be
1799 /// some screen font changes.
1800 /// FIXME: only the current view will be updated. the Gui
1801 /// class is able to furnish the list of views.
1802 updateFlags = Update::Force;
1806 case LFUN_WINDOW_NEW:
1807 LyX::ref().newLyXView();
1810 case LFUN_WINDOW_CLOSE:
1811 BOOST_ASSERT(lyx_view_);
1812 BOOST_ASSERT(theApp());
1813 // update bookmark pit of the current buffer before window close
1814 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1815 gotoBookmark(i+1, false, false);
1816 // ask the user for saving changes or cancel quit
1817 if (!theBufferList().quitWriteAll())
1822 case LFUN_BOOKMARK_GOTO:
1823 // go to bookmark, open unopened file and switch to buffer if necessary
1824 gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
1827 case LFUN_BOOKMARK_CLEAR:
1828 LyX::ref().session().bookmarks().clear();
1831 case LFUN_TOOLBAR_TOGGLE: {
1832 BOOST_ASSERT(lyx_view_);
1833 string const name = cmd.getArg(0);
1834 bool const allowauto = cmd.getArg(1) == "allowauto";
1835 lyx_view_->toggleToolbarState(name, allowauto);
1836 ToolbarInfo * tbi = lyx_view_->getToolbarInfo(name);
1838 setMessage(bformat(_("Unknown toolbar \"%1$s\""),
1843 if (tbi->flags & ToolbarInfo::ON)
1845 else if (tbi->flags & ToolbarInfo::OFF)
1847 else if (tbi->flags & ToolbarInfo::AUTO)
1850 setMessage(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1851 _(tbi->gui_name), state));
1856 BOOST_ASSERT(lyx_view_);
1857 view()->cursor().dispatch(cmd);
1858 updateFlags = view()->cursor().result().update();
1859 if (!view()->cursor().result().dispatched())
1860 updateFlags = view()->dispatch(cmd);
1865 if (lyx_view_ && view()->buffer()) {
1866 // BufferView::update() updates the ViewMetricsInfo and
1867 // also initializes the position cache for all insets in
1868 // (at least partially) visible top-level paragraphs.
1869 // We will redraw the screen only if needed.
1870 if (view()->update(updateFlags)) {
1871 // Buffer::changed() signals that a repaint is needed.
1872 // The frontend (WorkArea) knows which area to repaint
1873 // thanks to the ViewMetricsInfo updated above.
1874 view()->buffer()->changed();
1877 lyx_view_->updateStatusBar();
1879 // if we executed a mutating lfun, mark the buffer as dirty
1881 && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
1882 && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
1883 view()->buffer()->markDirty();
1885 //Do we have a selection?
1886 theSelection().haveSelection(view()->cursor().selection());
1888 if (view()->cursor().inTexted()) {
1889 lyx_view_->updateLayoutChoice();
1893 if (!quitting && lyx_view_) {
1894 lyx_view_->updateMenubar();
1895 lyx_view_->updateToolbars();
1896 // Some messages may already be translated, so we cannot use _()
1897 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
1902 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
1904 const bool verbose = (cmd.origin == FuncRequest::MENU
1905 || cmd.origin == FuncRequest::TOOLBAR
1906 || cmd.origin == FuncRequest::COMMANDBUFFER);
1908 if (cmd.action == LFUN_SELF_INSERT || !verbose) {
1909 LYXERR(Debug::ACTION) << "dispatch msg is " << to_utf8(msg) << endl;
1911 lyx_view_->message(msg);
1915 docstring dispatch_msg = msg;
1916 if (!dispatch_msg.empty())
1917 dispatch_msg += ' ';
1919 docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
1921 bool argsadded = false;
1923 if (!cmd.argument().empty()) {
1924 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1925 comname += ' ' + cmd.argument();
1930 docstring const shortcuts = theTopLevelKeymap().printbindings(cmd);
1932 if (!shortcuts.empty())
1933 comname += ": " + shortcuts;
1934 else if (!argsadded && !cmd.argument().empty())
1935 comname += ' ' + cmd.argument();
1937 if (!comname.empty()) {
1938 comname = rtrim(comname);
1939 dispatch_msg += '(' + rtrim(comname) + ')';
1942 LYXERR(Debug::ACTION) << "verbose dispatch msg "
1943 << to_utf8(dispatch_msg) << endl;
1944 if (!dispatch_msg.empty())
1945 lyx_view_->message(dispatch_msg);
1949 void LyXFunc::menuNew(string const & name, bool fromTemplate)
1951 // FIXME: initpath is not used. What to do?
1952 string initpath = lyxrc.document_path;
1953 string filename(name);
1955 if (view()->buffer()) {
1956 string const trypath = lyx_view_->buffer()->filePath();
1957 // If directory is writeable, use this as default.
1958 if (isDirWriteable(FileName(trypath)))
1962 static int newfile_number;
1964 if (filename.empty()) {
1965 filename = addName(lyxrc.document_path,
1966 "newfile" + convert<string>(++newfile_number) + ".lyx");
1967 while (theBufferList().exists(filename) ||
1968 fs::is_readable(FileName(filename).toFilesystemEncoding())) {
1970 filename = addName(lyxrc.document_path,
1971 "newfile" + convert<string>(newfile_number) +
1976 // The template stuff
1979 FileDialog fileDlg(_("Select template file"),
1980 LFUN_SELECT_FILE_SYNC,
1981 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
1982 make_pair(_("Templates|#T#t"), from_utf8(lyxrc.template_path)));
1984 FileDialog::Result result =
1985 fileDlg.open(from_utf8(lyxrc.template_path),
1986 FileFilterList(_("LyX Documents (*.lyx)")),
1989 if (result.first == FileDialog::Later)
1991 if (result.second.empty())
1993 templname = to_utf8(result.second);
1996 Buffer * const b = newFile(filename, templname, !name.empty());
1999 lyx_view_->setBuffer(b);
2004 void LyXFunc::open(string const & fname)
2006 string initpath = lyxrc.document_path;
2008 if (view()->buffer()) {
2009 string const trypath = lyx_view_->buffer()->filePath();
2010 // If directory is writeable, use this as default.
2011 if (isDirWriteable(FileName(trypath)))
2017 if (fname.empty()) {
2018 FileDialog fileDlg(_("Select document to open"),
2020 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2021 make_pair(_("Examples|#E#e"), from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2023 FileDialog::Result result =
2024 fileDlg.open(from_utf8(initpath),
2025 FileFilterList(_("LyX Documents (*.lyx)")),
2028 if (result.first == FileDialog::Later)
2031 filename = to_utf8(result.second);
2033 // check selected filename
2034 if (filename.empty()) {
2035 lyx_view_->message(_("Canceled."));
2041 // get absolute path of file and add ".lyx" to the filename if
2043 FileName const fullname = fileSearch(string(), filename, "lyx");
2044 if (!fullname.empty())
2045 filename = fullname.absFilename();
2047 // if the file doesn't exist, let the user create one
2048 if (!fs::exists(fullname.toFilesystemEncoding())) {
2049 // the user specifically chose this name. Believe him.
2050 Buffer * const b = newFile(filename, string(), true);
2052 lyx_view_->setBuffer(b);
2056 docstring const disp_fn = makeDisplayPath(filename);
2057 lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
2060 if (lyx_view_->loadLyXFile(fullname)) {
2061 str2 = bformat(_("Document %1$s opened."), disp_fn);
2063 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2065 lyx_view_->message(str2);
2069 void LyXFunc::doImport(string const & argument)
2072 string filename = split(argument, format, ' ');
2074 LYXERR(Debug::INFO) << "LyXFunc::doImport: " << format
2075 << " file: " << filename << endl;
2077 // need user interaction
2078 if (filename.empty()) {
2079 string initpath = lyxrc.document_path;
2081 if (view()->buffer()) {
2082 string const trypath = lyx_view_->buffer()->filePath();
2083 // If directory is writeable, use this as default.
2084 if (isDirWriteable(FileName(trypath)))
2088 docstring const text = bformat(_("Select %1$s file to import"),
2089 formats.prettyName(format));
2091 FileDialog fileDlg(text,
2093 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2094 make_pair(_("Examples|#E#e"),
2095 from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2097 docstring filter = formats.prettyName(format);
2100 filter += from_utf8(formats.extension(format));
2103 FileDialog::Result result =
2104 fileDlg.open(from_utf8(initpath),
2105 FileFilterList(filter),
2108 if (result.first == FileDialog::Later)
2111 filename = to_utf8(result.second);
2113 // check selected filename
2114 if (filename.empty())
2115 lyx_view_->message(_("Canceled."));
2118 if (filename.empty())
2121 // get absolute path of file
2122 FileName const fullname(makeAbsPath(filename));
2124 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
2126 // Check if the document already is open
2127 if (use_gui && theBufferList().exists(lyxfile.absFilename())) {
2128 if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) {
2129 lyx_view_->message(_("Canceled."));
2134 // if the file exists already, and we didn't do
2135 // -i lyx thefile.lyx, warn
2136 if (fs::exists(lyxfile.toFilesystemEncoding()) && fullname != lyxfile) {
2137 docstring const file = makeDisplayPath(lyxfile.absFilename(), 30);
2139 docstring text = bformat(_("The document %1$s already exists.\n\n"
2140 "Do you want to overwrite that document?"), file);
2141 int const ret = Alert::prompt(_("Overwrite document?"),
2142 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2145 lyx_view_->message(_("Canceled."));
2150 ErrorList errorList;
2151 Importer::Import(lyx_view_, fullname, format, errorList);
2152 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2156 void LyXFunc::closeBuffer()
2158 // goto bookmark to update bookmark pit.
2159 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2160 gotoBookmark(i+1, false, false);
2162 theBufferList().close(lyx_view_->buffer(), true);
2166 void LyXFunc::reloadBuffer()
2168 FileName filename(lyx_view_->buffer()->fileName());
2170 lyx_view_->loadLyXFile(filename);
2173 // Each "lyx_view_" should have it's own message method. lyxview and
2174 // the minibuffer would use the minibuffer, but lyxserver would
2175 // send an ERROR signal to its client. Alejandro 970603
2176 // This function is bit problematic when it comes to NLS, to make the
2177 // lyx servers client be language indepenent we must not translate
2178 // strings sent to this func.
2179 void LyXFunc::setErrorMessage(docstring const & m) const
2181 dispatch_buffer = m;
2186 void LyXFunc::setMessage(docstring const & m) const
2188 dispatch_buffer = m;
2192 docstring const LyXFunc::viewStatusMessage()
2194 // When meta-fake key is pressed, show the key sequence so far + "M-".
2196 return keyseq->print(true) + "M-";
2198 // Else, when a non-complete key sequence is pressed,
2199 // show the available options.
2200 if (keyseq->length() > 0 && !keyseq->deleted())
2201 return keyseq->printOptions(true);
2203 if (!view()->buffer())
2204 return _("Welcome to LyX!");
2206 return view()->cursor().currentState();
2210 BufferView * LyXFunc::view() const
2212 BOOST_ASSERT(lyx_view_);
2213 return lyx_view_->view();
2217 bool LyXFunc::wasMetaKey() const
2219 return (meta_fake_bit != key_modifier::none);
2225 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2227 // Why the switch you might ask. It is a trick to ensure that all
2228 // the elements in the LyXRCTags enum is handled. As you can see
2229 // there are no breaks at all. So it is just a huge fall-through.
2230 // The nice thing is that we will get a warning from the compiler
2231 // if we forget an element.
2232 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2234 case LyXRC::RC_ACCEPT_COMPOUND:
2235 case LyXRC::RC_ALT_LANG:
2236 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
2237 case LyXRC::RC_PLAINTEXT_LINELEN:
2238 case LyXRC::RC_AUTOREGIONDELETE:
2239 case LyXRC::RC_AUTORESET_OPTIONS:
2240 case LyXRC::RC_AUTOSAVE:
2241 case LyXRC::RC_AUTO_NUMBER:
2242 case LyXRC::RC_BACKUPDIR_PATH:
2243 case LyXRC::RC_BIBTEX_COMMAND:
2244 case LyXRC::RC_BINDFILE:
2245 case LyXRC::RC_CHECKLASTFILES:
2246 case LyXRC::RC_USELASTFILEPOS:
2247 case LyXRC::RC_LOADSESSION:
2248 case LyXRC::RC_CHKTEX_COMMAND:
2249 case LyXRC::RC_CONVERTER:
2250 case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
2251 case LyXRC::RC_COPIER:
2252 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2253 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2254 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2255 case LyXRC::RC_DATE_INSERT_FORMAT:
2256 case LyXRC::RC_DEFAULT_LANGUAGE:
2257 case LyXRC::RC_DEFAULT_PAPERSIZE:
2258 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2259 case LyXRC::RC_DISPLAY_GRAPHICS:
2260 case LyXRC::RC_DOCUMENTPATH:
2261 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2262 string const encoded = FileName(
2263 lyxrc_new.document_path).toFilesystemEncoding();
2264 if (fs::exists(encoded) && fs::is_directory(encoded))
2265 support::package().document_dir() = FileName(lyxrc.document_path);
2267 case LyXRC::RC_ESC_CHARS:
2268 case LyXRC::RC_FONT_ENCODING:
2269 case LyXRC::RC_FORMAT:
2270 case LyXRC::RC_INDEX_COMMAND:
2271 case LyXRC::RC_INPUT:
2272 case LyXRC::RC_KBMAP:
2273 case LyXRC::RC_KBMAP_PRIMARY:
2274 case LyXRC::RC_KBMAP_SECONDARY:
2275 case LyXRC::RC_LABEL_INIT_LENGTH:
2276 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2277 case LyXRC::RC_LANGUAGE_AUTO_END:
2278 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2279 case LyXRC::RC_LANGUAGE_COMMAND_END:
2280 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2281 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2282 case LyXRC::RC_LANGUAGE_PACKAGE:
2283 case LyXRC::RC_LANGUAGE_USE_BABEL:
2284 case LyXRC::RC_MAKE_BACKUP:
2285 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2286 case LyXRC::RC_NUMLASTFILES:
2287 case LyXRC::RC_PATH_PREFIX:
2288 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2289 support::prependEnvPath("PATH", lyxrc.path_prefix);
2291 case LyXRC::RC_PERS_DICT:
2292 case LyXRC::RC_PREVIEW:
2293 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2294 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2295 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2296 case LyXRC::RC_PRINTCOPIESFLAG:
2297 case LyXRC::RC_PRINTER:
2298 case LyXRC::RC_PRINTEVENPAGEFLAG:
2299 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2300 case LyXRC::RC_PRINTFILEEXTENSION:
2301 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2302 case LyXRC::RC_PRINTODDPAGEFLAG:
2303 case LyXRC::RC_PRINTPAGERANGEFLAG:
2304 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2305 case LyXRC::RC_PRINTPAPERFLAG:
2306 case LyXRC::RC_PRINTREVERSEFLAG:
2307 case LyXRC::RC_PRINTSPOOL_COMMAND:
2308 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2309 case LyXRC::RC_PRINTTOFILE:
2310 case LyXRC::RC_PRINTTOPRINTER:
2311 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2312 case LyXRC::RC_PRINT_COMMAND:
2313 case LyXRC::RC_RTL_SUPPORT:
2314 case LyXRC::RC_SCREEN_DPI:
2315 case LyXRC::RC_SCREEN_FONT_ROMAN:
2316 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2317 case LyXRC::RC_SCREEN_FONT_SANS:
2318 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2319 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2320 case LyXRC::RC_SCREEN_FONT_SIZES:
2321 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2322 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2323 case LyXRC::RC_SCREEN_GEOMETRY_HEIGHT:
2324 case LyXRC::RC_SCREEN_GEOMETRY_WIDTH:
2325 case LyXRC::RC_SCREEN_GEOMETRY_XYSAVED:
2326 case LyXRC::RC_SCREEN_ZOOM:
2327 case LyXRC::RC_SERVERPIPE:
2328 case LyXRC::RC_SET_COLOR:
2329 case LyXRC::RC_SHOW_BANNER:
2330 case LyXRC::RC_SPELL_COMMAND:
2331 case LyXRC::RC_TEMPDIRPATH:
2332 case LyXRC::RC_TEMPLATEPATH:
2333 case LyXRC::RC_TEX_ALLOWS_SPACES:
2334 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2335 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2336 support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2338 case LyXRC::RC_UIFILE:
2339 case LyXRC::RC_USER_EMAIL:
2340 case LyXRC::RC_USER_NAME:
2341 case LyXRC::RC_USETEMPDIR:
2342 case LyXRC::RC_USE_ALT_LANG:
2343 case LyXRC::RC_USE_CONVERTER_CACHE:
2344 case LyXRC::RC_USE_ESC_CHARS:
2345 case LyXRC::RC_USE_INP_ENC:
2346 case LyXRC::RC_USE_PERS_DICT:
2347 case LyXRC::RC_USE_SPELL_LIB:
2348 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2349 case LyXRC::RC_VIEWER:
2350 case LyXRC::RC_LAST: