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 #ifdef WITH_WARNINGS
1602 #warning FIXME!! The graphics cache no longer has a changeDisplay method.
1605 graphics::GCache::get().changeDisplay(true);
1612 BOOST_ASSERT(lyx_view_);
1613 lyx_view_->message(from_utf8(argument));
1616 case LFUN_EXTERNAL_EDIT: {
1617 BOOST_ASSERT(lyx_view_);
1618 FuncRequest fr(action, argument);
1619 InsetExternal().dispatch(view()->cursor(), fr);
1623 case LFUN_GRAPHICS_EDIT: {
1624 FuncRequest fr(action, argument);
1625 InsetGraphics().dispatch(view()->cursor(), fr);
1629 case LFUN_INSET_APPLY: {
1630 BOOST_ASSERT(lyx_view_);
1631 string const name = cmd.getArg(0);
1632 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1634 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1635 inset->dispatch(view()->cursor(), fr);
1637 FuncRequest fr(LFUN_INSET_INSERT, argument);
1640 // ideally, the update flag should be set by the insets,
1641 // but this is not possible currently
1642 updateFlags = Update::Force | Update::FitCursor;
1646 case LFUN_ALL_INSETS_TOGGLE: {
1647 BOOST_ASSERT(lyx_view_);
1649 string const name = split(argument, action, ' ');
1650 Inset::Code const inset_code =
1651 Inset::translate(name);
1653 Cursor & cur = view()->cursor();
1654 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1656 Inset & inset = lyx_view_->buffer()->inset();
1657 InsetIterator it = inset_iterator_begin(inset);
1658 InsetIterator const end = inset_iterator_end(inset);
1659 for (; it != end; ++it) {
1660 if (!it->asInsetMath()
1661 && (inset_code == Inset::NO_CODE
1662 || inset_code == it->lyxCode())) {
1663 Cursor tmpcur = cur;
1664 tmpcur.pushLeft(*it);
1665 it->dispatch(tmpcur, fr);
1668 updateFlags = Update::Force | Update::FitCursor;
1672 case LFUN_BUFFER_LANGUAGE: {
1673 BOOST_ASSERT(lyx_view_);
1674 Buffer & buffer = *lyx_view_->buffer();
1675 Language const * oldL = buffer.params().language;
1676 Language const * newL = languages.getLanguage(argument);
1677 if (!newL || oldL == newL)
1680 if (oldL->rightToLeft() == newL->rightToLeft()
1681 && !buffer.isMultiLingual())
1682 buffer.changeLanguage(oldL, newL);
1686 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1687 string const fname =
1688 addName(addPath(package().user_support().absFilename(), "templates/"),
1690 Buffer defaults(fname);
1692 istringstream ss(argument);
1695 int const unknown_tokens = defaults.readHeader(lex);
1697 if (unknown_tokens != 0) {
1698 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1699 << unknown_tokens << " unknown token"
1700 << (unknown_tokens == 1 ? "" : "s")
1704 if (defaults.writeFile(FileName(defaults.fileName())))
1705 setMessage(bformat(_("Document defaults saved in %1$s"),
1706 makeDisplayPath(fname)));
1708 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1712 case LFUN_BUFFER_PARAMS_APPLY: {
1713 BOOST_ASSERT(lyx_view_);
1714 biblio::CiteEngine const engine =
1715 lyx_view_->buffer()->params().getEngine();
1717 istringstream ss(argument);
1720 int const unknown_tokens =
1721 lyx_view_->buffer()->readHeader(lex);
1723 if (unknown_tokens != 0) {
1724 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1725 << unknown_tokens << " unknown token"
1726 << (unknown_tokens == 1 ? "" : "s")
1729 if (engine == lyx_view_->buffer()->params().getEngine())
1732 Cursor & cur = view()->cursor();
1733 FuncRequest fr(LFUN_INSET_REFRESH);
1735 Inset & inset = lyx_view_->buffer()->inset();
1736 InsetIterator it = inset_iterator_begin(inset);
1737 InsetIterator const end = inset_iterator_end(inset);
1738 for (; it != end; ++it)
1739 if (it->lyxCode() == Inset::CITE_CODE)
1740 it->dispatch(cur, fr);
1744 case LFUN_TEXTCLASS_APPLY: {
1745 BOOST_ASSERT(lyx_view_);
1746 Buffer * buffer = lyx_view_->buffer();
1748 textclass_type const old_class =
1749 buffer->params().textclass;
1751 loadTextclass(argument);
1753 std::pair<bool, textclass_type> const tc_pair =
1754 textclasslist.numberOfClass(argument);
1759 textclass_type const new_class = tc_pair.second;
1760 if (old_class == new_class)
1764 lyx_view_->message(_("Converting document to new document class..."));
1765 recordUndoFullDocument(view());
1766 buffer->params().textclass = new_class;
1767 StableDocIterator backcur(view()->cursor());
1768 ErrorList & el = buffer->errorList("Class Switch");
1769 cap::switchBetweenClasses(
1770 old_class, new_class,
1771 static_cast<InsetText &>(buffer->inset()), el);
1773 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
1775 buffer->errors("Class Switch");
1776 updateLabels(*buffer);
1777 updateFlags = Update::Force | Update::FitCursor;
1781 case LFUN_TEXTCLASS_LOAD:
1782 loadTextclass(argument);
1785 case LFUN_LYXRC_APPLY: {
1786 LyXRC const lyxrc_orig = lyxrc;
1788 istringstream ss(argument);
1789 bool const success = lyxrc.read(ss) == 0;
1792 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1793 << "Unable to read lyxrc data"
1798 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1800 /// We force the redraw in any case because there might be
1801 /// some screen font changes.
1802 /// FIXME: only the current view will be updated. the Gui
1803 /// class is able to furnish the list of views.
1804 updateFlags = Update::Force;
1808 case LFUN_WINDOW_NEW:
1809 LyX::ref().newLyXView();
1812 case LFUN_WINDOW_CLOSE:
1813 BOOST_ASSERT(lyx_view_);
1814 BOOST_ASSERT(theApp());
1815 // update bookmark pit of the current buffer before window close
1816 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1817 gotoBookmark(i+1, false, false);
1818 // ask the user for saving changes or cancel quit
1819 if (!theBufferList().quitWriteAll())
1824 case LFUN_BOOKMARK_GOTO:
1825 // go to bookmark, open unopened file and switch to buffer if necessary
1826 gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
1829 case LFUN_BOOKMARK_CLEAR:
1830 LyX::ref().session().bookmarks().clear();
1833 case LFUN_TOOLBAR_TOGGLE: {
1834 BOOST_ASSERT(lyx_view_);
1835 string const name = cmd.getArg(0);
1836 bool const allowauto = cmd.getArg(1) == "allowauto";
1837 lyx_view_->toggleToolbarState(name, allowauto);
1838 ToolbarInfo * tbi = lyx_view_->getToolbarInfo(name);
1840 setMessage(bformat(_("Unknown toolbar \"%1$s\""),
1845 if (tbi->flags & ToolbarInfo::ON)
1847 else if (tbi->flags & ToolbarInfo::OFF)
1849 else if (tbi->flags & ToolbarInfo::AUTO)
1852 setMessage(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1853 _(tbi->gui_name), state));
1858 BOOST_ASSERT(lyx_view_);
1859 view()->cursor().dispatch(cmd);
1860 updateFlags = view()->cursor().result().update();
1861 if (!view()->cursor().result().dispatched())
1862 updateFlags = view()->dispatch(cmd);
1867 if (lyx_view_ && view()->buffer()) {
1868 // BufferView::update() updates the ViewMetricsInfo and
1869 // also initializes the position cache for all insets in
1870 // (at least partially) visible top-level paragraphs.
1871 // We will redraw the screen only if needed.
1872 if (view()->update(updateFlags)) {
1873 // Buffer::changed() signals that a repaint is needed.
1874 // The frontend (WorkArea) knows which area to repaint
1875 // thanks to the ViewMetricsInfo updated above.
1876 view()->buffer()->changed();
1879 lyx_view_->updateStatusBar();
1881 // if we executed a mutating lfun, mark the buffer as dirty
1883 && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
1884 && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
1885 view()->buffer()->markDirty();
1887 //Do we have a selection?
1888 theSelection().haveSelection(view()->cursor().selection());
1890 if (view()->cursor().inTexted()) {
1891 lyx_view_->updateLayoutChoice();
1895 if (!quitting && lyx_view_) {
1896 lyx_view_->updateMenubar();
1897 lyx_view_->updateToolbars();
1898 // Some messages may already be translated, so we cannot use _()
1899 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
1904 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
1906 const bool verbose = (cmd.origin == FuncRequest::MENU
1907 || cmd.origin == FuncRequest::TOOLBAR
1908 || cmd.origin == FuncRequest::COMMANDBUFFER);
1910 if (cmd.action == LFUN_SELF_INSERT || !verbose) {
1911 LYXERR(Debug::ACTION) << "dispatch msg is " << to_utf8(msg) << endl;
1913 lyx_view_->message(msg);
1917 docstring dispatch_msg = msg;
1918 if (!dispatch_msg.empty())
1919 dispatch_msg += ' ';
1921 docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
1923 bool argsadded = false;
1925 if (!cmd.argument().empty()) {
1926 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1927 comname += ' ' + cmd.argument();
1932 docstring const shortcuts = theTopLevelKeymap().printbindings(cmd);
1934 if (!shortcuts.empty())
1935 comname += ": " + shortcuts;
1936 else if (!argsadded && !cmd.argument().empty())
1937 comname += ' ' + cmd.argument();
1939 if (!comname.empty()) {
1940 comname = rtrim(comname);
1941 dispatch_msg += '(' + rtrim(comname) + ')';
1944 LYXERR(Debug::ACTION) << "verbose dispatch msg "
1945 << to_utf8(dispatch_msg) << endl;
1946 if (!dispatch_msg.empty())
1947 lyx_view_->message(dispatch_msg);
1951 void LyXFunc::menuNew(string const & name, bool fromTemplate)
1953 // FIXME: initpath is not used. What to do?
1954 string initpath = lyxrc.document_path;
1955 string filename(name);
1957 if (view()->buffer()) {
1958 string const trypath = lyx_view_->buffer()->filePath();
1959 // If directory is writeable, use this as default.
1960 if (isDirWriteable(FileName(trypath)))
1964 static int newfile_number;
1966 if (filename.empty()) {
1967 filename = addName(lyxrc.document_path,
1968 "newfile" + convert<string>(++newfile_number) + ".lyx");
1969 while (theBufferList().exists(filename) ||
1970 fs::is_readable(FileName(filename).toFilesystemEncoding())) {
1972 filename = addName(lyxrc.document_path,
1973 "newfile" + convert<string>(newfile_number) +
1978 // The template stuff
1981 FileDialog fileDlg(_("Select template file"),
1982 LFUN_SELECT_FILE_SYNC,
1983 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
1984 make_pair(_("Templates|#T#t"), from_utf8(lyxrc.template_path)));
1986 FileDialog::Result result =
1987 fileDlg.open(from_utf8(lyxrc.template_path),
1988 FileFilterList(_("LyX Documents (*.lyx)")),
1991 if (result.first == FileDialog::Later)
1993 if (result.second.empty())
1995 templname = to_utf8(result.second);
1998 Buffer * const b = newFile(filename, templname, !name.empty());
2001 lyx_view_->setBuffer(b);
2006 void LyXFunc::open(string const & fname)
2008 string initpath = lyxrc.document_path;
2010 if (view()->buffer()) {
2011 string const trypath = lyx_view_->buffer()->filePath();
2012 // If directory is writeable, use this as default.
2013 if (isDirWriteable(FileName(trypath)))
2019 if (fname.empty()) {
2020 FileDialog fileDlg(_("Select document to open"),
2022 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2023 make_pair(_("Examples|#E#e"), from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2025 FileDialog::Result result =
2026 fileDlg.open(from_utf8(initpath),
2027 FileFilterList(_("LyX Documents (*.lyx)")),
2030 if (result.first == FileDialog::Later)
2033 filename = to_utf8(result.second);
2035 // check selected filename
2036 if (filename.empty()) {
2037 lyx_view_->message(_("Canceled."));
2043 // get absolute path of file and add ".lyx" to the filename if
2045 FileName const fullname = fileSearch(string(), filename, "lyx");
2046 if (!fullname.empty())
2047 filename = fullname.absFilename();
2049 // if the file doesn't exist, let the user create one
2050 if (!fs::exists(fullname.toFilesystemEncoding())) {
2051 // the user specifically chose this name. Believe him.
2052 Buffer * const b = newFile(filename, string(), true);
2054 lyx_view_->setBuffer(b);
2058 docstring const disp_fn = makeDisplayPath(filename);
2059 lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
2062 if (lyx_view_->loadLyXFile(fullname)) {
2063 str2 = bformat(_("Document %1$s opened."), disp_fn);
2065 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2067 lyx_view_->message(str2);
2071 void LyXFunc::doImport(string const & argument)
2074 string filename = split(argument, format, ' ');
2076 LYXERR(Debug::INFO) << "LyXFunc::doImport: " << format
2077 << " file: " << filename << endl;
2079 // need user interaction
2080 if (filename.empty()) {
2081 string initpath = lyxrc.document_path;
2083 if (view()->buffer()) {
2084 string const trypath = lyx_view_->buffer()->filePath();
2085 // If directory is writeable, use this as default.
2086 if (isDirWriteable(FileName(trypath)))
2090 docstring const text = bformat(_("Select %1$s file to import"),
2091 formats.prettyName(format));
2093 FileDialog fileDlg(text,
2095 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2096 make_pair(_("Examples|#E#e"),
2097 from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2099 docstring filter = formats.prettyName(format);
2102 filter += from_utf8(formats.extension(format));
2105 FileDialog::Result result =
2106 fileDlg.open(from_utf8(initpath),
2107 FileFilterList(filter),
2110 if (result.first == FileDialog::Later)
2113 filename = to_utf8(result.second);
2115 // check selected filename
2116 if (filename.empty())
2117 lyx_view_->message(_("Canceled."));
2120 if (filename.empty())
2123 // get absolute path of file
2124 FileName const fullname(makeAbsPath(filename));
2126 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
2128 // Check if the document already is open
2129 if (use_gui && theBufferList().exists(lyxfile.absFilename())) {
2130 if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) {
2131 lyx_view_->message(_("Canceled."));
2136 // if the file exists already, and we didn't do
2137 // -i lyx thefile.lyx, warn
2138 if (fs::exists(lyxfile.toFilesystemEncoding()) && fullname != lyxfile) {
2139 docstring const file = makeDisplayPath(lyxfile.absFilename(), 30);
2141 docstring text = bformat(_("The document %1$s already exists.\n\n"
2142 "Do you want to overwrite that document?"), file);
2143 int const ret = Alert::prompt(_("Overwrite document?"),
2144 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2147 lyx_view_->message(_("Canceled."));
2152 ErrorList errorList;
2153 Importer::Import(lyx_view_, fullname, format, errorList);
2154 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2158 void LyXFunc::closeBuffer()
2160 // goto bookmark to update bookmark pit.
2161 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2162 gotoBookmark(i+1, false, false);
2164 theBufferList().close(lyx_view_->buffer(), true);
2168 void LyXFunc::reloadBuffer()
2170 FileName filename(lyx_view_->buffer()->fileName());
2172 lyx_view_->loadLyXFile(filename);
2175 // Each "lyx_view_" should have it's own message method. lyxview and
2176 // the minibuffer would use the minibuffer, but lyxserver would
2177 // send an ERROR signal to its client. Alejandro 970603
2178 // This function is bit problematic when it comes to NLS, to make the
2179 // lyx servers client be language indepenent we must not translate
2180 // strings sent to this func.
2181 void LyXFunc::setErrorMessage(docstring const & m) const
2183 dispatch_buffer = m;
2188 void LyXFunc::setMessage(docstring const & m) const
2190 dispatch_buffer = m;
2194 docstring const LyXFunc::viewStatusMessage()
2196 // When meta-fake key is pressed, show the key sequence so far + "M-".
2198 return keyseq->print(true) + "M-";
2200 // Else, when a non-complete key sequence is pressed,
2201 // show the available options.
2202 if (keyseq->length() > 0 && !keyseq->deleted())
2203 return keyseq->printOptions(true);
2205 if (!view()->buffer())
2206 return _("Welcome to LyX!");
2208 return view()->cursor().currentState();
2212 BufferView * LyXFunc::view() const
2214 BOOST_ASSERT(lyx_view_);
2215 return lyx_view_->view();
2219 bool LyXFunc::wasMetaKey() const
2221 return (meta_fake_bit != key_modifier::none);
2227 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2229 // Why the switch you might ask. It is a trick to ensure that all
2230 // the elements in the LyXRCTags enum is handled. As you can see
2231 // there are no breaks at all. So it is just a huge fall-through.
2232 // The nice thing is that we will get a warning from the compiler
2233 // if we forget an element.
2234 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2236 case LyXRC::RC_ACCEPT_COMPOUND:
2237 case LyXRC::RC_ALT_LANG:
2238 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
2239 case LyXRC::RC_PLAINTEXT_LINELEN:
2240 case LyXRC::RC_AUTOREGIONDELETE:
2241 case LyXRC::RC_AUTORESET_OPTIONS:
2242 case LyXRC::RC_AUTOSAVE:
2243 case LyXRC::RC_AUTO_NUMBER:
2244 case LyXRC::RC_BACKUPDIR_PATH:
2245 case LyXRC::RC_BIBTEX_COMMAND:
2246 case LyXRC::RC_BINDFILE:
2247 case LyXRC::RC_CHECKLASTFILES:
2248 case LyXRC::RC_USELASTFILEPOS:
2249 case LyXRC::RC_LOADSESSION:
2250 case LyXRC::RC_CHKTEX_COMMAND:
2251 case LyXRC::RC_CONVERTER:
2252 case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
2253 case LyXRC::RC_COPIER:
2254 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2255 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2256 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2257 case LyXRC::RC_DATE_INSERT_FORMAT:
2258 case LyXRC::RC_DEFAULT_LANGUAGE:
2259 case LyXRC::RC_DEFAULT_PAPERSIZE:
2260 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2261 case LyXRC::RC_DISPLAY_GRAPHICS:
2262 case LyXRC::RC_DOCUMENTPATH:
2263 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2264 string const encoded = FileName(
2265 lyxrc_new.document_path).toFilesystemEncoding();
2266 if (fs::exists(encoded) && fs::is_directory(encoded))
2267 support::package().document_dir() = FileName(lyxrc.document_path);
2269 case LyXRC::RC_ESC_CHARS:
2270 case LyXRC::RC_FONT_ENCODING:
2271 case LyXRC::RC_FORMAT:
2272 case LyXRC::RC_INDEX_COMMAND:
2273 case LyXRC::RC_INPUT:
2274 case LyXRC::RC_KBMAP:
2275 case LyXRC::RC_KBMAP_PRIMARY:
2276 case LyXRC::RC_KBMAP_SECONDARY:
2277 case LyXRC::RC_LABEL_INIT_LENGTH:
2278 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2279 case LyXRC::RC_LANGUAGE_AUTO_END:
2280 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2281 case LyXRC::RC_LANGUAGE_COMMAND_END:
2282 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2283 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2284 case LyXRC::RC_LANGUAGE_PACKAGE:
2285 case LyXRC::RC_LANGUAGE_USE_BABEL:
2286 case LyXRC::RC_MAKE_BACKUP:
2287 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2288 case LyXRC::RC_NUMLASTFILES:
2289 case LyXRC::RC_PATH_PREFIX:
2290 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2291 support::prependEnvPath("PATH", lyxrc.path_prefix);
2293 case LyXRC::RC_PERS_DICT:
2294 case LyXRC::RC_PREVIEW:
2295 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2296 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2297 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2298 case LyXRC::RC_PRINTCOPIESFLAG:
2299 case LyXRC::RC_PRINTER:
2300 case LyXRC::RC_PRINTEVENPAGEFLAG:
2301 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2302 case LyXRC::RC_PRINTFILEEXTENSION:
2303 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2304 case LyXRC::RC_PRINTODDPAGEFLAG:
2305 case LyXRC::RC_PRINTPAGERANGEFLAG:
2306 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2307 case LyXRC::RC_PRINTPAPERFLAG:
2308 case LyXRC::RC_PRINTREVERSEFLAG:
2309 case LyXRC::RC_PRINTSPOOL_COMMAND:
2310 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2311 case LyXRC::RC_PRINTTOFILE:
2312 case LyXRC::RC_PRINTTOPRINTER:
2313 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2314 case LyXRC::RC_PRINT_COMMAND:
2315 case LyXRC::RC_RTL_SUPPORT:
2316 case LyXRC::RC_SCREEN_DPI:
2317 case LyXRC::RC_SCREEN_FONT_ROMAN:
2318 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2319 case LyXRC::RC_SCREEN_FONT_SANS:
2320 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2321 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2322 case LyXRC::RC_SCREEN_FONT_SIZES:
2323 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2324 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2325 case LyXRC::RC_SCREEN_GEOMETRY_HEIGHT:
2326 case LyXRC::RC_SCREEN_GEOMETRY_WIDTH:
2327 case LyXRC::RC_SCREEN_GEOMETRY_XYSAVED:
2328 case LyXRC::RC_SCREEN_ZOOM:
2329 case LyXRC::RC_SERVERPIPE:
2330 case LyXRC::RC_SET_COLOR:
2331 case LyXRC::RC_SHOW_BANNER:
2332 case LyXRC::RC_SPELL_COMMAND:
2333 case LyXRC::RC_TEMPDIRPATH:
2334 case LyXRC::RC_TEMPLATEPATH:
2335 case LyXRC::RC_TEX_ALLOWS_SPACES:
2336 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2337 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2338 support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2340 case LyXRC::RC_UIFILE:
2341 case LyXRC::RC_USER_EMAIL:
2342 case LyXRC::RC_USER_NAME:
2343 case LyXRC::RC_USETEMPDIR:
2344 case LyXRC::RC_USE_ALT_LANG:
2345 case LyXRC::RC_USE_CONVERTER_CACHE:
2346 case LyXRC::RC_USE_ESC_CHARS:
2347 case LyXRC::RC_USE_INP_ENC:
2348 case LyXRC::RC_USE_PERS_DICT:
2349 case LyXRC::RC_USE_SPELL_LIB:
2350 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2351 case LyXRC::RC_VIEWER:
2352 case LyXRC::RC_LAST: