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/Selection.h"
88 #include "frontends/WorkArea.h"
90 #include "support/environment.h"
91 #include "support/FileFilterList.h"
92 #include "support/filetools.h"
93 #include "support/ForkedcallsController.h"
94 #include "support/fs_extras.h"
95 #include "support/lstrings.h"
96 #include "support/Path.h"
97 #include "support/Package.h"
98 #include "support/Systemcall.h"
99 #include "support/convert.h"
100 #include "support/os.h"
102 #include <boost/current_function.hpp>
103 #include <boost/filesystem/operations.hpp>
108 using std::make_pair;
111 using std::istringstream;
112 using std::ostringstream;
114 namespace fs = boost::filesystem;
118 using bv_funcs::freefont2string;
120 using frontend::LyXView;
122 using support::absolutePath;
123 using support::addName;
124 using support::addPath;
125 using support::bformat;
126 using support::changeExtension;
127 using support::contains;
128 using support::FileFilterList;
129 using support::FileName;
130 using support::fileSearch;
131 using support::ForkedcallsController;
132 using support::i18nLibFileSearch;
133 using support::isDirWriteable;
134 using support::isFileReadable;
135 using support::isStrInt;
136 using support::makeAbsPath;
137 using support::makeDisplayPath;
138 using support::package;
139 using support::quoteName;
140 using support::rtrim;
141 using support::split;
142 using support::subst;
143 using support::Systemcall;
144 using support::token;
146 using support::prefixIs;
148 namespace Alert = frontend::Alert;
153 bool getLocalStatus(Cursor cursor,
154 FuncRequest const & cmd, FuncStatus & status)
156 // Try to fix cursor in case it is broken.
157 cursor.fixIfBroken();
159 // This is, of course, a mess. Better create a new doc iterator and use
160 // this in Inset::getStatus. This might require an additional
161 // BufferView * arg, though (which should be avoided)
162 //Cursor safe = *this;
164 for ( ; cursor.depth(); cursor.pop()) {
165 //lyxerr << "\nCursor::getStatus: cmd: " << cmd << endl << *this << endl;
166 BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
167 BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
168 BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
170 // The inset's getStatus() will return 'true' if it made
171 // a definitive decision on whether it want to handle the
172 // request or not. The result of this decision is put into
173 // the 'status' parameter.
174 if (cursor.inset().getStatus(cursor, cmd, status)) {
183 /** Return the change status at cursor position, taking in account the
184 * status at each level of the document iterator (a table in a deleted
185 * footnote is deleted).
186 * When \param outer is true, the top slice is not looked at.
188 Change::Type lookupChangeType(DocIterator const & dit, bool outer = false)
190 size_t const depth = dit.depth() - (outer ? 1 : 0);
192 for (size_t i = 0 ; i < depth ; ++i) {
193 CursorSlice const & slice = dit[i];
194 if (!slice.inset().inMathed()
195 && slice.pos() < slice.paragraph().size()) {
196 Change::Type const ch = slice.paragraph().lookupChange(slice.pos()).type;
197 if (ch != Change::UNCHANGED)
201 return Change::UNCHANGED;
209 meta_fake_bit(key_modifier::none)
214 void LyXFunc::initKeySequences(KeyMap * kb)
216 keyseq.reset(new KeySequence(kb, kb));
217 cancel_meta_seq.reset(new KeySequence(kb, kb));
221 void LyXFunc::setLyXView(LyXView * lv)
223 if (!quitting && lyx_view_ && lyx_view_->view() && lyx_view_ != lv)
224 // save current selection to the selection buffer to allow
225 // middle-button paste in another window
226 cap::saveSelection(lyx_view_->view()->cursor());
231 void LyXFunc::handleKeyFunc(kb_action action)
233 char_type c = encoded_last_key;
235 if (keyseq->length())
238 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
239 lyx_view_->view()->getIntl().getTransManager().deadkey(
240 c, get_accent(action).accent, view()->cursor().innerText(), view()->cursor());
241 // Need to clear, in case the minibuffer calls these
244 // copied verbatim from do_accent_char
245 view()->cursor().resetAnchor();
250 void LyXFunc::gotoBookmark(unsigned int idx, bool openFile, bool switchToBuffer)
252 BOOST_ASSERT(lyx_view_);
253 if (!LyX::ref().session().bookmarks().isValid(idx))
255 BookmarksSection::Bookmark const & bm = LyX::ref().session().bookmarks().bookmark(idx);
256 BOOST_ASSERT(!bm.filename.empty());
257 string const file = bm.filename.absFilename();
258 // if the file is not opened, open it.
259 if (!theBufferList().exists(file)) {
261 dispatch(FuncRequest(LFUN_FILE_OPEN, file));
265 // open may fail, so we need to test it again
266 if (!theBufferList().exists(file))
269 // if the current buffer is not that one, switch to it.
270 if (lyx_view_->buffer()->fileName() != file) {
273 dispatch(FuncRequest(LFUN_BUFFER_SWITCH, file));
275 // moveToPosition try paragraph id first and then paragraph (pit, pos).
276 if (!view()->moveToPosition(bm.bottom_pit, bm.bottom_pos,
277 bm.top_id, bm.top_pos))
280 // Cursor jump succeeded!
281 Cursor const & cur = view()->cursor();
282 pit_type new_pit = cur.pit();
283 pos_type new_pos = cur.pos();
284 int new_id = cur.paragraph().id();
286 // if bottom_pit, bottom_pos or top_id has been changed, update bookmark
287 // see http://bugzilla.lyx.org/show_bug.cgi?id=3092
288 if (bm.bottom_pit != new_pit || bm.bottom_pos != new_pos
289 || bm.top_id != new_id) {
290 const_cast<BookmarksSection::Bookmark &>(bm).updatePos(
291 new_pit, new_pos, new_id);
296 void LyXFunc::processKeySym(KeySymbolPtr keysym, key_modifier::state state)
298 LYXERR(Debug::KEY) << "KeySym is " << keysym->getSymbolName() << endl;
300 // Do nothing if we have nothing (JMarc)
301 if (!keysym->isOK()) {
302 LYXERR(Debug::KEY) << "Empty kbd action (probably composing)"
307 if (keysym->isModifier()) {
308 LYXERR(Debug::KEY) << "isModifier true" << endl;
312 //Encoding const * encoding = view()->cursor().getEncoding();
313 //encoded_last_key = keysym->getISOEncoded(encoding ? encoding->name() : "");
314 // FIXME: encoded_last_key shadows the member variable of the same
315 // name. Is that intended?
316 char_type encoded_last_key = keysym->getUCSEncoded();
318 // Do a one-deep top-level lookup for
319 // cancel and meta-fake keys. RVDK_PATCH_5
320 cancel_meta_seq->reset();
322 FuncRequest func = cancel_meta_seq->addkey(keysym, state);
323 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
324 << " action first set to [" << func.action << ']'
327 // When not cancel or meta-fake, do the normal lookup.
328 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
329 // Mostly, meta_fake_bit = key_modifier::none. RVDK_PATCH_5.
330 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_PREFIX)) {
331 // remove Caps Lock and Mod2 as a modifiers
332 func = keyseq->addkey(keysym, (state | meta_fake_bit));
333 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
334 << "action now set to ["
335 << func.action << ']' << endl;
338 // Dont remove this unless you know what you are doing.
339 meta_fake_bit = key_modifier::none;
341 // Can this happen now ?
342 if (func.action == LFUN_NOACTION) {
343 func = FuncRequest(LFUN_COMMAND_PREFIX);
346 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
348 << func.action << "]["
349 << to_utf8(keyseq->print(false)) << ']'
352 // already here we know if it any point in going further
353 // why not return already here if action == -1 and
354 // num_bytes == 0? (Lgb)
356 if (keyseq->length() > 1) {
357 lyx_view_->message(keyseq->print(true));
361 // Maybe user can only reach the key via holding down shift.
362 // Let's see. But only if shift is the only modifier
363 if (func.action == LFUN_UNKNOWN_ACTION &&
364 state == key_modifier::shift) {
365 LYXERR(Debug::KEY) << "Trying without shift" << endl;
366 func = keyseq->addkey(keysym, key_modifier::none);
367 LYXERR(Debug::KEY) << "Action now " << func.action << endl;
370 if (func.action == LFUN_UNKNOWN_ACTION) {
371 // Hmm, we didn't match any of the keysequences. See
372 // if it's normal insertable text not already covered
374 if (keysym->isText() && keyseq->length() == 1) {
375 LYXERR(Debug::KEY) << "isText() is true, inserting." << endl;
376 func = FuncRequest(LFUN_SELF_INSERT,
377 FuncRequest::KEYBOARD);
379 LYXERR(Debug::KEY) << "Unknown, !isText() - giving up" << endl;
380 lyx_view_->message(_("Unknown function."));
385 if (func.action == LFUN_SELF_INSERT) {
386 if (encoded_last_key != 0) {
387 docstring const arg(1, encoded_last_key);
388 dispatch(FuncRequest(LFUN_SELF_INSERT, arg,
389 FuncRequest::KEYBOARD));
391 << "SelfInsert arg[`" << to_utf8(arg) << "']" << endl;
397 /* When we move around, or type, it's nice to be able to see
398 * the cursor immediately after the keypress.
400 if (lyx_view_ && lyx_view_->currentWorkArea())
401 lyx_view_->currentWorkArea()->startBlinkingCursor();
405 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
407 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
410 Cursor & cur = view()->cursor();
412 /* In LyX/Mac, when a dialog is open, the menus of the
413 application can still be accessed without giving focus to
414 the main window. In this case, we want to disable the menu
415 entries that are buffer-related.
417 Note that this code is not perfect, as bug 1941 attests:
418 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
420 Buffer * buf = lyx_view_? lyx_view_->buffer() : 0;
421 if (lyx_view_ && cmd.origin == FuncRequest::MENU && !lyx_view_->hasFocus())
424 if (cmd.action == LFUN_NOACTION) {
425 flag.message(from_utf8(N_("Nothing to do")));
430 switch (cmd.action) {
431 case LFUN_UNKNOWN_ACTION:
432 #ifndef HAVE_LIBAIKSAURUS
433 case LFUN_THESAURUS_ENTRY:
443 if (flag.unknown()) {
444 flag.message(from_utf8(N_("Unknown action")));
448 if (!flag.enabled()) {
449 if (flag.message().empty())
450 flag.message(from_utf8(N_("Command disabled")));
454 // Check whether we need a buffer
455 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
457 flag.message(from_utf8(N_("Command not allowed with"
458 "out any document open")));
463 // I would really like to avoid having this switch and rather try to
464 // encode this in the function itself.
465 // -- And I'd rather let an inset decide which LFUNs it is willing
466 // to handle (Andre')
468 switch (cmd.action) {
469 case LFUN_BUFFER_TOGGLE_READ_ONLY:
470 flag.setOnOff(buf->isReadonly());
473 case LFUN_BUFFER_SWITCH:
474 // toggle on the current buffer, but do not toggle off
475 // the other ones (is that a good idea?)
476 if (buf && to_utf8(cmd.argument()) == buf->fileName())
480 case LFUN_BUFFER_EXPORT:
481 enable = cmd.argument() == "custom"
482 || Exporter::isExportable(*buf, to_utf8(cmd.argument()));
485 case LFUN_BUFFER_CHKTEX:
486 enable = buf->isLatex() && !lyxrc.chktex_command.empty();
489 case LFUN_BUILD_PROGRAM:
490 enable = Exporter::isExportable(*buf, "program");
493 case LFUN_LAYOUT_TABULAR:
494 enable = cur.innerInsetOfType(Inset::TABULAR_CODE);
498 case LFUN_LAYOUT_PARAGRAPH:
499 enable = !cur.inset().forceDefaultParagraphs(cur.idx());
502 case LFUN_VC_REGISTER:
503 enable = !buf->lyxvc().inUse();
505 case LFUN_VC_CHECK_IN:
506 enable = buf->lyxvc().inUse() && !buf->isReadonly();
508 case LFUN_VC_CHECK_OUT:
509 enable = buf->lyxvc().inUse() && buf->isReadonly();
512 case LFUN_VC_UNDO_LAST:
513 enable = buf->lyxvc().inUse();
515 case LFUN_BUFFER_RELOAD:
516 enable = !buf->isUnnamed() && fs::exists(buf->fileName())
517 && (!buf->isClean() || buf->isExternallyModified(Buffer::timestamp_method));
520 case LFUN_INSET_SETTINGS: {
524 Inset::Code code = cur.inset().lyxCode();
526 case Inset::TABULAR_CODE:
527 enable = cmd.argument() == "tabular";
529 case Inset::ERT_CODE:
530 enable = cmd.argument() == "ert";
532 case Inset::FLOAT_CODE:
533 enable = cmd.argument() == "float";
535 case Inset::WRAP_CODE:
536 enable = cmd.argument() == "wrap";
538 case Inset::NOTE_CODE:
539 enable = cmd.argument() == "note";
541 case Inset::BRANCH_CODE:
542 enable = cmd.argument() == "branch";
544 case Inset::BOX_CODE:
545 enable = cmd.argument() == "box";
547 case Inset::LISTINGS_CODE:
548 enable = cmd.argument() == "listings";
556 case LFUN_INSET_APPLY: {
557 string const name = cmd.getArg(0);
558 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
560 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
562 if (!inset->getStatus(cur, fr, fs)) {
563 // Every inset is supposed to handle this
568 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
569 flag |= getStatus(fr);
571 enable = flag.enabled();
575 case LFUN_DIALOG_TOGGLE:
576 flag.setOnOff(lyx_view_->getDialogs().visible(cmd.getArg(0)));
577 // fall through to set "enable"
578 case LFUN_DIALOG_SHOW: {
579 string const name = cmd.getArg(0);
581 enable = name == "aboutlyx"
582 || name == "file" //FIXME: should be removed.
584 || name == "texinfo";
585 else if (name == "print")
586 enable = Exporter::isExportable(*buf, "dvi")
587 && lyxrc.print_command != "none";
588 else if (name == "character")
589 enable = cur.inset().lyxCode() != Inset::ERT_CODE &&
590 cur.inset().lyxCode() != Inset::LISTINGS_CODE;
591 else if (name == "latexlog")
592 enable = isFileReadable(FileName(buf->getLogName().second));
593 else if (name == "spellchecker")
594 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
595 enable = !buf->isReadonly();
599 else if (name == "vclog")
600 enable = buf->lyxvc().inUse();
604 case LFUN_DIALOG_SHOW_NEW_INSET:
605 enable = cur.inset().lyxCode() != Inset::ERT_CODE &&
606 cur.inset().lyxCode() != Inset::LISTINGS_CODE;
607 if (cur.inset().lyxCode() == Inset::CAPTION_CODE) {
609 if (cur.inset().getStatus(cur, cmd, flag))
614 case LFUN_DIALOG_UPDATE: {
615 string const name = cmd.getArg(0);
617 enable = name == "prefs";
621 case LFUN_CITATION_INSERT: {
622 FuncRequest fr(LFUN_INSET_INSERT, "citation");
623 enable = getStatus(fr).enabled();
627 case LFUN_BUFFER_WRITE: {
628 enable = lyx_view_->buffer()->isUnnamed()
629 || !lyx_view_->buffer()->isClean();
634 case LFUN_BUFFER_WRITE_ALL: {
635 // We enable the command only if there are some modified buffers
636 Buffer * first = theBufferList().first();
637 bool modified = false;
641 // We cannot use a for loop as the buffer list is a cycle.
647 b = theBufferList().next(b);
648 } while (b != first);
656 case LFUN_BOOKMARK_GOTO: {
657 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
658 enable = LyX::ref().session().bookmarks().isValid(num);
662 case LFUN_BOOKMARK_CLEAR:
663 enable = LyX::ref().session().bookmarks().size() > 0;
666 case LFUN_TOOLBAR_TOGGLE: {
667 bool const current = lyx_view_->isToolbarVisible(cmd.getArg(0));
668 flag.setOnOff(current);
671 case LFUN_WINDOW_CLOSE: {
672 enable = (theApp()->gui().viewIds().size() > 1);
676 // this one is difficult to get right. As a half-baked
677 // solution, we consider only the first action of the sequence
678 case LFUN_COMMAND_SEQUENCE: {
679 // argument contains ';'-terminated commands
680 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
681 FuncRequest func(lyxaction.lookupFunc(firstcmd));
682 func.origin = cmd.origin;
683 flag = getStatus(func);
686 case LFUN_BUFFER_NEW:
687 case LFUN_BUFFER_NEW_TEMPLATE:
688 case LFUN_WORD_FIND_FORWARD:
689 case LFUN_WORD_FIND_BACKWARD:
690 case LFUN_COMMAND_PREFIX:
691 case LFUN_COMMAND_EXECUTE:
693 case LFUN_META_PREFIX:
694 case LFUN_BUFFER_CLOSE:
695 case LFUN_BUFFER_WRITE_AS:
696 case LFUN_BUFFER_UPDATE:
697 case LFUN_BUFFER_VIEW:
698 case LFUN_BUFFER_IMPORT:
699 case LFUN_BUFFER_AUTO_SAVE:
700 case LFUN_RECONFIGURE:
704 case LFUN_DROP_LAYOUTS_CHOICE:
706 case LFUN_SERVER_GET_NAME:
707 case LFUN_SERVER_NOTIFY:
708 case LFUN_SERVER_GOTO_FILE_ROW:
709 case LFUN_DIALOG_HIDE:
710 case LFUN_DIALOG_DISCONNECT_INSET:
711 case LFUN_BUFFER_CHILD_OPEN:
712 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
713 case LFUN_KEYMAP_OFF:
714 case LFUN_KEYMAP_PRIMARY:
715 case LFUN_KEYMAP_SECONDARY:
716 case LFUN_KEYMAP_TOGGLE:
718 case LFUN_BUFFER_EXPORT_CUSTOM:
719 case LFUN_BUFFER_PRINT:
720 case LFUN_PREFERENCES_SAVE:
721 case LFUN_SCREEN_FONT_UPDATE:
724 case LFUN_EXTERNAL_EDIT:
725 case LFUN_GRAPHICS_EDIT:
726 case LFUN_ALL_INSETS_TOGGLE:
727 case LFUN_BUFFER_LANGUAGE:
728 case LFUN_TEXTCLASS_APPLY:
729 case LFUN_TEXTCLASS_LOAD:
730 case LFUN_BUFFER_SAVE_AS_DEFAULT:
731 case LFUN_BUFFER_PARAMS_APPLY:
732 case LFUN_LAYOUT_MODULES_CLEAR:
733 case LFUN_LAYOUT_MODULE_ADD:
734 case LFUN_LYXRC_APPLY:
735 case LFUN_BUFFER_NEXT:
736 case LFUN_BUFFER_PREVIOUS:
737 case LFUN_WINDOW_NEW:
739 // these are handled in our dispatch()
743 if (!getLocalStatus(cur, cmd, flag))
744 flag = view()->getStatus(cmd);
750 // Can we use a readonly buffer?
751 if (buf && buf->isReadonly()
752 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
753 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
754 flag.message(from_utf8(N_("Document is read-only")));
758 // Are we in a DELETED change-tracking region?
759 if (buf && lookupChangeType(cur, true) == Change::DELETED
760 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
761 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
762 flag.message(from_utf8(N_("This portion of the document is deleted.")));
766 // the default error message if we disable the command
767 if (!flag.enabled() && flag.message().empty())
768 flag.message(from_utf8(N_("Command disabled")));
774 bool LyXFunc::ensureBufferClean(BufferView * bv)
776 Buffer & buf = bv->buffer();
780 docstring const file = makeDisplayPath(buf.fileName(), 30);
781 docstring text = bformat(_("The document %1$s has unsaved "
782 "changes.\n\nDo you want to save "
783 "the document?"), file);
784 int const ret = Alert::prompt(_("Save changed document?"),
785 text, 0, 1, _("&Save"),
789 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
791 return buf.isClean();
797 void showPrintError(string const & name)
799 docstring str = bformat(_("Could not print the document %1$s.\n"
800 "Check that your printer is set up correctly."),
801 makeDisplayPath(name, 50));
802 Alert::error(_("Print document failed"), str);
806 void loadTextclass(string const & name)
808 std::pair<bool, textclass_type> const tc_pair =
809 textclasslist.numberOfClass(name);
811 if (!tc_pair.first) {
812 lyxerr << "Document class \"" << name
813 << "\" does not exist."
818 textclass_type const tc = tc_pair.second;
820 if (!textclasslist[tc].load()) {
821 docstring s = bformat(_("The document class %1$s."
822 "could not be loaded."),
823 from_utf8(textclasslist[tc].name()));
824 Alert::error(_("Could not load class"), s);
829 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
834 void LyXFunc::dispatch(FuncRequest const & cmd)
836 string const argument = to_utf8(cmd.argument());
837 kb_action const action = cmd.action;
839 LYXERR(Debug::ACTION) << endl << "LyXFunc::dispatch: cmd: " << cmd << endl;
840 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
842 // we have not done anything wrong yet.
844 dispatch_buffer.erase();
846 // redraw the screen at the end (first of the two drawing steps).
847 //This is done unless explicitely requested otherwise
848 Update::flags updateFlags = Update::FitCursor;
850 FuncStatus const flag = getStatus(cmd);
851 if (!flag.enabled()) {
852 // We cannot use this function here
853 LYXERR(Debug::ACTION) << "LyXFunc::dispatch: "
854 << lyxaction.getActionName(action)
855 << " [" << action << "] is disabled at this location"
857 setErrorMessage(flag.message());
861 case LFUN_WORD_FIND_FORWARD:
862 case LFUN_WORD_FIND_BACKWARD: {
863 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
864 static docstring last_search;
865 docstring searched_string;
867 if (!cmd.argument().empty()) {
868 last_search = cmd.argument();
869 searched_string = cmd.argument();
871 searched_string = last_search;
874 if (searched_string.empty())
877 bool const fw = action == LFUN_WORD_FIND_FORWARD;
878 docstring const data =
879 find2string(searched_string, true, false, fw);
880 find(view(), FuncRequest(LFUN_WORD_FIND, data));
884 case LFUN_COMMAND_PREFIX:
885 BOOST_ASSERT(lyx_view_);
886 lyx_view_->message(keyseq->printOptions(true));
889 case LFUN_COMMAND_EXECUTE:
890 BOOST_ASSERT(lyx_view_);
891 lyx_view_->showMiniBuffer(true);
895 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
897 meta_fake_bit = key_modifier::none;
898 if (lyx_view_->buffer())
899 // cancel any selection
900 dispatch(FuncRequest(LFUN_MARK_OFF));
901 setMessage(from_ascii(N_("Cancel")));
904 case LFUN_META_PREFIX:
905 meta_fake_bit = key_modifier::alt;
906 setMessage(keyseq->print(true));
909 case LFUN_BUFFER_TOGGLE_READ_ONLY:
910 BOOST_ASSERT(lyx_view_ && lyx_view_->view() && lyx_view_->buffer());
911 if (lyx_view_->buffer()->lyxvc().inUse())
912 lyx_view_->buffer()->lyxvc().toggleReadOnly();
914 lyx_view_->buffer()->setReadonly(
915 !lyx_view_->buffer()->isReadonly());
918 // --- Menus -----------------------------------------------
919 case LFUN_BUFFER_NEW:
920 menuNew(argument, false);
921 updateFlags = Update::None;
924 case LFUN_BUFFER_NEW_TEMPLATE:
925 menuNew(argument, true);
926 updateFlags = Update::None;
929 case LFUN_BUFFER_CLOSE:
931 updateFlags = Update::None;
934 case LFUN_BUFFER_WRITE:
935 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
936 if (!lyx_view_->buffer()->isUnnamed()) {
937 docstring const str = bformat(_("Saving document %1$s..."),
938 makeDisplayPath(lyx_view_->buffer()->fileName()));
939 lyx_view_->message(str);
940 menuWrite(lyx_view_->buffer());
941 lyx_view_->message(str + _(" done."));
943 writeAs(lyx_view_->buffer());
945 updateFlags = Update::None;
948 case LFUN_BUFFER_WRITE_AS:
949 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
950 writeAs(lyx_view_->buffer(), argument);
951 updateFlags = Update::None;
954 case LFUN_BUFFER_WRITE_ALL: {
955 Buffer * first = theBufferList().first();
958 lyx_view_->message(_("Saving all documents..."));
960 // We cannot use a for loop as the buffer list cycles.
963 if (!b->isUnnamed()) {
965 lyxerr[Debug::ACTION] << "Saved " << b->fileName() << endl;
969 b = theBufferList().next(b);
970 } while (b != first);
971 lyx_view_->message(_("All documents saved."));
974 updateFlags = Update::None;
978 case LFUN_BUFFER_RELOAD: {
979 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
980 docstring const file = makeDisplayPath(lyx_view_->buffer()->fileName(), 20);
981 docstring text = bformat(_("Any changes will be lost. Are you sure "
982 "you want to revert to the saved version of the document %1$s?"), file);
983 int const ret = Alert::prompt(_("Revert to saved document?"),
984 text, 1, 1, _("&Revert"), _("&Cancel"));
991 case LFUN_BUFFER_UPDATE:
992 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
993 Exporter::Export(lyx_view_->buffer(), argument, true);
996 case LFUN_BUFFER_VIEW:
997 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
998 Exporter::preview(lyx_view_->buffer(), argument);
1001 case LFUN_BUILD_PROGRAM:
1002 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1003 Exporter::Export(lyx_view_->buffer(), "program", true);
1006 case LFUN_BUFFER_CHKTEX:
1007 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1008 lyx_view_->buffer()->runChktex();
1011 case LFUN_BUFFER_EXPORT:
1012 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1013 if (argument == "custom")
1014 lyx_view_->getDialogs().show("sendto");
1016 Exporter::Export(lyx_view_->buffer(), argument, false);
1020 case LFUN_BUFFER_EXPORT_CUSTOM: {
1021 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1023 string command = split(argument, format_name, ' ');
1024 Format const * format = formats.getFormat(format_name);
1026 lyxerr << "Format \"" << format_name
1027 << "\" not recognized!"
1032 Buffer * buffer = lyx_view_->buffer();
1034 // The name of the file created by the conversion process
1037 // Output to filename
1038 if (format->name() == "lyx") {
1039 string const latexname =
1040 buffer->getLatexName(false);
1041 filename = changeExtension(latexname,
1042 format->extension());
1043 filename = addName(buffer->temppath(), filename);
1045 if (!buffer->writeFile(FileName(filename)))
1049 Exporter::Export(buffer, format_name, true, filename);
1052 // Substitute $$FName for filename
1053 if (!contains(command, "$$FName"))
1054 command = "( " + command + " ) < $$FName";
1055 command = subst(command, "$$FName", filename);
1057 // Execute the command in the background
1059 call.startscript(Systemcall::DontWait, command);
1063 case LFUN_BUFFER_PRINT: {
1064 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1065 // FIXME: cmd.getArg() might fail if one of the arguments
1066 // contains double quotes
1067 string target = cmd.getArg(0);
1068 string target_name = cmd.getArg(1);
1069 string command = cmd.getArg(2);
1072 || target_name.empty()
1073 || command.empty()) {
1074 lyxerr << "Unable to parse \""
1075 << argument << '"' << endl;
1078 if (target != "printer" && target != "file") {
1079 lyxerr << "Unrecognized target \""
1080 << target << '"' << endl;
1084 Buffer * buffer = lyx_view_->buffer();
1086 if (!Exporter::Export(buffer, "dvi", true)) {
1087 showPrintError(buffer->fileName());
1091 // Push directory path.
1092 string const path(buffer->temppath());
1093 // Prevent the compiler from optimizing away p
1095 support::Path p(pp);
1097 // there are three cases here:
1098 // 1. we print to a file
1099 // 2. we print directly to a printer
1100 // 3. we print using a spool command (print to file first)
1103 string const dviname =
1104 changeExtension(buffer->getLatexName(true),
1107 if (target == "printer") {
1108 if (!lyxrc.print_spool_command.empty()) {
1109 // case 3: print using a spool
1110 string const psname =
1111 changeExtension(dviname,".ps");
1112 command += ' ' + lyxrc.print_to_file
1115 + quoteName(dviname);
1118 lyxrc.print_spool_command + ' ';
1119 if (target_name != "default") {
1120 command2 += lyxrc.print_spool_printerprefix
1124 command2 += quoteName(psname);
1126 // If successful, then spool command
1127 res = one.startscript(
1132 res = one.startscript(
1133 Systemcall::DontWait,
1136 // case 2: print directly to a printer
1137 if (target_name != "default")
1138 command += ' ' + lyxrc.print_to_printer + target_name + ' ';
1139 res = one.startscript(
1140 Systemcall::DontWait,
1141 command + quoteName(dviname));
1145 // case 1: print to a file
1146 FileName const filename(makeAbsPath(target_name,
1147 lyx_view_->buffer()->filePath()));
1148 FileName const dvifile(makeAbsPath(dviname, path));
1149 if (fs::exists(filename.toFilesystemEncoding())) {
1150 docstring text = bformat(
1151 _("The file %1$s already exists.\n\n"
1152 "Do you want to overwrite that file?"),
1153 makeDisplayPath(filename.absFilename()));
1154 if (Alert::prompt(_("Overwrite file?"),
1155 text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
1158 command += ' ' + lyxrc.print_to_file
1159 + quoteName(filename.toFilesystemEncoding())
1161 + quoteName(dvifile.toFilesystemEncoding());
1162 res = one.startscript(Systemcall::DontWait,
1167 showPrintError(buffer->fileName());
1171 case LFUN_BUFFER_IMPORT:
1176 // quitting is triggered by the gui code
1177 // (leaving the event loop).
1178 lyx_view_->message(from_utf8(N_("Exiting.")));
1179 if (theBufferList().quitWriteAll())
1180 theApp()->gui().closeAllViews();
1183 case LFUN_BUFFER_AUTO_SAVE:
1187 case LFUN_RECONFIGURE:
1188 BOOST_ASSERT(lyx_view_);
1189 reconfigure(*lyx_view_);
1192 case LFUN_HELP_OPEN: {
1193 BOOST_ASSERT(lyx_view_);
1194 string const arg = argument;
1196 setErrorMessage(from_ascii(N_("Missing argument")));
1199 FileName const fname = i18nLibFileSearch("doc", arg, "lyx");
1200 if (fname.empty()) {
1201 lyxerr << "LyX: unable to find documentation file `"
1202 << arg << "'. Bad installation?" << endl;
1205 lyx_view_->message(bformat(_("Opening help file %1$s..."),
1206 makeDisplayPath(fname.absFilename())));
1207 Buffer * buf = lyx_view_->loadLyXFile(fname, false);
1210 lyx_view_->setBuffer(buf);
1211 lyx_view_->showErrorList("Parse");
1213 updateFlags = Update::None;
1217 // --- version control -------------------------------
1218 case LFUN_VC_REGISTER:
1219 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1220 if (!ensureBufferClean(view()))
1222 if (!lyx_view_->buffer()->lyxvc().inUse()) {
1223 lyx_view_->buffer()->lyxvc().registrer();
1226 updateFlags = Update::Force;
1229 case LFUN_VC_CHECK_IN:
1230 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1231 if (!ensureBufferClean(view()))
1233 if (lyx_view_->buffer()->lyxvc().inUse()
1234 && !lyx_view_->buffer()->isReadonly()) {
1235 lyx_view_->buffer()->lyxvc().checkIn();
1240 case LFUN_VC_CHECK_OUT:
1241 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1242 if (!ensureBufferClean(view()))
1244 if (lyx_view_->buffer()->lyxvc().inUse()
1245 && lyx_view_->buffer()->isReadonly()) {
1246 lyx_view_->buffer()->lyxvc().checkOut();
1251 case LFUN_VC_REVERT:
1252 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1253 lyx_view_->buffer()->lyxvc().revert();
1257 case LFUN_VC_UNDO_LAST:
1258 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1259 lyx_view_->buffer()->lyxvc().undoLast();
1263 // --- buffers ----------------------------------------
1264 case LFUN_BUFFER_SWITCH:
1265 BOOST_ASSERT(lyx_view_);
1266 lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1267 updateFlags = Update::None;
1270 case LFUN_BUFFER_NEXT:
1271 BOOST_ASSERT(lyx_view_);
1272 lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer()));
1273 updateFlags = Update::None;
1276 case LFUN_BUFFER_PREVIOUS:
1277 BOOST_ASSERT(lyx_view_);
1278 lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer()));
1279 updateFlags = Update::None;
1283 BOOST_ASSERT(lyx_view_);
1284 newFile(*lyx_view_, argument);
1285 updateFlags = Update::None;
1288 case LFUN_FILE_OPEN:
1289 BOOST_ASSERT(lyx_view_);
1291 updateFlags = Update::None;
1294 case LFUN_DROP_LAYOUTS_CHOICE:
1295 BOOST_ASSERT(lyx_view_);
1296 lyx_view_->openLayoutList();
1299 case LFUN_MENU_OPEN:
1300 BOOST_ASSERT(lyx_view_);
1301 lyx_view_->openMenu(from_utf8(argument));
1304 // --- lyxserver commands ----------------------------
1305 case LFUN_SERVER_GET_NAME:
1306 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1307 setMessage(from_utf8(lyx_view_->buffer()->fileName()));
1308 LYXERR(Debug::INFO) << "FNAME["
1309 << lyx_view_->buffer()->fileName()
1313 case LFUN_SERVER_NOTIFY:
1314 dispatch_buffer = keyseq->print(false);
1315 theServer().notifyClient(to_utf8(dispatch_buffer));
1318 case LFUN_SERVER_GOTO_FILE_ROW: {
1319 BOOST_ASSERT(lyx_view_);
1322 istringstream is(argument);
1323 is >> file_name >> row;
1325 bool loaded = false;
1326 if (prefixIs(file_name, package().temp_dir().absFilename()))
1327 // Needed by inverse dvi search. If it is a file
1328 // in tmpdir, call the apropriated function
1329 buf = theBufferList().getBufferFromTmp(file_name);
1331 // Must replace extension of the file to be .lyx
1332 // and get full path
1333 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1334 // Either change buffer or load the file
1335 if (theBufferList().exists(s.absFilename()))
1336 buf = theBufferList().getBuffer(s.absFilename());
1338 buf = lyx_view_->loadLyXFile(s);
1344 updateFlags = Update::None;
1349 lyx_view_->setBuffer(buf);
1350 view()->setCursorFromRow(row);
1352 lyx_view_->showErrorList("Parse");
1353 updateFlags = Update::FitCursor;
1357 case LFUN_DIALOG_SHOW: {
1358 BOOST_ASSERT(lyx_view_);
1359 string const name = cmd.getArg(0);
1360 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1362 if (name == "character") {
1363 data = freefont2string();
1365 lyx_view_->getDialogs().show("character", data);
1366 } else if (name == "latexlog") {
1367 pair<Buffer::LogType, string> const logfile =
1368 lyx_view_->buffer()->getLogName();
1369 switch (logfile.first) {
1370 case Buffer::latexlog:
1373 case Buffer::buildlog:
1377 data += Lexer::quoteString(logfile.second);
1378 lyx_view_->getDialogs().show("log", data);
1379 } else if (name == "vclog") {
1380 string const data = "vc " +
1381 Lexer::quoteString(lyx_view_->buffer()->lyxvc().getLogFile());
1382 lyx_view_->getDialogs().show("log", data);
1384 lyx_view_->getDialogs().show(name, data);
1388 case LFUN_DIALOG_SHOW_NEW_INSET: {
1389 BOOST_ASSERT(lyx_view_);
1390 string const name = cmd.getArg(0);
1391 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1392 if (name == "bibitem" ||
1396 name == "nomenclature" ||
1400 InsetCommandParams p(name);
1401 data = InsetCommandMailer::params2string(name, p);
1402 } else if (name == "include") {
1403 // data is the include type: one of "include",
1404 // "input", "verbatiminput" or "verbatiminput*"
1406 // default type is requested
1408 InsetCommandParams p(data);
1409 data = InsetIncludeMailer::params2string(p);
1410 } else if (name == "box") {
1411 // \c data == "Boxed" || "Frameless" etc
1412 InsetBoxParams p(data);
1413 data = InsetBoxMailer::params2string(p);
1414 } else if (name == "branch") {
1415 InsetBranchParams p;
1416 data = InsetBranchMailer::params2string(p);
1417 } else if (name == "citation") {
1418 InsetCommandParams p("cite");
1419 data = InsetCommandMailer::params2string(name, p);
1420 } else if (name == "ert") {
1421 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1422 } else if (name == "external") {
1423 InsetExternalParams p;
1424 Buffer const & buffer = *lyx_view_->buffer();
1425 data = InsetExternalMailer::params2string(p, buffer);
1426 } else if (name == "float") {
1428 data = InsetFloatMailer::params2string(p);
1429 } else if (name == "listings") {
1430 InsetListingsParams p;
1431 data = InsetListingsMailer::params2string(p);
1432 } else if (name == "graphics") {
1433 InsetGraphicsParams p;
1434 Buffer const & buffer = *lyx_view_->buffer();
1435 data = InsetGraphicsMailer::params2string(p, buffer);
1436 } else if (name == "note") {
1438 data = InsetNoteMailer::params2string(p);
1439 } else if (name == "vspace") {
1441 data = InsetVSpaceMailer::params2string(space);
1442 } else if (name == "wrap") {
1444 data = InsetWrapMailer::params2string(p);
1446 lyx_view_->getDialogs().show(name, data, 0);
1450 case LFUN_DIALOG_UPDATE: {
1451 BOOST_ASSERT(lyx_view_);
1452 string const & name = argument;
1453 // Can only update a dialog connected to an existing inset
1454 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1456 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1457 inset->dispatch(view()->cursor(), fr);
1458 } else if (name == "paragraph") {
1459 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1460 } else if (name == "prefs") {
1461 lyx_view_->getDialogs().update(name, string());
1466 case LFUN_DIALOG_HIDE:
1467 LyX::cref().hideDialogs(argument, 0);
1470 case LFUN_DIALOG_TOGGLE: {
1471 BOOST_ASSERT(lyx_view_);
1472 if (lyx_view_->getDialogs().visible(cmd.getArg(0)))
1473 dispatch(FuncRequest(LFUN_DIALOG_HIDE, argument));
1475 dispatch(FuncRequest(LFUN_DIALOG_SHOW, argument));
1479 case LFUN_DIALOG_DISCONNECT_INSET:
1480 BOOST_ASSERT(lyx_view_);
1481 lyx_view_->getDialogs().disconnect(argument);
1485 case LFUN_CITATION_INSERT: {
1486 BOOST_ASSERT(lyx_view_);
1487 if (!argument.empty()) {
1488 // we can have one optional argument, delimited by '|'
1489 // citation-insert <key>|<text_before>
1490 // this should be enhanced to also support text_after
1491 // and citation style
1492 string arg = argument;
1494 if (contains(argument, "|")) {
1495 arg = token(argument, '|', 0);
1496 opt1 = token(argument, '|', 1);
1498 InsetCommandParams icp("cite");
1499 icp["key"] = from_utf8(arg);
1501 icp["before"] = from_utf8(opt1);
1502 string icstr = InsetCommandMailer::params2string("citation", icp);
1503 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1506 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1510 case LFUN_BUFFER_CHILD_OPEN: {
1511 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1512 Buffer * parent = lyx_view_->buffer();
1513 FileName filename = makeAbsPath(argument, parent->filePath());
1514 view()->saveBookmark(false);
1516 bool parsed = false;
1517 if (theBufferList().exists(filename.absFilename())) {
1518 child = theBufferList().getBuffer(filename.absFilename());
1520 setMessage(bformat(_("Opening child document %1$s..."),
1521 makeDisplayPath(filename.absFilename())));
1522 child = lyx_view_->loadLyXFile(filename, true);
1526 // Set the parent name of the child document.
1527 // This makes insertion of citations and references in the child work,
1528 // when the target is in the parent or another child document.
1529 child->setParentName(parent->fileName());
1530 updateLabels(*child->getMasterBuffer());
1531 lyx_view_->setBuffer(child);
1533 lyx_view_->showErrorList("Parse");
1536 // If a screen update is required (in case where auto_open is false),
1537 // setBuffer() would have taken care of it already. Otherwise we shall
1538 // reset the update flag because it can cause a circular problem.
1540 updateFlags = Update::None;
1544 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1545 BOOST_ASSERT(lyx_view_);
1546 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1549 case LFUN_KEYMAP_OFF:
1550 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1551 lyx_view_->view()->getIntl().keyMapOn(false);
1554 case LFUN_KEYMAP_PRIMARY:
1555 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1556 lyx_view_->view()->getIntl().keyMapPrim();
1559 case LFUN_KEYMAP_SECONDARY:
1560 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1561 lyx_view_->view()->getIntl().keyMapSec();
1564 case LFUN_KEYMAP_TOGGLE:
1565 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1566 lyx_view_->view()->getIntl().toggleKeyMap();
1572 string rest = split(argument, countstr, ' ');
1573 istringstream is(countstr);
1576 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1577 for (int i = 0; i < count; ++i)
1578 dispatch(lyxaction.lookupFunc(rest));
1582 case LFUN_COMMAND_SEQUENCE: {
1583 // argument contains ';'-terminated commands
1584 string arg = argument;
1585 while (!arg.empty()) {
1587 arg = split(arg, first, ';');
1588 FuncRequest func(lyxaction.lookupFunc(first));
1589 func.origin = cmd.origin;
1595 case LFUN_PREFERENCES_SAVE: {
1596 lyxrc.write(makeAbsPath("preferences",
1597 package().user_support().absFilename()),
1602 case LFUN_SCREEN_FONT_UPDATE:
1603 BOOST_ASSERT(lyx_view_);
1604 // handle the screen font changes.
1605 theFontLoader().update();
1606 /// FIXME: only the current view will be updated. the Gui
1607 /// class is able to furnish the list of views.
1608 updateFlags = Update::Force;
1611 case LFUN_SET_COLOR: {
1613 string const x11_name = split(argument, lyx_name, ' ');
1614 if (lyx_name.empty() || x11_name.empty()) {
1615 setErrorMessage(from_ascii(N_(
1616 "Syntax: set-color <lyx_name>"
1621 bool const graphicsbg_changed =
1622 (lyx_name == lcolor.getLyXName(Color::graphicsbg) &&
1623 x11_name != lcolor.getX11Name(Color::graphicsbg));
1625 if (!lcolor.setColor(lyx_name, x11_name)) {
1627 bformat(_("Set-color \"%1$s\" failed "
1628 "- color is undefined or "
1629 "may not be redefined"),
1630 from_utf8(lyx_name)));
1634 theApp()->updateColor(lcolor.getFromLyXName(lyx_name));
1636 if (graphicsbg_changed) {
1637 // FIXME: The graphics cache no longer has a changeDisplay method.
1639 graphics::GCache::get().changeDisplay(true);
1646 BOOST_ASSERT(lyx_view_);
1647 lyx_view_->message(from_utf8(argument));
1650 case LFUN_EXTERNAL_EDIT: {
1651 BOOST_ASSERT(lyx_view_);
1652 FuncRequest fr(action, argument);
1653 InsetExternal().dispatch(view()->cursor(), fr);
1657 case LFUN_GRAPHICS_EDIT: {
1658 FuncRequest fr(action, argument);
1659 InsetGraphics().dispatch(view()->cursor(), fr);
1663 case LFUN_INSET_APPLY: {
1664 BOOST_ASSERT(lyx_view_);
1665 string const name = cmd.getArg(0);
1666 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1668 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1669 inset->dispatch(view()->cursor(), fr);
1671 FuncRequest fr(LFUN_INSET_INSERT, argument);
1674 // ideally, the update flag should be set by the insets,
1675 // but this is not possible currently
1676 updateFlags = Update::Force | Update::FitCursor;
1680 case LFUN_ALL_INSETS_TOGGLE: {
1681 BOOST_ASSERT(lyx_view_);
1683 string const name = split(argument, action, ' ');
1684 Inset::Code const inset_code =
1685 Inset::translate(name);
1687 Cursor & cur = view()->cursor();
1688 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1690 Inset & inset = lyx_view_->buffer()->inset();
1691 InsetIterator it = inset_iterator_begin(inset);
1692 InsetIterator const end = inset_iterator_end(inset);
1693 for (; it != end; ++it) {
1694 if (!it->asInsetMath()
1695 && (inset_code == Inset::NO_CODE
1696 || inset_code == it->lyxCode())) {
1697 Cursor tmpcur = cur;
1698 tmpcur.pushLeft(*it);
1699 it->dispatch(tmpcur, fr);
1702 updateFlags = Update::Force | Update::FitCursor;
1706 case LFUN_BUFFER_LANGUAGE: {
1707 BOOST_ASSERT(lyx_view_);
1708 Buffer & buffer = *lyx_view_->buffer();
1709 Language const * oldL = buffer.params().language;
1710 Language const * newL = languages.getLanguage(argument);
1711 if (!newL || oldL == newL)
1714 if (oldL->rightToLeft() == newL->rightToLeft()
1715 && !buffer.isMultiLingual())
1716 buffer.changeLanguage(oldL, newL);
1720 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1721 string const fname =
1722 addName(addPath(package().user_support().absFilename(), "templates/"),
1724 Buffer defaults(fname);
1726 istringstream ss(argument);
1729 int const unknown_tokens = defaults.readHeader(lex);
1731 if (unknown_tokens != 0) {
1732 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1733 << unknown_tokens << " unknown token"
1734 << (unknown_tokens == 1 ? "" : "s")
1738 if (defaults.writeFile(FileName(defaults.fileName())))
1739 setMessage(bformat(_("Document defaults saved in %1$s"),
1740 makeDisplayPath(fname)));
1742 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1746 case LFUN_BUFFER_PARAMS_APPLY: {
1747 BOOST_ASSERT(lyx_view_);
1748 biblio::CiteEngine const oldEngine =
1749 lyx_view_->buffer()->params().getEngine();
1751 Buffer * buffer = lyx_view_->buffer();
1753 TextClass_ptr oldClass = buffer->params().getTextClass_ptr();
1754 recordUndoFullDocument(view());
1756 istringstream ss(argument);
1759 int const unknown_tokens = buffer->readHeader(lex);
1761 if (unknown_tokens != 0) {
1762 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1763 << unknown_tokens << " unknown token"
1764 << (unknown_tokens == 1 ? "" : "s")
1768 updateLayout(oldClass, buffer);
1770 biblio::CiteEngine const newEngine =
1771 lyx_view_->buffer()->params().getEngine();
1773 if (oldEngine != newEngine) {
1774 Cursor & cur = view()->cursor();
1775 FuncRequest fr(LFUN_INSET_REFRESH);
1777 Inset & inset = lyx_view_->buffer()->inset();
1778 InsetIterator it = inset_iterator_begin(inset);
1779 InsetIterator const end = inset_iterator_end(inset);
1780 for (; it != end; ++it)
1781 if (it->lyxCode() == Inset::CITE_CODE)
1782 it->dispatch(cur, fr);
1785 updateFlags = Update::Force | Update::FitCursor;
1789 case LFUN_LAYOUT_MODULES_CLEAR: {
1790 BOOST_ASSERT(lyx_view_);
1791 Buffer * buffer = lyx_view_->buffer();
1792 TextClass_ptr oldClass = buffer->params().getTextClass_ptr();
1793 recordUndoFullDocument(view());
1794 buffer->params().clearLayoutModules();
1795 updateLayout(oldClass, buffer);
1796 updateFlags = Update::Force | Update::FitCursor;
1800 case LFUN_LAYOUT_MODULE_ADD: {
1801 BOOST_ASSERT(lyx_view_);
1802 Buffer * buffer = lyx_view_->buffer();
1803 TextClass_ptr oldClass = buffer->params().getTextClass_ptr();
1804 recordUndoFullDocument(view());
1805 buffer->params().addLayoutModule(argument);
1806 updateLayout(oldClass, buffer);
1807 updateFlags = Update::Force | Update::FitCursor;
1811 case LFUN_TEXTCLASS_APPLY: {
1812 BOOST_ASSERT(lyx_view_);
1813 Buffer * buffer = lyx_view_->buffer();
1815 loadTextclass(argument);
1817 std::pair<bool, textclass_type> const tc_pair =
1818 textclasslist.numberOfClass(argument);
1823 textclass_type const old_class = buffer->params().getBaseClass();
1824 textclass_type const new_class = tc_pair.second;
1826 if (old_class == new_class)
1830 //Save the old, possibly modular, layout for use in conversion.
1831 TextClass_ptr oldClass = buffer->params().getTextClass_ptr();
1832 recordUndoFullDocument(view());
1833 buffer->params().setBaseClass(new_class);
1834 updateLayout(oldClass, buffer);
1835 updateFlags = Update::Force | Update::FitCursor;
1839 case LFUN_TEXTCLASS_LOAD:
1840 loadTextclass(argument);
1843 case LFUN_LYXRC_APPLY: {
1844 LyXRC const lyxrc_orig = lyxrc;
1846 istringstream ss(argument);
1847 bool const success = lyxrc.read(ss) == 0;
1850 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1851 << "Unable to read lyxrc data"
1856 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1858 /// We force the redraw in any case because there might be
1859 /// some screen font changes.
1860 /// FIXME: only the current view will be updated. the Gui
1861 /// class is able to furnish the list of views.
1862 updateFlags = Update::Force;
1866 case LFUN_WINDOW_NEW:
1867 LyX::ref().newLyXView();
1870 case LFUN_WINDOW_CLOSE:
1871 BOOST_ASSERT(lyx_view_);
1872 BOOST_ASSERT(theApp());
1873 // update bookmark pit of the current buffer before window close
1874 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1875 gotoBookmark(i+1, false, false);
1876 // ask the user for saving changes or cancel quit
1877 if (!theBufferList().quitWriteAll())
1882 case LFUN_BOOKMARK_GOTO:
1883 // go to bookmark, open unopened file and switch to buffer if necessary
1884 gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
1887 case LFUN_BOOKMARK_CLEAR:
1888 LyX::ref().session().bookmarks().clear();
1891 case LFUN_TOOLBAR_TOGGLE: {
1892 BOOST_ASSERT(lyx_view_);
1893 string const name = cmd.getArg(0);
1894 bool const allowauto = cmd.getArg(1) == "allowauto";
1895 lyx_view_->toggleToolbarState(name, allowauto);
1896 ToolbarInfo * tbi = lyx_view_->getToolbarInfo(name);
1898 setMessage(bformat(_("Unknown toolbar \"%1$s\""),
1903 if (tbi->flags & ToolbarInfo::ON)
1905 else if (tbi->flags & ToolbarInfo::OFF)
1907 else if (tbi->flags & ToolbarInfo::AUTO)
1910 setMessage(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1911 _(tbi->gui_name), state));
1916 BOOST_ASSERT(lyx_view_);
1917 view()->cursor().dispatch(cmd);
1918 updateFlags = view()->cursor().result().update();
1919 if (!view()->cursor().result().dispatched())
1920 updateFlags = view()->dispatch(cmd);
1925 if (lyx_view_ && lyx_view_->buffer()) {
1926 // BufferView::update() updates the ViewMetricsInfo and
1927 // also initializes the position cache for all insets in
1928 // (at least partially) visible top-level paragraphs.
1929 // We will redraw the screen only if needed.
1930 if (view()->update(updateFlags)) {
1931 // Buffer::changed() signals that a repaint is needed.
1932 // The frontend (WorkArea) knows which area to repaint
1933 // thanks to the ViewMetricsInfo updated above.
1934 lyx_view_->buffer()->changed();
1937 lyx_view_->updateStatusBar();
1939 // if we executed a mutating lfun, mark the buffer as dirty
1941 && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
1942 && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
1943 lyx_view_->buffer()->markDirty();
1945 //Do we have a selection?
1946 theSelection().haveSelection(view()->cursor().selection());
1948 if (view()->cursor().inTexted()) {
1949 lyx_view_->updateLayoutChoice();
1953 if (!quitting && lyx_view_) {
1954 lyx_view_->updateToolbars();
1955 // Some messages may already be translated, so we cannot use _()
1956 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
1961 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
1963 const bool verbose = (cmd.origin == FuncRequest::MENU
1964 || cmd.origin == FuncRequest::TOOLBAR
1965 || cmd.origin == FuncRequest::COMMANDBUFFER);
1967 if (cmd.action == LFUN_SELF_INSERT || !verbose) {
1968 LYXERR(Debug::ACTION) << "dispatch msg is " << to_utf8(msg) << endl;
1970 lyx_view_->message(msg);
1974 docstring dispatch_msg = msg;
1975 if (!dispatch_msg.empty())
1976 dispatch_msg += ' ';
1978 docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
1980 bool argsadded = false;
1982 if (!cmd.argument().empty()) {
1983 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1984 comname += ' ' + cmd.argument();
1989 docstring const shortcuts = theTopLevelKeymap().printbindings(cmd);
1991 if (!shortcuts.empty())
1992 comname += ": " + shortcuts;
1993 else if (!argsadded && !cmd.argument().empty())
1994 comname += ' ' + cmd.argument();
1996 if (!comname.empty()) {
1997 comname = rtrim(comname);
1998 dispatch_msg += '(' + rtrim(comname) + ')';
2001 LYXERR(Debug::ACTION) << "verbose dispatch msg "
2002 << to_utf8(dispatch_msg) << endl;
2003 if (!dispatch_msg.empty())
2004 lyx_view_->message(dispatch_msg);
2008 void LyXFunc::menuNew(string const & name, bool fromTemplate)
2010 // FIXME: initpath is not used. What to do?
2011 string initpath = lyxrc.document_path;
2012 string filename(name);
2014 if (lyx_view_->buffer()) {
2015 string const trypath = lyx_view_->buffer()->filePath();
2016 // If directory is writeable, use this as default.
2017 if (isDirWriteable(FileName(trypath)))
2021 static int newfile_number;
2023 if (filename.empty()) {
2024 filename = addName(lyxrc.document_path,
2025 "newfile" + convert<string>(++newfile_number) + ".lyx");
2026 while (theBufferList().exists(filename) ||
2027 fs::is_readable(FileName(filename).toFilesystemEncoding())) {
2029 filename = addName(lyxrc.document_path,
2030 "newfile" + convert<string>(newfile_number) +
2035 // The template stuff
2038 FileDialog fileDlg(_("Select template file"),
2039 LFUN_SELECT_FILE_SYNC,
2040 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2041 make_pair(_("Templates|#T#t"), from_utf8(lyxrc.template_path)));
2043 FileDialog::Result result =
2044 fileDlg.open(from_utf8(lyxrc.template_path),
2045 FileFilterList(_("LyX Documents (*.lyx)")),
2048 if (result.first == FileDialog::Later)
2050 if (result.second.empty())
2052 templname = to_utf8(result.second);
2055 Buffer * const b = newFile(filename, templname, !name.empty());
2057 lyx_view_->setBuffer(b);
2061 void LyXFunc::open(string const & fname)
2063 string initpath = lyxrc.document_path;
2065 if (lyx_view_->buffer()) {
2066 string const trypath = lyx_view_->buffer()->filePath();
2067 // If directory is writeable, use this as default.
2068 if (isDirWriteable(FileName(trypath)))
2074 if (fname.empty()) {
2075 FileDialog fileDlg(_("Select document to open"),
2077 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2078 make_pair(_("Examples|#E#e"), from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2080 FileDialog::Result result =
2081 fileDlg.open(from_utf8(initpath),
2082 FileFilterList(_("LyX Documents (*.lyx)")),
2085 if (result.first == FileDialog::Later)
2088 filename = to_utf8(result.second);
2090 // check selected filename
2091 if (filename.empty()) {
2092 lyx_view_->message(_("Canceled."));
2098 // get absolute path of file and add ".lyx" to the filename if
2100 FileName const fullname = fileSearch(string(), filename, "lyx");
2101 if (!fullname.empty())
2102 filename = fullname.absFilename();
2104 // if the file doesn't exist, let the user create one
2105 if (!fs::exists(fullname.toFilesystemEncoding())) {
2106 // the user specifically chose this name. Believe him.
2107 Buffer * const b = newFile(filename, string(), true);
2109 lyx_view_->setBuffer(b);
2113 docstring const disp_fn = makeDisplayPath(filename);
2114 lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
2117 Buffer * buf = lyx_view_->loadLyXFile(fullname);
2120 lyx_view_->setBuffer(buf);
2121 lyx_view_->showErrorList("Parse");
2122 str2 = bformat(_("Document %1$s opened."), disp_fn);
2124 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2126 lyx_view_->message(str2);
2130 void LyXFunc::doImport(string const & argument)
2133 string filename = split(argument, format, ' ');
2135 LYXERR(Debug::INFO) << "LyXFunc::doImport: " << format
2136 << " file: " << filename << endl;
2138 // need user interaction
2139 if (filename.empty()) {
2140 string initpath = lyxrc.document_path;
2142 if (lyx_view_->buffer()) {
2143 string const trypath = lyx_view_->buffer()->filePath();
2144 // If directory is writeable, use this as default.
2145 if (isDirWriteable(FileName(trypath)))
2149 docstring const text = bformat(_("Select %1$s file to import"),
2150 formats.prettyName(format));
2152 FileDialog fileDlg(text,
2154 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2155 make_pair(_("Examples|#E#e"),
2156 from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2158 docstring filter = formats.prettyName(format);
2161 filter += from_utf8(formats.extension(format));
2164 FileDialog::Result result =
2165 fileDlg.open(from_utf8(initpath),
2166 FileFilterList(filter),
2169 if (result.first == FileDialog::Later)
2172 filename = to_utf8(result.second);
2174 // check selected filename
2175 if (filename.empty())
2176 lyx_view_->message(_("Canceled."));
2179 if (filename.empty())
2182 // get absolute path of file
2183 FileName const fullname(makeAbsPath(filename));
2185 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
2187 // Check if the document already is open
2188 if (use_gui && theBufferList().exists(lyxfile.absFilename())) {
2189 if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) {
2190 lyx_view_->message(_("Canceled."));
2195 // if the file exists already, and we didn't do
2196 // -i lyx thefile.lyx, warn
2197 if (fs::exists(lyxfile.toFilesystemEncoding()) && fullname != lyxfile) {
2198 docstring const file = makeDisplayPath(lyxfile.absFilename(), 30);
2200 docstring text = bformat(_("The document %1$s already exists.\n\n"
2201 "Do you want to overwrite that document?"), file);
2202 int const ret = Alert::prompt(_("Overwrite document?"),
2203 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2206 lyx_view_->message(_("Canceled."));
2211 ErrorList errorList;
2212 Importer::Import(lyx_view_, fullname, format, errorList);
2213 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2217 void LyXFunc::closeBuffer()
2219 // goto bookmark to update bookmark pit.
2220 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2221 gotoBookmark(i+1, false, false);
2223 theBufferList().close(lyx_view_->buffer(), true);
2227 void LyXFunc::reloadBuffer()
2229 FileName filename(lyx_view_->buffer()->fileName());
2230 docstring const disp_fn = makeDisplayPath(filename.absFilename());
2233 Buffer * buf = lyx_view_->loadLyXFile(filename);
2236 lyx_view_->setBuffer(buf);
2237 lyx_view_->showErrorList("Parse");
2238 str = bformat(_("Document %1$s reloaded."), disp_fn);
2240 str = bformat(_("Could not reload document %1$s"), disp_fn);
2242 lyx_view_->message(str);
2245 // Each "lyx_view_" should have it's own message method. lyxview and
2246 // the minibuffer would use the minibuffer, but lyxserver would
2247 // send an ERROR signal to its client. Alejandro 970603
2248 // This function is bit problematic when it comes to NLS, to make the
2249 // lyx servers client be language indepenent we must not translate
2250 // strings sent to this func.
2251 void LyXFunc::setErrorMessage(docstring const & m) const
2253 dispatch_buffer = m;
2258 void LyXFunc::setMessage(docstring const & m) const
2260 dispatch_buffer = m;
2264 docstring const LyXFunc::viewStatusMessage()
2266 // When meta-fake key is pressed, show the key sequence so far + "M-".
2268 return keyseq->print(true) + "M-";
2270 // Else, when a non-complete key sequence is pressed,
2271 // show the available options.
2272 if (keyseq->length() > 0 && !keyseq->deleted())
2273 return keyseq->printOptions(true);
2275 BOOST_ASSERT(lyx_view_);
2276 if (!lyx_view_->buffer())
2277 return _("Welcome to LyX!");
2279 return view()->cursor().currentState();
2283 BufferView * LyXFunc::view() const
2285 BOOST_ASSERT(lyx_view_);
2286 return lyx_view_->view();
2290 bool LyXFunc::wasMetaKey() const
2292 return (meta_fake_bit != key_modifier::none);
2296 void LyXFunc::updateLayout(TextClass_ptr const & oldlayout,
2299 lyx_view_->message(_("Converting document to new document class..."));
2301 StableDocIterator backcur(view()->cursor());
2302 ErrorList & el = buffer->errorList("Class Switch");
2303 cap::switchBetweenClasses(
2304 oldlayout, buffer->params().getTextClass_ptr(),
2305 static_cast<InsetText &>(buffer->inset()), el);
2307 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
2309 buffer->errors("Class Switch");
2310 updateLabels(*buffer);
2316 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2318 // Why the switch you might ask. It is a trick to ensure that all
2319 // the elements in the LyXRCTags enum is handled. As you can see
2320 // there are no breaks at all. So it is just a huge fall-through.
2321 // The nice thing is that we will get a warning from the compiler
2322 // if we forget an element.
2323 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2325 case LyXRC::RC_ACCEPT_COMPOUND:
2326 case LyXRC::RC_ALT_LANG:
2327 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
2328 case LyXRC::RC_PLAINTEXT_LINELEN:
2329 case LyXRC::RC_AUTOREGIONDELETE:
2330 case LyXRC::RC_AUTORESET_OPTIONS:
2331 case LyXRC::RC_AUTOSAVE:
2332 case LyXRC::RC_AUTO_NUMBER:
2333 case LyXRC::RC_BACKUPDIR_PATH:
2334 case LyXRC::RC_BIBTEX_COMMAND:
2335 case LyXRC::RC_BINDFILE:
2336 case LyXRC::RC_CHECKLASTFILES:
2337 case LyXRC::RC_USELASTFILEPOS:
2338 case LyXRC::RC_LOADSESSION:
2339 case LyXRC::RC_CHKTEX_COMMAND:
2340 case LyXRC::RC_CONVERTER:
2341 case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
2342 case LyXRC::RC_COPIER:
2343 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2344 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2345 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2346 case LyXRC::RC_DATE_INSERT_FORMAT:
2347 case LyXRC::RC_DEFAULT_LANGUAGE:
2348 case LyXRC::RC_DEFAULT_PAPERSIZE:
2349 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2350 case LyXRC::RC_DISPLAY_GRAPHICS:
2351 case LyXRC::RC_DOCUMENTPATH:
2352 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2353 string const encoded = FileName(
2354 lyxrc_new.document_path).toFilesystemEncoding();
2355 if (fs::exists(encoded) && fs::is_directory(encoded))
2356 support::package().document_dir() = FileName(lyxrc.document_path);
2358 case LyXRC::RC_ESC_CHARS:
2359 case LyXRC::RC_FONT_ENCODING:
2360 case LyXRC::RC_FORMAT:
2361 case LyXRC::RC_INDEX_COMMAND:
2362 case LyXRC::RC_INPUT:
2363 case LyXRC::RC_KBMAP:
2364 case LyXRC::RC_KBMAP_PRIMARY:
2365 case LyXRC::RC_KBMAP_SECONDARY:
2366 case LyXRC::RC_LABEL_INIT_LENGTH:
2367 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2368 case LyXRC::RC_LANGUAGE_AUTO_END:
2369 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2370 case LyXRC::RC_LANGUAGE_COMMAND_END:
2371 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2372 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2373 case LyXRC::RC_LANGUAGE_PACKAGE:
2374 case LyXRC::RC_LANGUAGE_USE_BABEL:
2375 case LyXRC::RC_MAKE_BACKUP:
2376 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2377 case LyXRC::RC_NUMLASTFILES:
2378 case LyXRC::RC_PATH_PREFIX:
2379 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2380 support::prependEnvPath("PATH", lyxrc.path_prefix);
2382 case LyXRC::RC_PERS_DICT:
2383 case LyXRC::RC_PREVIEW:
2384 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2385 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2386 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2387 case LyXRC::RC_PRINTCOPIESFLAG:
2388 case LyXRC::RC_PRINTER:
2389 case LyXRC::RC_PRINTEVENPAGEFLAG:
2390 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2391 case LyXRC::RC_PRINTFILEEXTENSION:
2392 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2393 case LyXRC::RC_PRINTODDPAGEFLAG:
2394 case LyXRC::RC_PRINTPAGERANGEFLAG:
2395 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2396 case LyXRC::RC_PRINTPAPERFLAG:
2397 case LyXRC::RC_PRINTREVERSEFLAG:
2398 case LyXRC::RC_PRINTSPOOL_COMMAND:
2399 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2400 case LyXRC::RC_PRINTTOFILE:
2401 case LyXRC::RC_PRINTTOPRINTER:
2402 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2403 case LyXRC::RC_PRINT_COMMAND:
2404 case LyXRC::RC_RTL_SUPPORT:
2405 case LyXRC::RC_SCREEN_DPI:
2406 case LyXRC::RC_SCREEN_FONT_ROMAN:
2407 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2408 case LyXRC::RC_SCREEN_FONT_SANS:
2409 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2410 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2411 case LyXRC::RC_SCREEN_FONT_SIZES:
2412 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2413 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2414 case LyXRC::RC_SCREEN_GEOMETRY_HEIGHT:
2415 case LyXRC::RC_SCREEN_GEOMETRY_WIDTH:
2416 case LyXRC::RC_SCREEN_GEOMETRY_XYSAVED:
2417 case LyXRC::RC_SCREEN_ZOOM:
2418 case LyXRC::RC_SERVERPIPE:
2419 case LyXRC::RC_SET_COLOR:
2420 case LyXRC::RC_SHOW_BANNER:
2421 case LyXRC::RC_SPELL_COMMAND:
2422 case LyXRC::RC_TEMPDIRPATH:
2423 case LyXRC::RC_TEMPLATEPATH:
2424 case LyXRC::RC_TEX_ALLOWS_SPACES:
2425 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2426 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2427 support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2429 case LyXRC::RC_UIFILE:
2430 case LyXRC::RC_USER_EMAIL:
2431 case LyXRC::RC_USER_NAME:
2432 case LyXRC::RC_USETEMPDIR:
2433 case LyXRC::RC_USE_ALT_LANG:
2434 case LyXRC::RC_USE_CONVERTER_CACHE:
2435 case LyXRC::RC_USE_ESC_CHARS:
2436 case LyXRC::RC_USE_INP_ENC:
2437 case LyXRC::RC_USE_PERS_DICT:
2438 case LyXRC::RC_USE_SPELL_LIB:
2439 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2440 case LyXRC::RC_VIEWER:
2441 case LyXRC::RC_LAST: