3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Alfredo Braunstein
7 * \author Lars Gullik Bjønnes
8 * \author Jean-Marc Lasgouttes
9 * \author Angus Leeming
11 * \author André Pönitz
14 * \author Martin Vermeer
15 * \author Jürgen Vigna
17 * Full author contact details are available in file CREDITS.
25 #include "BranchList.h"
26 #include "buffer_funcs.h"
28 #include "BufferList.h"
29 #include "BufferParams.h"
30 #include "bufferview_funcs.h"
31 #include "BufferView.h"
35 #include "CutAndPaste.h"
37 #include "DispatchResult.h"
39 #include "ErrorList.h"
42 #include "FuncRequest.h"
43 #include "FuncStatus.h"
46 #include "InsetIterator.h"
51 #include "LyXAction.h"
56 #include "Paragraph.h"
57 #include "ParagraphParameters.h"
58 #include "ParIterator.h"
62 #include "TextClassList.h"
63 #include "ToolbarBackend.h"
66 #include "insets/InsetBox.h"
67 #include "insets/InsetBranch.h"
68 #include "insets/InsetCommand.h"
69 #include "insets/InsetERT.h"
70 #include "insets/InsetExternal.h"
71 #include "insets/InsetFloat.h"
72 #include "insets/InsetListings.h"
73 #include "insets/InsetGraphics.h"
74 #include "insets/InsetInclude.h"
75 #include "insets/InsetNote.h"
76 #include "insets/InsetTabular.h"
77 #include "insets/InsetVSpace.h"
78 #include "insets/InsetWrap.h"
80 #include "frontends/Application.h"
81 #include "frontends/alert.h"
82 #include "frontends/Dialogs.h"
83 #include "frontends/FileDialog.h"
84 #include "frontends/FontLoader.h"
85 #include "frontends/Gui.h"
86 #include "frontends/KeySymbol.h"
87 #include "frontends/LyXView.h"
88 #include "frontends/Selection.h"
89 #include "frontends/WorkArea.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>
109 using std::make_pair;
112 using std::istringstream;
113 using std::ostringstream;
115 namespace fs = boost::filesystem;
119 using bv_funcs::freefont2string;
121 using frontend::LyXView;
123 using support::absolutePath;
124 using support::addName;
125 using support::addPath;
126 using support::bformat;
127 using support::changeExtension;
128 using support::contains;
129 using support::FileFilterList;
130 using support::FileName;
131 using support::fileSearch;
132 using support::ForkedcallsController;
133 using support::i18nLibFileSearch;
134 using support::isDirWriteable;
135 using support::isFileReadable;
136 using support::isStrInt;
137 using support::makeAbsPath;
138 using support::makeDisplayPath;
139 using support::package;
140 using support::quoteName;
141 using support::rtrim;
142 using support::split;
143 using support::subst;
144 using support::Systemcall;
145 using support::token;
147 using support::prefixIs;
149 namespace Alert = frontend::Alert;
154 bool getLocalStatus(Cursor cursor,
155 FuncRequest const & cmd, FuncStatus & status)
157 // Try to fix cursor in case it is broken.
158 cursor.fixIfBroken();
160 // This is, of course, a mess. Better create a new doc iterator and use
161 // this in Inset::getStatus. This might require an additional
162 // BufferView * arg, though (which should be avoided)
163 //Cursor safe = *this;
165 for ( ; cursor.depth(); cursor.pop()) {
166 //lyxerr << "\nCursor::getStatus: cmd: " << cmd << endl << *this << endl;
167 BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
168 BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
169 BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
171 // The inset's getStatus() will return 'true' if it made
172 // a definitive decision on whether it want to handle the
173 // request or not. The result of this decision is put into
174 // the 'status' parameter.
175 if (cursor.inset().getStatus(cursor, cmd, status)) {
184 /** Return the change status at cursor position, taking in account the
185 * status at each level of the document iterator (a table in a deleted
186 * footnote is deleted).
187 * When \param outer is true, the top slice is not looked at.
189 Change::Type lookupChangeType(DocIterator const & dit, bool outer = false)
191 size_t const depth = dit.depth() - (outer ? 1 : 0);
193 for (size_t i = 0 ; i < depth ; ++i) {
194 CursorSlice const & slice = dit[i];
195 if (!slice.inset().inMathed()
196 && slice.pos() < slice.paragraph().size()) {
197 Change::Type const ch = slice.paragraph().lookupChange(slice.pos()).type;
198 if (ch != Change::UNCHANGED)
202 return Change::UNCHANGED;
209 : lyx_view_(0), encoded_last_key(0), meta_fake_bit(key_modifier::none)
214 void LyXFunc::initKeySequences(KeyMap * kb)
216 keyseq = KeySequence(kb, kb);
217 cancel_meta_seq = 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;
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(KeySymbol const & keysym,
297 key_modifier::state state)
299 LYXERR(Debug::KEY) << "KeySym is " << keysym.getSymbolName() << endl;
301 // Do nothing if we have nothing (JMarc)
302 if (!keysym.isOK()) {
303 LYXERR(Debug::KEY) << "Empty kbd action (probably composing)"
308 if (keysym.isModifier()) {
309 LYXERR(Debug::KEY) << "isModifier true" << endl;
313 //Encoding const * encoding = view()->cursor().getEncoding();
314 //encoded_last_key = keysym.getISOEncoded(encoding ? encoding->name() : "");
315 // FIXME: encoded_last_key shadows the member variable of the same
316 // name. Is that intended?
317 char_type encoded_last_key = keysym.getUCSEncoded();
319 // Do a one-deep top-level lookup for
320 // cancel and meta-fake keys. RVDK_PATCH_5
321 cancel_meta_seq.reset();
323 FuncRequest func = cancel_meta_seq.addkey(keysym, state);
324 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
325 << " action first set to [" << func.action << ']'
328 // When not cancel or meta-fake, do the normal lookup.
329 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
330 // Mostly, meta_fake_bit = key_modifier::none. RVDK_PATCH_5.
331 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_PREFIX)) {
332 // remove Caps Lock and Mod2 as a modifiers
333 func = keyseq.addkey(keysym, (state | meta_fake_bit));
334 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
335 << "action now set to ["
336 << func.action << ']' << endl;
339 // Dont remove this unless you know what you are doing.
340 meta_fake_bit = key_modifier::none;
342 // Can this happen now ?
343 if (func.action == LFUN_NOACTION) {
344 func = FuncRequest(LFUN_COMMAND_PREFIX);
347 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
349 << func.action << "]["
350 << to_utf8(keyseq.print(false)) << ']'
353 // already here we know if it any point in going further
354 // why not return already here if action == -1 and
355 // num_bytes == 0? (Lgb)
357 if (keyseq.length() > 1) {
358 lyx_view_->message(keyseq.print(true));
362 // Maybe user can only reach the key via holding down shift.
363 // Let's see. But only if shift is the only modifier
364 if (func.action == LFUN_UNKNOWN_ACTION &&
365 state == key_modifier::shift) {
366 LYXERR(Debug::KEY) << "Trying without shift" << endl;
367 func = keyseq.addkey(keysym, key_modifier::none);
368 LYXERR(Debug::KEY) << "Action now " << func.action << endl;
371 if (func.action == LFUN_UNKNOWN_ACTION) {
372 // Hmm, we didn't match any of the keysequences. See
373 // if it's normal insertable text not already covered
375 if (keysym.isText() && keyseq.length() == 1) {
376 LYXERR(Debug::KEY) << "isText() is true, inserting." << endl;
377 func = FuncRequest(LFUN_SELF_INSERT,
378 FuncRequest::KEYBOARD);
380 LYXERR(Debug::KEY) << "Unknown, !isText() - giving up" << endl;
381 lyx_view_->message(_("Unknown function."));
386 if (func.action == LFUN_SELF_INSERT) {
387 if (encoded_last_key != 0) {
388 docstring const arg(1, encoded_last_key);
389 dispatch(FuncRequest(LFUN_SELF_INSERT, arg,
390 FuncRequest::KEYBOARD));
392 << "SelfInsert arg[`" << to_utf8(arg) << "']" << endl;
398 /* When we move around, or type, it's nice to be able to see
399 * the cursor immediately after the keypress.
401 if (lyx_view_ && lyx_view_->currentWorkArea())
402 lyx_view_->currentWorkArea()->startBlinkingCursor();
406 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
408 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
411 Cursor & cur = view()->cursor();
413 /* In LyX/Mac, when a dialog is open, the menus of the
414 application can still be accessed without giving focus to
415 the main window. In this case, we want to disable the menu
416 entries that are buffer-related.
418 Note that this code is not perfect, as bug 1941 attests:
419 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
421 Buffer * buf = lyx_view_? lyx_view_->buffer() : 0;
422 if (lyx_view_ && cmd.origin == FuncRequest::MENU && !lyx_view_->hasFocus())
425 if (cmd.action == LFUN_NOACTION) {
426 flag.message(from_utf8(N_("Nothing to do")));
431 switch (cmd.action) {
432 case LFUN_UNKNOWN_ACTION:
433 #ifndef HAVE_LIBAIKSAURUS
434 case LFUN_THESAURUS_ENTRY:
444 if (flag.unknown()) {
445 flag.message(from_utf8(N_("Unknown action")));
449 if (!flag.enabled()) {
450 if (flag.message().empty())
451 flag.message(from_utf8(N_("Command disabled")));
455 // Check whether we need a buffer
456 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
458 flag.message(from_utf8(N_("Command not allowed with"
459 "out any document open")));
464 // I would really like to avoid having this switch and rather try to
465 // encode this in the function itself.
466 // -- And I'd rather let an inset decide which LFUNs it is willing
467 // to handle (Andre')
469 switch (cmd.action) {
470 case LFUN_BUFFER_TOGGLE_READ_ONLY:
471 flag.setOnOff(buf->isReadonly());
474 case LFUN_BUFFER_SWITCH:
475 // toggle on the current buffer, but do not toggle off
476 // the other ones (is that a good idea?)
477 if (buf && to_utf8(cmd.argument()) == buf->fileName())
481 case LFUN_BUFFER_EXPORT:
482 enable = cmd.argument() == "custom"
483 || Exporter::isExportable(*buf, to_utf8(cmd.argument()));
486 case LFUN_BUFFER_CHKTEX:
487 enable = buf->isLatex() && !lyxrc.chktex_command.empty();
490 case LFUN_BUILD_PROGRAM:
491 enable = Exporter::isExportable(*buf, "program");
494 case LFUN_LAYOUT_TABULAR:
495 enable = cur.innerInsetOfType(Inset::TABULAR_CODE);
499 case LFUN_LAYOUT_PARAGRAPH:
500 enable = !cur.inset().forceDefaultParagraphs(cur.idx());
503 case LFUN_VC_REGISTER:
504 enable = !buf->lyxvc().inUse();
506 case LFUN_VC_CHECK_IN:
507 enable = buf->lyxvc().inUse() && !buf->isReadonly();
509 case LFUN_VC_CHECK_OUT:
510 enable = buf->lyxvc().inUse() && buf->isReadonly();
513 case LFUN_VC_UNDO_LAST:
514 enable = buf->lyxvc().inUse();
516 case LFUN_BUFFER_RELOAD:
517 enable = !buf->isUnnamed() && fs::exists(buf->fileName())
518 && (!buf->isClean() || buf->isExternallyModified(Buffer::timestamp_method));
521 case LFUN_INSET_SETTINGS: {
525 Inset::Code code = cur.inset().lyxCode();
527 case Inset::TABULAR_CODE:
528 enable = cmd.argument() == "tabular";
530 case Inset::ERT_CODE:
531 enable = cmd.argument() == "ert";
533 case Inset::FLOAT_CODE:
534 enable = cmd.argument() == "float";
536 case Inset::WRAP_CODE:
537 enable = cmd.argument() == "wrap";
539 case Inset::NOTE_CODE:
540 enable = cmd.argument() == "note";
542 case Inset::BRANCH_CODE:
543 enable = cmd.argument() == "branch";
545 case Inset::BOX_CODE:
546 enable = cmd.argument() == "box";
548 case Inset::LISTINGS_CODE:
549 enable = cmd.argument() == "listings";
557 case LFUN_INSET_APPLY: {
558 string const name = cmd.getArg(0);
559 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
561 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
563 if (!inset->getStatus(cur, fr, fs)) {
564 // Every inset is supposed to handle this
569 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
570 flag |= getStatus(fr);
572 enable = flag.enabled();
576 case LFUN_DIALOG_TOGGLE:
577 flag.setOnOff(lyx_view_->getDialogs().visible(cmd.getArg(0)));
578 // fall through to set "enable"
579 case LFUN_DIALOG_SHOW: {
580 string const name = cmd.getArg(0);
582 enable = name == "aboutlyx"
583 || name == "file" //FIXME: should be removed.
585 || name == "texinfo";
586 else if (name == "print")
587 enable = Exporter::isExportable(*buf, "dvi")
588 && lyxrc.print_command != "none";
589 else if (name == "character")
590 enable = cur.inset().lyxCode() != Inset::ERT_CODE &&
591 cur.inset().lyxCode() != Inset::LISTINGS_CODE;
592 else if (name == "latexlog")
593 enable = isFileReadable(FileName(buf->getLogName().second));
594 else if (name == "spellchecker")
595 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
596 enable = !buf->isReadonly();
600 else if (name == "vclog")
601 enable = buf->lyxvc().inUse();
605 case LFUN_DIALOG_SHOW_NEW_INSET:
606 enable = cur.inset().lyxCode() != Inset::ERT_CODE &&
607 cur.inset().lyxCode() != Inset::LISTINGS_CODE;
608 if (cur.inset().lyxCode() == Inset::CAPTION_CODE) {
610 if (cur.inset().getStatus(cur, cmd, flag))
615 case LFUN_DIALOG_UPDATE: {
616 string const name = cmd.getArg(0);
618 enable = name == "prefs";
622 case LFUN_CITATION_INSERT: {
623 FuncRequest fr(LFUN_INSET_INSERT, "citation");
624 enable = getStatus(fr).enabled();
628 case LFUN_BUFFER_WRITE: {
629 enable = lyx_view_->buffer()->isUnnamed()
630 || !lyx_view_->buffer()->isClean();
635 case LFUN_BUFFER_WRITE_ALL: {
636 // We enable the command only if there are some modified buffers
637 Buffer * first = theBufferList().first();
638 bool modified = false;
642 // We cannot use a for loop as the buffer list is a cycle.
648 b = theBufferList().next(b);
649 } while (b != first);
657 case LFUN_BOOKMARK_GOTO: {
658 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
659 enable = LyX::ref().session().bookmarks().isValid(num);
663 case LFUN_BOOKMARK_CLEAR:
664 enable = LyX::ref().session().bookmarks().size() > 0;
667 case LFUN_TOOLBAR_TOGGLE: {
668 bool const current = lyx_view_->isToolbarVisible(cmd.getArg(0));
669 flag.setOnOff(current);
672 case LFUN_WINDOW_CLOSE: {
673 enable = (theApp()->gui().viewIds().size() > 1);
677 // this one is difficult to get right. As a half-baked
678 // solution, we consider only the first action of the sequence
679 case LFUN_COMMAND_SEQUENCE: {
680 // argument contains ';'-terminated commands
681 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
682 FuncRequest func(lyxaction.lookupFunc(firstcmd));
683 func.origin = cmd.origin;
684 flag = getStatus(func);
687 case LFUN_BUFFER_NEW:
688 case LFUN_BUFFER_NEW_TEMPLATE:
689 case LFUN_WORD_FIND_FORWARD:
690 case LFUN_WORD_FIND_BACKWARD:
691 case LFUN_COMMAND_PREFIX:
692 case LFUN_COMMAND_EXECUTE:
694 case LFUN_META_PREFIX:
695 case LFUN_BUFFER_CLOSE:
696 case LFUN_BUFFER_WRITE_AS:
697 case LFUN_BUFFER_UPDATE:
698 case LFUN_BUFFER_VIEW:
699 case LFUN_BUFFER_IMPORT:
700 case LFUN_BUFFER_AUTO_SAVE:
701 case LFUN_RECONFIGURE:
705 case LFUN_DROP_LAYOUTS_CHOICE:
707 case LFUN_SERVER_GET_NAME:
708 case LFUN_SERVER_NOTIFY:
709 case LFUN_SERVER_GOTO_FILE_ROW:
710 case LFUN_DIALOG_HIDE:
711 case LFUN_DIALOG_DISCONNECT_INSET:
712 case LFUN_BUFFER_CHILD_OPEN:
713 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
714 case LFUN_KEYMAP_OFF:
715 case LFUN_KEYMAP_PRIMARY:
716 case LFUN_KEYMAP_SECONDARY:
717 case LFUN_KEYMAP_TOGGLE:
719 case LFUN_BUFFER_EXPORT_CUSTOM:
720 case LFUN_BUFFER_PRINT:
721 case LFUN_PREFERENCES_SAVE:
722 case LFUN_SCREEN_FONT_UPDATE:
725 case LFUN_EXTERNAL_EDIT:
726 case LFUN_GRAPHICS_EDIT:
727 case LFUN_ALL_INSETS_TOGGLE:
728 case LFUN_BUFFER_LANGUAGE:
729 case LFUN_TEXTCLASS_APPLY:
730 case LFUN_TEXTCLASS_LOAD:
731 case LFUN_BUFFER_SAVE_AS_DEFAULT:
732 case LFUN_BUFFER_PARAMS_APPLY:
733 case LFUN_LAYOUT_MODULES_CLEAR:
734 case LFUN_LAYOUT_MODULE_ADD:
735 case LFUN_LAYOUT_RELOAD:
736 case LFUN_LYXRC_APPLY:
737 case LFUN_BUFFER_NEXT:
738 case LFUN_BUFFER_PREVIOUS:
739 case LFUN_WINDOW_NEW:
741 // these are handled in our dispatch()
745 if (!getLocalStatus(cur, cmd, flag))
746 flag = view()->getStatus(cmd);
752 // Can we use a readonly buffer?
753 if (buf && buf->isReadonly()
754 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
755 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
756 flag.message(from_utf8(N_("Document is read-only")));
760 // Are we in a DELETED change-tracking region?
761 if (buf && lookupChangeType(cur, true) == Change::DELETED
762 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
763 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
764 flag.message(from_utf8(N_("This portion of the document is deleted.")));
768 // the default error message if we disable the command
769 if (!flag.enabled() && flag.message().empty())
770 flag.message(from_utf8(N_("Command disabled")));
776 bool LyXFunc::ensureBufferClean(BufferView * bv)
778 Buffer & buf = bv->buffer();
782 docstring const file = makeDisplayPath(buf.fileName(), 30);
783 docstring text = bformat(_("The document %1$s has unsaved "
784 "changes.\n\nDo you want to save "
785 "the document?"), file);
786 int const ret = Alert::prompt(_("Save changed document?"),
787 text, 0, 1, _("&Save"),
791 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
793 return buf.isClean();
799 void showPrintError(string const & name)
801 docstring str = bformat(_("Could not print the document %1$s.\n"
802 "Check that your printer is set up correctly."),
803 makeDisplayPath(name, 50));
804 Alert::error(_("Print document failed"), str);
808 void loadTextClass(string const & name)
810 std::pair<bool, textclass_type> const tc_pair =
811 textclasslist.numberOfClass(name);
813 if (!tc_pair.first) {
814 lyxerr << "Document class \"" << name
815 << "\" does not exist."
820 textclass_type const tc = tc_pair.second;
822 if (!textclasslist[tc].load()) {
823 docstring s = bformat(_("The document class %1$s."
824 "could not be loaded."),
825 from_utf8(textclasslist[tc].name()));
826 Alert::error(_("Could not load class"), s);
831 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
836 void LyXFunc::dispatch(FuncRequest const & cmd)
838 string const argument = to_utf8(cmd.argument());
839 kb_action const action = cmd.action;
841 LYXERR(Debug::ACTION) << endl << "LyXFunc::dispatch: cmd: " << cmd << endl;
842 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
844 // we have not done anything wrong yet.
846 dispatch_buffer.erase();
848 // redraw the screen at the end (first of the two drawing steps).
849 //This is done unless explicitely requested otherwise
850 Update::flags updateFlags = Update::FitCursor;
852 FuncStatus const flag = getStatus(cmd);
853 if (!flag.enabled()) {
854 // We cannot use this function here
855 LYXERR(Debug::ACTION) << "LyXFunc::dispatch: "
856 << lyxaction.getActionName(action)
857 << " [" << action << "] is disabled at this location"
859 setErrorMessage(flag.message());
863 case LFUN_WORD_FIND_FORWARD:
864 case LFUN_WORD_FIND_BACKWARD: {
865 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
866 static docstring last_search;
867 docstring searched_string;
869 if (!cmd.argument().empty()) {
870 last_search = cmd.argument();
871 searched_string = cmd.argument();
873 searched_string = last_search;
876 if (searched_string.empty())
879 bool const fw = action == LFUN_WORD_FIND_FORWARD;
880 docstring const data =
881 find2string(searched_string, true, false, fw);
882 find(view(), FuncRequest(LFUN_WORD_FIND, data));
886 case LFUN_COMMAND_PREFIX:
887 BOOST_ASSERT(lyx_view_);
888 lyx_view_->message(keyseq.printOptions(true));
891 case LFUN_COMMAND_EXECUTE:
892 BOOST_ASSERT(lyx_view_);
893 lyx_view_->showMiniBuffer(true);
897 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
899 meta_fake_bit = key_modifier::none;
900 if (lyx_view_->buffer())
901 // cancel any selection
902 dispatch(FuncRequest(LFUN_MARK_OFF));
903 setMessage(from_ascii(N_("Cancel")));
906 case LFUN_META_PREFIX:
907 meta_fake_bit = key_modifier::alt;
908 setMessage(keyseq.print(true));
911 case LFUN_BUFFER_TOGGLE_READ_ONLY:
912 BOOST_ASSERT(lyx_view_ && lyx_view_->view() && lyx_view_->buffer());
913 if (lyx_view_->buffer()->lyxvc().inUse())
914 lyx_view_->buffer()->lyxvc().toggleReadOnly();
916 lyx_view_->buffer()->setReadonly(
917 !lyx_view_->buffer()->isReadonly());
920 // --- Menus -----------------------------------------------
921 case LFUN_BUFFER_NEW:
922 menuNew(argument, false);
923 updateFlags = Update::None;
926 case LFUN_BUFFER_NEW_TEMPLATE:
927 menuNew(argument, true);
928 updateFlags = Update::None;
931 case LFUN_BUFFER_CLOSE:
933 updateFlags = Update::None;
936 case LFUN_BUFFER_WRITE:
937 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
938 if (!lyx_view_->buffer()->isUnnamed()) {
939 docstring const str = bformat(_("Saving document %1$s..."),
940 makeDisplayPath(lyx_view_->buffer()->fileName()));
941 lyx_view_->message(str);
942 menuWrite(lyx_view_->buffer());
943 lyx_view_->message(str + _(" done."));
945 writeAs(lyx_view_->buffer());
947 updateFlags = Update::None;
950 case LFUN_BUFFER_WRITE_AS:
951 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
952 writeAs(lyx_view_->buffer(), argument);
953 updateFlags = Update::None;
956 case LFUN_BUFFER_WRITE_ALL: {
957 Buffer * first = theBufferList().first();
960 lyx_view_->message(_("Saving all documents..."));
962 // We cannot use a for loop as the buffer list cycles.
965 if (!b->isUnnamed()) {
967 lyxerr[Debug::ACTION] << "Saved " << b->fileName() << endl;
971 b = theBufferList().next(b);
972 } while (b != first);
973 lyx_view_->message(_("All documents saved."));
976 updateFlags = Update::None;
980 case LFUN_BUFFER_RELOAD: {
981 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
982 docstring const file = makeDisplayPath(lyx_view_->buffer()->fileName(), 20);
983 docstring text = bformat(_("Any changes will be lost. Are you sure "
984 "you want to revert to the saved version of the document %1$s?"), file);
985 int const ret = Alert::prompt(_("Revert to saved document?"),
986 text, 1, 1, _("&Revert"), _("&Cancel"));
993 case LFUN_BUFFER_UPDATE:
994 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
995 Exporter::Export(lyx_view_->buffer(), argument, true);
998 case LFUN_BUFFER_VIEW:
999 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1000 Exporter::preview(lyx_view_->buffer(), argument);
1003 case LFUN_BUILD_PROGRAM:
1004 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1005 Exporter::Export(lyx_view_->buffer(), "program", true);
1008 case LFUN_BUFFER_CHKTEX:
1009 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1010 lyx_view_->buffer()->runChktex();
1013 case LFUN_BUFFER_EXPORT:
1014 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1015 if (argument == "custom")
1016 lyx_view_->getDialogs().show("sendto");
1018 Exporter::Export(lyx_view_->buffer(), argument, false);
1022 case LFUN_BUFFER_EXPORT_CUSTOM: {
1023 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1025 string command = split(argument, format_name, ' ');
1026 Format const * format = formats.getFormat(format_name);
1028 lyxerr << "Format \"" << format_name
1029 << "\" not recognized!"
1034 Buffer * buffer = lyx_view_->buffer();
1036 // The name of the file created by the conversion process
1039 // Output to filename
1040 if (format->name() == "lyx") {
1041 string const latexname =
1042 buffer->getLatexName(false);
1043 filename = changeExtension(latexname,
1044 format->extension());
1045 filename = addName(buffer->temppath(), filename);
1047 if (!buffer->writeFile(FileName(filename)))
1051 Exporter::Export(buffer, format_name, true, filename);
1054 // Substitute $$FName for filename
1055 if (!contains(command, "$$FName"))
1056 command = "( " + command + " ) < $$FName";
1057 command = subst(command, "$$FName", filename);
1059 // Execute the command in the background
1061 call.startscript(Systemcall::DontWait, command);
1065 case LFUN_BUFFER_PRINT: {
1066 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1067 // FIXME: cmd.getArg() might fail if one of the arguments
1068 // contains double quotes
1069 string target = cmd.getArg(0);
1070 string target_name = cmd.getArg(1);
1071 string command = cmd.getArg(2);
1074 || target_name.empty()
1075 || command.empty()) {
1076 lyxerr << "Unable to parse \""
1077 << argument << '"' << endl;
1080 if (target != "printer" && target != "file") {
1081 lyxerr << "Unrecognized target \""
1082 << target << '"' << endl;
1086 Buffer * buffer = lyx_view_->buffer();
1088 if (!Exporter::Export(buffer, "dvi", true)) {
1089 showPrintError(buffer->fileName());
1093 // Push directory path.
1094 string const path(buffer->temppath());
1095 // Prevent the compiler from optimizing away p
1097 support::Path p(pp);
1099 // there are three cases here:
1100 // 1. we print to a file
1101 // 2. we print directly to a printer
1102 // 3. we print using a spool command (print to file first)
1105 string const dviname =
1106 changeExtension(buffer->getLatexName(true),
1109 if (target == "printer") {
1110 if (!lyxrc.print_spool_command.empty()) {
1111 // case 3: print using a spool
1112 string const psname =
1113 changeExtension(dviname,".ps");
1114 command += ' ' + lyxrc.print_to_file
1117 + quoteName(dviname);
1120 lyxrc.print_spool_command + ' ';
1121 if (target_name != "default") {
1122 command2 += lyxrc.print_spool_printerprefix
1126 command2 += quoteName(psname);
1128 // If successful, then spool command
1129 res = one.startscript(
1134 res = one.startscript(
1135 Systemcall::DontWait,
1138 // case 2: print directly to a printer
1139 if (target_name != "default")
1140 command += ' ' + lyxrc.print_to_printer + target_name + ' ';
1141 res = one.startscript(
1142 Systemcall::DontWait,
1143 command + quoteName(dviname));
1147 // case 1: print to a file
1148 FileName const filename(makeAbsPath(target_name,
1149 lyx_view_->buffer()->filePath()));
1150 FileName const dvifile(makeAbsPath(dviname, path));
1151 if (fs::exists(filename.toFilesystemEncoding())) {
1152 docstring text = bformat(
1153 _("The file %1$s already exists.\n\n"
1154 "Do you want to overwrite that file?"),
1155 makeDisplayPath(filename.absFilename()));
1156 if (Alert::prompt(_("Overwrite file?"),
1157 text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
1160 command += ' ' + lyxrc.print_to_file
1161 + quoteName(filename.toFilesystemEncoding())
1163 + quoteName(dvifile.toFilesystemEncoding());
1164 res = one.startscript(Systemcall::DontWait,
1169 showPrintError(buffer->fileName());
1173 case LFUN_BUFFER_IMPORT:
1178 // quitting is triggered by the gui code
1179 // (leaving the event loop).
1180 lyx_view_->message(from_utf8(N_("Exiting.")));
1181 if (theBufferList().quitWriteAll())
1182 theApp()->gui().closeAllViews();
1185 case LFUN_BUFFER_AUTO_SAVE:
1189 case LFUN_RECONFIGURE:
1190 BOOST_ASSERT(lyx_view_);
1191 reconfigure(*lyx_view_);
1194 case LFUN_HELP_OPEN: {
1195 BOOST_ASSERT(lyx_view_);
1196 string const arg = argument;
1198 setErrorMessage(from_ascii(N_("Missing argument")));
1201 FileName const fname = i18nLibFileSearch("doc", arg, "lyx");
1202 if (fname.empty()) {
1203 lyxerr << "LyX: unable to find documentation file `"
1204 << arg << "'. Bad installation?" << endl;
1207 lyx_view_->message(bformat(_("Opening help file %1$s..."),
1208 makeDisplayPath(fname.absFilename())));
1209 Buffer * buf = lyx_view_->loadLyXFile(fname, false);
1212 lyx_view_->setBuffer(buf);
1213 lyx_view_->showErrorList("Parse");
1215 updateFlags = Update::None;
1219 // --- version control -------------------------------
1220 case LFUN_VC_REGISTER:
1221 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1222 if (!ensureBufferClean(view()))
1224 if (!lyx_view_->buffer()->lyxvc().inUse()) {
1225 lyx_view_->buffer()->lyxvc().registrer();
1228 updateFlags = Update::Force;
1231 case LFUN_VC_CHECK_IN:
1232 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1233 if (!ensureBufferClean(view()))
1235 if (lyx_view_->buffer()->lyxvc().inUse()
1236 && !lyx_view_->buffer()->isReadonly()) {
1237 lyx_view_->buffer()->lyxvc().checkIn();
1242 case LFUN_VC_CHECK_OUT:
1243 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1244 if (!ensureBufferClean(view()))
1246 if (lyx_view_->buffer()->lyxvc().inUse()
1247 && lyx_view_->buffer()->isReadonly()) {
1248 lyx_view_->buffer()->lyxvc().checkOut();
1253 case LFUN_VC_REVERT:
1254 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1255 lyx_view_->buffer()->lyxvc().revert();
1259 case LFUN_VC_UNDO_LAST:
1260 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1261 lyx_view_->buffer()->lyxvc().undoLast();
1265 // --- buffers ----------------------------------------
1266 case LFUN_BUFFER_SWITCH:
1267 BOOST_ASSERT(lyx_view_);
1268 lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1269 updateFlags = Update::None;
1272 case LFUN_BUFFER_NEXT:
1273 BOOST_ASSERT(lyx_view_);
1274 lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer()));
1275 updateFlags = Update::None;
1278 case LFUN_BUFFER_PREVIOUS:
1279 BOOST_ASSERT(lyx_view_);
1280 lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer()));
1281 updateFlags = Update::None;
1285 BOOST_ASSERT(lyx_view_);
1286 newFile(*lyx_view_, argument);
1287 updateFlags = Update::None;
1290 case LFUN_FILE_OPEN:
1291 BOOST_ASSERT(lyx_view_);
1293 updateFlags = Update::None;
1296 case LFUN_DROP_LAYOUTS_CHOICE:
1297 BOOST_ASSERT(lyx_view_);
1298 lyx_view_->openLayoutList();
1301 case LFUN_MENU_OPEN:
1302 BOOST_ASSERT(lyx_view_);
1303 lyx_view_->openMenu(from_utf8(argument));
1306 // --- lyxserver commands ----------------------------
1307 case LFUN_SERVER_GET_NAME:
1308 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1309 setMessage(from_utf8(lyx_view_->buffer()->fileName()));
1310 LYXERR(Debug::INFO) << "FNAME["
1311 << lyx_view_->buffer()->fileName()
1315 case LFUN_SERVER_NOTIFY:
1316 dispatch_buffer = keyseq.print(false);
1317 theServer().notifyClient(to_utf8(dispatch_buffer));
1320 case LFUN_SERVER_GOTO_FILE_ROW: {
1321 BOOST_ASSERT(lyx_view_);
1324 istringstream is(argument);
1325 is >> file_name >> row;
1327 bool loaded = false;
1328 if (prefixIs(file_name, package().temp_dir().absFilename()))
1329 // Needed by inverse dvi search. If it is a file
1330 // in tmpdir, call the apropriated function
1331 buf = theBufferList().getBufferFromTmp(file_name);
1333 // Must replace extension of the file to be .lyx
1334 // and get full path
1335 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1336 // Either change buffer or load the file
1337 if (theBufferList().exists(s.absFilename()))
1338 buf = theBufferList().getBuffer(s.absFilename());
1340 buf = lyx_view_->loadLyXFile(s);
1346 updateFlags = Update::None;
1351 lyx_view_->setBuffer(buf);
1352 view()->setCursorFromRow(row);
1354 lyx_view_->showErrorList("Parse");
1355 updateFlags = Update::FitCursor;
1359 case LFUN_DIALOG_SHOW: {
1360 BOOST_ASSERT(lyx_view_);
1361 string const name = cmd.getArg(0);
1362 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1364 if (name == "character") {
1365 data = freefont2string();
1367 lyx_view_->getDialogs().show("character", data);
1368 } else if (name == "latexlog") {
1369 pair<Buffer::LogType, string> const logfile =
1370 lyx_view_->buffer()->getLogName();
1371 switch (logfile.first) {
1372 case Buffer::latexlog:
1375 case Buffer::buildlog:
1379 data += Lexer::quoteString(logfile.second);
1380 lyx_view_->getDialogs().show("log", data);
1381 } else if (name == "vclog") {
1382 string const data = "vc " +
1383 Lexer::quoteString(lyx_view_->buffer()->lyxvc().getLogFile());
1384 lyx_view_->getDialogs().show("log", data);
1386 lyx_view_->getDialogs().show(name, data);
1390 case LFUN_DIALOG_SHOW_NEW_INSET: {
1391 BOOST_ASSERT(lyx_view_);
1392 string const name = cmd.getArg(0);
1393 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1394 if (name == "bibitem" ||
1398 name == "nomenclature" ||
1402 InsetCommandParams p(name);
1403 data = InsetCommandMailer::params2string(name, p);
1404 } else if (name == "include") {
1405 // data is the include type: one of "include",
1406 // "input", "verbatiminput" or "verbatiminput*"
1408 // default type is requested
1410 InsetCommandParams p(data);
1411 data = InsetIncludeMailer::params2string(p);
1412 } else if (name == "box") {
1413 // \c data == "Boxed" || "Frameless" etc
1414 InsetBoxParams p(data);
1415 data = InsetBoxMailer::params2string(p);
1416 } else if (name == "branch") {
1417 InsetBranchParams p;
1418 data = InsetBranchMailer::params2string(p);
1419 } else if (name == "citation") {
1420 InsetCommandParams p("cite");
1421 data = InsetCommandMailer::params2string(name, p);
1422 } else if (name == "ert") {
1423 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1424 } else if (name == "external") {
1425 InsetExternalParams p;
1426 Buffer const & buffer = *lyx_view_->buffer();
1427 data = InsetExternalMailer::params2string(p, buffer);
1428 } else if (name == "float") {
1430 data = InsetFloatMailer::params2string(p);
1431 } else if (name == "listings") {
1432 InsetListingsParams p;
1433 data = InsetListingsMailer::params2string(p);
1434 } else if (name == "graphics") {
1435 InsetGraphicsParams p;
1436 Buffer const & buffer = *lyx_view_->buffer();
1437 data = InsetGraphicsMailer::params2string(p, buffer);
1438 } else if (name == "note") {
1440 data = InsetNoteMailer::params2string(p);
1441 } else if (name == "vspace") {
1443 data = InsetVSpaceMailer::params2string(space);
1444 } else if (name == "wrap") {
1446 data = InsetWrapMailer::params2string(p);
1448 lyx_view_->getDialogs().show(name, data, 0);
1452 case LFUN_DIALOG_UPDATE: {
1453 BOOST_ASSERT(lyx_view_);
1454 string const & name = argument;
1455 // Can only update a dialog connected to an existing inset
1456 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1458 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1459 inset->dispatch(view()->cursor(), fr);
1460 } else if (name == "paragraph") {
1461 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1462 } else if (name == "prefs") {
1463 lyx_view_->getDialogs().update(name, string());
1468 case LFUN_DIALOG_HIDE:
1469 LyX::cref().hideDialogs(argument, 0);
1472 case LFUN_DIALOG_TOGGLE: {
1473 BOOST_ASSERT(lyx_view_);
1474 if (lyx_view_->getDialogs().visible(cmd.getArg(0)))
1475 dispatch(FuncRequest(LFUN_DIALOG_HIDE, argument));
1477 dispatch(FuncRequest(LFUN_DIALOG_SHOW, argument));
1481 case LFUN_DIALOG_DISCONNECT_INSET:
1482 BOOST_ASSERT(lyx_view_);
1483 lyx_view_->getDialogs().disconnect(argument);
1487 case LFUN_CITATION_INSERT: {
1488 BOOST_ASSERT(lyx_view_);
1489 if (!argument.empty()) {
1490 // we can have one optional argument, delimited by '|'
1491 // citation-insert <key>|<text_before>
1492 // this should be enhanced to also support text_after
1493 // and citation style
1494 string arg = argument;
1496 if (contains(argument, "|")) {
1497 arg = token(argument, '|', 0);
1498 opt1 = token(argument, '|', 1);
1500 InsetCommandParams icp("cite");
1501 icp["key"] = from_utf8(arg);
1503 icp["before"] = from_utf8(opt1);
1504 string icstr = InsetCommandMailer::params2string("citation", icp);
1505 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1508 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1512 case LFUN_BUFFER_CHILD_OPEN: {
1513 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1514 Buffer * parent = lyx_view_->buffer();
1515 FileName filename = makeAbsPath(argument, parent->filePath());
1516 view()->saveBookmark(false);
1518 bool parsed = false;
1519 if (theBufferList().exists(filename.absFilename())) {
1520 child = theBufferList().getBuffer(filename.absFilename());
1522 setMessage(bformat(_("Opening child document %1$s..."),
1523 makeDisplayPath(filename.absFilename())));
1524 child = lyx_view_->loadLyXFile(filename, true);
1528 // Set the parent name of the child document.
1529 // This makes insertion of citations and references in the child work,
1530 // when the target is in the parent or another child document.
1531 child->setParentName(parent->fileName());
1532 updateLabels(*child->getMasterBuffer());
1533 lyx_view_->setBuffer(child);
1535 lyx_view_->showErrorList("Parse");
1538 // If a screen update is required (in case where auto_open is false),
1539 // setBuffer() would have taken care of it already. Otherwise we shall
1540 // reset the update flag because it can cause a circular problem.
1542 updateFlags = Update::None;
1546 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1547 BOOST_ASSERT(lyx_view_);
1548 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1551 case LFUN_KEYMAP_OFF:
1552 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1553 lyx_view_->view()->getIntl().keyMapOn(false);
1556 case LFUN_KEYMAP_PRIMARY:
1557 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1558 lyx_view_->view()->getIntl().keyMapPrim();
1561 case LFUN_KEYMAP_SECONDARY:
1562 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1563 lyx_view_->view()->getIntl().keyMapSec();
1566 case LFUN_KEYMAP_TOGGLE:
1567 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1568 lyx_view_->view()->getIntl().toggleKeyMap();
1574 string rest = split(argument, countstr, ' ');
1575 istringstream is(countstr);
1578 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1579 for (int i = 0; i < count; ++i)
1580 dispatch(lyxaction.lookupFunc(rest));
1584 case LFUN_COMMAND_SEQUENCE: {
1585 // argument contains ';'-terminated commands
1586 string arg = argument;
1587 while (!arg.empty()) {
1589 arg = split(arg, first, ';');
1590 FuncRequest func(lyxaction.lookupFunc(first));
1591 func.origin = cmd.origin;
1597 case LFUN_PREFERENCES_SAVE: {
1598 lyxrc.write(makeAbsPath("preferences",
1599 package().user_support().absFilename()),
1604 case LFUN_SCREEN_FONT_UPDATE:
1605 BOOST_ASSERT(lyx_view_);
1606 // handle the screen font changes.
1607 theFontLoader().update();
1608 /// FIXME: only the current view will be updated. the Gui
1609 /// class is able to furnish the list of views.
1610 updateFlags = Update::Force;
1613 case LFUN_SET_COLOR: {
1615 string const x11_name = split(argument, lyx_name, ' ');
1616 if (lyx_name.empty() || x11_name.empty()) {
1617 setErrorMessage(from_ascii(N_(
1618 "Syntax: set-color <lyx_name>"
1623 bool const graphicsbg_changed =
1624 (lyx_name == lcolor.getLyXName(Color::graphicsbg) &&
1625 x11_name != lcolor.getX11Name(Color::graphicsbg));
1627 if (!lcolor.setColor(lyx_name, x11_name)) {
1629 bformat(_("Set-color \"%1$s\" failed "
1630 "- color is undefined or "
1631 "may not be redefined"),
1632 from_utf8(lyx_name)));
1636 theApp()->updateColor(lcolor.getFromLyXName(lyx_name));
1638 if (graphicsbg_changed) {
1639 // FIXME: The graphics cache no longer has a changeDisplay method.
1641 graphics::GCache::get().changeDisplay(true);
1648 BOOST_ASSERT(lyx_view_);
1649 lyx_view_->message(from_utf8(argument));
1652 case LFUN_EXTERNAL_EDIT: {
1653 BOOST_ASSERT(lyx_view_);
1654 FuncRequest fr(action, argument);
1655 InsetExternal().dispatch(view()->cursor(), fr);
1659 case LFUN_GRAPHICS_EDIT: {
1660 FuncRequest fr(action, argument);
1661 InsetGraphics().dispatch(view()->cursor(), fr);
1665 case LFUN_INSET_APPLY: {
1666 BOOST_ASSERT(lyx_view_);
1667 string const name = cmd.getArg(0);
1668 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1670 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1671 inset->dispatch(view()->cursor(), fr);
1673 FuncRequest fr(LFUN_INSET_INSERT, argument);
1676 // ideally, the update flag should be set by the insets,
1677 // but this is not possible currently
1678 updateFlags = Update::Force | Update::FitCursor;
1682 case LFUN_ALL_INSETS_TOGGLE: {
1683 BOOST_ASSERT(lyx_view_);
1685 string const name = split(argument, action, ' ');
1686 Inset::Code const inset_code =
1687 Inset::translate(name);
1689 Cursor & cur = view()->cursor();
1690 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1692 Inset & inset = lyx_view_->buffer()->inset();
1693 InsetIterator it = inset_iterator_begin(inset);
1694 InsetIterator const end = inset_iterator_end(inset);
1695 for (; it != end; ++it) {
1696 if (!it->asInsetMath()
1697 && (inset_code == Inset::NO_CODE
1698 || inset_code == it->lyxCode())) {
1699 Cursor tmpcur = cur;
1700 tmpcur.pushLeft(*it);
1701 it->dispatch(tmpcur, fr);
1704 updateFlags = Update::Force | Update::FitCursor;
1708 case LFUN_BUFFER_LANGUAGE: {
1709 BOOST_ASSERT(lyx_view_);
1710 Buffer & buffer = *lyx_view_->buffer();
1711 Language const * oldL = buffer.params().language;
1712 Language const * newL = languages.getLanguage(argument);
1713 if (!newL || oldL == newL)
1716 if (oldL->rightToLeft() == newL->rightToLeft()
1717 && !buffer.isMultiLingual())
1718 buffer.changeLanguage(oldL, newL);
1722 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1723 string const fname =
1724 addName(addPath(package().user_support().absFilename(), "templates/"),
1726 Buffer defaults(fname);
1728 istringstream ss(argument);
1731 int const unknown_tokens = defaults.readHeader(lex);
1733 if (unknown_tokens != 0) {
1734 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1735 << unknown_tokens << " unknown token"
1736 << (unknown_tokens == 1 ? "" : "s")
1740 if (defaults.writeFile(FileName(defaults.fileName())))
1741 setMessage(bformat(_("Document defaults saved in %1$s"),
1742 makeDisplayPath(fname)));
1744 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1748 case LFUN_BUFFER_PARAMS_APPLY: {
1749 BOOST_ASSERT(lyx_view_);
1750 biblio::CiteEngine const oldEngine =
1751 lyx_view_->buffer()->params().getEngine();
1753 Buffer * buffer = lyx_view_->buffer();
1755 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1756 recordUndoFullDocument(view());
1758 istringstream ss(argument);
1761 int const unknown_tokens = buffer->readHeader(lex);
1763 if (unknown_tokens != 0) {
1764 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1765 << unknown_tokens << " unknown token"
1766 << (unknown_tokens == 1 ? "" : "s")
1770 updateLayout(oldClass, buffer);
1772 biblio::CiteEngine const newEngine =
1773 lyx_view_->buffer()->params().getEngine();
1775 if (oldEngine != newEngine) {
1776 Cursor & cur = view()->cursor();
1777 FuncRequest fr(LFUN_INSET_REFRESH);
1779 Inset & inset = lyx_view_->buffer()->inset();
1780 InsetIterator it = inset_iterator_begin(inset);
1781 InsetIterator const end = inset_iterator_end(inset);
1782 for (; it != end; ++it)
1783 if (it->lyxCode() == Inset::CITE_CODE)
1784 it->dispatch(cur, fr);
1787 updateFlags = Update::Force | Update::FitCursor;
1791 case LFUN_LAYOUT_MODULES_CLEAR: {
1792 BOOST_ASSERT(lyx_view_);
1793 Buffer * buffer = lyx_view_->buffer();
1794 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1795 recordUndoFullDocument(view());
1796 buffer->params().clearLayoutModules();
1797 updateLayout(oldClass, buffer);
1798 updateFlags = Update::Force | Update::FitCursor;
1802 case LFUN_LAYOUT_MODULE_ADD: {
1803 BOOST_ASSERT(lyx_view_);
1804 Buffer * buffer = lyx_view_->buffer();
1805 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1806 recordUndoFullDocument(view());
1807 buffer->params().addLayoutModule(argument);
1808 updateLayout(oldClass, buffer);
1809 updateFlags = Update::Force | Update::FitCursor;
1813 case LFUN_TEXTCLASS_APPLY: {
1814 BOOST_ASSERT(lyx_view_);
1815 Buffer * buffer = lyx_view_->buffer();
1817 loadTextClass(argument);
1819 std::pair<bool, textclass_type> const tc_pair =
1820 textclasslist.numberOfClass(argument);
1825 textclass_type const old_class = buffer->params().getBaseClass();
1826 textclass_type const new_class = tc_pair.second;
1828 if (old_class == new_class)
1832 //Save the old, possibly modular, layout for use in conversion.
1833 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1834 recordUndoFullDocument(view());
1835 buffer->params().setBaseClass(new_class);
1836 updateLayout(oldClass, buffer);
1837 updateFlags = Update::Force | Update::FitCursor;
1841 case LFUN_LAYOUT_RELOAD: {
1842 BOOST_ASSERT(lyx_view_);
1843 Buffer * buffer = lyx_view_->buffer();
1844 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1845 textclass_type const tc = buffer->params().getBaseClass();
1846 textclasslist.reset(tc);
1847 buffer->params().setBaseClass(tc);
1848 updateLayout(oldClass, buffer);
1849 updateFlags = Update::Force | Update::FitCursor;
1853 case LFUN_TEXTCLASS_LOAD:
1854 loadTextClass(argument);
1857 case LFUN_LYXRC_APPLY: {
1858 LyXRC const lyxrc_orig = lyxrc;
1860 istringstream ss(argument);
1861 bool const success = lyxrc.read(ss) == 0;
1864 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1865 << "Unable to read lyxrc data"
1870 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1872 /// We force the redraw in any case because there might be
1873 /// some screen font changes.
1874 /// FIXME: only the current view will be updated. the Gui
1875 /// class is able to furnish the list of views.
1876 updateFlags = Update::Force;
1880 case LFUN_WINDOW_NEW:
1881 LyX::ref().newLyXView();
1884 case LFUN_WINDOW_CLOSE:
1885 BOOST_ASSERT(lyx_view_);
1886 BOOST_ASSERT(theApp());
1887 // update bookmark pit of the current buffer before window close
1888 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1889 gotoBookmark(i+1, false, false);
1890 // ask the user for saving changes or cancel quit
1891 if (!theBufferList().quitWriteAll())
1896 case LFUN_BOOKMARK_GOTO:
1897 // go to bookmark, open unopened file and switch to buffer if necessary
1898 gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
1901 case LFUN_BOOKMARK_CLEAR:
1902 LyX::ref().session().bookmarks().clear();
1905 case LFUN_TOOLBAR_TOGGLE: {
1906 BOOST_ASSERT(lyx_view_);
1907 string const name = cmd.getArg(0);
1908 bool const allowauto = cmd.getArg(1) == "allowauto";
1909 lyx_view_->toggleToolbarState(name, allowauto);
1910 ToolbarInfo * tbi = lyx_view_->getToolbarInfo(name);
1912 setMessage(bformat(_("Unknown toolbar \"%1$s\""),
1917 if (tbi->flags & ToolbarInfo::ON)
1919 else if (tbi->flags & ToolbarInfo::OFF)
1921 else if (tbi->flags & ToolbarInfo::AUTO)
1924 setMessage(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1925 _(tbi->gui_name), state));
1930 BOOST_ASSERT(lyx_view_);
1931 view()->cursor().dispatch(cmd);
1932 updateFlags = view()->cursor().result().update();
1933 if (!view()->cursor().result().dispatched())
1934 updateFlags = view()->dispatch(cmd);
1939 if (lyx_view_ && lyx_view_->buffer()) {
1940 // BufferView::update() updates the ViewMetricsInfo and
1941 // also initializes the position cache for all insets in
1942 // (at least partially) visible top-level paragraphs.
1943 // We will redraw the screen only if needed.
1944 if (view()->update(updateFlags)) {
1945 // Buffer::changed() signals that a repaint is needed.
1946 // The frontend (WorkArea) knows which area to repaint
1947 // thanks to the ViewMetricsInfo updated above.
1948 lyx_view_->buffer()->changed();
1951 lyx_view_->updateStatusBar();
1953 // if we executed a mutating lfun, mark the buffer as dirty
1955 && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
1956 && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
1957 lyx_view_->buffer()->markDirty();
1959 //Do we have a selection?
1960 theSelection().haveSelection(view()->cursor().selection());
1962 if (view()->cursor().inTexted()) {
1963 lyx_view_->updateLayoutChoice();
1967 if (!quitting && lyx_view_) {
1968 lyx_view_->updateToolbars();
1969 // Some messages may already be translated, so we cannot use _()
1970 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
1975 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
1977 const bool verbose = (cmd.origin == FuncRequest::MENU
1978 || cmd.origin == FuncRequest::TOOLBAR
1979 || cmd.origin == FuncRequest::COMMANDBUFFER);
1981 if (cmd.action == LFUN_SELF_INSERT || !verbose) {
1982 LYXERR(Debug::ACTION) << "dispatch msg is " << to_utf8(msg) << endl;
1984 lyx_view_->message(msg);
1988 docstring dispatch_msg = msg;
1989 if (!dispatch_msg.empty())
1990 dispatch_msg += ' ';
1992 docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
1994 bool argsadded = false;
1996 if (!cmd.argument().empty()) {
1997 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1998 comname += ' ' + cmd.argument();
2003 docstring const shortcuts = theTopLevelKeymap().printbindings(cmd);
2005 if (!shortcuts.empty())
2006 comname += ": " + shortcuts;
2007 else if (!argsadded && !cmd.argument().empty())
2008 comname += ' ' + cmd.argument();
2010 if (!comname.empty()) {
2011 comname = rtrim(comname);
2012 dispatch_msg += '(' + rtrim(comname) + ')';
2015 LYXERR(Debug::ACTION) << "verbose dispatch msg "
2016 << to_utf8(dispatch_msg) << endl;
2017 if (!dispatch_msg.empty())
2018 lyx_view_->message(dispatch_msg);
2022 void LyXFunc::menuNew(string const & name, bool fromTemplate)
2024 // FIXME: initpath is not used. What to do?
2025 string initpath = lyxrc.document_path;
2026 string filename(name);
2028 if (lyx_view_->buffer()) {
2029 string const trypath = lyx_view_->buffer()->filePath();
2030 // If directory is writeable, use this as default.
2031 if (isDirWriteable(FileName(trypath)))
2035 static int newfile_number;
2037 if (filename.empty()) {
2038 filename = addName(lyxrc.document_path,
2039 "newfile" + convert<string>(++newfile_number) + ".lyx");
2040 while (theBufferList().exists(filename) ||
2041 fs::is_readable(FileName(filename).toFilesystemEncoding())) {
2043 filename = addName(lyxrc.document_path,
2044 "newfile" + convert<string>(newfile_number) +
2049 // The template stuff
2052 FileDialog fileDlg(_("Select template file"),
2053 LFUN_SELECT_FILE_SYNC,
2054 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2055 make_pair(_("Templates|#T#t"), from_utf8(lyxrc.template_path)));
2057 FileDialog::Result result =
2058 fileDlg.open(from_utf8(lyxrc.template_path),
2059 FileFilterList(_("LyX Documents (*.lyx)")),
2062 if (result.first == FileDialog::Later)
2064 if (result.second.empty())
2066 templname = to_utf8(result.second);
2069 Buffer * const b = newFile(filename, templname, !name.empty());
2071 lyx_view_->setBuffer(b);
2075 void LyXFunc::open(string const & fname)
2077 string initpath = lyxrc.document_path;
2079 if (lyx_view_->buffer()) {
2080 string const trypath = lyx_view_->buffer()->filePath();
2081 // If directory is writeable, use this as default.
2082 if (isDirWriteable(FileName(trypath)))
2088 if (fname.empty()) {
2089 FileDialog fileDlg(_("Select document to open"),
2091 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2092 make_pair(_("Examples|#E#e"), from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2094 FileDialog::Result result =
2095 fileDlg.open(from_utf8(initpath),
2096 FileFilterList(_("LyX Documents (*.lyx)")),
2099 if (result.first == FileDialog::Later)
2102 filename = to_utf8(result.second);
2104 // check selected filename
2105 if (filename.empty()) {
2106 lyx_view_->message(_("Canceled."));
2112 // get absolute path of file and add ".lyx" to the filename if
2114 FileName const fullname = fileSearch(string(), filename, "lyx");
2115 if (!fullname.empty())
2116 filename = fullname.absFilename();
2118 // if the file doesn't exist, let the user create one
2119 if (!fs::exists(fullname.toFilesystemEncoding())) {
2120 // the user specifically chose this name. Believe him.
2121 Buffer * const b = newFile(filename, string(), true);
2123 lyx_view_->setBuffer(b);
2127 docstring const disp_fn = makeDisplayPath(filename);
2128 lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
2131 Buffer * buf = lyx_view_->loadLyXFile(fullname);
2134 lyx_view_->setBuffer(buf);
2135 lyx_view_->showErrorList("Parse");
2136 str2 = bformat(_("Document %1$s opened."), disp_fn);
2138 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2140 lyx_view_->message(str2);
2144 void LyXFunc::doImport(string const & argument)
2147 string filename = split(argument, format, ' ');
2149 LYXERR(Debug::INFO) << "LyXFunc::doImport: " << format
2150 << " file: " << filename << endl;
2152 // need user interaction
2153 if (filename.empty()) {
2154 string initpath = lyxrc.document_path;
2156 if (lyx_view_->buffer()) {
2157 string const trypath = lyx_view_->buffer()->filePath();
2158 // If directory is writeable, use this as default.
2159 if (isDirWriteable(FileName(trypath)))
2163 docstring const text = bformat(_("Select %1$s file to import"),
2164 formats.prettyName(format));
2166 FileDialog fileDlg(text,
2168 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2169 make_pair(_("Examples|#E#e"),
2170 from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2172 docstring filter = formats.prettyName(format);
2175 filter += from_utf8(formats.extension(format));
2178 FileDialog::Result result =
2179 fileDlg.open(from_utf8(initpath),
2180 FileFilterList(filter),
2183 if (result.first == FileDialog::Later)
2186 filename = to_utf8(result.second);
2188 // check selected filename
2189 if (filename.empty())
2190 lyx_view_->message(_("Canceled."));
2193 if (filename.empty())
2196 // get absolute path of file
2197 FileName const fullname(makeAbsPath(filename));
2199 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
2201 // Check if the document already is open
2202 if (use_gui && theBufferList().exists(lyxfile.absFilename())) {
2203 if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) {
2204 lyx_view_->message(_("Canceled."));
2209 // if the file exists already, and we didn't do
2210 // -i lyx thefile.lyx, warn
2211 if (fs::exists(lyxfile.toFilesystemEncoding()) && fullname != lyxfile) {
2212 docstring const file = makeDisplayPath(lyxfile.absFilename(), 30);
2214 docstring text = bformat(_("The document %1$s already exists.\n\n"
2215 "Do you want to overwrite that document?"), file);
2216 int const ret = Alert::prompt(_("Overwrite document?"),
2217 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2220 lyx_view_->message(_("Canceled."));
2225 ErrorList errorList;
2226 Importer::Import(lyx_view_, fullname, format, errorList);
2227 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2231 void LyXFunc::closeBuffer()
2233 // goto bookmark to update bookmark pit.
2234 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2235 gotoBookmark(i+1, false, false);
2237 theBufferList().close(lyx_view_->buffer(), true);
2241 void LyXFunc::reloadBuffer()
2243 FileName filename(lyx_view_->buffer()->fileName());
2244 docstring const disp_fn = makeDisplayPath(filename.absFilename());
2247 Buffer * buf = lyx_view_->loadLyXFile(filename);
2250 lyx_view_->setBuffer(buf);
2251 lyx_view_->showErrorList("Parse");
2252 str = bformat(_("Document %1$s reloaded."), disp_fn);
2254 str = bformat(_("Could not reload document %1$s"), disp_fn);
2256 lyx_view_->message(str);
2259 // Each "lyx_view_" should have it's own message method. lyxview and
2260 // the minibuffer would use the minibuffer, but lyxserver would
2261 // send an ERROR signal to its client. Alejandro 970603
2262 // This function is bit problematic when it comes to NLS, to make the
2263 // lyx servers client be language indepenent we must not translate
2264 // strings sent to this func.
2265 void LyXFunc::setErrorMessage(docstring const & m) const
2267 dispatch_buffer = m;
2272 void LyXFunc::setMessage(docstring const & m) const
2274 dispatch_buffer = m;
2278 docstring const LyXFunc::viewStatusMessage()
2280 // When meta-fake key is pressed, show the key sequence so far + "M-".
2282 return keyseq.print(true) + "M-";
2284 // Else, when a non-complete key sequence is pressed,
2285 // show the available options.
2286 if (keyseq.length() > 0 && !keyseq.deleted())
2287 return keyseq.printOptions(true);
2289 BOOST_ASSERT(lyx_view_);
2290 if (!lyx_view_->buffer())
2291 return _("Welcome to LyX!");
2293 return view()->cursor().currentState();
2297 BufferView * LyXFunc::view() const
2299 BOOST_ASSERT(lyx_view_);
2300 return lyx_view_->view();
2304 bool LyXFunc::wasMetaKey() const
2306 return (meta_fake_bit != key_modifier::none);
2310 void LyXFunc::updateLayout(TextClassPtr const & oldlayout,
2313 lyx_view_->message(_("Converting document to new document class..."));
2315 StableDocIterator backcur(view()->cursor());
2316 ErrorList & el = buffer->errorList("Class Switch");
2317 cap::switchBetweenClasses(
2318 oldlayout, buffer->params().getTextClassPtr(),
2319 static_cast<InsetText &>(buffer->inset()), el);
2321 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
2323 buffer->errors("Class Switch");
2324 updateLabels(*buffer);
2330 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2332 // Why the switch you might ask. It is a trick to ensure that all
2333 // the elements in the LyXRCTags enum is handled. As you can see
2334 // there are no breaks at all. So it is just a huge fall-through.
2335 // The nice thing is that we will get a warning from the compiler
2336 // if we forget an element.
2337 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2339 case LyXRC::RC_ACCEPT_COMPOUND:
2340 case LyXRC::RC_ALT_LANG:
2341 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
2342 case LyXRC::RC_PLAINTEXT_LINELEN:
2343 case LyXRC::RC_AUTOREGIONDELETE:
2344 case LyXRC::RC_AUTORESET_OPTIONS:
2345 case LyXRC::RC_AUTOSAVE:
2346 case LyXRC::RC_AUTO_NUMBER:
2347 case LyXRC::RC_BACKUPDIR_PATH:
2348 case LyXRC::RC_BIBTEX_COMMAND:
2349 case LyXRC::RC_BINDFILE:
2350 case LyXRC::RC_CHECKLASTFILES:
2351 case LyXRC::RC_USELASTFILEPOS:
2352 case LyXRC::RC_LOADSESSION:
2353 case LyXRC::RC_CHKTEX_COMMAND:
2354 case LyXRC::RC_CONVERTER:
2355 case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
2356 case LyXRC::RC_COPIER:
2357 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2358 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2359 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2360 case LyXRC::RC_DATE_INSERT_FORMAT:
2361 case LyXRC::RC_DEFAULT_LANGUAGE:
2362 case LyXRC::RC_DEFAULT_PAPERSIZE:
2363 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2364 case LyXRC::RC_DISPLAY_GRAPHICS:
2365 case LyXRC::RC_DOCUMENTPATH:
2366 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2367 string const encoded = FileName(
2368 lyxrc_new.document_path).toFilesystemEncoding();
2369 if (fs::exists(encoded) && fs::is_directory(encoded))
2370 support::package().document_dir() = FileName(lyxrc.document_path);
2372 case LyXRC::RC_ESC_CHARS:
2373 case LyXRC::RC_FONT_ENCODING:
2374 case LyXRC::RC_FORMAT:
2375 case LyXRC::RC_INDEX_COMMAND:
2376 case LyXRC::RC_INPUT:
2377 case LyXRC::RC_KBMAP:
2378 case LyXRC::RC_KBMAP_PRIMARY:
2379 case LyXRC::RC_KBMAP_SECONDARY:
2380 case LyXRC::RC_LABEL_INIT_LENGTH:
2381 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2382 case LyXRC::RC_LANGUAGE_AUTO_END:
2383 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2384 case LyXRC::RC_LANGUAGE_COMMAND_END:
2385 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2386 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2387 case LyXRC::RC_LANGUAGE_PACKAGE:
2388 case LyXRC::RC_LANGUAGE_USE_BABEL:
2389 case LyXRC::RC_MAKE_BACKUP:
2390 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2391 case LyXRC::RC_NUMLASTFILES:
2392 case LyXRC::RC_PATH_PREFIX:
2393 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2394 support::prependEnvPath("PATH", lyxrc.path_prefix);
2396 case LyXRC::RC_PERS_DICT:
2397 case LyXRC::RC_PREVIEW:
2398 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2399 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2400 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2401 case LyXRC::RC_PRINTCOPIESFLAG:
2402 case LyXRC::RC_PRINTER:
2403 case LyXRC::RC_PRINTEVENPAGEFLAG:
2404 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2405 case LyXRC::RC_PRINTFILEEXTENSION:
2406 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2407 case LyXRC::RC_PRINTODDPAGEFLAG:
2408 case LyXRC::RC_PRINTPAGERANGEFLAG:
2409 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2410 case LyXRC::RC_PRINTPAPERFLAG:
2411 case LyXRC::RC_PRINTREVERSEFLAG:
2412 case LyXRC::RC_PRINTSPOOL_COMMAND:
2413 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2414 case LyXRC::RC_PRINTTOFILE:
2415 case LyXRC::RC_PRINTTOPRINTER:
2416 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2417 case LyXRC::RC_PRINT_COMMAND:
2418 case LyXRC::RC_RTL_SUPPORT:
2419 case LyXRC::RC_SCREEN_DPI:
2420 case LyXRC::RC_SCREEN_FONT_ROMAN:
2421 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2422 case LyXRC::RC_SCREEN_FONT_SANS:
2423 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2424 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2425 case LyXRC::RC_SCREEN_FONT_SIZES:
2426 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2427 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2428 case LyXRC::RC_SCREEN_GEOMETRY_HEIGHT:
2429 case LyXRC::RC_SCREEN_GEOMETRY_WIDTH:
2430 case LyXRC::RC_SCREEN_GEOMETRY_XYSAVED:
2431 case LyXRC::RC_SCREEN_ZOOM:
2432 case LyXRC::RC_SERVERPIPE:
2433 case LyXRC::RC_SET_COLOR:
2434 case LyXRC::RC_SHOW_BANNER:
2435 case LyXRC::RC_SPELL_COMMAND:
2436 case LyXRC::RC_TEMPDIRPATH:
2437 case LyXRC::RC_TEMPLATEPATH:
2438 case LyXRC::RC_TEX_ALLOWS_SPACES:
2439 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2440 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2441 support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2443 case LyXRC::RC_UIFILE:
2444 case LyXRC::RC_USER_EMAIL:
2445 case LyXRC::RC_USER_NAME:
2446 case LyXRC::RC_USETEMPDIR:
2447 case LyXRC::RC_USE_ALT_LANG:
2448 case LyXRC::RC_USE_CONVERTER_CACHE:
2449 case LyXRC::RC_USE_ESC_CHARS:
2450 case LyXRC::RC_USE_INP_ENC:
2451 case LyXRC::RC_USE_PERS_DICT:
2452 case LyXRC::RC_USE_SPELL_LIB:
2453 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2454 case LyXRC::RC_VIEWER:
2455 case LyXRC::RC_LAST: