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_LAYOUT_RELOAD:
735 case LFUN_LYXRC_APPLY:
736 case LFUN_BUFFER_NEXT:
737 case LFUN_BUFFER_PREVIOUS:
738 case LFUN_WINDOW_NEW:
740 // these are handled in our dispatch()
744 if (!getLocalStatus(cur, cmd, flag))
745 flag = view()->getStatus(cmd);
751 // Can we use a readonly buffer?
752 if (buf && buf->isReadonly()
753 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
754 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
755 flag.message(from_utf8(N_("Document is read-only")));
759 // Are we in a DELETED change-tracking region?
760 if (buf && lookupChangeType(cur, true) == Change::DELETED
761 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
762 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
763 flag.message(from_utf8(N_("This portion of the document is deleted.")));
767 // the default error message if we disable the command
768 if (!flag.enabled() && flag.message().empty())
769 flag.message(from_utf8(N_("Command disabled")));
775 bool LyXFunc::ensureBufferClean(BufferView * bv)
777 Buffer & buf = bv->buffer();
781 docstring const file = makeDisplayPath(buf.fileName(), 30);
782 docstring text = bformat(_("The document %1$s has unsaved "
783 "changes.\n\nDo you want to save "
784 "the document?"), file);
785 int const ret = Alert::prompt(_("Save changed document?"),
786 text, 0, 1, _("&Save"),
790 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
792 return buf.isClean();
798 void showPrintError(string const & name)
800 docstring str = bformat(_("Could not print the document %1$s.\n"
801 "Check that your printer is set up correctly."),
802 makeDisplayPath(name, 50));
803 Alert::error(_("Print document failed"), str);
807 void loadTextclass(string const & name)
809 std::pair<bool, textclass_type> const tc_pair =
810 textclasslist.numberOfClass(name);
812 if (!tc_pair.first) {
813 lyxerr << "Document class \"" << name
814 << "\" does not exist."
819 textclass_type const tc = tc_pair.second;
821 if (!textclasslist[tc].load()) {
822 docstring s = bformat(_("The document class %1$s."
823 "could not be loaded."),
824 from_utf8(textclasslist[tc].name()));
825 Alert::error(_("Could not load class"), s);
830 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
835 void LyXFunc::dispatch(FuncRequest const & cmd)
837 string const argument = to_utf8(cmd.argument());
838 kb_action const action = cmd.action;
840 LYXERR(Debug::ACTION) << endl << "LyXFunc::dispatch: cmd: " << cmd << endl;
841 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
843 // we have not done anything wrong yet.
845 dispatch_buffer.erase();
847 // redraw the screen at the end (first of the two drawing steps).
848 //This is done unless explicitely requested otherwise
849 Update::flags updateFlags = Update::FitCursor;
851 FuncStatus const flag = getStatus(cmd);
852 if (!flag.enabled()) {
853 // We cannot use this function here
854 LYXERR(Debug::ACTION) << "LyXFunc::dispatch: "
855 << lyxaction.getActionName(action)
856 << " [" << action << "] is disabled at this location"
858 setErrorMessage(flag.message());
862 case LFUN_WORD_FIND_FORWARD:
863 case LFUN_WORD_FIND_BACKWARD: {
864 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
865 static docstring last_search;
866 docstring searched_string;
868 if (!cmd.argument().empty()) {
869 last_search = cmd.argument();
870 searched_string = cmd.argument();
872 searched_string = last_search;
875 if (searched_string.empty())
878 bool const fw = action == LFUN_WORD_FIND_FORWARD;
879 docstring const data =
880 find2string(searched_string, true, false, fw);
881 find(view(), FuncRequest(LFUN_WORD_FIND, data));
885 case LFUN_COMMAND_PREFIX:
886 BOOST_ASSERT(lyx_view_);
887 lyx_view_->message(keyseq->printOptions(true));
890 case LFUN_COMMAND_EXECUTE:
891 BOOST_ASSERT(lyx_view_);
892 lyx_view_->showMiniBuffer(true);
896 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
898 meta_fake_bit = key_modifier::none;
899 if (lyx_view_->buffer())
900 // cancel any selection
901 dispatch(FuncRequest(LFUN_MARK_OFF));
902 setMessage(from_ascii(N_("Cancel")));
905 case LFUN_META_PREFIX:
906 meta_fake_bit = key_modifier::alt;
907 setMessage(keyseq->print(true));
910 case LFUN_BUFFER_TOGGLE_READ_ONLY:
911 BOOST_ASSERT(lyx_view_ && lyx_view_->view() && lyx_view_->buffer());
912 if (lyx_view_->buffer()->lyxvc().inUse())
913 lyx_view_->buffer()->lyxvc().toggleReadOnly();
915 lyx_view_->buffer()->setReadonly(
916 !lyx_view_->buffer()->isReadonly());
919 // --- Menus -----------------------------------------------
920 case LFUN_BUFFER_NEW:
921 menuNew(argument, false);
922 updateFlags = Update::None;
925 case LFUN_BUFFER_NEW_TEMPLATE:
926 menuNew(argument, true);
927 updateFlags = Update::None;
930 case LFUN_BUFFER_CLOSE:
932 updateFlags = Update::None;
935 case LFUN_BUFFER_WRITE:
936 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
937 if (!lyx_view_->buffer()->isUnnamed()) {
938 docstring const str = bformat(_("Saving document %1$s..."),
939 makeDisplayPath(lyx_view_->buffer()->fileName()));
940 lyx_view_->message(str);
941 menuWrite(lyx_view_->buffer());
942 lyx_view_->message(str + _(" done."));
944 writeAs(lyx_view_->buffer());
946 updateFlags = Update::None;
949 case LFUN_BUFFER_WRITE_AS:
950 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
951 writeAs(lyx_view_->buffer(), argument);
952 updateFlags = Update::None;
955 case LFUN_BUFFER_WRITE_ALL: {
956 Buffer * first = theBufferList().first();
959 lyx_view_->message(_("Saving all documents..."));
961 // We cannot use a for loop as the buffer list cycles.
964 if (!b->isUnnamed()) {
966 lyxerr[Debug::ACTION] << "Saved " << b->fileName() << endl;
970 b = theBufferList().next(b);
971 } while (b != first);
972 lyx_view_->message(_("All documents saved."));
975 updateFlags = Update::None;
979 case LFUN_BUFFER_RELOAD: {
980 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
981 docstring const file = makeDisplayPath(lyx_view_->buffer()->fileName(), 20);
982 docstring text = bformat(_("Any changes will be lost. Are you sure "
983 "you want to revert to the saved version of the document %1$s?"), file);
984 int const ret = Alert::prompt(_("Revert to saved document?"),
985 text, 1, 1, _("&Revert"), _("&Cancel"));
992 case LFUN_BUFFER_UPDATE:
993 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
994 Exporter::Export(lyx_view_->buffer(), argument, true);
997 case LFUN_BUFFER_VIEW:
998 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
999 Exporter::preview(lyx_view_->buffer(), argument);
1002 case LFUN_BUILD_PROGRAM:
1003 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1004 Exporter::Export(lyx_view_->buffer(), "program", true);
1007 case LFUN_BUFFER_CHKTEX:
1008 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1009 lyx_view_->buffer()->runChktex();
1012 case LFUN_BUFFER_EXPORT:
1013 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1014 if (argument == "custom")
1015 lyx_view_->getDialogs().show("sendto");
1017 Exporter::Export(lyx_view_->buffer(), argument, false);
1021 case LFUN_BUFFER_EXPORT_CUSTOM: {
1022 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1024 string command = split(argument, format_name, ' ');
1025 Format const * format = formats.getFormat(format_name);
1027 lyxerr << "Format \"" << format_name
1028 << "\" not recognized!"
1033 Buffer * buffer = lyx_view_->buffer();
1035 // The name of the file created by the conversion process
1038 // Output to filename
1039 if (format->name() == "lyx") {
1040 string const latexname =
1041 buffer->getLatexName(false);
1042 filename = changeExtension(latexname,
1043 format->extension());
1044 filename = addName(buffer->temppath(), filename);
1046 if (!buffer->writeFile(FileName(filename)))
1050 Exporter::Export(buffer, format_name, true, filename);
1053 // Substitute $$FName for filename
1054 if (!contains(command, "$$FName"))
1055 command = "( " + command + " ) < $$FName";
1056 command = subst(command, "$$FName", filename);
1058 // Execute the command in the background
1060 call.startscript(Systemcall::DontWait, command);
1064 case LFUN_BUFFER_PRINT: {
1065 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1066 // FIXME: cmd.getArg() might fail if one of the arguments
1067 // contains double quotes
1068 string target = cmd.getArg(0);
1069 string target_name = cmd.getArg(1);
1070 string command = cmd.getArg(2);
1073 || target_name.empty()
1074 || command.empty()) {
1075 lyxerr << "Unable to parse \""
1076 << argument << '"' << endl;
1079 if (target != "printer" && target != "file") {
1080 lyxerr << "Unrecognized target \""
1081 << target << '"' << endl;
1085 Buffer * buffer = lyx_view_->buffer();
1087 if (!Exporter::Export(buffer, "dvi", true)) {
1088 showPrintError(buffer->fileName());
1092 // Push directory path.
1093 string const path(buffer->temppath());
1094 // Prevent the compiler from optimizing away p
1096 support::Path p(pp);
1098 // there are three cases here:
1099 // 1. we print to a file
1100 // 2. we print directly to a printer
1101 // 3. we print using a spool command (print to file first)
1104 string const dviname =
1105 changeExtension(buffer->getLatexName(true),
1108 if (target == "printer") {
1109 if (!lyxrc.print_spool_command.empty()) {
1110 // case 3: print using a spool
1111 string const psname =
1112 changeExtension(dviname,".ps");
1113 command += ' ' + lyxrc.print_to_file
1116 + quoteName(dviname);
1119 lyxrc.print_spool_command + ' ';
1120 if (target_name != "default") {
1121 command2 += lyxrc.print_spool_printerprefix
1125 command2 += quoteName(psname);
1127 // If successful, then spool command
1128 res = one.startscript(
1133 res = one.startscript(
1134 Systemcall::DontWait,
1137 // case 2: print directly to a printer
1138 if (target_name != "default")
1139 command += ' ' + lyxrc.print_to_printer + target_name + ' ';
1140 res = one.startscript(
1141 Systemcall::DontWait,
1142 command + quoteName(dviname));
1146 // case 1: print to a file
1147 FileName const filename(makeAbsPath(target_name,
1148 lyx_view_->buffer()->filePath()));
1149 FileName const dvifile(makeAbsPath(dviname, path));
1150 if (fs::exists(filename.toFilesystemEncoding())) {
1151 docstring text = bformat(
1152 _("The file %1$s already exists.\n\n"
1153 "Do you want to overwrite that file?"),
1154 makeDisplayPath(filename.absFilename()));
1155 if (Alert::prompt(_("Overwrite file?"),
1156 text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
1159 command += ' ' + lyxrc.print_to_file
1160 + quoteName(filename.toFilesystemEncoding())
1162 + quoteName(dvifile.toFilesystemEncoding());
1163 res = one.startscript(Systemcall::DontWait,
1168 showPrintError(buffer->fileName());
1172 case LFUN_BUFFER_IMPORT:
1177 // quitting is triggered by the gui code
1178 // (leaving the event loop).
1179 lyx_view_->message(from_utf8(N_("Exiting.")));
1180 if (theBufferList().quitWriteAll())
1181 theApp()->gui().closeAllViews();
1184 case LFUN_BUFFER_AUTO_SAVE:
1188 case LFUN_RECONFIGURE:
1189 BOOST_ASSERT(lyx_view_);
1190 reconfigure(*lyx_view_);
1193 case LFUN_HELP_OPEN: {
1194 BOOST_ASSERT(lyx_view_);
1195 string const arg = argument;
1197 setErrorMessage(from_ascii(N_("Missing argument")));
1200 FileName const fname = i18nLibFileSearch("doc", arg, "lyx");
1201 if (fname.empty()) {
1202 lyxerr << "LyX: unable to find documentation file `"
1203 << arg << "'. Bad installation?" << endl;
1206 lyx_view_->message(bformat(_("Opening help file %1$s..."),
1207 makeDisplayPath(fname.absFilename())));
1208 Buffer * buf = lyx_view_->loadLyXFile(fname, false);
1211 lyx_view_->setBuffer(buf);
1212 lyx_view_->showErrorList("Parse");
1214 updateFlags = Update::None;
1218 // --- version control -------------------------------
1219 case LFUN_VC_REGISTER:
1220 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1221 if (!ensureBufferClean(view()))
1223 if (!lyx_view_->buffer()->lyxvc().inUse()) {
1224 lyx_view_->buffer()->lyxvc().registrer();
1227 updateFlags = Update::Force;
1230 case LFUN_VC_CHECK_IN:
1231 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1232 if (!ensureBufferClean(view()))
1234 if (lyx_view_->buffer()->lyxvc().inUse()
1235 && !lyx_view_->buffer()->isReadonly()) {
1236 lyx_view_->buffer()->lyxvc().checkIn();
1241 case LFUN_VC_CHECK_OUT:
1242 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1243 if (!ensureBufferClean(view()))
1245 if (lyx_view_->buffer()->lyxvc().inUse()
1246 && lyx_view_->buffer()->isReadonly()) {
1247 lyx_view_->buffer()->lyxvc().checkOut();
1252 case LFUN_VC_REVERT:
1253 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1254 lyx_view_->buffer()->lyxvc().revert();
1258 case LFUN_VC_UNDO_LAST:
1259 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1260 lyx_view_->buffer()->lyxvc().undoLast();
1264 // --- buffers ----------------------------------------
1265 case LFUN_BUFFER_SWITCH:
1266 BOOST_ASSERT(lyx_view_);
1267 lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1268 updateFlags = Update::None;
1271 case LFUN_BUFFER_NEXT:
1272 BOOST_ASSERT(lyx_view_);
1273 lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer()));
1274 updateFlags = Update::None;
1277 case LFUN_BUFFER_PREVIOUS:
1278 BOOST_ASSERT(lyx_view_);
1279 lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer()));
1280 updateFlags = Update::None;
1284 BOOST_ASSERT(lyx_view_);
1285 newFile(*lyx_view_, argument);
1286 updateFlags = Update::None;
1289 case LFUN_FILE_OPEN:
1290 BOOST_ASSERT(lyx_view_);
1292 updateFlags = Update::None;
1295 case LFUN_DROP_LAYOUTS_CHOICE:
1296 BOOST_ASSERT(lyx_view_);
1297 lyx_view_->openLayoutList();
1300 case LFUN_MENU_OPEN:
1301 BOOST_ASSERT(lyx_view_);
1302 lyx_view_->openMenu(from_utf8(argument));
1305 // --- lyxserver commands ----------------------------
1306 case LFUN_SERVER_GET_NAME:
1307 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1308 setMessage(from_utf8(lyx_view_->buffer()->fileName()));
1309 LYXERR(Debug::INFO) << "FNAME["
1310 << lyx_view_->buffer()->fileName()
1314 case LFUN_SERVER_NOTIFY:
1315 dispatch_buffer = keyseq->print(false);
1316 theServer().notifyClient(to_utf8(dispatch_buffer));
1319 case LFUN_SERVER_GOTO_FILE_ROW: {
1320 BOOST_ASSERT(lyx_view_);
1323 istringstream is(argument);
1324 is >> file_name >> row;
1326 bool loaded = false;
1327 if (prefixIs(file_name, package().temp_dir().absFilename()))
1328 // Needed by inverse dvi search. If it is a file
1329 // in tmpdir, call the apropriated function
1330 buf = theBufferList().getBufferFromTmp(file_name);
1332 // Must replace extension of the file to be .lyx
1333 // and get full path
1334 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1335 // Either change buffer or load the file
1336 if (theBufferList().exists(s.absFilename()))
1337 buf = theBufferList().getBuffer(s.absFilename());
1339 buf = lyx_view_->loadLyXFile(s);
1345 updateFlags = Update::None;
1350 lyx_view_->setBuffer(buf);
1351 view()->setCursorFromRow(row);
1353 lyx_view_->showErrorList("Parse");
1354 updateFlags = Update::FitCursor;
1358 case LFUN_DIALOG_SHOW: {
1359 BOOST_ASSERT(lyx_view_);
1360 string const name = cmd.getArg(0);
1361 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1363 if (name == "character") {
1364 data = freefont2string();
1366 lyx_view_->getDialogs().show("character", data);
1367 } else if (name == "latexlog") {
1368 pair<Buffer::LogType, string> const logfile =
1369 lyx_view_->buffer()->getLogName();
1370 switch (logfile.first) {
1371 case Buffer::latexlog:
1374 case Buffer::buildlog:
1378 data += Lexer::quoteString(logfile.second);
1379 lyx_view_->getDialogs().show("log", data);
1380 } else if (name == "vclog") {
1381 string const data = "vc " +
1382 Lexer::quoteString(lyx_view_->buffer()->lyxvc().getLogFile());
1383 lyx_view_->getDialogs().show("log", data);
1385 lyx_view_->getDialogs().show(name, data);
1389 case LFUN_DIALOG_SHOW_NEW_INSET: {
1390 BOOST_ASSERT(lyx_view_);
1391 string const name = cmd.getArg(0);
1392 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1393 if (name == "bibitem" ||
1397 name == "nomenclature" ||
1401 InsetCommandParams p(name);
1402 data = InsetCommandMailer::params2string(name, p);
1403 } else if (name == "include") {
1404 // data is the include type: one of "include",
1405 // "input", "verbatiminput" or "verbatiminput*"
1407 // default type is requested
1409 InsetCommandParams p(data);
1410 data = InsetIncludeMailer::params2string(p);
1411 } else if (name == "box") {
1412 // \c data == "Boxed" || "Frameless" etc
1413 InsetBoxParams p(data);
1414 data = InsetBoxMailer::params2string(p);
1415 } else if (name == "branch") {
1416 InsetBranchParams p;
1417 data = InsetBranchMailer::params2string(p);
1418 } else if (name == "citation") {
1419 InsetCommandParams p("cite");
1420 data = InsetCommandMailer::params2string(name, p);
1421 } else if (name == "ert") {
1422 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1423 } else if (name == "external") {
1424 InsetExternalParams p;
1425 Buffer const & buffer = *lyx_view_->buffer();
1426 data = InsetExternalMailer::params2string(p, buffer);
1427 } else if (name == "float") {
1429 data = InsetFloatMailer::params2string(p);
1430 } else if (name == "listings") {
1431 InsetListingsParams p;
1432 data = InsetListingsMailer::params2string(p);
1433 } else if (name == "graphics") {
1434 InsetGraphicsParams p;
1435 Buffer const & buffer = *lyx_view_->buffer();
1436 data = InsetGraphicsMailer::params2string(p, buffer);
1437 } else if (name == "note") {
1439 data = InsetNoteMailer::params2string(p);
1440 } else if (name == "vspace") {
1442 data = InsetVSpaceMailer::params2string(space);
1443 } else if (name == "wrap") {
1445 data = InsetWrapMailer::params2string(p);
1447 lyx_view_->getDialogs().show(name, data, 0);
1451 case LFUN_DIALOG_UPDATE: {
1452 BOOST_ASSERT(lyx_view_);
1453 string const & name = argument;
1454 // Can only update a dialog connected to an existing inset
1455 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1457 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1458 inset->dispatch(view()->cursor(), fr);
1459 } else if (name == "paragraph") {
1460 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1461 } else if (name == "prefs") {
1462 lyx_view_->getDialogs().update(name, string());
1467 case LFUN_DIALOG_HIDE:
1468 LyX::cref().hideDialogs(argument, 0);
1471 case LFUN_DIALOG_TOGGLE: {
1472 BOOST_ASSERT(lyx_view_);
1473 if (lyx_view_->getDialogs().visible(cmd.getArg(0)))
1474 dispatch(FuncRequest(LFUN_DIALOG_HIDE, argument));
1476 dispatch(FuncRequest(LFUN_DIALOG_SHOW, argument));
1480 case LFUN_DIALOG_DISCONNECT_INSET:
1481 BOOST_ASSERT(lyx_view_);
1482 lyx_view_->getDialogs().disconnect(argument);
1486 case LFUN_CITATION_INSERT: {
1487 BOOST_ASSERT(lyx_view_);
1488 if (!argument.empty()) {
1489 // we can have one optional argument, delimited by '|'
1490 // citation-insert <key>|<text_before>
1491 // this should be enhanced to also support text_after
1492 // and citation style
1493 string arg = argument;
1495 if (contains(argument, "|")) {
1496 arg = token(argument, '|', 0);
1497 opt1 = token(argument, '|', 1);
1499 InsetCommandParams icp("cite");
1500 icp["key"] = from_utf8(arg);
1502 icp["before"] = from_utf8(opt1);
1503 string icstr = InsetCommandMailer::params2string("citation", icp);
1504 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1507 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1511 case LFUN_BUFFER_CHILD_OPEN: {
1512 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1513 Buffer * parent = lyx_view_->buffer();
1514 FileName filename = makeAbsPath(argument, parent->filePath());
1515 view()->saveBookmark(false);
1517 bool parsed = false;
1518 if (theBufferList().exists(filename.absFilename())) {
1519 child = theBufferList().getBuffer(filename.absFilename());
1521 setMessage(bformat(_("Opening child document %1$s..."),
1522 makeDisplayPath(filename.absFilename())));
1523 child = lyx_view_->loadLyXFile(filename, true);
1527 // Set the parent name of the child document.
1528 // This makes insertion of citations and references in the child work,
1529 // when the target is in the parent or another child document.
1530 child->setParentName(parent->fileName());
1531 updateLabels(*child->getMasterBuffer());
1532 lyx_view_->setBuffer(child);
1534 lyx_view_->showErrorList("Parse");
1537 // If a screen update is required (in case where auto_open is false),
1538 // setBuffer() would have taken care of it already. Otherwise we shall
1539 // reset the update flag because it can cause a circular problem.
1541 updateFlags = Update::None;
1545 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1546 BOOST_ASSERT(lyx_view_);
1547 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1550 case LFUN_KEYMAP_OFF:
1551 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1552 lyx_view_->view()->getIntl().keyMapOn(false);
1555 case LFUN_KEYMAP_PRIMARY:
1556 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1557 lyx_view_->view()->getIntl().keyMapPrim();
1560 case LFUN_KEYMAP_SECONDARY:
1561 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1562 lyx_view_->view()->getIntl().keyMapSec();
1565 case LFUN_KEYMAP_TOGGLE:
1566 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1567 lyx_view_->view()->getIntl().toggleKeyMap();
1573 string rest = split(argument, countstr, ' ');
1574 istringstream is(countstr);
1577 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1578 for (int i = 0; i < count; ++i)
1579 dispatch(lyxaction.lookupFunc(rest));
1583 case LFUN_COMMAND_SEQUENCE: {
1584 // argument contains ';'-terminated commands
1585 string arg = argument;
1586 while (!arg.empty()) {
1588 arg = split(arg, first, ';');
1589 FuncRequest func(lyxaction.lookupFunc(first));
1590 func.origin = cmd.origin;
1596 case LFUN_PREFERENCES_SAVE: {
1597 lyxrc.write(makeAbsPath("preferences",
1598 package().user_support().absFilename()),
1603 case LFUN_SCREEN_FONT_UPDATE:
1604 BOOST_ASSERT(lyx_view_);
1605 // handle the screen font changes.
1606 theFontLoader().update();
1607 /// FIXME: only the current view will be updated. the Gui
1608 /// class is able to furnish the list of views.
1609 updateFlags = Update::Force;
1612 case LFUN_SET_COLOR: {
1614 string const x11_name = split(argument, lyx_name, ' ');
1615 if (lyx_name.empty() || x11_name.empty()) {
1616 setErrorMessage(from_ascii(N_(
1617 "Syntax: set-color <lyx_name>"
1622 bool const graphicsbg_changed =
1623 (lyx_name == lcolor.getLyXName(Color::graphicsbg) &&
1624 x11_name != lcolor.getX11Name(Color::graphicsbg));
1626 if (!lcolor.setColor(lyx_name, x11_name)) {
1628 bformat(_("Set-color \"%1$s\" failed "
1629 "- color is undefined or "
1630 "may not be redefined"),
1631 from_utf8(lyx_name)));
1635 theApp()->updateColor(lcolor.getFromLyXName(lyx_name));
1637 if (graphicsbg_changed) {
1638 // FIXME: The graphics cache no longer has a changeDisplay method.
1640 graphics::GCache::get().changeDisplay(true);
1647 BOOST_ASSERT(lyx_view_);
1648 lyx_view_->message(from_utf8(argument));
1651 case LFUN_EXTERNAL_EDIT: {
1652 BOOST_ASSERT(lyx_view_);
1653 FuncRequest fr(action, argument);
1654 InsetExternal().dispatch(view()->cursor(), fr);
1658 case LFUN_GRAPHICS_EDIT: {
1659 FuncRequest fr(action, argument);
1660 InsetGraphics().dispatch(view()->cursor(), fr);
1664 case LFUN_INSET_APPLY: {
1665 BOOST_ASSERT(lyx_view_);
1666 string const name = cmd.getArg(0);
1667 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1669 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1670 inset->dispatch(view()->cursor(), fr);
1672 FuncRequest fr(LFUN_INSET_INSERT, argument);
1675 // ideally, the update flag should be set by the insets,
1676 // but this is not possible currently
1677 updateFlags = Update::Force | Update::FitCursor;
1681 case LFUN_ALL_INSETS_TOGGLE: {
1682 BOOST_ASSERT(lyx_view_);
1684 string const name = split(argument, action, ' ');
1685 Inset::Code const inset_code =
1686 Inset::translate(name);
1688 Cursor & cur = view()->cursor();
1689 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1691 Inset & inset = lyx_view_->buffer()->inset();
1692 InsetIterator it = inset_iterator_begin(inset);
1693 InsetIterator const end = inset_iterator_end(inset);
1694 for (; it != end; ++it) {
1695 if (!it->asInsetMath()
1696 && (inset_code == Inset::NO_CODE
1697 || inset_code == it->lyxCode())) {
1698 Cursor tmpcur = cur;
1699 tmpcur.pushLeft(*it);
1700 it->dispatch(tmpcur, fr);
1703 updateFlags = Update::Force | Update::FitCursor;
1707 case LFUN_BUFFER_LANGUAGE: {
1708 BOOST_ASSERT(lyx_view_);
1709 Buffer & buffer = *lyx_view_->buffer();
1710 Language const * oldL = buffer.params().language;
1711 Language const * newL = languages.getLanguage(argument);
1712 if (!newL || oldL == newL)
1715 if (oldL->rightToLeft() == newL->rightToLeft()
1716 && !buffer.isMultiLingual())
1717 buffer.changeLanguage(oldL, newL);
1721 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1722 string const fname =
1723 addName(addPath(package().user_support().absFilename(), "templates/"),
1725 Buffer defaults(fname);
1727 istringstream ss(argument);
1730 int const unknown_tokens = defaults.readHeader(lex);
1732 if (unknown_tokens != 0) {
1733 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1734 << unknown_tokens << " unknown token"
1735 << (unknown_tokens == 1 ? "" : "s")
1739 if (defaults.writeFile(FileName(defaults.fileName())))
1740 setMessage(bformat(_("Document defaults saved in %1$s"),
1741 makeDisplayPath(fname)));
1743 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1747 case LFUN_BUFFER_PARAMS_APPLY: {
1748 BOOST_ASSERT(lyx_view_);
1749 biblio::CiteEngine const oldEngine =
1750 lyx_view_->buffer()->params().getEngine();
1752 Buffer * buffer = lyx_view_->buffer();
1754 TextClass_ptr oldClass = buffer->params().getTextClass_ptr();
1755 recordUndoFullDocument(view());
1757 istringstream ss(argument);
1760 int const unknown_tokens = buffer->readHeader(lex);
1762 if (unknown_tokens != 0) {
1763 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1764 << unknown_tokens << " unknown token"
1765 << (unknown_tokens == 1 ? "" : "s")
1769 updateLayout(oldClass, buffer);
1771 biblio::CiteEngine const newEngine =
1772 lyx_view_->buffer()->params().getEngine();
1774 if (oldEngine != newEngine) {
1775 Cursor & cur = view()->cursor();
1776 FuncRequest fr(LFUN_INSET_REFRESH);
1778 Inset & inset = lyx_view_->buffer()->inset();
1779 InsetIterator it = inset_iterator_begin(inset);
1780 InsetIterator const end = inset_iterator_end(inset);
1781 for (; it != end; ++it)
1782 if (it->lyxCode() == Inset::CITE_CODE)
1783 it->dispatch(cur, fr);
1786 updateFlags = Update::Force | Update::FitCursor;
1790 case LFUN_LAYOUT_MODULES_CLEAR: {
1791 BOOST_ASSERT(lyx_view_);
1792 Buffer * buffer = lyx_view_->buffer();
1793 TextClass_ptr oldClass = buffer->params().getTextClass_ptr();
1794 recordUndoFullDocument(view());
1795 buffer->params().clearLayoutModules();
1796 updateLayout(oldClass, buffer);
1797 updateFlags = Update::Force | Update::FitCursor;
1801 case LFUN_LAYOUT_MODULE_ADD: {
1802 BOOST_ASSERT(lyx_view_);
1803 Buffer * buffer = lyx_view_->buffer();
1804 TextClass_ptr oldClass = buffer->params().getTextClass_ptr();
1805 recordUndoFullDocument(view());
1806 buffer->params().addLayoutModule(argument);
1807 updateLayout(oldClass, buffer);
1808 updateFlags = Update::Force | Update::FitCursor;
1812 case LFUN_TEXTCLASS_APPLY: {
1813 BOOST_ASSERT(lyx_view_);
1814 Buffer * buffer = lyx_view_->buffer();
1816 loadTextclass(argument);
1818 std::pair<bool, textclass_type> const tc_pair =
1819 textclasslist.numberOfClass(argument);
1824 textclass_type const old_class = buffer->params().getBaseClass();
1825 textclass_type const new_class = tc_pair.second;
1827 if (old_class == new_class)
1831 //Save the old, possibly modular, layout for use in conversion.
1832 TextClass_ptr oldClass = buffer->params().getTextClass_ptr();
1833 recordUndoFullDocument(view());
1834 buffer->params().setBaseClass(new_class);
1835 updateLayout(oldClass, buffer);
1836 updateFlags = Update::Force | Update::FitCursor;
1840 case LFUN_LAYOUT_RELOAD: {
1841 BOOST_ASSERT(lyx_view_);
1842 Buffer * buffer = lyx_view_->buffer();
1843 TextClass_ptr oldClass = buffer->params().getTextClass_ptr();
1844 textclass_type const tc = buffer->params().getBaseClass();
1845 textclasslist.reset(tc);
1846 buffer->params().setBaseClass(tc);
1847 updateLayout(oldClass, buffer);
1848 updateFlags = Update::Force | Update::FitCursor;
1852 case LFUN_TEXTCLASS_LOAD:
1853 loadTextclass(argument);
1856 case LFUN_LYXRC_APPLY: {
1857 LyXRC const lyxrc_orig = lyxrc;
1859 istringstream ss(argument);
1860 bool const success = lyxrc.read(ss) == 0;
1863 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1864 << "Unable to read lyxrc data"
1869 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1871 /// We force the redraw in any case because there might be
1872 /// some screen font changes.
1873 /// FIXME: only the current view will be updated. the Gui
1874 /// class is able to furnish the list of views.
1875 updateFlags = Update::Force;
1879 case LFUN_WINDOW_NEW:
1880 LyX::ref().newLyXView();
1883 case LFUN_WINDOW_CLOSE:
1884 BOOST_ASSERT(lyx_view_);
1885 BOOST_ASSERT(theApp());
1886 // update bookmark pit of the current buffer before window close
1887 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1888 gotoBookmark(i+1, false, false);
1889 // ask the user for saving changes or cancel quit
1890 if (!theBufferList().quitWriteAll())
1895 case LFUN_BOOKMARK_GOTO:
1896 // go to bookmark, open unopened file and switch to buffer if necessary
1897 gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
1900 case LFUN_BOOKMARK_CLEAR:
1901 LyX::ref().session().bookmarks().clear();
1904 case LFUN_TOOLBAR_TOGGLE: {
1905 BOOST_ASSERT(lyx_view_);
1906 string const name = cmd.getArg(0);
1907 bool const allowauto = cmd.getArg(1) == "allowauto";
1908 lyx_view_->toggleToolbarState(name, allowauto);
1909 ToolbarInfo * tbi = lyx_view_->getToolbarInfo(name);
1911 setMessage(bformat(_("Unknown toolbar \"%1$s\""),
1916 if (tbi->flags & ToolbarInfo::ON)
1918 else if (tbi->flags & ToolbarInfo::OFF)
1920 else if (tbi->flags & ToolbarInfo::AUTO)
1923 setMessage(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1924 _(tbi->gui_name), state));
1929 BOOST_ASSERT(lyx_view_);
1930 view()->cursor().dispatch(cmd);
1931 updateFlags = view()->cursor().result().update();
1932 if (!view()->cursor().result().dispatched())
1933 updateFlags = view()->dispatch(cmd);
1938 if (lyx_view_ && lyx_view_->buffer()) {
1939 // BufferView::update() updates the ViewMetricsInfo and
1940 // also initializes the position cache for all insets in
1941 // (at least partially) visible top-level paragraphs.
1942 // We will redraw the screen only if needed.
1943 if (view()->update(updateFlags)) {
1944 // Buffer::changed() signals that a repaint is needed.
1945 // The frontend (WorkArea) knows which area to repaint
1946 // thanks to the ViewMetricsInfo updated above.
1947 lyx_view_->buffer()->changed();
1950 lyx_view_->updateStatusBar();
1952 // if we executed a mutating lfun, mark the buffer as dirty
1954 && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
1955 && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
1956 lyx_view_->buffer()->markDirty();
1958 //Do we have a selection?
1959 theSelection().haveSelection(view()->cursor().selection());
1961 if (view()->cursor().inTexted()) {
1962 lyx_view_->updateLayoutChoice();
1966 if (!quitting && lyx_view_) {
1967 lyx_view_->updateToolbars();
1968 // Some messages may already be translated, so we cannot use _()
1969 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
1974 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
1976 const bool verbose = (cmd.origin == FuncRequest::MENU
1977 || cmd.origin == FuncRequest::TOOLBAR
1978 || cmd.origin == FuncRequest::COMMANDBUFFER);
1980 if (cmd.action == LFUN_SELF_INSERT || !verbose) {
1981 LYXERR(Debug::ACTION) << "dispatch msg is " << to_utf8(msg) << endl;
1983 lyx_view_->message(msg);
1987 docstring dispatch_msg = msg;
1988 if (!dispatch_msg.empty())
1989 dispatch_msg += ' ';
1991 docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
1993 bool argsadded = false;
1995 if (!cmd.argument().empty()) {
1996 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1997 comname += ' ' + cmd.argument();
2002 docstring const shortcuts = theTopLevelKeymap().printbindings(cmd);
2004 if (!shortcuts.empty())
2005 comname += ": " + shortcuts;
2006 else if (!argsadded && !cmd.argument().empty())
2007 comname += ' ' + cmd.argument();
2009 if (!comname.empty()) {
2010 comname = rtrim(comname);
2011 dispatch_msg += '(' + rtrim(comname) + ')';
2014 LYXERR(Debug::ACTION) << "verbose dispatch msg "
2015 << to_utf8(dispatch_msg) << endl;
2016 if (!dispatch_msg.empty())
2017 lyx_view_->message(dispatch_msg);
2021 void LyXFunc::menuNew(string const & name, bool fromTemplate)
2023 // FIXME: initpath is not used. What to do?
2024 string initpath = lyxrc.document_path;
2025 string filename(name);
2027 if (lyx_view_->buffer()) {
2028 string const trypath = lyx_view_->buffer()->filePath();
2029 // If directory is writeable, use this as default.
2030 if (isDirWriteable(FileName(trypath)))
2034 static int newfile_number;
2036 if (filename.empty()) {
2037 filename = addName(lyxrc.document_path,
2038 "newfile" + convert<string>(++newfile_number) + ".lyx");
2039 while (theBufferList().exists(filename) ||
2040 fs::is_readable(FileName(filename).toFilesystemEncoding())) {
2042 filename = addName(lyxrc.document_path,
2043 "newfile" + convert<string>(newfile_number) +
2048 // The template stuff
2051 FileDialog fileDlg(_("Select template file"),
2052 LFUN_SELECT_FILE_SYNC,
2053 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2054 make_pair(_("Templates|#T#t"), from_utf8(lyxrc.template_path)));
2056 FileDialog::Result result =
2057 fileDlg.open(from_utf8(lyxrc.template_path),
2058 FileFilterList(_("LyX Documents (*.lyx)")),
2061 if (result.first == FileDialog::Later)
2063 if (result.second.empty())
2065 templname = to_utf8(result.second);
2068 Buffer * const b = newFile(filename, templname, !name.empty());
2070 lyx_view_->setBuffer(b);
2074 void LyXFunc::open(string const & fname)
2076 string initpath = lyxrc.document_path;
2078 if (lyx_view_->buffer()) {
2079 string const trypath = lyx_view_->buffer()->filePath();
2080 // If directory is writeable, use this as default.
2081 if (isDirWriteable(FileName(trypath)))
2087 if (fname.empty()) {
2088 FileDialog fileDlg(_("Select document to open"),
2090 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2091 make_pair(_("Examples|#E#e"), from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2093 FileDialog::Result result =
2094 fileDlg.open(from_utf8(initpath),
2095 FileFilterList(_("LyX Documents (*.lyx)")),
2098 if (result.first == FileDialog::Later)
2101 filename = to_utf8(result.second);
2103 // check selected filename
2104 if (filename.empty()) {
2105 lyx_view_->message(_("Canceled."));
2111 // get absolute path of file and add ".lyx" to the filename if
2113 FileName const fullname = fileSearch(string(), filename, "lyx");
2114 if (!fullname.empty())
2115 filename = fullname.absFilename();
2117 // if the file doesn't exist, let the user create one
2118 if (!fs::exists(fullname.toFilesystemEncoding())) {
2119 // the user specifically chose this name. Believe him.
2120 Buffer * const b = newFile(filename, string(), true);
2122 lyx_view_->setBuffer(b);
2126 docstring const disp_fn = makeDisplayPath(filename);
2127 lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
2130 Buffer * buf = lyx_view_->loadLyXFile(fullname);
2133 lyx_view_->setBuffer(buf);
2134 lyx_view_->showErrorList("Parse");
2135 str2 = bformat(_("Document %1$s opened."), disp_fn);
2137 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2139 lyx_view_->message(str2);
2143 void LyXFunc::doImport(string const & argument)
2146 string filename = split(argument, format, ' ');
2148 LYXERR(Debug::INFO) << "LyXFunc::doImport: " << format
2149 << " file: " << filename << endl;
2151 // need user interaction
2152 if (filename.empty()) {
2153 string initpath = lyxrc.document_path;
2155 if (lyx_view_->buffer()) {
2156 string const trypath = lyx_view_->buffer()->filePath();
2157 // If directory is writeable, use this as default.
2158 if (isDirWriteable(FileName(trypath)))
2162 docstring const text = bformat(_("Select %1$s file to import"),
2163 formats.prettyName(format));
2165 FileDialog fileDlg(text,
2167 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2168 make_pair(_("Examples|#E#e"),
2169 from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2171 docstring filter = formats.prettyName(format);
2174 filter += from_utf8(formats.extension(format));
2177 FileDialog::Result result =
2178 fileDlg.open(from_utf8(initpath),
2179 FileFilterList(filter),
2182 if (result.first == FileDialog::Later)
2185 filename = to_utf8(result.second);
2187 // check selected filename
2188 if (filename.empty())
2189 lyx_view_->message(_("Canceled."));
2192 if (filename.empty())
2195 // get absolute path of file
2196 FileName const fullname(makeAbsPath(filename));
2198 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
2200 // Check if the document already is open
2201 if (use_gui && theBufferList().exists(lyxfile.absFilename())) {
2202 if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) {
2203 lyx_view_->message(_("Canceled."));
2208 // if the file exists already, and we didn't do
2209 // -i lyx thefile.lyx, warn
2210 if (fs::exists(lyxfile.toFilesystemEncoding()) && fullname != lyxfile) {
2211 docstring const file = makeDisplayPath(lyxfile.absFilename(), 30);
2213 docstring text = bformat(_("The document %1$s already exists.\n\n"
2214 "Do you want to overwrite that document?"), file);
2215 int const ret = Alert::prompt(_("Overwrite document?"),
2216 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2219 lyx_view_->message(_("Canceled."));
2224 ErrorList errorList;
2225 Importer::Import(lyx_view_, fullname, format, errorList);
2226 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2230 void LyXFunc::closeBuffer()
2232 // goto bookmark to update bookmark pit.
2233 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2234 gotoBookmark(i+1, false, false);
2236 theBufferList().close(lyx_view_->buffer(), true);
2240 void LyXFunc::reloadBuffer()
2242 FileName filename(lyx_view_->buffer()->fileName());
2243 docstring const disp_fn = makeDisplayPath(filename.absFilename());
2246 Buffer * buf = lyx_view_->loadLyXFile(filename);
2249 lyx_view_->setBuffer(buf);
2250 lyx_view_->showErrorList("Parse");
2251 str = bformat(_("Document %1$s reloaded."), disp_fn);
2253 str = bformat(_("Could not reload document %1$s"), disp_fn);
2255 lyx_view_->message(str);
2258 // Each "lyx_view_" should have it's own message method. lyxview and
2259 // the minibuffer would use the minibuffer, but lyxserver would
2260 // send an ERROR signal to its client. Alejandro 970603
2261 // This function is bit problematic when it comes to NLS, to make the
2262 // lyx servers client be language indepenent we must not translate
2263 // strings sent to this func.
2264 void LyXFunc::setErrorMessage(docstring const & m) const
2266 dispatch_buffer = m;
2271 void LyXFunc::setMessage(docstring const & m) const
2273 dispatch_buffer = m;
2277 docstring const LyXFunc::viewStatusMessage()
2279 // When meta-fake key is pressed, show the key sequence so far + "M-".
2281 return keyseq->print(true) + "M-";
2283 // Else, when a non-complete key sequence is pressed,
2284 // show the available options.
2285 if (keyseq->length() > 0 && !keyseq->deleted())
2286 return keyseq->printOptions(true);
2288 BOOST_ASSERT(lyx_view_);
2289 if (!lyx_view_->buffer())
2290 return _("Welcome to LyX!");
2292 return view()->cursor().currentState();
2296 BufferView * LyXFunc::view() const
2298 BOOST_ASSERT(lyx_view_);
2299 return lyx_view_->view();
2303 bool LyXFunc::wasMetaKey() const
2305 return (meta_fake_bit != key_modifier::none);
2309 void LyXFunc::updateLayout(TextClass_ptr const & oldlayout,
2312 lyx_view_->message(_("Converting document to new document class..."));
2314 StableDocIterator backcur(view()->cursor());
2315 ErrorList & el = buffer->errorList("Class Switch");
2316 cap::switchBetweenClasses(
2317 oldlayout, buffer->params().getTextClass_ptr(),
2318 static_cast<InsetText &>(buffer->inset()), el);
2320 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
2322 buffer->errors("Class Switch");
2323 updateLabels(*buffer);
2329 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2331 // Why the switch you might ask. It is a trick to ensure that all
2332 // the elements in the LyXRCTags enum is handled. As you can see
2333 // there are no breaks at all. So it is just a huge fall-through.
2334 // The nice thing is that we will get a warning from the compiler
2335 // if we forget an element.
2336 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2338 case LyXRC::RC_ACCEPT_COMPOUND:
2339 case LyXRC::RC_ALT_LANG:
2340 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
2341 case LyXRC::RC_PLAINTEXT_LINELEN:
2342 case LyXRC::RC_AUTOREGIONDELETE:
2343 case LyXRC::RC_AUTORESET_OPTIONS:
2344 case LyXRC::RC_AUTOSAVE:
2345 case LyXRC::RC_AUTO_NUMBER:
2346 case LyXRC::RC_BACKUPDIR_PATH:
2347 case LyXRC::RC_BIBTEX_COMMAND:
2348 case LyXRC::RC_BINDFILE:
2349 case LyXRC::RC_CHECKLASTFILES:
2350 case LyXRC::RC_USELASTFILEPOS:
2351 case LyXRC::RC_LOADSESSION:
2352 case LyXRC::RC_CHKTEX_COMMAND:
2353 case LyXRC::RC_CONVERTER:
2354 case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
2355 case LyXRC::RC_COPIER:
2356 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2357 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2358 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2359 case LyXRC::RC_DATE_INSERT_FORMAT:
2360 case LyXRC::RC_DEFAULT_LANGUAGE:
2361 case LyXRC::RC_DEFAULT_PAPERSIZE:
2362 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2363 case LyXRC::RC_DISPLAY_GRAPHICS:
2364 case LyXRC::RC_DOCUMENTPATH:
2365 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2366 string const encoded = FileName(
2367 lyxrc_new.document_path).toFilesystemEncoding();
2368 if (fs::exists(encoded) && fs::is_directory(encoded))
2369 support::package().document_dir() = FileName(lyxrc.document_path);
2371 case LyXRC::RC_ESC_CHARS:
2372 case LyXRC::RC_FONT_ENCODING:
2373 case LyXRC::RC_FORMAT:
2374 case LyXRC::RC_INDEX_COMMAND:
2375 case LyXRC::RC_INPUT:
2376 case LyXRC::RC_KBMAP:
2377 case LyXRC::RC_KBMAP_PRIMARY:
2378 case LyXRC::RC_KBMAP_SECONDARY:
2379 case LyXRC::RC_LABEL_INIT_LENGTH:
2380 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2381 case LyXRC::RC_LANGUAGE_AUTO_END:
2382 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2383 case LyXRC::RC_LANGUAGE_COMMAND_END:
2384 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2385 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2386 case LyXRC::RC_LANGUAGE_PACKAGE:
2387 case LyXRC::RC_LANGUAGE_USE_BABEL:
2388 case LyXRC::RC_MAKE_BACKUP:
2389 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2390 case LyXRC::RC_NUMLASTFILES:
2391 case LyXRC::RC_PATH_PREFIX:
2392 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2393 support::prependEnvPath("PATH", lyxrc.path_prefix);
2395 case LyXRC::RC_PERS_DICT:
2396 case LyXRC::RC_PREVIEW:
2397 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2398 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2399 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2400 case LyXRC::RC_PRINTCOPIESFLAG:
2401 case LyXRC::RC_PRINTER:
2402 case LyXRC::RC_PRINTEVENPAGEFLAG:
2403 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2404 case LyXRC::RC_PRINTFILEEXTENSION:
2405 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2406 case LyXRC::RC_PRINTODDPAGEFLAG:
2407 case LyXRC::RC_PRINTPAGERANGEFLAG:
2408 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2409 case LyXRC::RC_PRINTPAPERFLAG:
2410 case LyXRC::RC_PRINTREVERSEFLAG:
2411 case LyXRC::RC_PRINTSPOOL_COMMAND:
2412 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2413 case LyXRC::RC_PRINTTOFILE:
2414 case LyXRC::RC_PRINTTOPRINTER:
2415 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2416 case LyXRC::RC_PRINT_COMMAND:
2417 case LyXRC::RC_RTL_SUPPORT:
2418 case LyXRC::RC_SCREEN_DPI:
2419 case LyXRC::RC_SCREEN_FONT_ROMAN:
2420 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2421 case LyXRC::RC_SCREEN_FONT_SANS:
2422 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2423 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2424 case LyXRC::RC_SCREEN_FONT_SIZES:
2425 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2426 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2427 case LyXRC::RC_SCREEN_GEOMETRY_HEIGHT:
2428 case LyXRC::RC_SCREEN_GEOMETRY_WIDTH:
2429 case LyXRC::RC_SCREEN_GEOMETRY_XYSAVED:
2430 case LyXRC::RC_SCREEN_ZOOM:
2431 case LyXRC::RC_SERVERPIPE:
2432 case LyXRC::RC_SET_COLOR:
2433 case LyXRC::RC_SHOW_BANNER:
2434 case LyXRC::RC_SPELL_COMMAND:
2435 case LyXRC::RC_TEMPDIRPATH:
2436 case LyXRC::RC_TEMPLATEPATH:
2437 case LyXRC::RC_TEX_ALLOWS_SPACES:
2438 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2439 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2440 support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2442 case LyXRC::RC_UIFILE:
2443 case LyXRC::RC_USER_EMAIL:
2444 case LyXRC::RC_USER_NAME:
2445 case LyXRC::RC_USETEMPDIR:
2446 case LyXRC::RC_USE_ALT_LANG:
2447 case LyXRC::RC_USE_CONVERTER_CACHE:
2448 case LyXRC::RC_USE_ESC_CHARS:
2449 case LyXRC::RC_USE_INP_ENC:
2450 case LyXRC::RC_USE_PERS_DICT:
2451 case LyXRC::RC_USE_SPELL_LIB:
2452 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2453 case LyXRC::RC_VIEWER:
2454 case LyXRC::RC_LAST: