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.h"
33 #include "CutAndPaste.h"
35 #include "DispatchResult.h"
37 #include "ErrorList.h"
39 #include "FuncRequest.h"
40 #include "FuncStatus.h"
43 #include "InsetIterator.h"
48 #include "LyXAction.h"
53 #include "Paragraph.h"
54 #include "ParagraphParameters.h"
55 #include "ParIterator.h"
59 #include "TextClassList.h"
60 #include "ToolbarBackend.h"
62 #include "insets/InsetBox.h"
63 #include "insets/InsetBranch.h"
64 #include "insets/InsetCommand.h"
65 #include "insets/InsetERT.h"
66 #include "insets/InsetExternal.h"
67 #include "insets/InsetFloat.h"
68 #include "insets/InsetListings.h"
69 #include "insets/InsetGraphics.h"
70 #include "insets/InsetInclude.h"
71 #include "insets/InsetNote.h"
72 #include "insets/InsetTabular.h"
73 #include "insets/InsetVSpace.h"
74 #include "insets/InsetWrap.h"
76 #include "frontends/Application.h"
77 #include "frontends/alert.h"
78 #include "frontends/Dialogs.h"
79 #include "frontends/FileDialog.h"
80 #include "frontends/FontLoader.h"
81 #include "frontends/Gui.h"
82 #include "frontends/KeySymbol.h"
83 #include "frontends/LyXView.h"
84 #include "frontends/Selection.h"
85 #include "frontends/WorkArea.h"
87 #include "support/environment.h"
88 #include "support/FileFilterList.h"
89 #include "support/filetools.h"
90 #include "support/fs_extras.h"
91 #include "support/lstrings.h"
92 #include "support/Path.h"
93 #include "support/Package.h"
94 #include "support/Systemcall.h"
95 #include "support/convert.h"
96 #include "support/os.h"
98 #include <boost/current_function.hpp>
99 #include <boost/filesystem/operations.hpp>
104 using std::make_pair;
107 using std::istringstream;
108 using std::ostringstream;
110 namespace fs = boost::filesystem;
114 using frontend::LyXView;
116 using support::absolutePath;
117 using support::addName;
118 using support::addPath;
119 using support::bformat;
120 using support::changeExtension;
121 using support::contains;
122 using support::FileFilterList;
123 using support::FileName;
124 using support::fileSearch;
125 using support::i18nLibFileSearch;
126 using support::makeDisplayPath;
127 using support::makeAbsPath;
128 using support::package;
129 using support::quoteName;
130 using support::rtrim;
131 using support::split;
132 using support::subst;
133 using support::Systemcall;
134 using support::token;
136 using support::prefixIs;
138 namespace Alert = frontend::Alert;
140 extern bool quitting;
144 // This function runs "configure" and then rereads lyx.defaults to
145 // reconfigure the automatic settings.
146 void reconfigure(LyXView & lv, string const & option)
148 // emit message signal.
149 lv.message(_("Running configure..."));
151 // Run configure in user lyx directory
152 support::Path p(package().user_support());
153 string configure_command = package().configure_command();
154 configure_command += option;
156 int ret = one.startscript(Systemcall::Wait, configure_command);
158 // emit message signal.
159 lv.message(_("Reloading configuration..."));
160 lyxrc.read(support::libFileSearch(string(), "lyxrc.defaults"));
161 // Re-read packages.lst
162 LaTeXFeatures::getAvailable();
165 Alert::information(_("System reconfiguration failed"),
166 _("The system reconfiguration has failed.\n"
167 "Default textclass is used but LyX may "
168 "not be able to work properly.\n"
169 "Please reconfigure again if needed."));
172 Alert::information(_("System reconfigured"),
173 _("The system has been reconfigured.\n"
174 "You need to restart LyX to make use of any\n"
175 "updated document class specifications."));
179 bool getLocalStatus(Cursor cursor, FuncRequest const & cmd, FuncStatus & status)
181 // Try to fix cursor in case it is broken.
182 cursor.fixIfBroken();
184 // This is, of course, a mess. Better create a new doc iterator and use
185 // this in Inset::getStatus. This might require an additional
186 // BufferView * arg, though (which should be avoided)
187 //Cursor safe = *this;
189 for ( ; cursor.depth(); cursor.pop()) {
190 //lyxerr << "\nCursor::getStatus: cmd: " << cmd << endl << *this << endl;
191 BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
192 BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
193 BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
195 // The inset's getStatus() will return 'true' if it made
196 // a definitive decision on whether it want to handle the
197 // request or not. The result of this decision is put into
198 // the 'status' parameter.
199 if (cursor.inset().getStatus(cursor, cmd, status)) {
208 /** Return the change status at cursor position, taking in account the
209 * status at each level of the document iterator (a table in a deleted
210 * footnote is deleted).
211 * When \param outer is true, the top slice is not looked at.
213 Change::Type lookupChangeType(DocIterator const & dit, bool outer = false)
215 size_t const depth = dit.depth() - (outer ? 1 : 0);
217 for (size_t i = 0 ; i < depth ; ++i) {
218 CursorSlice const & slice = dit[i];
219 if (!slice.inset().inMathed()
220 && slice.pos() < slice.paragraph().size()) {
221 Change::Type const ch = slice.paragraph().lookupChange(slice.pos()).type;
222 if (ch != Change::UNCHANGED)
226 return Change::UNCHANGED;
233 : lyx_view_(0), encoded_last_key(0), meta_fake_bit(NoModifier)
238 void LyXFunc::initKeySequences(KeyMap * kb)
240 keyseq = KeySequence(kb, kb);
241 cancel_meta_seq = KeySequence(kb, kb);
245 void LyXFunc::setLyXView(LyXView * lv)
247 if (!quitting && lyx_view_ && lyx_view_->view() && lyx_view_ != lv)
248 // save current selection to the selection buffer to allow
249 // middle-button paste in another window
250 cap::saveSelection(lyx_view_->view()->cursor());
255 void LyXFunc::handleKeyFunc(kb_action action)
257 char_type c = encoded_last_key;
262 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
263 lyx_view_->view()->getIntl().getTransManager().deadkey(
264 c, get_accent(action).accent, view()->cursor().innerText(), view()->cursor());
265 // Need to clear, in case the minibuffer calls these
268 // copied verbatim from do_accent_char
269 view()->cursor().resetAnchor();
270 view()->processUpdateFlags(Update::FitCursor);
274 void LyXFunc::gotoBookmark(unsigned int idx, bool openFile, bool switchToBuffer)
276 BOOST_ASSERT(lyx_view_);
277 if (!LyX::ref().session().bookmarks().isValid(idx))
279 BookmarksSection::Bookmark const & bm = LyX::ref().session().bookmarks().bookmark(idx);
280 BOOST_ASSERT(!bm.filename.empty());
281 string const file = bm.filename.absFilename();
282 // if the file is not opened, open it.
283 if (!theBufferList().exists(file)) {
285 dispatch(FuncRequest(LFUN_FILE_OPEN, file));
289 // open may fail, so we need to test it again
290 if (!theBufferList().exists(file))
293 // if the current buffer is not that one, switch to it.
294 if (lyx_view_->buffer()->absFileName() != file) {
297 dispatch(FuncRequest(LFUN_BUFFER_SWITCH, file));
299 // moveToPosition try paragraph id first and then paragraph (pit, pos).
300 if (!view()->moveToPosition(bm.bottom_pit, bm.bottom_pos,
301 bm.top_id, bm.top_pos))
304 // Cursor jump succeeded!
305 Cursor const & cur = view()->cursor();
306 pit_type new_pit = cur.pit();
307 pos_type new_pos = cur.pos();
308 int new_id = cur.paragraph().id();
310 // if bottom_pit, bottom_pos or top_id has been changed, update bookmark
311 // see http://bugzilla.lyx.org/show_bug.cgi?id=3092
312 if (bm.bottom_pit != new_pit || bm.bottom_pos != new_pos
313 || bm.top_id != new_id) {
314 const_cast<BookmarksSection::Bookmark &>(bm).updatePos(
315 new_pit, new_pos, new_id);
321 void restartCursor(LyXView * lv)
323 /* When we move around, or type, it's nice to be able to see
324 * the cursor immediately after the keypress.
326 if (lv && lv->currentWorkArea())
327 lv->currentWorkArea()->startBlinkingCursor();
331 void LyXFunc::processKeySym(KeySymbol const & keysym, KeyModifier state)
333 LYXERR(Debug::KEY) << "KeySym is " << keysym.getSymbolName() << endl;
335 // Do nothing if we have nothing (JMarc)
336 if (!keysym.isOK()) {
337 LYXERR(Debug::KEY) << "Empty kbd action (probably composing)"
339 restartCursor(lyx_view_);
343 if (keysym.isModifier()) {
344 LYXERR(Debug::KEY) << "isModifier true" << endl;
345 restartCursor(lyx_view_);
349 //Encoding const * encoding = view()->cursor().getEncoding();
350 //encoded_last_key = keysym.getISOEncoded(encoding ? encoding->name() : "");
351 // FIXME: encoded_last_key shadows the member variable of the same
352 // name. Is that intended?
353 char_type encoded_last_key = keysym.getUCSEncoded();
355 // Do a one-deep top-level lookup for
356 // cancel and meta-fake keys. RVDK_PATCH_5
357 cancel_meta_seq.reset();
359 FuncRequest func = cancel_meta_seq.addkey(keysym, state);
360 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
361 << " action first set to [" << func.action << ']'
364 // When not cancel or meta-fake, do the normal lookup.
365 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
366 // Mostly, meta_fake_bit = NoModifier. RVDK_PATCH_5.
367 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_PREFIX)) {
368 // remove Caps Lock and Mod2 as a modifiers
369 func = keyseq.addkey(keysym, (state | meta_fake_bit));
370 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
371 << "action now set to ["
372 << func.action << ']' << endl;
375 // Dont remove this unless you know what you are doing.
376 meta_fake_bit = NoModifier;
378 // Can this happen now ?
379 if (func.action == LFUN_NOACTION)
380 func = FuncRequest(LFUN_COMMAND_PREFIX);
382 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
384 << func.action << "]["
385 << to_utf8(keyseq.print(false)) << ']'
388 // already here we know if it any point in going further
389 // why not return already here if action == -1 and
390 // num_bytes == 0? (Lgb)
392 if (keyseq.length() > 1)
393 lyx_view_->message(keyseq.print(true));
396 // Maybe user can only reach the key via holding down shift.
397 // Let's see. But only if shift is the only modifier
398 if (func.action == LFUN_UNKNOWN_ACTION && state == ShiftModifier) {
399 LYXERR(Debug::KEY) << "Trying without shift" << endl;
400 func = keyseq.addkey(keysym, NoModifier);
401 LYXERR(Debug::KEY) << "Action now " << func.action << endl;
404 if (func.action == LFUN_UNKNOWN_ACTION) {
405 // Hmm, we didn't match any of the keysequences. See
406 // if it's normal insertable text not already covered
408 if (keysym.isText() && keyseq.length() == 1) {
409 LYXERR(Debug::KEY) << "isText() is true, inserting." << endl;
410 func = FuncRequest(LFUN_SELF_INSERT,
411 FuncRequest::KEYBOARD);
413 LYXERR(Debug::KEY) << "Unknown, !isText() - giving up" << endl;
414 lyx_view_->message(_("Unknown function."));
415 restartCursor(lyx_view_);
420 if (func.action == LFUN_SELF_INSERT) {
421 if (encoded_last_key != 0) {
422 docstring const arg(1, encoded_last_key);
423 dispatch(FuncRequest(LFUN_SELF_INSERT, arg,
424 FuncRequest::KEYBOARD));
426 << "SelfInsert arg[`" << to_utf8(arg) << "']" << endl;
432 restartCursor(lyx_view_);
436 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
438 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
441 /* In LyX/Mac, when a dialog is open, the menus of the
442 application can still be accessed without giving focus to
443 the main window. In this case, we want to disable the menu
444 entries that are buffer-related.
446 Note that this code is not perfect, as bug 1941 attests:
447 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
449 Buffer * buf = lyx_view_? lyx_view_->buffer() : 0;
450 if (lyx_view_ && cmd.origin == FuncRequest::MENU && !lyx_view_->hasFocus())
453 if (cmd.action == LFUN_NOACTION) {
454 flag.message(from_utf8(N_("Nothing to do")));
459 switch (cmd.action) {
460 case LFUN_UNKNOWN_ACTION:
461 #ifndef HAVE_LIBAIKSAURUS
462 case LFUN_THESAURUS_ENTRY:
472 if (flag.unknown()) {
473 flag.message(from_utf8(N_("Unknown action")));
477 if (!flag.enabled()) {
478 if (flag.message().empty())
479 flag.message(from_utf8(N_("Command disabled")));
483 // Check whether we need a buffer
484 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
486 flag.message(from_utf8(N_("Command not allowed with"
487 "out any document open")));
492 // I would really like to avoid having this switch and rather try to
493 // encode this in the function itself.
494 // -- And I'd rather let an inset decide which LFUNs it is willing
495 // to handle (Andre')
497 switch (cmd.action) {
498 case LFUN_BUFFER_TOGGLE_READ_ONLY:
499 flag.setOnOff(buf->isReadonly());
502 case LFUN_BUFFER_SWITCH:
503 // toggle on the current buffer, but do not toggle off
504 // the other ones (is that a good idea?)
505 if (buf && to_utf8(cmd.argument()) == buf->absFileName())
509 case LFUN_BUFFER_EXPORT:
510 enable = cmd.argument() == "custom"
511 || buf->isExportable(to_utf8(cmd.argument()));
514 case LFUN_BUFFER_CHKTEX:
515 enable = buf->isLatex() && !lyxrc.chktex_command.empty();
518 case LFUN_BUILD_PROGRAM:
519 enable = buf->isExportable("program");
522 case LFUN_VC_REGISTER:
523 enable = !buf->lyxvc().inUse();
525 case LFUN_VC_CHECK_IN:
526 enable = buf->lyxvc().inUse() && !buf->isReadonly();
528 case LFUN_VC_CHECK_OUT:
529 enable = buf->lyxvc().inUse() && buf->isReadonly();
532 case LFUN_VC_UNDO_LAST:
533 enable = buf->lyxvc().inUse();
535 case LFUN_BUFFER_RELOAD:
536 enable = !buf->isUnnamed() && fs::exists(buf->absFileName())
537 && (!buf->isClean() || buf->isExternallyModified(Buffer::timestamp_method));
540 case LFUN_INSET_APPLY: {
545 string const name = cmd.getArg(0);
546 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
548 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
550 if (!inset->getStatus(view()->cursor(), fr, fs)) {
551 // Every inset is supposed to handle this
556 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
557 flag |= getStatus(fr);
559 enable = flag.enabled();
563 case LFUN_DIALOG_TOGGLE:
564 flag.setOnOff(lyx_view_->getDialogs().visible(cmd.getArg(0)));
565 // fall through to set "enable"
566 case LFUN_DIALOG_SHOW: {
567 string const name = cmd.getArg(0);
569 enable = name == "aboutlyx"
570 || name == "file" //FIXME: should be removed.
572 || name == "texinfo";
573 else if (name == "print")
574 enable = buf->isExportable("dvi")
575 && lyxrc.print_command != "none";
576 else if (name == "character") {
580 InsetCode ic = view()->cursor().inset().lyxCode();
581 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
584 else if (name == "latexlog")
585 enable = FileName(buf->logName().second).isFileReadable();
586 else if (name == "spellchecker")
587 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
588 enable = !buf->isReadonly();
592 else if (name == "vclog")
593 enable = buf->lyxvc().inUse();
597 case LFUN_DIALOG_UPDATE: {
598 string const name = cmd.getArg(0);
600 enable = name == "prefs";
604 case LFUN_CITATION_INSERT: {
605 FuncRequest fr(LFUN_INSET_INSERT, "citation");
606 enable = getStatus(fr).enabled();
610 case LFUN_BUFFER_WRITE: {
611 enable = lyx_view_->buffer()->isUnnamed()
612 || !lyx_view_->buffer()->isClean();
617 case LFUN_BUFFER_WRITE_ALL: {
618 // We enable the command only if there are some modified buffers
619 Buffer * first = theBufferList().first();
620 bool modified = false;
624 // We cannot use a for loop as the buffer list is a cycle.
630 b = theBufferList().next(b);
631 } while (b != first);
639 case LFUN_BOOKMARK_GOTO: {
640 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
641 enable = LyX::ref().session().bookmarks().isValid(num);
645 case LFUN_BOOKMARK_CLEAR:
646 enable = LyX::ref().session().bookmarks().size() > 0;
649 case LFUN_TOOLBAR_TOGGLE: {
650 bool const current = lyx_view_->isToolbarVisible(cmd.getArg(0));
651 flag.setOnOff(current);
654 case LFUN_WINDOW_CLOSE: {
655 enable = (theApp()->gui().viewIds().size() > 1);
659 // this one is difficult to get right. As a half-baked
660 // solution, we consider only the first action of the sequence
661 case LFUN_COMMAND_SEQUENCE: {
662 // argument contains ';'-terminated commands
663 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
664 FuncRequest func(lyxaction.lookupFunc(firstcmd));
665 func.origin = cmd.origin;
666 flag = getStatus(func);
669 case LFUN_BUFFER_NEW:
670 case LFUN_BUFFER_NEW_TEMPLATE:
671 case LFUN_WORD_FIND_FORWARD:
672 case LFUN_WORD_FIND_BACKWARD:
673 case LFUN_COMMAND_PREFIX:
674 case LFUN_COMMAND_EXECUTE:
676 case LFUN_META_PREFIX:
677 case LFUN_BUFFER_CLOSE:
678 case LFUN_BUFFER_WRITE_AS:
679 case LFUN_BUFFER_UPDATE:
680 case LFUN_BUFFER_VIEW:
681 case LFUN_MASTER_BUFFER_UPDATE:
682 case LFUN_MASTER_BUFFER_VIEW:
683 case LFUN_BUFFER_IMPORT:
684 case LFUN_BUFFER_AUTO_SAVE:
685 case LFUN_RECONFIGURE:
689 case LFUN_DROP_LAYOUTS_CHOICE:
691 case LFUN_SERVER_GET_NAME:
692 case LFUN_SERVER_NOTIFY:
693 case LFUN_SERVER_GOTO_FILE_ROW:
694 case LFUN_DIALOG_HIDE:
695 case LFUN_DIALOG_DISCONNECT_INSET:
696 case LFUN_BUFFER_CHILD_OPEN:
697 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
698 case LFUN_KEYMAP_OFF:
699 case LFUN_KEYMAP_PRIMARY:
700 case LFUN_KEYMAP_SECONDARY:
701 case LFUN_KEYMAP_TOGGLE:
703 case LFUN_BUFFER_EXPORT_CUSTOM:
704 case LFUN_BUFFER_PRINT:
705 case LFUN_PREFERENCES_SAVE:
706 case LFUN_SCREEN_FONT_UPDATE:
709 case LFUN_EXTERNAL_EDIT:
710 case LFUN_GRAPHICS_EDIT:
711 case LFUN_ALL_INSETS_TOGGLE:
712 case LFUN_BUFFER_LANGUAGE:
713 case LFUN_TEXTCLASS_APPLY:
714 case LFUN_TEXTCLASS_LOAD:
715 case LFUN_BUFFER_SAVE_AS_DEFAULT:
716 case LFUN_BUFFER_PARAMS_APPLY:
717 case LFUN_LAYOUT_MODULES_CLEAR:
718 case LFUN_LAYOUT_MODULE_ADD:
719 case LFUN_LAYOUT_RELOAD:
720 case LFUN_LYXRC_APPLY:
721 case LFUN_BUFFER_NEXT:
722 case LFUN_BUFFER_PREVIOUS:
723 case LFUN_WINDOW_NEW:
725 // these are handled in our dispatch()
733 if (!getLocalStatus(view()->cursor(), cmd, flag))
734 flag = view()->getStatus(cmd);
740 // Can we use a readonly buffer?
741 if (buf && buf->isReadonly()
742 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
743 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
744 flag.message(from_utf8(N_("Document is read-only")));
748 // Are we in a DELETED change-tracking region?
750 && lookupChangeType(view()->cursor(), true) == Change::DELETED
751 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
752 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
753 flag.message(from_utf8(N_("This portion of the document is deleted.")));
757 // the default error message if we disable the command
758 if (!flag.enabled() && flag.message().empty())
759 flag.message(from_utf8(N_("Command disabled")));
765 bool LyXFunc::ensureBufferClean(BufferView * bv)
767 Buffer & buf = bv->buffer();
771 docstring const file = makeDisplayPath(buf.absFileName(), 30);
772 docstring text = bformat(_("The document %1$s has unsaved "
773 "changes.\n\nDo you want to save "
774 "the document?"), file);
775 int const ret = Alert::prompt(_("Save changed document?"),
776 text, 0, 1, _("&Save"),
780 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
782 return buf.isClean();
788 void showPrintError(string const & name)
790 docstring str = bformat(_("Could not print the document %1$s.\n"
791 "Check that your printer is set up correctly."),
792 makeDisplayPath(name, 50));
793 Alert::error(_("Print document failed"), str);
797 void loadTextClass(string const & name)
799 std::pair<bool, textclass_type> const tc_pair =
800 textclasslist.numberOfClass(name);
802 if (!tc_pair.first) {
803 lyxerr << "Document class \"" << name
804 << "\" does not exist."
809 textclass_type const tc = tc_pair.second;
811 if (!textclasslist[tc].load()) {
812 docstring s = bformat(_("The document class %1$s."
813 "could not be loaded."),
814 from_utf8(textclasslist[tc].name()));
815 Alert::error(_("Could not load class"), s);
820 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
825 void LyXFunc::dispatch(FuncRequest const & cmd)
827 string const argument = to_utf8(cmd.argument());
828 kb_action const action = cmd.action;
830 LYXERR(Debug::ACTION) << endl << "LyXFunc::dispatch: cmd: " << cmd << endl;
831 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
833 // we have not done anything wrong yet.
835 dispatch_buffer.erase();
837 // redraw the screen at the end (first of the two drawing steps).
838 //This is done unless explicitely requested otherwise
839 Update::flags updateFlags = Update::FitCursor;
841 FuncStatus const flag = getStatus(cmd);
842 if (!flag.enabled()) {
843 // We cannot use this function here
844 LYXERR(Debug::ACTION) << "LyXFunc::dispatch: "
845 << lyxaction.getActionName(action)
846 << " [" << action << "] is disabled at this location"
848 setErrorMessage(flag.message());
852 case LFUN_WORD_FIND_FORWARD:
853 case LFUN_WORD_FIND_BACKWARD: {
854 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
855 static docstring last_search;
856 docstring searched_string;
858 if (!cmd.argument().empty()) {
859 last_search = cmd.argument();
860 searched_string = cmd.argument();
862 searched_string = last_search;
865 if (searched_string.empty())
868 bool const fw = action == LFUN_WORD_FIND_FORWARD;
869 docstring const data =
870 find2string(searched_string, true, false, fw);
871 find(view(), FuncRequest(LFUN_WORD_FIND, data));
875 case LFUN_COMMAND_PREFIX:
876 BOOST_ASSERT(lyx_view_);
877 lyx_view_->message(keyseq.printOptions(true));
880 case LFUN_COMMAND_EXECUTE:
881 BOOST_ASSERT(lyx_view_);
882 lyx_view_->showMiniBuffer(true);
886 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
888 meta_fake_bit = NoModifier;
889 if (lyx_view_->buffer())
890 // cancel any selection
891 dispatch(FuncRequest(LFUN_MARK_OFF));
892 setMessage(from_ascii(N_("Cancel")));
895 case LFUN_META_PREFIX:
896 meta_fake_bit = AltModifier;
897 setMessage(keyseq.print(true));
900 case LFUN_BUFFER_TOGGLE_READ_ONLY: {
901 BOOST_ASSERT(lyx_view_ && lyx_view_->view() && lyx_view_->buffer());
902 Buffer * buf = lyx_view_->buffer();
903 if (buf->lyxvc().inUse())
904 buf->lyxvc().toggleReadOnly();
906 buf->setReadonly(!lyx_view_->buffer()->isReadonly());
910 // --- Menus -----------------------------------------------
911 case LFUN_BUFFER_NEW:
912 menuNew(argument, false);
913 updateFlags = Update::None;
916 case LFUN_BUFFER_NEW_TEMPLATE:
917 menuNew(argument, true);
918 updateFlags = Update::None;
921 case LFUN_BUFFER_CLOSE:
923 updateFlags = Update::None;
926 case LFUN_BUFFER_WRITE:
927 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
928 if (!lyx_view_->buffer()->isUnnamed()) {
929 docstring const str = bformat(_("Saving document %1$s..."),
930 makeDisplayPath(lyx_view_->buffer()->absFileName()));
931 lyx_view_->message(str);
932 lyx_view_->buffer()->menuWrite();
933 lyx_view_->message(str + _(" done."));
935 lyx_view_->buffer()->writeAs();
937 updateFlags = Update::None;
940 case LFUN_BUFFER_WRITE_AS:
941 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
942 lyx_view_->buffer()->writeAs(argument);
943 updateFlags = Update::None;
946 case LFUN_BUFFER_WRITE_ALL: {
947 Buffer * first = theBufferList().first();
950 lyx_view_->message(_("Saving all documents..."));
952 // We cannot use a for loop as the buffer list cycles.
955 if (!b->isUnnamed()) {
957 lyxerr[Debug::ACTION] << "Saved " << b->absFileName() << endl;
961 b = theBufferList().next(b);
962 } while (b != first);
963 lyx_view_->message(_("All documents saved."));
966 updateFlags = Update::None;
970 case LFUN_BUFFER_RELOAD: {
971 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
972 docstring const file = makeDisplayPath(lyx_view_->buffer()->absFileName(), 20);
973 docstring text = bformat(_("Any changes will be lost. Are you sure "
974 "you want to revert to the saved version of the document %1$s?"), file);
975 int const ret = Alert::prompt(_("Revert to saved document?"),
976 text, 1, 1, _("&Revert"), _("&Cancel"));
983 case LFUN_BUFFER_UPDATE:
984 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
985 lyx_view_->buffer()->doExport(argument, true);
988 case LFUN_BUFFER_VIEW:
989 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
990 lyx_view_->buffer()->preview(argument);
993 case LFUN_MASTER_BUFFER_UPDATE:
994 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->masterBuffer());
995 lyx_view_->buffer()->masterBuffer()->doExport(argument, true);
998 case LFUN_MASTER_BUFFER_VIEW:
999 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->masterBuffer());
1000 lyx_view_->buffer()->masterBuffer()->preview(argument);
1003 case LFUN_BUILD_PROGRAM:
1004 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1005 lyx_view_->buffer()->doExport("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 lyx_view_->buffer()->doExport(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 = buffer->latexName(false);
1041 filename = changeExtension(latexname,
1042 format->extension());
1043 filename = addName(buffer->temppath(), filename);
1045 if (!buffer->writeFile(FileName(filename)))
1049 buffer->doExport(format_name, true, filename);
1052 // Substitute $$FName for filename
1053 if (!contains(command, "$$FName"))
1054 command = "( " + command + " ) < $$FName";
1055 command = subst(command, "$$FName", filename);
1057 // Execute the command in the background
1059 call.startscript(Systemcall::DontWait, command);
1063 case LFUN_BUFFER_PRINT: {
1064 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1065 // FIXME: cmd.getArg() might fail if one of the arguments
1066 // contains double quotes
1067 string target = cmd.getArg(0);
1068 string target_name = cmd.getArg(1);
1069 string command = cmd.getArg(2);
1072 || target_name.empty()
1073 || command.empty()) {
1074 lyxerr << "Unable to parse \""
1075 << argument << '"' << endl;
1078 if (target != "printer" && target != "file") {
1079 lyxerr << "Unrecognized target \""
1080 << target << '"' << endl;
1084 Buffer * buffer = lyx_view_->buffer();
1086 if (!buffer->doExport("dvi", true)) {
1087 showPrintError(buffer->absFileName());
1091 // Push directory path.
1092 string const path = buffer->temppath();
1093 // Prevent the compiler from optimizing away p
1095 support::Path p(pp);
1097 // there are three cases here:
1098 // 1. we print to a file
1099 // 2. we print directly to a printer
1100 // 3. we print using a spool command (print to file first)
1103 string const dviname =
1104 changeExtension(buffer->latexName(true), "dvi");
1106 if (target == "printer") {
1107 if (!lyxrc.print_spool_command.empty()) {
1108 // case 3: print using a spool
1109 string const psname =
1110 changeExtension(dviname,".ps");
1111 command += ' ' + lyxrc.print_to_file
1114 + quoteName(dviname);
1117 lyxrc.print_spool_command + ' ';
1118 if (target_name != "default") {
1119 command2 += lyxrc.print_spool_printerprefix
1123 command2 += quoteName(psname);
1125 // If successful, then spool command
1126 res = one.startscript(
1131 res = one.startscript(
1132 Systemcall::DontWait,
1135 // case 2: print directly to a printer
1136 if (target_name != "default")
1137 command += ' ' + lyxrc.print_to_printer + target_name + ' ';
1138 res = one.startscript(
1139 Systemcall::DontWait,
1140 command + quoteName(dviname));
1144 // case 1: print to a file
1145 FileName const filename(makeAbsPath(target_name,
1146 lyx_view_->buffer()->filePath()));
1147 FileName const dvifile(makeAbsPath(dviname, path));
1148 if (filename.exists()) {
1149 docstring text = bformat(
1150 _("The file %1$s already exists.\n\n"
1151 "Do you want to overwrite that file?"),
1152 makeDisplayPath(filename.absFilename()));
1153 if (Alert::prompt(_("Overwrite file?"),
1154 text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
1157 command += ' ' + lyxrc.print_to_file
1158 + quoteName(filename.toFilesystemEncoding())
1160 + quoteName(dvifile.toFilesystemEncoding());
1161 res = one.startscript(Systemcall::DontWait,
1166 showPrintError(buffer->absFileName());
1170 case LFUN_BUFFER_IMPORT:
1175 // quitting is triggered by the gui code
1176 // (leaving the event loop).
1177 lyx_view_->message(from_utf8(N_("Exiting.")));
1178 if (theBufferList().quitWriteAll())
1179 theApp()->gui().closeAllViews();
1182 case LFUN_BUFFER_AUTO_SAVE:
1183 lyx_view_->buffer()->autoSave();
1186 case LFUN_RECONFIGURE:
1187 BOOST_ASSERT(lyx_view_);
1188 // argument is any additional parameter to the configure.py command
1189 reconfigure(*lyx_view_, argument);
1192 case LFUN_HELP_OPEN: {
1193 BOOST_ASSERT(lyx_view_);
1194 string const arg = argument;
1196 setErrorMessage(from_ascii(N_("Missing argument")));
1199 FileName const fname = i18nLibFileSearch("doc", arg, "lyx");
1200 if (fname.empty()) {
1201 lyxerr << "LyX: unable to find documentation file `"
1202 << arg << "'. Bad installation?" << endl;
1205 lyx_view_->message(bformat(_("Opening help file %1$s..."),
1206 makeDisplayPath(fname.absFilename())));
1207 Buffer * buf = lyx_view_->loadLyXFile(fname, false);
1210 lyx_view_->setBuffer(buf);
1211 lyx_view_->showErrorList("Parse");
1213 updateFlags = Update::None;
1217 // --- version control -------------------------------
1218 case LFUN_VC_REGISTER:
1219 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1220 if (!ensureBufferClean(view()))
1222 if (!lyx_view_->buffer()->lyxvc().inUse()) {
1223 lyx_view_->buffer()->lyxvc().registrer();
1226 updateFlags = Update::Force;
1229 case LFUN_VC_CHECK_IN:
1230 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1231 if (!ensureBufferClean(view()))
1233 if (lyx_view_->buffer()->lyxvc().inUse()
1234 && !lyx_view_->buffer()->isReadonly()) {
1235 lyx_view_->buffer()->lyxvc().checkIn();
1240 case LFUN_VC_CHECK_OUT:
1241 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1242 if (!ensureBufferClean(view()))
1244 if (lyx_view_->buffer()->lyxvc().inUse()
1245 && lyx_view_->buffer()->isReadonly()) {
1246 lyx_view_->buffer()->lyxvc().checkOut();
1251 case LFUN_VC_REVERT:
1252 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1253 lyx_view_->buffer()->lyxvc().revert();
1257 case LFUN_VC_UNDO_LAST:
1258 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1259 lyx_view_->buffer()->lyxvc().undoLast();
1263 // --- buffers ----------------------------------------
1264 case LFUN_BUFFER_SWITCH:
1265 BOOST_ASSERT(lyx_view_);
1266 lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1267 updateFlags = Update::None;
1270 case LFUN_BUFFER_NEXT:
1271 BOOST_ASSERT(lyx_view_);
1272 lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer()));
1273 updateFlags = Update::None;
1276 case LFUN_BUFFER_PREVIOUS:
1277 BOOST_ASSERT(lyx_view_);
1278 lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer()));
1279 updateFlags = Update::None;
1282 case LFUN_FILE_NEW: {
1283 BOOST_ASSERT(lyx_view_);
1285 string tmpname = split(argument, name, ':'); // Split filename
1286 Buffer * const b = newFile(name, tmpname);
1288 lyx_view_->setBuffer(b);
1289 updateFlags = Update::None;
1293 case LFUN_FILE_OPEN:
1294 BOOST_ASSERT(lyx_view_);
1296 updateFlags = Update::None;
1299 case LFUN_DROP_LAYOUTS_CHOICE:
1300 BOOST_ASSERT(lyx_view_);
1301 lyx_view_->openLayoutList();
1304 case LFUN_MENU_OPEN:
1305 BOOST_ASSERT(lyx_view_);
1306 lyx_view_->openMenu(from_utf8(argument));
1309 // --- lyxserver commands ----------------------------
1310 case LFUN_SERVER_GET_NAME:
1311 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1312 setMessage(from_utf8(lyx_view_->buffer()->absFileName()));
1313 LYXERR(Debug::INFO) << "FNAME["
1314 << lyx_view_->buffer()->absFileName()
1318 case LFUN_SERVER_NOTIFY:
1319 dispatch_buffer = keyseq.print(false);
1320 theServer().notifyClient(to_utf8(dispatch_buffer));
1323 case LFUN_SERVER_GOTO_FILE_ROW: {
1324 BOOST_ASSERT(lyx_view_);
1327 istringstream is(argument);
1328 is >> file_name >> row;
1330 bool loaded = false;
1331 if (prefixIs(file_name, package().temp_dir().absFilename()))
1332 // Needed by inverse dvi search. If it is a file
1333 // in tmpdir, call the apropriated function
1334 buf = theBufferList().getBufferFromTmp(file_name);
1336 // Must replace extension of the file to be .lyx
1337 // and get full path
1338 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1339 // Either change buffer or load the file
1340 if (theBufferList().exists(s.absFilename()))
1341 buf = theBufferList().getBuffer(s.absFilename());
1343 buf = lyx_view_->loadLyXFile(s);
1349 updateFlags = Update::None;
1354 lyx_view_->setBuffer(buf);
1355 view()->setCursorFromRow(row);
1357 lyx_view_->showErrorList("Parse");
1358 updateFlags = Update::FitCursor;
1362 case LFUN_DIALOG_SHOW: {
1363 BOOST_ASSERT(lyx_view_);
1364 string const name = cmd.getArg(0);
1365 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1367 if (name == "character") {
1368 data = freefont2string();
1370 lyx_view_->getDialogs().show("character", data);
1371 } else if (name == "latexlog") {
1372 pair<Buffer::LogType, string> const logfile =
1373 lyx_view_->buffer()->logName();
1374 switch (logfile.first) {
1375 case Buffer::latexlog:
1378 case Buffer::buildlog:
1382 data += Lexer::quoteString(logfile.second);
1383 lyx_view_->getDialogs().show("log", data);
1384 } else if (name == "vclog") {
1385 string const data = "vc " +
1386 Lexer::quoteString(lyx_view_->buffer()->lyxvc().getLogFile());
1387 lyx_view_->getDialogs().show("log", data);
1389 lyx_view_->getDialogs().show(name, data);
1393 case LFUN_DIALOG_SHOW_NEW_INSET: {
1394 BOOST_ASSERT(lyx_view_);
1395 string const name = cmd.getArg(0);
1396 InsetCode code = insetCode(name);
1397 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1398 bool insetCodeOK = true;
1407 case HYPERLINK_CODE: {
1408 InsetCommandParams p(code);
1409 data = InsetCommandMailer::params2string(name, p);
1412 case INCLUDE_CODE: {
1413 // data is the include type: one of "include",
1414 // "input", "verbatiminput" or "verbatiminput*"
1416 // default type is requested
1418 InsetCommandParams p(INCLUDE_CODE, data);
1419 data = InsetIncludeMailer::params2string(p);
1423 // \c data == "Boxed" || "Frameless" etc
1424 InsetBoxParams p(data);
1425 data = InsetBoxMailer::params2string(p);
1429 InsetBranchParams p;
1430 data = InsetBranchMailer::params2string(p);
1434 InsetCommandParams p(CITE_CODE);
1435 data = InsetCommandMailer::params2string(name, p);
1439 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1442 case EXTERNAL_CODE: {
1443 InsetExternalParams p;
1444 Buffer const & buffer = *lyx_view_->buffer();
1445 data = InsetExternalMailer::params2string(p, buffer);
1450 data = InsetFloatMailer::params2string(p);
1453 case LISTINGS_CODE: {
1454 InsetListingsParams p;
1455 data = InsetListingsMailer::params2string(p);
1458 case GRAPHICS_CODE: {
1459 InsetGraphicsParams p;
1460 Buffer const & buffer = *lyx_view_->buffer();
1461 data = InsetGraphicsMailer::params2string(p, buffer);
1466 data = InsetNoteMailer::params2string(p);
1471 data = InsetVSpaceMailer::params2string(space);
1476 data = InsetWrapMailer::params2string(p);
1480 lyxerr << "Inset type '" << name <<
1481 "' not recognized in LFUN_DIALOG_SHOW_NEW_INSET" << std:: endl;
1482 insetCodeOK = false;
1484 } // end switch(code)
1486 lyx_view_->getDialogs().show(name, data, 0);
1490 case LFUN_DIALOG_UPDATE: {
1491 BOOST_ASSERT(lyx_view_);
1492 string const & name = argument;
1493 // Can only update a dialog connected to an existing inset
1494 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1496 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1497 inset->dispatch(view()->cursor(), fr);
1498 } else if (name == "paragraph") {
1499 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1500 } else if (name == "prefs") {
1501 lyx_view_->getDialogs().update(name, string());
1506 case LFUN_DIALOG_HIDE:
1507 LyX::cref().hideDialogs(argument, 0);
1510 case LFUN_DIALOG_TOGGLE: {
1511 BOOST_ASSERT(lyx_view_);
1512 if (lyx_view_->getDialogs().visible(cmd.getArg(0)))
1513 dispatch(FuncRequest(LFUN_DIALOG_HIDE, argument));
1515 dispatch(FuncRequest(LFUN_DIALOG_SHOW, argument));
1519 case LFUN_DIALOG_DISCONNECT_INSET:
1520 BOOST_ASSERT(lyx_view_);
1521 lyx_view_->getDialogs().disconnect(argument);
1525 case LFUN_CITATION_INSERT: {
1526 BOOST_ASSERT(lyx_view_);
1527 if (!argument.empty()) {
1528 // we can have one optional argument, delimited by '|'
1529 // citation-insert <key>|<text_before>
1530 // this should be enhanced to also support text_after
1531 // and citation style
1532 string arg = argument;
1534 if (contains(argument, "|")) {
1535 arg = token(argument, '|', 0);
1536 opt1 = token(argument, '|', 1);
1538 InsetCommandParams icp(CITE_CODE);
1539 icp["key"] = from_utf8(arg);
1541 icp["before"] = from_utf8(opt1);
1542 string icstr = InsetCommandMailer::params2string("citation", icp);
1543 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1546 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1550 case LFUN_BUFFER_CHILD_OPEN: {
1551 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1552 Buffer * parent = lyx_view_->buffer();
1553 FileName filename = makeAbsPath(argument, parent->filePath());
1554 view()->saveBookmark(false);
1556 bool parsed = false;
1557 if (theBufferList().exists(filename.absFilename())) {
1558 child = theBufferList().getBuffer(filename.absFilename());
1560 setMessage(bformat(_("Opening child document %1$s..."),
1561 makeDisplayPath(filename.absFilename())));
1562 child = lyx_view_->loadLyXFile(filename, true);
1566 // Set the parent name of the child document.
1567 // This makes insertion of citations and references in the child work,
1568 // when the target is in the parent or another child document.
1569 child->setParentName(parent->absFileName());
1570 updateLabels(*child->masterBuffer());
1571 lyx_view_->setBuffer(child);
1573 lyx_view_->showErrorList("Parse");
1576 // If a screen update is required (in case where auto_open is false),
1577 // setBuffer() would have taken care of it already. Otherwise we shall
1578 // reset the update flag because it can cause a circular problem.
1580 updateFlags = Update::None;
1584 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1585 BOOST_ASSERT(lyx_view_);
1586 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1589 case LFUN_KEYMAP_OFF:
1590 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1591 lyx_view_->view()->getIntl().keyMapOn(false);
1594 case LFUN_KEYMAP_PRIMARY:
1595 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1596 lyx_view_->view()->getIntl().keyMapPrim();
1599 case LFUN_KEYMAP_SECONDARY:
1600 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1601 lyx_view_->view()->getIntl().keyMapSec();
1604 case LFUN_KEYMAP_TOGGLE:
1605 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1606 lyx_view_->view()->getIntl().toggleKeyMap();
1612 string rest = split(argument, countstr, ' ');
1613 istringstream is(countstr);
1616 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1617 for (int i = 0; i < count; ++i)
1618 dispatch(lyxaction.lookupFunc(rest));
1622 case LFUN_COMMAND_SEQUENCE: {
1623 // argument contains ';'-terminated commands
1624 string arg = argument;
1625 while (!arg.empty()) {
1627 arg = split(arg, first, ';');
1628 FuncRequest func(lyxaction.lookupFunc(first));
1629 func.origin = cmd.origin;
1635 case LFUN_PREFERENCES_SAVE: {
1636 lyxrc.write(makeAbsPath("preferences",
1637 package().user_support().absFilename()),
1642 case LFUN_SCREEN_FONT_UPDATE:
1643 BOOST_ASSERT(lyx_view_);
1644 // handle the screen font changes.
1645 theFontLoader().update();
1646 /// FIXME: only the current view will be updated. the Gui
1647 /// class is able to furnish the list of views.
1648 updateFlags = Update::Force;
1651 case LFUN_SET_COLOR: {
1653 string const x11_name = split(argument, lyx_name, ' ');
1654 if (lyx_name.empty() || x11_name.empty()) {
1655 setErrorMessage(from_ascii(N_(
1656 "Syntax: set-color <lyx_name>"
1661 bool const graphicsbg_changed =
1662 (lyx_name == lcolor.getLyXName(Color::graphicsbg) &&
1663 x11_name != lcolor.getX11Name(Color::graphicsbg));
1665 if (!lcolor.setColor(lyx_name, x11_name)) {
1667 bformat(_("Set-color \"%1$s\" failed "
1668 "- color is undefined or "
1669 "may not be redefined"),
1670 from_utf8(lyx_name)));
1674 theApp()->updateColor(lcolor.getFromLyXName(lyx_name));
1676 if (graphicsbg_changed) {
1677 // FIXME: The graphics cache no longer has a changeDisplay method.
1679 graphics::GCache::get().changeDisplay(true);
1686 BOOST_ASSERT(lyx_view_);
1687 lyx_view_->message(from_utf8(argument));
1690 case LFUN_EXTERNAL_EDIT: {
1691 BOOST_ASSERT(lyx_view_);
1692 FuncRequest fr(action, argument);
1693 InsetExternal().dispatch(view()->cursor(), fr);
1697 case LFUN_GRAPHICS_EDIT: {
1698 FuncRequest fr(action, argument);
1699 InsetGraphics().dispatch(view()->cursor(), fr);
1703 case LFUN_INSET_APPLY: {
1704 BOOST_ASSERT(lyx_view_);
1705 string const name = cmd.getArg(0);
1706 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1708 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1709 inset->dispatch(view()->cursor(), fr);
1711 FuncRequest fr(LFUN_INSET_INSERT, argument);
1714 // ideally, the update flag should be set by the insets,
1715 // but this is not possible currently
1716 updateFlags = Update::Force | Update::FitCursor;
1720 case LFUN_ALL_INSETS_TOGGLE: {
1721 BOOST_ASSERT(lyx_view_);
1723 string const name = split(argument, action, ' ');
1724 InsetCode const inset_code = insetCode(name);
1726 Cursor & cur = view()->cursor();
1727 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1729 Inset & inset = lyx_view_->buffer()->inset();
1730 InsetIterator it = inset_iterator_begin(inset);
1731 InsetIterator const end = inset_iterator_end(inset);
1732 for (; it != end; ++it) {
1733 if (!it->asInsetMath()
1734 && (inset_code == NO_CODE
1735 || inset_code == it->lyxCode())) {
1736 Cursor tmpcur = cur;
1737 tmpcur.pushLeft(*it);
1738 it->dispatch(tmpcur, fr);
1741 updateFlags = Update::Force | Update::FitCursor;
1745 case LFUN_BUFFER_LANGUAGE: {
1746 BOOST_ASSERT(lyx_view_);
1747 Buffer & buffer = *lyx_view_->buffer();
1748 Language const * oldL = buffer.params().language;
1749 Language const * newL = languages.getLanguage(argument);
1750 if (!newL || oldL == newL)
1753 if (oldL->rightToLeft() == newL->rightToLeft()
1754 && !buffer.isMultiLingual())
1755 buffer.changeLanguage(oldL, newL);
1759 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1760 string const fname =
1761 addName(addPath(package().user_support().absFilename(), "templates/"),
1763 Buffer defaults(fname);
1765 istringstream ss(argument);
1768 int const unknown_tokens = defaults.readHeader(lex);
1770 if (unknown_tokens != 0) {
1771 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1772 << unknown_tokens << " unknown token"
1773 << (unknown_tokens == 1 ? "" : "s")
1777 if (defaults.writeFile(FileName(defaults.absFileName())))
1778 setMessage(bformat(_("Document defaults saved in %1$s"),
1779 makeDisplayPath(fname)));
1781 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1785 case LFUN_BUFFER_PARAMS_APPLY: {
1786 BOOST_ASSERT(lyx_view_);
1787 biblio::CiteEngine const oldEngine =
1788 lyx_view_->buffer()->params().getEngine();
1790 Buffer * buffer = lyx_view_->buffer();
1792 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1794 Cursor & cur = view()->cursor();
1795 cur.recordUndoFullDocument();
1797 istringstream ss(argument);
1800 int const unknown_tokens = buffer->readHeader(lex);
1802 if (unknown_tokens != 0) {
1803 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1804 << unknown_tokens << " unknown token"
1805 << (unknown_tokens == 1 ? "" : "s")
1809 updateLayout(oldClass, buffer);
1811 biblio::CiteEngine const newEngine =
1812 lyx_view_->buffer()->params().getEngine();
1814 if (oldEngine != newEngine) {
1815 FuncRequest fr(LFUN_INSET_REFRESH);
1817 Inset & inset = lyx_view_->buffer()->inset();
1818 InsetIterator it = inset_iterator_begin(inset);
1819 InsetIterator const end = inset_iterator_end(inset);
1820 for (; it != end; ++it)
1821 if (it->lyxCode() == CITE_CODE)
1822 it->dispatch(cur, fr);
1825 updateFlags = Update::Force | Update::FitCursor;
1829 case LFUN_LAYOUT_MODULES_CLEAR: {
1830 BOOST_ASSERT(lyx_view_);
1831 Buffer * buffer = lyx_view_->buffer();
1832 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1833 view()->cursor().recordUndoFullDocument();
1834 buffer->params().clearLayoutModules();
1835 updateLayout(oldClass, buffer);
1836 updateFlags = Update::Force | Update::FitCursor;
1840 case LFUN_LAYOUT_MODULE_ADD: {
1841 BOOST_ASSERT(lyx_view_);
1842 Buffer * buffer = lyx_view_->buffer();
1843 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1844 view()->cursor().recordUndoFullDocument();
1845 buffer->params().addLayoutModule(argument);
1846 updateLayout(oldClass, buffer);
1847 updateFlags = Update::Force | Update::FitCursor;
1851 case LFUN_TEXTCLASS_APPLY: {
1852 BOOST_ASSERT(lyx_view_);
1853 Buffer * buffer = lyx_view_->buffer();
1855 loadTextClass(argument);
1857 std::pair<bool, textclass_type> const tc_pair =
1858 textclasslist.numberOfClass(argument);
1863 textclass_type const old_class = buffer->params().getBaseClass();
1864 textclass_type const new_class = tc_pair.second;
1866 if (old_class == new_class)
1870 //Save the old, possibly modular, layout for use in conversion.
1871 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1872 view()->cursor().recordUndoFullDocument();
1873 buffer->params().setBaseClass(new_class);
1874 updateLayout(oldClass, buffer);
1875 updateFlags = Update::Force | Update::FitCursor;
1879 case LFUN_LAYOUT_RELOAD: {
1880 BOOST_ASSERT(lyx_view_);
1881 Buffer * buffer = lyx_view_->buffer();
1882 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1883 textclass_type const tc = buffer->params().getBaseClass();
1884 textclasslist.reset(tc);
1885 buffer->params().setBaseClass(tc);
1886 updateLayout(oldClass, buffer);
1887 updateFlags = Update::Force | Update::FitCursor;
1891 case LFUN_TEXTCLASS_LOAD:
1892 loadTextClass(argument);
1895 case LFUN_LYXRC_APPLY: {
1896 LyXRC const lyxrc_orig = lyxrc;
1898 istringstream ss(argument);
1899 bool const success = lyxrc.read(ss) == 0;
1902 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1903 << "Unable to read lyxrc data"
1908 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1910 /// We force the redraw in any case because there might be
1911 /// some screen font changes.
1912 /// FIXME: only the current view will be updated. the Gui
1913 /// class is able to furnish the list of views.
1914 updateFlags = Update::Force;
1918 case LFUN_WINDOW_NEW:
1919 LyX::ref().newLyXView();
1922 case LFUN_WINDOW_CLOSE:
1923 BOOST_ASSERT(lyx_view_);
1924 BOOST_ASSERT(theApp());
1925 // update bookmark pit of the current buffer before window close
1926 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1927 gotoBookmark(i+1, false, false);
1928 // ask the user for saving changes or cancel quit
1929 if (!theBufferList().quitWriteAll())
1934 case LFUN_BOOKMARK_GOTO:
1935 // go to bookmark, open unopened file and switch to buffer if necessary
1936 gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
1939 case LFUN_BOOKMARK_CLEAR:
1940 LyX::ref().session().bookmarks().clear();
1943 case LFUN_TOOLBAR_TOGGLE: {
1944 BOOST_ASSERT(lyx_view_);
1945 string const name = cmd.getArg(0);
1946 bool const allowauto = cmd.getArg(1) == "allowauto";
1947 lyx_view_->toggleToolbarState(name, allowauto);
1948 ToolbarInfo * tbi = lyx_view_->getToolbarInfo(name);
1950 setMessage(bformat(_("Unknown toolbar \"%1$s\""),
1955 if (tbi->flags & ToolbarInfo::ON)
1957 else if (tbi->flags & ToolbarInfo::OFF)
1959 else if (tbi->flags & ToolbarInfo::AUTO)
1962 setMessage(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1963 _(tbi->gui_name), state));
1968 BOOST_ASSERT(lyx_view_);
1969 view()->cursor().dispatch(cmd);
1970 updateFlags = view()->cursor().result().update();
1971 if (!view()->cursor().result().dispatched())
1972 updateFlags = view()->dispatch(cmd);
1977 if (lyx_view_ && lyx_view_->buffer()) {
1978 // BufferView::update() updates the ViewMetricsInfo and
1979 // also initializes the position cache for all insets in
1980 // (at least partially) visible top-level paragraphs.
1981 // We will redraw the screen only if needed.
1982 view()->processUpdateFlags(updateFlags);
1983 lyx_view_->updateStatusBar();
1985 // if we executed a mutating lfun, mark the buffer as dirty
1987 && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
1988 && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
1989 lyx_view_->buffer()->markDirty();
1991 //Do we have a selection?
1992 theSelection().haveSelection(view()->cursor().selection());
1994 if (view()->cursor().inTexted()) {
1995 lyx_view_->updateLayoutChoice();
1999 if (!quitting && lyx_view_) {
2000 lyx_view_->updateToolbars();
2001 // Some messages may already be translated, so we cannot use _()
2002 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
2007 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
2009 const bool verbose = (cmd.origin == FuncRequest::MENU
2010 || cmd.origin == FuncRequest::TOOLBAR
2011 || cmd.origin == FuncRequest::COMMANDBUFFER);
2013 if (cmd.action == LFUN_SELF_INSERT || !verbose) {
2014 LYXERR(Debug::ACTION) << "dispatch msg is " << to_utf8(msg) << endl;
2016 lyx_view_->message(msg);
2020 docstring dispatch_msg = msg;
2021 if (!dispatch_msg.empty())
2022 dispatch_msg += ' ';
2024 docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
2026 bool argsadded = false;
2028 if (!cmd.argument().empty()) {
2029 if (cmd.action != LFUN_UNKNOWN_ACTION) {
2030 comname += ' ' + cmd.argument();
2035 docstring const shortcuts = theTopLevelKeymap().printbindings(cmd);
2037 if (!shortcuts.empty())
2038 comname += ": " + shortcuts;
2039 else if (!argsadded && !cmd.argument().empty())
2040 comname += ' ' + cmd.argument();
2042 if (!comname.empty()) {
2043 comname = rtrim(comname);
2044 dispatch_msg += '(' + rtrim(comname) + ')';
2047 LYXERR(Debug::ACTION) << "verbose dispatch msg "
2048 << to_utf8(dispatch_msg) << endl;
2049 if (!dispatch_msg.empty())
2050 lyx_view_->message(dispatch_msg);
2054 void LyXFunc::menuNew(string const & name, bool fromTemplate)
2056 // FIXME: initpath is not used. What to do?
2057 string initpath = lyxrc.document_path;
2058 string filename(name);
2060 if (lyx_view_->buffer()) {
2061 string const trypath = lyx_view_->buffer()->filePath();
2062 // If directory is writeable, use this as default.
2063 if (FileName(trypath).isDirWritable())
2067 static int newfile_number;
2069 if (filename.empty()) {
2070 filename = addName(lyxrc.document_path,
2071 "newfile" + convert<string>(++newfile_number) + ".lyx");
2072 while (theBufferList().exists(filename) ||
2073 FileName(filename).isReadable()) {
2075 filename = addName(lyxrc.document_path,
2076 "newfile" + convert<string>(newfile_number) +
2081 // The template stuff
2084 FileDialog fileDlg(_("Select template file"),
2085 LFUN_SELECT_FILE_SYNC,
2086 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2087 make_pair(_("Templates|#T#t"), from_utf8(lyxrc.template_path)));
2089 FileDialog::Result result =
2090 fileDlg.open(from_utf8(lyxrc.template_path),
2091 FileFilterList(_("LyX Documents (*.lyx)")),
2094 if (result.first == FileDialog::Later)
2096 if (result.second.empty())
2098 templname = to_utf8(result.second);
2101 Buffer * const b = newFile(filename, templname, !name.empty());
2103 lyx_view_->setBuffer(b);
2107 void LyXFunc::open(string const & fname)
2109 string initpath = lyxrc.document_path;
2111 if (lyx_view_->buffer()) {
2112 string const trypath = lyx_view_->buffer()->filePath();
2113 // If directory is writeable, use this as default.
2114 if (FileName(trypath).isDirWritable())
2120 if (fname.empty()) {
2121 FileDialog fileDlg(_("Select document to open"),
2123 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2124 make_pair(_("Examples|#E#e"), from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2126 FileDialog::Result result =
2127 fileDlg.open(from_utf8(initpath),
2128 FileFilterList(_("LyX Documents (*.lyx)")),
2131 if (result.first == FileDialog::Later)
2134 filename = to_utf8(result.second);
2136 // check selected filename
2137 if (filename.empty()) {
2138 lyx_view_->message(_("Canceled."));
2144 // get absolute path of file and add ".lyx" to the filename if
2146 FileName const fullname = fileSearch(string(), filename, "lyx");
2147 if (!fullname.empty())
2148 filename = fullname.absFilename();
2150 // if the file doesn't exist, let the user create one
2151 if (!fullname.exists()) {
2152 // the user specifically chose this name. Believe him.
2153 Buffer * const b = newFile(filename, string(), true);
2155 lyx_view_->setBuffer(b);
2159 docstring const disp_fn = makeDisplayPath(filename);
2160 lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
2163 Buffer * buf = lyx_view_->loadLyXFile(fullname);
2166 lyx_view_->setBuffer(buf);
2167 lyx_view_->showErrorList("Parse");
2168 str2 = bformat(_("Document %1$s opened."), disp_fn);
2170 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2172 lyx_view_->message(str2);
2176 void LyXFunc::doImport(string const & argument)
2179 string filename = split(argument, format, ' ');
2181 LYXERR(Debug::INFO) << "LyXFunc::doImport: " << format
2182 << " file: " << filename << endl;
2184 // need user interaction
2185 if (filename.empty()) {
2186 string initpath = lyxrc.document_path;
2188 if (lyx_view_->buffer()) {
2189 string const trypath = lyx_view_->buffer()->filePath();
2190 // If directory is writeable, use this as default.
2191 if (FileName(trypath).isDirWritable())
2195 docstring const text = bformat(_("Select %1$s file to import"),
2196 formats.prettyName(format));
2198 FileDialog fileDlg(text,
2200 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2201 make_pair(_("Examples|#E#e"),
2202 from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2204 docstring filter = formats.prettyName(format);
2207 filter += from_utf8(formats.extension(format));
2210 FileDialog::Result result =
2211 fileDlg.open(from_utf8(initpath),
2212 FileFilterList(filter),
2215 if (result.first == FileDialog::Later)
2218 filename = to_utf8(result.second);
2220 // check selected filename
2221 if (filename.empty())
2222 lyx_view_->message(_("Canceled."));
2225 if (filename.empty())
2228 // get absolute path of file
2229 FileName const fullname(makeAbsPath(filename));
2231 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
2233 // Check if the document already is open
2234 if (use_gui && theBufferList().exists(lyxfile.absFilename())) {
2235 if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) {
2236 lyx_view_->message(_("Canceled."));
2241 // if the file exists already, and we didn't do
2242 // -i lyx thefile.lyx, warn
2243 if (lyxfile.exists() && fullname != lyxfile) {
2244 docstring const file = makeDisplayPath(lyxfile.absFilename(), 30);
2246 docstring text = bformat(_("The document %1$s already exists.\n\n"
2247 "Do you want to overwrite that document?"), file);
2248 int const ret = Alert::prompt(_("Overwrite document?"),
2249 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2252 lyx_view_->message(_("Canceled."));
2257 ErrorList errorList;
2258 Importer::Import(lyx_view_, fullname, format, errorList);
2259 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2263 void LyXFunc::closeBuffer()
2265 // goto bookmark to update bookmark pit.
2266 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2267 gotoBookmark(i+1, false, false);
2269 theBufferList().close(lyx_view_->buffer(), true);
2273 void LyXFunc::reloadBuffer()
2275 FileName filename(lyx_view_->buffer()->absFileName());
2276 docstring const disp_fn = makeDisplayPath(filename.absFilename());
2279 Buffer * buf = lyx_view_->loadLyXFile(filename);
2282 lyx_view_->setBuffer(buf);
2283 lyx_view_->showErrorList("Parse");
2284 str = bformat(_("Document %1$s reloaded."), disp_fn);
2286 str = bformat(_("Could not reload document %1$s"), disp_fn);
2288 lyx_view_->message(str);
2291 // Each "lyx_view_" should have it's own message method. lyxview and
2292 // the minibuffer would use the minibuffer, but lyxserver would
2293 // send an ERROR signal to its client. Alejandro 970603
2294 // This function is bit problematic when it comes to NLS, to make the
2295 // lyx servers client be language indepenent we must not translate
2296 // strings sent to this func.
2297 void LyXFunc::setErrorMessage(docstring const & m) const
2299 dispatch_buffer = m;
2304 void LyXFunc::setMessage(docstring const & m) const
2306 dispatch_buffer = m;
2310 docstring const LyXFunc::viewStatusMessage()
2312 // When meta-fake key is pressed, show the key sequence so far + "M-".
2314 return keyseq.print(true) + "M-";
2316 // Else, when a non-complete key sequence is pressed,
2317 // show the available options.
2318 if (keyseq.length() > 0 && !keyseq.deleted())
2319 return keyseq.printOptions(true);
2321 BOOST_ASSERT(lyx_view_);
2322 if (!lyx_view_->buffer())
2323 return _("Welcome to LyX!");
2325 return view()->cursor().currentState();
2329 BufferView * LyXFunc::view() const
2331 BOOST_ASSERT(lyx_view_);
2332 return lyx_view_->view();
2336 bool LyXFunc::wasMetaKey() const
2338 return (meta_fake_bit != NoModifier);
2342 void LyXFunc::updateLayout(TextClassPtr const & oldlayout,
2345 lyx_view_->message(_("Converting document to new document class..."));
2347 StableDocIterator backcur(view()->cursor());
2348 ErrorList & el = buffer->errorList("Class Switch");
2349 cap::switchBetweenClasses(
2350 oldlayout, buffer->params().getTextClassPtr(),
2351 static_cast<InsetText &>(buffer->inset()), el);
2353 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
2355 buffer->errors("Class Switch");
2356 updateLabels(*buffer);
2362 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2364 // Why the switch you might ask. It is a trick to ensure that all
2365 // the elements in the LyXRCTags enum is handled. As you can see
2366 // there are no breaks at all. So it is just a huge fall-through.
2367 // The nice thing is that we will get a warning from the compiler
2368 // if we forget an element.
2369 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2371 case LyXRC::RC_ACCEPT_COMPOUND:
2372 case LyXRC::RC_ALT_LANG:
2373 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
2374 case LyXRC::RC_PLAINTEXT_LINELEN:
2375 case LyXRC::RC_AUTOREGIONDELETE:
2376 case LyXRC::RC_AUTORESET_OPTIONS:
2377 case LyXRC::RC_AUTOSAVE:
2378 case LyXRC::RC_AUTO_NUMBER:
2379 case LyXRC::RC_BACKUPDIR_PATH:
2380 case LyXRC::RC_BIBTEX_COMMAND:
2381 case LyXRC::RC_BINDFILE:
2382 case LyXRC::RC_CHECKLASTFILES:
2383 case LyXRC::RC_USELASTFILEPOS:
2384 case LyXRC::RC_LOADSESSION:
2385 case LyXRC::RC_CHKTEX_COMMAND:
2386 case LyXRC::RC_CONVERTER:
2387 case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
2388 case LyXRC::RC_COPIER:
2389 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2390 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2391 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2392 case LyXRC::RC_DATE_INSERT_FORMAT:
2393 case LyXRC::RC_DEFAULT_LANGUAGE:
2394 case LyXRC::RC_DEFAULT_PAPERSIZE:
2395 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2396 case LyXRC::RC_DISPLAY_GRAPHICS:
2397 case LyXRC::RC_DOCUMENTPATH:
2398 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2399 FileName path(lyxrc_new.document_path);
2400 if (path.exists() && path.isDirectory())
2401 support::package().document_dir() = FileName(lyxrc.document_path);
2403 case LyXRC::RC_ESC_CHARS:
2404 case LyXRC::RC_FONT_ENCODING:
2405 case LyXRC::RC_FORMAT:
2406 case LyXRC::RC_INDEX_COMMAND:
2407 case LyXRC::RC_INPUT:
2408 case LyXRC::RC_KBMAP:
2409 case LyXRC::RC_KBMAP_PRIMARY:
2410 case LyXRC::RC_KBMAP_SECONDARY:
2411 case LyXRC::RC_LABEL_INIT_LENGTH:
2412 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2413 case LyXRC::RC_LANGUAGE_AUTO_END:
2414 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2415 case LyXRC::RC_LANGUAGE_COMMAND_END:
2416 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2417 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2418 case LyXRC::RC_LANGUAGE_PACKAGE:
2419 case LyXRC::RC_LANGUAGE_USE_BABEL:
2420 case LyXRC::RC_MAKE_BACKUP:
2421 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2422 case LyXRC::RC_NUMLASTFILES:
2423 case LyXRC::RC_PATH_PREFIX:
2424 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2425 support::prependEnvPath("PATH", lyxrc.path_prefix);
2427 case LyXRC::RC_PERS_DICT:
2428 case LyXRC::RC_PREVIEW:
2429 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2430 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2431 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2432 case LyXRC::RC_PRINTCOPIESFLAG:
2433 case LyXRC::RC_PRINTER:
2434 case LyXRC::RC_PRINTEVENPAGEFLAG:
2435 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2436 case LyXRC::RC_PRINTFILEEXTENSION:
2437 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2438 case LyXRC::RC_PRINTODDPAGEFLAG:
2439 case LyXRC::RC_PRINTPAGERANGEFLAG:
2440 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2441 case LyXRC::RC_PRINTPAPERFLAG:
2442 case LyXRC::RC_PRINTREVERSEFLAG:
2443 case LyXRC::RC_PRINTSPOOL_COMMAND:
2444 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2445 case LyXRC::RC_PRINTTOFILE:
2446 case LyXRC::RC_PRINTTOPRINTER:
2447 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2448 case LyXRC::RC_PRINT_COMMAND:
2449 case LyXRC::RC_RTL_SUPPORT:
2450 case LyXRC::RC_SCREEN_DPI:
2451 case LyXRC::RC_SCREEN_FONT_ROMAN:
2452 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2453 case LyXRC::RC_SCREEN_FONT_SANS:
2454 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2455 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2456 case LyXRC::RC_SCREEN_FONT_SIZES:
2457 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2458 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2459 case LyXRC::RC_SCREEN_GEOMETRY_HEIGHT:
2460 case LyXRC::RC_SCREEN_GEOMETRY_WIDTH:
2461 case LyXRC::RC_SCREEN_GEOMETRY_XYSAVED:
2462 case LyXRC::RC_SCREEN_ZOOM:
2463 case LyXRC::RC_SERVERPIPE:
2464 case LyXRC::RC_SET_COLOR:
2465 case LyXRC::RC_SHOW_BANNER:
2466 case LyXRC::RC_SPELL_COMMAND:
2467 case LyXRC::RC_TEMPDIRPATH:
2468 case LyXRC::RC_TEMPLATEPATH:
2469 case LyXRC::RC_TEX_ALLOWS_SPACES:
2470 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2471 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2472 support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2474 case LyXRC::RC_UIFILE:
2475 case LyXRC::RC_USER_EMAIL:
2476 case LyXRC::RC_USER_NAME:
2477 case LyXRC::RC_USETEMPDIR:
2478 case LyXRC::RC_USE_ALT_LANG:
2479 case LyXRC::RC_USE_CONVERTER_CACHE:
2480 case LyXRC::RC_USE_ESC_CHARS:
2481 case LyXRC::RC_USE_INP_ENC:
2482 case LyXRC::RC_USE_PERS_DICT:
2483 case LyXRC::RC_USE_SPELL_LIB:
2484 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2485 case LyXRC::RC_VIEWER:
2486 case LyXRC::RC_LAST: