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"
40 #include "FuncRequest.h"
41 #include "FuncStatus.h"
44 #include "InsetIterator.h"
49 #include "LyXAction.h"
54 #include "Paragraph.h"
55 #include "ParagraphParameters.h"
56 #include "ParIterator.h"
60 #include "TextClassList.h"
61 #include "ToolbarBackend.h"
63 #include "insets/InsetBox.h"
64 #include "insets/InsetBranch.h"
65 #include "insets/InsetCommand.h"
66 #include "insets/InsetERT.h"
67 #include "insets/InsetExternal.h"
68 #include "insets/InsetFloat.h"
69 #include "insets/InsetListings.h"
70 #include "insets/InsetGraphics.h"
71 #include "insets/InsetInclude.h"
72 #include "insets/InsetNote.h"
73 #include "insets/InsetTabular.h"
74 #include "insets/InsetVSpace.h"
75 #include "insets/InsetWrap.h"
77 #include "frontends/Application.h"
78 #include "frontends/alert.h"
79 #include "frontends/Dialogs.h"
80 #include "frontends/FileDialog.h"
81 #include "frontends/FontLoader.h"
82 #include "frontends/Gui.h"
83 #include "frontends/KeySymbol.h"
84 #include "frontends/LyXView.h"
85 #include "frontends/Selection.h"
86 #include "frontends/WorkArea.h"
88 #include "support/environment.h"
89 #include "support/FileFilterList.h"
90 #include "support/filetools.h"
91 #include "support/fs_extras.h"
92 #include "support/lstrings.h"
93 #include "support/Path.h"
94 #include "support/Package.h"
95 #include "support/Systemcall.h"
96 #include "support/convert.h"
97 #include "support/os.h"
99 #include <boost/current_function.hpp>
100 #include <boost/filesystem/operations.hpp>
105 using std::make_pair;
108 using std::istringstream;
109 using std::ostringstream;
111 namespace fs = boost::filesystem;
115 using frontend::LyXView;
117 using support::absolutePath;
118 using support::addName;
119 using support::addPath;
120 using support::bformat;
121 using support::changeExtension;
122 using support::contains;
123 using support::FileFilterList;
124 using support::FileName;
125 using support::fileSearch;
126 using support::i18nLibFileSearch;
127 using support::makeDisplayPath;
128 using support::makeAbsPath;
129 using support::package;
130 using support::quoteName;
131 using support::rtrim;
132 using support::split;
133 using support::subst;
134 using support::Systemcall;
135 using support::token;
137 using support::prefixIs;
139 namespace Alert = frontend::Alert;
141 extern bool quitting;
145 // This function runs "configure" and then rereads lyx.defaults to
146 // reconfigure the automatic settings.
147 void reconfigure(LyXView & lv, string const & option)
149 // emit message signal.
150 lv.message(_("Running configure..."));
152 // Run configure in user lyx directory
153 support::Path p(package().user_support());
154 string configure_command = package().configure_command();
155 configure_command += option;
157 int ret = one.startscript(Systemcall::Wait, configure_command);
159 // emit message signal.
160 lv.message(_("Reloading configuration..."));
161 lyxrc.read(support::libFileSearch(string(), "lyxrc.defaults"));
162 // Re-read packages.lst
163 LaTeXFeatures::getAvailable();
166 Alert::information(_("System reconfiguration failed"),
167 _("The system reconfiguration has failed.\n"
168 "Default textclass is used but LyX may "
169 "not be able to work properly.\n"
170 "Please reconfigure again if needed."));
173 Alert::information(_("System reconfigured"),
174 _("The system has been reconfigured.\n"
175 "You need to restart LyX to make use of any\n"
176 "updated document class specifications."));
180 bool getLocalStatus(Cursor cursor, FuncRequest const & cmd, FuncStatus & status)
182 // Try to fix cursor in case it is broken.
183 cursor.fixIfBroken();
185 // This is, of course, a mess. Better create a new doc iterator and use
186 // this in Inset::getStatus. This might require an additional
187 // BufferView * arg, though (which should be avoided)
188 //Cursor safe = *this;
190 for ( ; cursor.depth(); cursor.pop()) {
191 //lyxerr << "\nCursor::getStatus: cmd: " << cmd << endl << *this << endl;
192 BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
193 BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
194 BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
196 // The inset's getStatus() will return 'true' if it made
197 // a definitive decision on whether it want to handle the
198 // request or not. The result of this decision is put into
199 // the 'status' parameter.
200 if (cursor.inset().getStatus(cursor, cmd, status)) {
209 /** Return the change status at cursor position, taking in account the
210 * status at each level of the document iterator (a table in a deleted
211 * footnote is deleted).
212 * When \param outer is true, the top slice is not looked at.
214 Change::Type lookupChangeType(DocIterator const & dit, bool outer = false)
216 size_t const depth = dit.depth() - (outer ? 1 : 0);
218 for (size_t i = 0 ; i < depth ; ++i) {
219 CursorSlice const & slice = dit[i];
220 if (!slice.inset().inMathed()
221 && slice.pos() < slice.paragraph().size()) {
222 Change::Type const ch = slice.paragraph().lookupChange(slice.pos()).type;
223 if (ch != Change::UNCHANGED)
227 return Change::UNCHANGED;
234 : lyx_view_(0), encoded_last_key(0), meta_fake_bit(NoModifier)
239 void LyXFunc::initKeySequences(KeyMap * kb)
241 keyseq = KeySequence(kb, kb);
242 cancel_meta_seq = KeySequence(kb, kb);
246 void LyXFunc::setLyXView(LyXView * lv)
248 if (!quitting && lyx_view_ && lyx_view_->view() && lyx_view_ != lv)
249 // save current selection to the selection buffer to allow
250 // middle-button paste in another window
251 cap::saveSelection(lyx_view_->view()->cursor());
256 void LyXFunc::handleKeyFunc(kb_action action)
258 char_type c = encoded_last_key;
263 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
264 lyx_view_->view()->getIntl().getTransManager().deadkey(
265 c, get_accent(action).accent, view()->cursor().innerText(), view()->cursor());
266 // Need to clear, in case the minibuffer calls these
269 // copied verbatim from do_accent_char
270 view()->cursor().resetAnchor();
271 view()->processUpdateFlags(Update::FitCursor);
275 void LyXFunc::gotoBookmark(unsigned int idx, bool openFile, bool switchToBuffer)
277 BOOST_ASSERT(lyx_view_);
278 if (!LyX::ref().session().bookmarks().isValid(idx))
280 BookmarksSection::Bookmark const & bm = LyX::ref().session().bookmarks().bookmark(idx);
281 BOOST_ASSERT(!bm.filename.empty());
282 string const file = bm.filename.absFilename();
283 // if the file is not opened, open it.
284 if (!theBufferList().exists(file)) {
286 dispatch(FuncRequest(LFUN_FILE_OPEN, file));
290 // open may fail, so we need to test it again
291 if (!theBufferList().exists(file))
294 // if the current buffer is not that one, switch to it.
295 if (lyx_view_->buffer()->absFileName() != file) {
298 dispatch(FuncRequest(LFUN_BUFFER_SWITCH, file));
300 // moveToPosition try paragraph id first and then paragraph (pit, pos).
301 if (!view()->moveToPosition(bm.bottom_pit, bm.bottom_pos,
302 bm.top_id, bm.top_pos))
305 // Cursor jump succeeded!
306 Cursor const & cur = view()->cursor();
307 pit_type new_pit = cur.pit();
308 pos_type new_pos = cur.pos();
309 int new_id = cur.paragraph().id();
311 // if bottom_pit, bottom_pos or top_id has been changed, update bookmark
312 // see http://bugzilla.lyx.org/show_bug.cgi?id=3092
313 if (bm.bottom_pit != new_pit || bm.bottom_pos != new_pos
314 || bm.top_id != new_id) {
315 const_cast<BookmarksSection::Bookmark &>(bm).updatePos(
316 new_pit, new_pos, new_id);
322 void restartCursor(LyXView * lv)
324 /* When we move around, or type, it's nice to be able to see
325 * the cursor immediately after the keypress.
327 if (lv && lv->currentWorkArea())
328 lv->currentWorkArea()->startBlinkingCursor();
332 void LyXFunc::processKeySym(KeySymbol const & keysym, KeyModifier state)
334 LYXERR(Debug::KEY) << "KeySym is " << keysym.getSymbolName() << endl;
336 // Do nothing if we have nothing (JMarc)
337 if (!keysym.isOK()) {
338 LYXERR(Debug::KEY) << "Empty kbd action (probably composing)"
340 restartCursor(lyx_view_);
344 if (keysym.isModifier()) {
345 LYXERR(Debug::KEY) << "isModifier true" << endl;
346 restartCursor(lyx_view_);
350 //Encoding const * encoding = view()->cursor().getEncoding();
351 //encoded_last_key = keysym.getISOEncoded(encoding ? encoding->name() : "");
352 // FIXME: encoded_last_key shadows the member variable of the same
353 // name. Is that intended?
354 char_type encoded_last_key = keysym.getUCSEncoded();
356 // Do a one-deep top-level lookup for
357 // cancel and meta-fake keys. RVDK_PATCH_5
358 cancel_meta_seq.reset();
360 FuncRequest func = cancel_meta_seq.addkey(keysym, state);
361 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
362 << " action first set to [" << func.action << ']'
365 // When not cancel or meta-fake, do the normal lookup.
366 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
367 // Mostly, meta_fake_bit = NoModifier. RVDK_PATCH_5.
368 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_PREFIX)) {
369 // remove Caps Lock and Mod2 as a modifiers
370 func = keyseq.addkey(keysym, (state | meta_fake_bit));
371 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
372 << "action now set to ["
373 << func.action << ']' << endl;
376 // Dont remove this unless you know what you are doing.
377 meta_fake_bit = NoModifier;
379 // Can this happen now ?
380 if (func.action == LFUN_NOACTION)
381 func = FuncRequest(LFUN_COMMAND_PREFIX);
383 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
385 << func.action << "]["
386 << to_utf8(keyseq.print(false)) << ']'
389 // already here we know if it any point in going further
390 // why not return already here if action == -1 and
391 // num_bytes == 0? (Lgb)
393 if (keyseq.length() > 1)
394 lyx_view_->message(keyseq.print(true));
397 // Maybe user can only reach the key via holding down shift.
398 // Let's see. But only if shift is the only modifier
399 if (func.action == LFUN_UNKNOWN_ACTION && state == ShiftModifier) {
400 LYXERR(Debug::KEY) << "Trying without shift" << endl;
401 func = keyseq.addkey(keysym, NoModifier);
402 LYXERR(Debug::KEY) << "Action now " << func.action << endl;
405 if (func.action == LFUN_UNKNOWN_ACTION) {
406 // Hmm, we didn't match any of the keysequences. See
407 // if it's normal insertable text not already covered
409 if (keysym.isText() && keyseq.length() == 1) {
410 LYXERR(Debug::KEY) << "isText() is true, inserting." << endl;
411 func = FuncRequest(LFUN_SELF_INSERT,
412 FuncRequest::KEYBOARD);
414 LYXERR(Debug::KEY) << "Unknown, !isText() - giving up" << endl;
415 lyx_view_->message(_("Unknown function."));
416 restartCursor(lyx_view_);
421 if (func.action == LFUN_SELF_INSERT) {
422 if (encoded_last_key != 0) {
423 docstring const arg(1, encoded_last_key);
424 dispatch(FuncRequest(LFUN_SELF_INSERT, arg,
425 FuncRequest::KEYBOARD));
427 << "SelfInsert arg[`" << to_utf8(arg) << "']" << endl;
433 restartCursor(lyx_view_);
437 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
439 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
442 /* In LyX/Mac, when a dialog is open, the menus of the
443 application can still be accessed without giving focus to
444 the main window. In this case, we want to disable the menu
445 entries that are buffer-related.
447 Note that this code is not perfect, as bug 1941 attests:
448 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
450 Buffer * buf = lyx_view_? lyx_view_->buffer() : 0;
451 if (lyx_view_ && cmd.origin == FuncRequest::MENU && !lyx_view_->hasFocus())
454 if (cmd.action == LFUN_NOACTION) {
455 flag.message(from_utf8(N_("Nothing to do")));
460 switch (cmd.action) {
461 case LFUN_UNKNOWN_ACTION:
462 #ifndef HAVE_LIBAIKSAURUS
463 case LFUN_THESAURUS_ENTRY:
473 if (flag.unknown()) {
474 flag.message(from_utf8(N_("Unknown action")));
478 if (!flag.enabled()) {
479 if (flag.message().empty())
480 flag.message(from_utf8(N_("Command disabled")));
484 // Check whether we need a buffer
485 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
487 flag.message(from_utf8(N_("Command not allowed with"
488 "out any document open")));
493 // I would really like to avoid having this switch and rather try to
494 // encode this in the function itself.
495 // -- And I'd rather let an inset decide which LFUNs it is willing
496 // to handle (Andre')
498 switch (cmd.action) {
499 case LFUN_BUFFER_TOGGLE_READ_ONLY:
500 flag.setOnOff(buf->isReadonly());
503 case LFUN_BUFFER_SWITCH:
504 // toggle on the current buffer, but do not toggle off
505 // the other ones (is that a good idea?)
506 if (buf && to_utf8(cmd.argument()) == buf->absFileName())
510 case LFUN_BUFFER_EXPORT:
511 enable = cmd.argument() == "custom"
512 || Exporter::isExportable(*buf, to_utf8(cmd.argument()));
515 case LFUN_BUFFER_CHKTEX:
516 enable = buf->isLatex() && !lyxrc.chktex_command.empty();
519 case LFUN_BUILD_PROGRAM:
520 enable = Exporter::isExportable(*buf, "program");
523 case LFUN_VC_REGISTER:
524 enable = !buf->lyxvc().inUse();
526 case LFUN_VC_CHECK_IN:
527 enable = buf->lyxvc().inUse() && !buf->isReadonly();
529 case LFUN_VC_CHECK_OUT:
530 enable = buf->lyxvc().inUse() && buf->isReadonly();
533 case LFUN_VC_UNDO_LAST:
534 enable = buf->lyxvc().inUse();
536 case LFUN_BUFFER_RELOAD:
537 enable = !buf->isUnnamed() && fs::exists(buf->absFileName())
538 && (!buf->isClean() || buf->isExternallyModified(Buffer::timestamp_method));
541 case LFUN_INSET_APPLY: {
546 string const name = cmd.getArg(0);
547 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
549 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
551 if (!inset->getStatus(view()->cursor(), fr, fs)) {
552 // Every inset is supposed to handle this
557 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
558 flag |= getStatus(fr);
560 enable = flag.enabled();
564 case LFUN_DIALOG_TOGGLE:
565 flag.setOnOff(lyx_view_->getDialogs().visible(cmd.getArg(0)));
566 // fall through to set "enable"
567 case LFUN_DIALOG_SHOW: {
568 string const name = cmd.getArg(0);
570 enable = name == "aboutlyx"
571 || name == "file" //FIXME: should be removed.
573 || name == "texinfo";
574 else if (name == "print")
575 enable = Exporter::isExportable(*buf, "dvi")
576 && lyxrc.print_command != "none";
577 else if (name == "character") {
581 InsetCode ic = view()->cursor().inset().lyxCode();
582 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
585 else if (name == "latexlog")
586 enable = FileName(buf->logName().second).isFileReadable();
587 else if (name == "spellchecker")
588 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
589 enable = !buf->isReadonly();
593 else if (name == "vclog")
594 enable = buf->lyxvc().inUse();
598 case LFUN_DIALOG_UPDATE: {
599 string const name = cmd.getArg(0);
601 enable = name == "prefs";
605 case LFUN_CITATION_INSERT: {
606 FuncRequest fr(LFUN_INSET_INSERT, "citation");
607 enable = getStatus(fr).enabled();
611 case LFUN_BUFFER_WRITE: {
612 enable = lyx_view_->buffer()->isUnnamed()
613 || !lyx_view_->buffer()->isClean();
618 case LFUN_BUFFER_WRITE_ALL: {
619 // We enable the command only if there are some modified buffers
620 Buffer * first = theBufferList().first();
621 bool modified = false;
625 // We cannot use a for loop as the buffer list is a cycle.
631 b = theBufferList().next(b);
632 } while (b != first);
640 case LFUN_BOOKMARK_GOTO: {
641 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
642 enable = LyX::ref().session().bookmarks().isValid(num);
646 case LFUN_BOOKMARK_CLEAR:
647 enable = LyX::ref().session().bookmarks().size() > 0;
650 case LFUN_TOOLBAR_TOGGLE: {
651 bool const current = lyx_view_->isToolbarVisible(cmd.getArg(0));
652 flag.setOnOff(current);
655 case LFUN_WINDOW_CLOSE: {
656 enable = (theApp()->gui().viewIds().size() > 1);
660 // this one is difficult to get right. As a half-baked
661 // solution, we consider only the first action of the sequence
662 case LFUN_COMMAND_SEQUENCE: {
663 // argument contains ';'-terminated commands
664 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
665 FuncRequest func(lyxaction.lookupFunc(firstcmd));
666 func.origin = cmd.origin;
667 flag = getStatus(func);
670 case LFUN_BUFFER_NEW:
671 case LFUN_BUFFER_NEW_TEMPLATE:
672 case LFUN_WORD_FIND_FORWARD:
673 case LFUN_WORD_FIND_BACKWARD:
674 case LFUN_COMMAND_PREFIX:
675 case LFUN_COMMAND_EXECUTE:
677 case LFUN_META_PREFIX:
678 case LFUN_BUFFER_CLOSE:
679 case LFUN_BUFFER_WRITE_AS:
680 case LFUN_BUFFER_UPDATE:
681 case LFUN_BUFFER_VIEW:
682 case LFUN_MASTER_BUFFER_UPDATE:
683 case LFUN_MASTER_BUFFER_VIEW:
684 case LFUN_BUFFER_IMPORT:
685 case LFUN_BUFFER_AUTO_SAVE:
686 case LFUN_RECONFIGURE:
690 case LFUN_DROP_LAYOUTS_CHOICE:
692 case LFUN_SERVER_GET_NAME:
693 case LFUN_SERVER_NOTIFY:
694 case LFUN_SERVER_GOTO_FILE_ROW:
695 case LFUN_DIALOG_HIDE:
696 case LFUN_DIALOG_DISCONNECT_INSET:
697 case LFUN_BUFFER_CHILD_OPEN:
698 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
699 case LFUN_KEYMAP_OFF:
700 case LFUN_KEYMAP_PRIMARY:
701 case LFUN_KEYMAP_SECONDARY:
702 case LFUN_KEYMAP_TOGGLE:
704 case LFUN_BUFFER_EXPORT_CUSTOM:
705 case LFUN_BUFFER_PRINT:
706 case LFUN_PREFERENCES_SAVE:
707 case LFUN_SCREEN_FONT_UPDATE:
710 case LFUN_EXTERNAL_EDIT:
711 case LFUN_GRAPHICS_EDIT:
712 case LFUN_ALL_INSETS_TOGGLE:
713 case LFUN_BUFFER_LANGUAGE:
714 case LFUN_TEXTCLASS_APPLY:
715 case LFUN_TEXTCLASS_LOAD:
716 case LFUN_BUFFER_SAVE_AS_DEFAULT:
717 case LFUN_BUFFER_PARAMS_APPLY:
718 case LFUN_LAYOUT_MODULES_CLEAR:
719 case LFUN_LAYOUT_MODULE_ADD:
720 case LFUN_LAYOUT_RELOAD:
721 case LFUN_LYXRC_APPLY:
722 case LFUN_BUFFER_NEXT:
723 case LFUN_BUFFER_PREVIOUS:
724 case LFUN_WINDOW_NEW:
726 // these are handled in our dispatch()
734 if (!getLocalStatus(view()->cursor(), cmd, flag))
735 flag = view()->getStatus(cmd);
741 // Can we use a readonly buffer?
742 if (buf && buf->isReadonly()
743 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
744 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
745 flag.message(from_utf8(N_("Document is read-only")));
749 // Are we in a DELETED change-tracking region?
751 && lookupChangeType(view()->cursor(), true) == Change::DELETED
752 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
753 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
754 flag.message(from_utf8(N_("This portion of the document is deleted.")));
758 // the default error message if we disable the command
759 if (!flag.enabled() && flag.message().empty())
760 flag.message(from_utf8(N_("Command disabled")));
766 bool LyXFunc::ensureBufferClean(BufferView * bv)
768 Buffer & buf = bv->buffer();
772 docstring const file = makeDisplayPath(buf.absFileName(), 30);
773 docstring text = bformat(_("The document %1$s has unsaved "
774 "changes.\n\nDo you want to save "
775 "the document?"), file);
776 int const ret = Alert::prompt(_("Save changed document?"),
777 text, 0, 1, _("&Save"),
781 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
783 return buf.isClean();
789 void showPrintError(string const & name)
791 docstring str = bformat(_("Could not print the document %1$s.\n"
792 "Check that your printer is set up correctly."),
793 makeDisplayPath(name, 50));
794 Alert::error(_("Print document failed"), str);
798 void loadTextClass(string const & name)
800 std::pair<bool, textclass_type> const tc_pair =
801 textclasslist.numberOfClass(name);
803 if (!tc_pair.first) {
804 lyxerr << "Document class \"" << name
805 << "\" does not exist."
810 textclass_type const tc = tc_pair.second;
812 if (!textclasslist[tc].load()) {
813 docstring s = bformat(_("The document class %1$s."
814 "could not be loaded."),
815 from_utf8(textclasslist[tc].name()));
816 Alert::error(_("Could not load class"), s);
821 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
826 void LyXFunc::dispatch(FuncRequest const & cmd)
828 string const argument = to_utf8(cmd.argument());
829 kb_action const action = cmd.action;
831 LYXERR(Debug::ACTION) << endl << "LyXFunc::dispatch: cmd: " << cmd << endl;
832 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
834 // we have not done anything wrong yet.
836 dispatch_buffer.erase();
838 // redraw the screen at the end (first of the two drawing steps).
839 //This is done unless explicitely requested otherwise
840 Update::flags updateFlags = Update::FitCursor;
842 FuncStatus const flag = getStatus(cmd);
843 if (!flag.enabled()) {
844 // We cannot use this function here
845 LYXERR(Debug::ACTION) << "LyXFunc::dispatch: "
846 << lyxaction.getActionName(action)
847 << " [" << action << "] is disabled at this location"
849 setErrorMessage(flag.message());
853 case LFUN_WORD_FIND_FORWARD:
854 case LFUN_WORD_FIND_BACKWARD: {
855 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
856 static docstring last_search;
857 docstring searched_string;
859 if (!cmd.argument().empty()) {
860 last_search = cmd.argument();
861 searched_string = cmd.argument();
863 searched_string = last_search;
866 if (searched_string.empty())
869 bool const fw = action == LFUN_WORD_FIND_FORWARD;
870 docstring const data =
871 find2string(searched_string, true, false, fw);
872 find(view(), FuncRequest(LFUN_WORD_FIND, data));
876 case LFUN_COMMAND_PREFIX:
877 BOOST_ASSERT(lyx_view_);
878 lyx_view_->message(keyseq.printOptions(true));
881 case LFUN_COMMAND_EXECUTE:
882 BOOST_ASSERT(lyx_view_);
883 lyx_view_->showMiniBuffer(true);
887 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
889 meta_fake_bit = NoModifier;
890 if (lyx_view_->buffer())
891 // cancel any selection
892 dispatch(FuncRequest(LFUN_MARK_OFF));
893 setMessage(from_ascii(N_("Cancel")));
896 case LFUN_META_PREFIX:
897 meta_fake_bit = AltModifier;
898 setMessage(keyseq.print(true));
901 case LFUN_BUFFER_TOGGLE_READ_ONLY: {
902 BOOST_ASSERT(lyx_view_ && lyx_view_->view() && lyx_view_->buffer());
903 Buffer * buf = lyx_view_->buffer();
904 if (buf->lyxvc().inUse())
905 buf->lyxvc().toggleReadOnly();
907 buf->setReadonly(!lyx_view_->buffer()->isReadonly());
911 // --- Menus -----------------------------------------------
912 case LFUN_BUFFER_NEW:
913 menuNew(argument, false);
914 updateFlags = Update::None;
917 case LFUN_BUFFER_NEW_TEMPLATE:
918 menuNew(argument, true);
919 updateFlags = Update::None;
922 case LFUN_BUFFER_CLOSE:
924 updateFlags = Update::None;
927 case LFUN_BUFFER_WRITE:
928 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
929 if (!lyx_view_->buffer()->isUnnamed()) {
930 docstring const str = bformat(_("Saving document %1$s..."),
931 makeDisplayPath(lyx_view_->buffer()->absFileName()));
932 lyx_view_->message(str);
933 lyx_view_->buffer()->menuWrite();
934 lyx_view_->message(str + _(" done."));
936 lyx_view_->buffer()->writeAs();
938 updateFlags = Update::None;
941 case LFUN_BUFFER_WRITE_AS:
942 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
943 lyx_view_->buffer()->writeAs(argument);
944 updateFlags = Update::None;
947 case LFUN_BUFFER_WRITE_ALL: {
948 Buffer * first = theBufferList().first();
951 lyx_view_->message(_("Saving all documents..."));
953 // We cannot use a for loop as the buffer list cycles.
956 if (!b->isUnnamed()) {
958 lyxerr[Debug::ACTION] << "Saved " << b->absFileName() << endl;
962 b = theBufferList().next(b);
963 } while (b != first);
964 lyx_view_->message(_("All documents saved."));
967 updateFlags = Update::None;
971 case LFUN_BUFFER_RELOAD: {
972 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
973 docstring const file = makeDisplayPath(lyx_view_->buffer()->absFileName(), 20);
974 docstring text = bformat(_("Any changes will be lost. Are you sure "
975 "you want to revert to the saved version of the document %1$s?"), file);
976 int const ret = Alert::prompt(_("Revert to saved document?"),
977 text, 1, 1, _("&Revert"), _("&Cancel"));
984 case LFUN_BUFFER_UPDATE:
985 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
986 Exporter::Export(lyx_view_->buffer(), argument, true);
989 case LFUN_BUFFER_VIEW:
990 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
991 Exporter::preview(lyx_view_->buffer(), argument);
994 case LFUN_MASTER_BUFFER_UPDATE:
995 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->masterBuffer());
996 Exporter::Export(lyx_view_->buffer()->masterBuffer(), argument, true);
999 case LFUN_MASTER_BUFFER_VIEW:
1000 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->masterBuffer());
1001 Exporter::preview(lyx_view_->buffer()->masterBuffer(), argument);
1004 case LFUN_BUILD_PROGRAM:
1005 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1006 Exporter::Export(lyx_view_->buffer(), "program", true);
1009 case LFUN_BUFFER_CHKTEX:
1010 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1011 lyx_view_->buffer()->runChktex();
1014 case LFUN_BUFFER_EXPORT:
1015 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1016 if (argument == "custom")
1017 lyx_view_->getDialogs().show("sendto");
1019 Exporter::Export(lyx_view_->buffer(), argument, false);
1023 case LFUN_BUFFER_EXPORT_CUSTOM: {
1024 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1026 string command = split(argument, format_name, ' ');
1027 Format const * format = formats.getFormat(format_name);
1029 lyxerr << "Format \"" << format_name
1030 << "\" not recognized!"
1035 Buffer * buffer = lyx_view_->buffer();
1037 // The name of the file created by the conversion process
1040 // Output to filename
1041 if (format->name() == "lyx") {
1042 string const latexname = buffer->latexName(false);
1043 filename = changeExtension(latexname,
1044 format->extension());
1045 filename = addName(buffer->temppath(), filename);
1047 if (!buffer->writeFile(FileName(filename)))
1051 Exporter::Export(buffer, format_name, true, filename);
1054 // Substitute $$FName for filename
1055 if (!contains(command, "$$FName"))
1056 command = "( " + command + " ) < $$FName";
1057 command = subst(command, "$$FName", filename);
1059 // Execute the command in the background
1061 call.startscript(Systemcall::DontWait, command);
1065 case LFUN_BUFFER_PRINT: {
1066 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1067 // FIXME: cmd.getArg() might fail if one of the arguments
1068 // contains double quotes
1069 string target = cmd.getArg(0);
1070 string target_name = cmd.getArg(1);
1071 string command = cmd.getArg(2);
1074 || target_name.empty()
1075 || command.empty()) {
1076 lyxerr << "Unable to parse \""
1077 << argument << '"' << endl;
1080 if (target != "printer" && target != "file") {
1081 lyxerr << "Unrecognized target \""
1082 << target << '"' << endl;
1086 Buffer * buffer = lyx_view_->buffer();
1088 if (!Exporter::Export(buffer, "dvi", true)) {
1089 showPrintError(buffer->absFileName());
1093 // Push directory path.
1094 string const path = buffer->temppath();
1095 // Prevent the compiler from optimizing away p
1097 support::Path p(pp);
1099 // there are three cases here:
1100 // 1. we print to a file
1101 // 2. we print directly to a printer
1102 // 3. we print using a spool command (print to file first)
1105 string const dviname =
1106 changeExtension(buffer->latexName(true), "dvi");
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 (filename.exists()) {
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->absFileName());
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:
1185 lyx_view_->buffer()->autoSave();
1188 case LFUN_RECONFIGURE:
1189 BOOST_ASSERT(lyx_view_);
1190 // argument is any additional parameter to the configure.py command
1191 reconfigure(*lyx_view_, argument);
1194 case LFUN_HELP_OPEN: {
1195 BOOST_ASSERT(lyx_view_);
1196 string const arg = argument;
1198 setErrorMessage(from_ascii(N_("Missing argument")));
1201 FileName const fname = i18nLibFileSearch("doc", arg, "lyx");
1202 if (fname.empty()) {
1203 lyxerr << "LyX: unable to find documentation file `"
1204 << arg << "'. Bad installation?" << endl;
1207 lyx_view_->message(bformat(_("Opening help file %1$s..."),
1208 makeDisplayPath(fname.absFilename())));
1209 Buffer * buf = lyx_view_->loadLyXFile(fname, false);
1212 lyx_view_->setBuffer(buf);
1213 lyx_view_->showErrorList("Parse");
1215 updateFlags = Update::None;
1219 // --- version control -------------------------------
1220 case LFUN_VC_REGISTER:
1221 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1222 if (!ensureBufferClean(view()))
1224 if (!lyx_view_->buffer()->lyxvc().inUse()) {
1225 lyx_view_->buffer()->lyxvc().registrer();
1228 updateFlags = Update::Force;
1231 case LFUN_VC_CHECK_IN:
1232 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1233 if (!ensureBufferClean(view()))
1235 if (lyx_view_->buffer()->lyxvc().inUse()
1236 && !lyx_view_->buffer()->isReadonly()) {
1237 lyx_view_->buffer()->lyxvc().checkIn();
1242 case LFUN_VC_CHECK_OUT:
1243 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1244 if (!ensureBufferClean(view()))
1246 if (lyx_view_->buffer()->lyxvc().inUse()
1247 && lyx_view_->buffer()->isReadonly()) {
1248 lyx_view_->buffer()->lyxvc().checkOut();
1253 case LFUN_VC_REVERT:
1254 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1255 lyx_view_->buffer()->lyxvc().revert();
1259 case LFUN_VC_UNDO_LAST:
1260 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1261 lyx_view_->buffer()->lyxvc().undoLast();
1265 // --- buffers ----------------------------------------
1266 case LFUN_BUFFER_SWITCH:
1267 BOOST_ASSERT(lyx_view_);
1268 lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1269 updateFlags = Update::None;
1272 case LFUN_BUFFER_NEXT:
1273 BOOST_ASSERT(lyx_view_);
1274 lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer()));
1275 updateFlags = Update::None;
1278 case LFUN_BUFFER_PREVIOUS:
1279 BOOST_ASSERT(lyx_view_);
1280 lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer()));
1281 updateFlags = Update::None;
1284 case LFUN_FILE_NEW: {
1285 BOOST_ASSERT(lyx_view_);
1287 string tmpname = split(argument, name, ':'); // Split filename
1288 Buffer * const b = newFile(name, tmpname);
1290 lyx_view_->setBuffer(b);
1291 updateFlags = Update::None;
1295 case LFUN_FILE_OPEN:
1296 BOOST_ASSERT(lyx_view_);
1298 updateFlags = Update::None;
1301 case LFUN_DROP_LAYOUTS_CHOICE:
1302 BOOST_ASSERT(lyx_view_);
1303 lyx_view_->openLayoutList();
1306 case LFUN_MENU_OPEN:
1307 BOOST_ASSERT(lyx_view_);
1308 lyx_view_->openMenu(from_utf8(argument));
1311 // --- lyxserver commands ----------------------------
1312 case LFUN_SERVER_GET_NAME:
1313 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1314 setMessage(from_utf8(lyx_view_->buffer()->absFileName()));
1315 LYXERR(Debug::INFO) << "FNAME["
1316 << lyx_view_->buffer()->absFileName()
1320 case LFUN_SERVER_NOTIFY:
1321 dispatch_buffer = keyseq.print(false);
1322 theServer().notifyClient(to_utf8(dispatch_buffer));
1325 case LFUN_SERVER_GOTO_FILE_ROW: {
1326 BOOST_ASSERT(lyx_view_);
1329 istringstream is(argument);
1330 is >> file_name >> row;
1332 bool loaded = false;
1333 if (prefixIs(file_name, package().temp_dir().absFilename()))
1334 // Needed by inverse dvi search. If it is a file
1335 // in tmpdir, call the apropriated function
1336 buf = theBufferList().getBufferFromTmp(file_name);
1338 // Must replace extension of the file to be .lyx
1339 // and get full path
1340 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1341 // Either change buffer or load the file
1342 if (theBufferList().exists(s.absFilename()))
1343 buf = theBufferList().getBuffer(s.absFilename());
1345 buf = lyx_view_->loadLyXFile(s);
1351 updateFlags = Update::None;
1356 lyx_view_->setBuffer(buf);
1357 view()->setCursorFromRow(row);
1359 lyx_view_->showErrorList("Parse");
1360 updateFlags = Update::FitCursor;
1364 case LFUN_DIALOG_SHOW: {
1365 BOOST_ASSERT(lyx_view_);
1366 string const name = cmd.getArg(0);
1367 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1369 if (name == "character") {
1370 data = freefont2string();
1372 lyx_view_->getDialogs().show("character", data);
1373 } else if (name == "latexlog") {
1374 pair<Buffer::LogType, string> const logfile =
1375 lyx_view_->buffer()->logName();
1376 switch (logfile.first) {
1377 case Buffer::latexlog:
1380 case Buffer::buildlog:
1384 data += Lexer::quoteString(logfile.second);
1385 lyx_view_->getDialogs().show("log", data);
1386 } else if (name == "vclog") {
1387 string const data = "vc " +
1388 Lexer::quoteString(lyx_view_->buffer()->lyxvc().getLogFile());
1389 lyx_view_->getDialogs().show("log", data);
1391 lyx_view_->getDialogs().show(name, data);
1395 case LFUN_DIALOG_SHOW_NEW_INSET: {
1396 BOOST_ASSERT(lyx_view_);
1397 string const name = cmd.getArg(0);
1398 InsetCode code = insetCode(name);
1399 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1400 bool insetCodeOK = true;
1409 case HYPERLINK_CODE: {
1410 InsetCommandParams p(code);
1411 data = InsetCommandMailer::params2string(name, p);
1414 case INCLUDE_CODE: {
1415 // data is the include type: one of "include",
1416 // "input", "verbatiminput" or "verbatiminput*"
1418 // default type is requested
1420 InsetCommandParams p(INCLUDE_CODE, data);
1421 data = InsetIncludeMailer::params2string(p);
1425 // \c data == "Boxed" || "Frameless" etc
1426 InsetBoxParams p(data);
1427 data = InsetBoxMailer::params2string(p);
1431 InsetBranchParams p;
1432 data = InsetBranchMailer::params2string(p);
1436 InsetCommandParams p(CITE_CODE);
1437 data = InsetCommandMailer::params2string(name, p);
1441 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1444 case EXTERNAL_CODE: {
1445 InsetExternalParams p;
1446 Buffer const & buffer = *lyx_view_->buffer();
1447 data = InsetExternalMailer::params2string(p, buffer);
1452 data = InsetFloatMailer::params2string(p);
1455 case LISTINGS_CODE: {
1456 InsetListingsParams p;
1457 data = InsetListingsMailer::params2string(p);
1460 case GRAPHICS_CODE: {
1461 InsetGraphicsParams p;
1462 Buffer const & buffer = *lyx_view_->buffer();
1463 data = InsetGraphicsMailer::params2string(p, buffer);
1468 data = InsetNoteMailer::params2string(p);
1473 data = InsetVSpaceMailer::params2string(space);
1478 data = InsetWrapMailer::params2string(p);
1482 lyxerr << "Inset type '" << name <<
1483 "' not recognized in LFUN_DIALOG_SHOW_NEW_INSET" << std:: endl;
1484 insetCodeOK = false;
1486 } // end switch(code)
1488 lyx_view_->getDialogs().show(name, data, 0);
1492 case LFUN_DIALOG_UPDATE: {
1493 BOOST_ASSERT(lyx_view_);
1494 string const & name = argument;
1495 // Can only update a dialog connected to an existing inset
1496 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1498 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1499 inset->dispatch(view()->cursor(), fr);
1500 } else if (name == "paragraph") {
1501 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1502 } else if (name == "prefs") {
1503 lyx_view_->getDialogs().update(name, string());
1508 case LFUN_DIALOG_HIDE:
1509 LyX::cref().hideDialogs(argument, 0);
1512 case LFUN_DIALOG_TOGGLE: {
1513 BOOST_ASSERT(lyx_view_);
1514 if (lyx_view_->getDialogs().visible(cmd.getArg(0)))
1515 dispatch(FuncRequest(LFUN_DIALOG_HIDE, argument));
1517 dispatch(FuncRequest(LFUN_DIALOG_SHOW, argument));
1521 case LFUN_DIALOG_DISCONNECT_INSET:
1522 BOOST_ASSERT(lyx_view_);
1523 lyx_view_->getDialogs().disconnect(argument);
1527 case LFUN_CITATION_INSERT: {
1528 BOOST_ASSERT(lyx_view_);
1529 if (!argument.empty()) {
1530 // we can have one optional argument, delimited by '|'
1531 // citation-insert <key>|<text_before>
1532 // this should be enhanced to also support text_after
1533 // and citation style
1534 string arg = argument;
1536 if (contains(argument, "|")) {
1537 arg = token(argument, '|', 0);
1538 opt1 = token(argument, '|', 1);
1540 InsetCommandParams icp(CITE_CODE);
1541 icp["key"] = from_utf8(arg);
1543 icp["before"] = from_utf8(opt1);
1544 string icstr = InsetCommandMailer::params2string("citation", icp);
1545 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1548 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1552 case LFUN_BUFFER_CHILD_OPEN: {
1553 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1554 Buffer * parent = lyx_view_->buffer();
1555 FileName filename = makeAbsPath(argument, parent->filePath());
1556 view()->saveBookmark(false);
1558 bool parsed = false;
1559 if (theBufferList().exists(filename.absFilename())) {
1560 child = theBufferList().getBuffer(filename.absFilename());
1562 setMessage(bformat(_("Opening child document %1$s..."),
1563 makeDisplayPath(filename.absFilename())));
1564 child = lyx_view_->loadLyXFile(filename, true);
1568 // Set the parent name of the child document.
1569 // This makes insertion of citations and references in the child work,
1570 // when the target is in the parent or another child document.
1571 child->setParentName(parent->absFileName());
1572 updateLabels(*child->masterBuffer());
1573 lyx_view_->setBuffer(child);
1575 lyx_view_->showErrorList("Parse");
1578 // If a screen update is required (in case where auto_open is false),
1579 // setBuffer() would have taken care of it already. Otherwise we shall
1580 // reset the update flag because it can cause a circular problem.
1582 updateFlags = Update::None;
1586 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1587 BOOST_ASSERT(lyx_view_);
1588 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1591 case LFUN_KEYMAP_OFF:
1592 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1593 lyx_view_->view()->getIntl().keyMapOn(false);
1596 case LFUN_KEYMAP_PRIMARY:
1597 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1598 lyx_view_->view()->getIntl().keyMapPrim();
1601 case LFUN_KEYMAP_SECONDARY:
1602 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1603 lyx_view_->view()->getIntl().keyMapSec();
1606 case LFUN_KEYMAP_TOGGLE:
1607 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1608 lyx_view_->view()->getIntl().toggleKeyMap();
1614 string rest = split(argument, countstr, ' ');
1615 istringstream is(countstr);
1618 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1619 for (int i = 0; i < count; ++i)
1620 dispatch(lyxaction.lookupFunc(rest));
1624 case LFUN_COMMAND_SEQUENCE: {
1625 // argument contains ';'-terminated commands
1626 string arg = argument;
1627 while (!arg.empty()) {
1629 arg = split(arg, first, ';');
1630 FuncRequest func(lyxaction.lookupFunc(first));
1631 func.origin = cmd.origin;
1637 case LFUN_PREFERENCES_SAVE: {
1638 lyxrc.write(makeAbsPath("preferences",
1639 package().user_support().absFilename()),
1644 case LFUN_SCREEN_FONT_UPDATE:
1645 BOOST_ASSERT(lyx_view_);
1646 // handle the screen font changes.
1647 theFontLoader().update();
1648 /// FIXME: only the current view will be updated. the Gui
1649 /// class is able to furnish the list of views.
1650 updateFlags = Update::Force;
1653 case LFUN_SET_COLOR: {
1655 string const x11_name = split(argument, lyx_name, ' ');
1656 if (lyx_name.empty() || x11_name.empty()) {
1657 setErrorMessage(from_ascii(N_(
1658 "Syntax: set-color <lyx_name>"
1663 bool const graphicsbg_changed =
1664 (lyx_name == lcolor.getLyXName(Color::graphicsbg) &&
1665 x11_name != lcolor.getX11Name(Color::graphicsbg));
1667 if (!lcolor.setColor(lyx_name, x11_name)) {
1669 bformat(_("Set-color \"%1$s\" failed "
1670 "- color is undefined or "
1671 "may not be redefined"),
1672 from_utf8(lyx_name)));
1676 theApp()->updateColor(lcolor.getFromLyXName(lyx_name));
1678 if (graphicsbg_changed) {
1679 // FIXME: The graphics cache no longer has a changeDisplay method.
1681 graphics::GCache::get().changeDisplay(true);
1688 BOOST_ASSERT(lyx_view_);
1689 lyx_view_->message(from_utf8(argument));
1692 case LFUN_EXTERNAL_EDIT: {
1693 BOOST_ASSERT(lyx_view_);
1694 FuncRequest fr(action, argument);
1695 InsetExternal().dispatch(view()->cursor(), fr);
1699 case LFUN_GRAPHICS_EDIT: {
1700 FuncRequest fr(action, argument);
1701 InsetGraphics().dispatch(view()->cursor(), fr);
1705 case LFUN_INSET_APPLY: {
1706 BOOST_ASSERT(lyx_view_);
1707 string const name = cmd.getArg(0);
1708 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1710 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1711 inset->dispatch(view()->cursor(), fr);
1713 FuncRequest fr(LFUN_INSET_INSERT, argument);
1716 // ideally, the update flag should be set by the insets,
1717 // but this is not possible currently
1718 updateFlags = Update::Force | Update::FitCursor;
1722 case LFUN_ALL_INSETS_TOGGLE: {
1723 BOOST_ASSERT(lyx_view_);
1725 string const name = split(argument, action, ' ');
1726 InsetCode const inset_code = insetCode(name);
1728 Cursor & cur = view()->cursor();
1729 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1731 Inset & inset = lyx_view_->buffer()->inset();
1732 InsetIterator it = inset_iterator_begin(inset);
1733 InsetIterator const end = inset_iterator_end(inset);
1734 for (; it != end; ++it) {
1735 if (!it->asInsetMath()
1736 && (inset_code == NO_CODE
1737 || inset_code == it->lyxCode())) {
1738 Cursor tmpcur = cur;
1739 tmpcur.pushLeft(*it);
1740 it->dispatch(tmpcur, fr);
1743 updateFlags = Update::Force | Update::FitCursor;
1747 case LFUN_BUFFER_LANGUAGE: {
1748 BOOST_ASSERT(lyx_view_);
1749 Buffer & buffer = *lyx_view_->buffer();
1750 Language const * oldL = buffer.params().language;
1751 Language const * newL = languages.getLanguage(argument);
1752 if (!newL || oldL == newL)
1755 if (oldL->rightToLeft() == newL->rightToLeft()
1756 && !buffer.isMultiLingual())
1757 buffer.changeLanguage(oldL, newL);
1761 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1762 string const fname =
1763 addName(addPath(package().user_support().absFilename(), "templates/"),
1765 Buffer defaults(fname);
1767 istringstream ss(argument);
1770 int const unknown_tokens = defaults.readHeader(lex);
1772 if (unknown_tokens != 0) {
1773 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1774 << unknown_tokens << " unknown token"
1775 << (unknown_tokens == 1 ? "" : "s")
1779 if (defaults.writeFile(FileName(defaults.absFileName())))
1780 setMessage(bformat(_("Document defaults saved in %1$s"),
1781 makeDisplayPath(fname)));
1783 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1787 case LFUN_BUFFER_PARAMS_APPLY: {
1788 BOOST_ASSERT(lyx_view_);
1789 biblio::CiteEngine const oldEngine =
1790 lyx_view_->buffer()->params().getEngine();
1792 Buffer * buffer = lyx_view_->buffer();
1794 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1796 Cursor & cur = view()->cursor();
1797 cur.recordUndoFullDocument();
1799 istringstream ss(argument);
1802 int const unknown_tokens = buffer->readHeader(lex);
1804 if (unknown_tokens != 0) {
1805 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1806 << unknown_tokens << " unknown token"
1807 << (unknown_tokens == 1 ? "" : "s")
1811 updateLayout(oldClass, buffer);
1813 biblio::CiteEngine const newEngine =
1814 lyx_view_->buffer()->params().getEngine();
1816 if (oldEngine != newEngine) {
1817 FuncRequest fr(LFUN_INSET_REFRESH);
1819 Inset & inset = lyx_view_->buffer()->inset();
1820 InsetIterator it = inset_iterator_begin(inset);
1821 InsetIterator const end = inset_iterator_end(inset);
1822 for (; it != end; ++it)
1823 if (it->lyxCode() == CITE_CODE)
1824 it->dispatch(cur, fr);
1827 updateFlags = Update::Force | Update::FitCursor;
1831 case LFUN_LAYOUT_MODULES_CLEAR: {
1832 BOOST_ASSERT(lyx_view_);
1833 Buffer * buffer = lyx_view_->buffer();
1834 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1835 view()->cursor().recordUndoFullDocument();
1836 buffer->params().clearLayoutModules();
1837 updateLayout(oldClass, buffer);
1838 updateFlags = Update::Force | Update::FitCursor;
1842 case LFUN_LAYOUT_MODULE_ADD: {
1843 BOOST_ASSERT(lyx_view_);
1844 Buffer * buffer = lyx_view_->buffer();
1845 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1846 view()->cursor().recordUndoFullDocument();
1847 buffer->params().addLayoutModule(argument);
1848 updateLayout(oldClass, buffer);
1849 updateFlags = Update::Force | Update::FitCursor;
1853 case LFUN_TEXTCLASS_APPLY: {
1854 BOOST_ASSERT(lyx_view_);
1855 Buffer * buffer = lyx_view_->buffer();
1857 loadTextClass(argument);
1859 std::pair<bool, textclass_type> const tc_pair =
1860 textclasslist.numberOfClass(argument);
1865 textclass_type const old_class = buffer->params().getBaseClass();
1866 textclass_type const new_class = tc_pair.second;
1868 if (old_class == new_class)
1872 //Save the old, possibly modular, layout for use in conversion.
1873 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1874 view()->cursor().recordUndoFullDocument();
1875 buffer->params().setBaseClass(new_class);
1876 updateLayout(oldClass, buffer);
1877 updateFlags = Update::Force | Update::FitCursor;
1881 case LFUN_LAYOUT_RELOAD: {
1882 BOOST_ASSERT(lyx_view_);
1883 Buffer * buffer = lyx_view_->buffer();
1884 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1885 textclass_type const tc = buffer->params().getBaseClass();
1886 textclasslist.reset(tc);
1887 buffer->params().setBaseClass(tc);
1888 updateLayout(oldClass, buffer);
1889 updateFlags = Update::Force | Update::FitCursor;
1893 case LFUN_TEXTCLASS_LOAD:
1894 loadTextClass(argument);
1897 case LFUN_LYXRC_APPLY: {
1898 LyXRC const lyxrc_orig = lyxrc;
1900 istringstream ss(argument);
1901 bool const success = lyxrc.read(ss) == 0;
1904 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1905 << "Unable to read lyxrc data"
1910 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1912 /// We force the redraw in any case because there might be
1913 /// some screen font changes.
1914 /// FIXME: only the current view will be updated. the Gui
1915 /// class is able to furnish the list of views.
1916 updateFlags = Update::Force;
1920 case LFUN_WINDOW_NEW:
1921 LyX::ref().newLyXView();
1924 case LFUN_WINDOW_CLOSE:
1925 BOOST_ASSERT(lyx_view_);
1926 BOOST_ASSERT(theApp());
1927 // update bookmark pit of the current buffer before window close
1928 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1929 gotoBookmark(i+1, false, false);
1930 // ask the user for saving changes or cancel quit
1931 if (!theBufferList().quitWriteAll())
1936 case LFUN_BOOKMARK_GOTO:
1937 // go to bookmark, open unopened file and switch to buffer if necessary
1938 gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
1941 case LFUN_BOOKMARK_CLEAR:
1942 LyX::ref().session().bookmarks().clear();
1945 case LFUN_TOOLBAR_TOGGLE: {
1946 BOOST_ASSERT(lyx_view_);
1947 string const name = cmd.getArg(0);
1948 bool const allowauto = cmd.getArg(1) == "allowauto";
1949 lyx_view_->toggleToolbarState(name, allowauto);
1950 ToolbarInfo * tbi = lyx_view_->getToolbarInfo(name);
1952 setMessage(bformat(_("Unknown toolbar \"%1$s\""),
1957 if (tbi->flags & ToolbarInfo::ON)
1959 else if (tbi->flags & ToolbarInfo::OFF)
1961 else if (tbi->flags & ToolbarInfo::AUTO)
1964 setMessage(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1965 _(tbi->gui_name), state));
1970 BOOST_ASSERT(lyx_view_);
1971 view()->cursor().dispatch(cmd);
1972 updateFlags = view()->cursor().result().update();
1973 if (!view()->cursor().result().dispatched())
1974 updateFlags = view()->dispatch(cmd);
1979 if (lyx_view_ && lyx_view_->buffer()) {
1980 // BufferView::update() updates the ViewMetricsInfo and
1981 // also initializes the position cache for all insets in
1982 // (at least partially) visible top-level paragraphs.
1983 // We will redraw the screen only if needed.
1984 view()->processUpdateFlags(updateFlags);
1985 lyx_view_->updateStatusBar();
1987 // if we executed a mutating lfun, mark the buffer as dirty
1989 && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
1990 && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
1991 lyx_view_->buffer()->markDirty();
1993 //Do we have a selection?
1994 theSelection().haveSelection(view()->cursor().selection());
1996 if (view()->cursor().inTexted()) {
1997 lyx_view_->updateLayoutChoice();
2001 if (!quitting && lyx_view_) {
2002 lyx_view_->updateToolbars();
2003 // Some messages may already be translated, so we cannot use _()
2004 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
2009 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
2011 const bool verbose = (cmd.origin == FuncRequest::MENU
2012 || cmd.origin == FuncRequest::TOOLBAR
2013 || cmd.origin == FuncRequest::COMMANDBUFFER);
2015 if (cmd.action == LFUN_SELF_INSERT || !verbose) {
2016 LYXERR(Debug::ACTION) << "dispatch msg is " << to_utf8(msg) << endl;
2018 lyx_view_->message(msg);
2022 docstring dispatch_msg = msg;
2023 if (!dispatch_msg.empty())
2024 dispatch_msg += ' ';
2026 docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
2028 bool argsadded = false;
2030 if (!cmd.argument().empty()) {
2031 if (cmd.action != LFUN_UNKNOWN_ACTION) {
2032 comname += ' ' + cmd.argument();
2037 docstring const shortcuts = theTopLevelKeymap().printbindings(cmd);
2039 if (!shortcuts.empty())
2040 comname += ": " + shortcuts;
2041 else if (!argsadded && !cmd.argument().empty())
2042 comname += ' ' + cmd.argument();
2044 if (!comname.empty()) {
2045 comname = rtrim(comname);
2046 dispatch_msg += '(' + rtrim(comname) + ')';
2049 LYXERR(Debug::ACTION) << "verbose dispatch msg "
2050 << to_utf8(dispatch_msg) << endl;
2051 if (!dispatch_msg.empty())
2052 lyx_view_->message(dispatch_msg);
2056 void LyXFunc::menuNew(string const & name, bool fromTemplate)
2058 // FIXME: initpath is not used. What to do?
2059 string initpath = lyxrc.document_path;
2060 string filename(name);
2062 if (lyx_view_->buffer()) {
2063 string const trypath = lyx_view_->buffer()->filePath();
2064 // If directory is writeable, use this as default.
2065 if (FileName(trypath).isDirWritable())
2069 static int newfile_number;
2071 if (filename.empty()) {
2072 filename = addName(lyxrc.document_path,
2073 "newfile" + convert<string>(++newfile_number) + ".lyx");
2074 while (theBufferList().exists(filename) ||
2075 FileName(filename).isReadable()) {
2077 filename = addName(lyxrc.document_path,
2078 "newfile" + convert<string>(newfile_number) +
2083 // The template stuff
2086 FileDialog fileDlg(_("Select template file"),
2087 LFUN_SELECT_FILE_SYNC,
2088 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2089 make_pair(_("Templates|#T#t"), from_utf8(lyxrc.template_path)));
2091 FileDialog::Result result =
2092 fileDlg.open(from_utf8(lyxrc.template_path),
2093 FileFilterList(_("LyX Documents (*.lyx)")),
2096 if (result.first == FileDialog::Later)
2098 if (result.second.empty())
2100 templname = to_utf8(result.second);
2103 Buffer * const b = newFile(filename, templname, !name.empty());
2105 lyx_view_->setBuffer(b);
2109 void LyXFunc::open(string const & fname)
2111 string initpath = lyxrc.document_path;
2113 if (lyx_view_->buffer()) {
2114 string const trypath = lyx_view_->buffer()->filePath();
2115 // If directory is writeable, use this as default.
2116 if (FileName(trypath).isDirWritable())
2122 if (fname.empty()) {
2123 FileDialog fileDlg(_("Select document to open"),
2125 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2126 make_pair(_("Examples|#E#e"), from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2128 FileDialog::Result result =
2129 fileDlg.open(from_utf8(initpath),
2130 FileFilterList(_("LyX Documents (*.lyx)")),
2133 if (result.first == FileDialog::Later)
2136 filename = to_utf8(result.second);
2138 // check selected filename
2139 if (filename.empty()) {
2140 lyx_view_->message(_("Canceled."));
2146 // get absolute path of file and add ".lyx" to the filename if
2148 FileName const fullname = fileSearch(string(), filename, "lyx");
2149 if (!fullname.empty())
2150 filename = fullname.absFilename();
2152 // if the file doesn't exist, let the user create one
2153 if (!fullname.exists()) {
2154 // the user specifically chose this name. Believe him.
2155 Buffer * const b = newFile(filename, string(), true);
2157 lyx_view_->setBuffer(b);
2161 docstring const disp_fn = makeDisplayPath(filename);
2162 lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
2165 Buffer * buf = lyx_view_->loadLyXFile(fullname);
2168 lyx_view_->setBuffer(buf);
2169 lyx_view_->showErrorList("Parse");
2170 str2 = bformat(_("Document %1$s opened."), disp_fn);
2172 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2174 lyx_view_->message(str2);
2178 void LyXFunc::doImport(string const & argument)
2181 string filename = split(argument, format, ' ');
2183 LYXERR(Debug::INFO) << "LyXFunc::doImport: " << format
2184 << " file: " << filename << endl;
2186 // need user interaction
2187 if (filename.empty()) {
2188 string initpath = lyxrc.document_path;
2190 if (lyx_view_->buffer()) {
2191 string const trypath = lyx_view_->buffer()->filePath();
2192 // If directory is writeable, use this as default.
2193 if (FileName(trypath).isDirWritable())
2197 docstring const text = bformat(_("Select %1$s file to import"),
2198 formats.prettyName(format));
2200 FileDialog fileDlg(text,
2202 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2203 make_pair(_("Examples|#E#e"),
2204 from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2206 docstring filter = formats.prettyName(format);
2209 filter += from_utf8(formats.extension(format));
2212 FileDialog::Result result =
2213 fileDlg.open(from_utf8(initpath),
2214 FileFilterList(filter),
2217 if (result.first == FileDialog::Later)
2220 filename = to_utf8(result.second);
2222 // check selected filename
2223 if (filename.empty())
2224 lyx_view_->message(_("Canceled."));
2227 if (filename.empty())
2230 // get absolute path of file
2231 FileName const fullname(makeAbsPath(filename));
2233 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
2235 // Check if the document already is open
2236 if (use_gui && theBufferList().exists(lyxfile.absFilename())) {
2237 if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) {
2238 lyx_view_->message(_("Canceled."));
2243 // if the file exists already, and we didn't do
2244 // -i lyx thefile.lyx, warn
2245 if (lyxfile.exists() && fullname != lyxfile) {
2246 docstring const file = makeDisplayPath(lyxfile.absFilename(), 30);
2248 docstring text = bformat(_("The document %1$s already exists.\n\n"
2249 "Do you want to overwrite that document?"), file);
2250 int const ret = Alert::prompt(_("Overwrite document?"),
2251 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2254 lyx_view_->message(_("Canceled."));
2259 ErrorList errorList;
2260 Importer::Import(lyx_view_, fullname, format, errorList);
2261 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2265 void LyXFunc::closeBuffer()
2267 // goto bookmark to update bookmark pit.
2268 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2269 gotoBookmark(i+1, false, false);
2271 theBufferList().close(lyx_view_->buffer(), true);
2275 void LyXFunc::reloadBuffer()
2277 FileName filename(lyx_view_->buffer()->absFileName());
2278 docstring const disp_fn = makeDisplayPath(filename.absFilename());
2281 Buffer * buf = lyx_view_->loadLyXFile(filename);
2284 lyx_view_->setBuffer(buf);
2285 lyx_view_->showErrorList("Parse");
2286 str = bformat(_("Document %1$s reloaded."), disp_fn);
2288 str = bformat(_("Could not reload document %1$s"), disp_fn);
2290 lyx_view_->message(str);
2293 // Each "lyx_view_" should have it's own message method. lyxview and
2294 // the minibuffer would use the minibuffer, but lyxserver would
2295 // send an ERROR signal to its client. Alejandro 970603
2296 // This function is bit problematic when it comes to NLS, to make the
2297 // lyx servers client be language indepenent we must not translate
2298 // strings sent to this func.
2299 void LyXFunc::setErrorMessage(docstring const & m) const
2301 dispatch_buffer = m;
2306 void LyXFunc::setMessage(docstring const & m) const
2308 dispatch_buffer = m;
2312 docstring const LyXFunc::viewStatusMessage()
2314 // When meta-fake key is pressed, show the key sequence so far + "M-".
2316 return keyseq.print(true) + "M-";
2318 // Else, when a non-complete key sequence is pressed,
2319 // show the available options.
2320 if (keyseq.length() > 0 && !keyseq.deleted())
2321 return keyseq.printOptions(true);
2323 BOOST_ASSERT(lyx_view_);
2324 if (!lyx_view_->buffer())
2325 return _("Welcome to LyX!");
2327 return view()->cursor().currentState();
2331 BufferView * LyXFunc::view() const
2333 BOOST_ASSERT(lyx_view_);
2334 return lyx_view_->view();
2338 bool LyXFunc::wasMetaKey() const
2340 return (meta_fake_bit != NoModifier);
2344 void LyXFunc::updateLayout(TextClassPtr const & oldlayout,
2347 lyx_view_->message(_("Converting document to new document class..."));
2349 StableDocIterator backcur(view()->cursor());
2350 ErrorList & el = buffer->errorList("Class Switch");
2351 cap::switchBetweenClasses(
2352 oldlayout, buffer->params().getTextClassPtr(),
2353 static_cast<InsetText &>(buffer->inset()), el);
2355 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
2357 buffer->errors("Class Switch");
2358 updateLabels(*buffer);
2364 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2366 // Why the switch you might ask. It is a trick to ensure that all
2367 // the elements in the LyXRCTags enum is handled. As you can see
2368 // there are no breaks at all. So it is just a huge fall-through.
2369 // The nice thing is that we will get a warning from the compiler
2370 // if we forget an element.
2371 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2373 case LyXRC::RC_ACCEPT_COMPOUND:
2374 case LyXRC::RC_ALT_LANG:
2375 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
2376 case LyXRC::RC_PLAINTEXT_LINELEN:
2377 case LyXRC::RC_AUTOREGIONDELETE:
2378 case LyXRC::RC_AUTORESET_OPTIONS:
2379 case LyXRC::RC_AUTOSAVE:
2380 case LyXRC::RC_AUTO_NUMBER:
2381 case LyXRC::RC_BACKUPDIR_PATH:
2382 case LyXRC::RC_BIBTEX_COMMAND:
2383 case LyXRC::RC_BINDFILE:
2384 case LyXRC::RC_CHECKLASTFILES:
2385 case LyXRC::RC_USELASTFILEPOS:
2386 case LyXRC::RC_LOADSESSION:
2387 case LyXRC::RC_CHKTEX_COMMAND:
2388 case LyXRC::RC_CONVERTER:
2389 case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
2390 case LyXRC::RC_COPIER:
2391 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2392 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2393 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2394 case LyXRC::RC_DATE_INSERT_FORMAT:
2395 case LyXRC::RC_DEFAULT_LANGUAGE:
2396 case LyXRC::RC_DEFAULT_PAPERSIZE:
2397 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2398 case LyXRC::RC_DISPLAY_GRAPHICS:
2399 case LyXRC::RC_DOCUMENTPATH:
2400 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2401 FileName path(lyxrc_new.document_path);
2402 if (path.exists() && path.isDirectory())
2403 support::package().document_dir() = FileName(lyxrc.document_path);
2405 case LyXRC::RC_ESC_CHARS:
2406 case LyXRC::RC_FONT_ENCODING:
2407 case LyXRC::RC_FORMAT:
2408 case LyXRC::RC_INDEX_COMMAND:
2409 case LyXRC::RC_INPUT:
2410 case LyXRC::RC_KBMAP:
2411 case LyXRC::RC_KBMAP_PRIMARY:
2412 case LyXRC::RC_KBMAP_SECONDARY:
2413 case LyXRC::RC_LABEL_INIT_LENGTH:
2414 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2415 case LyXRC::RC_LANGUAGE_AUTO_END:
2416 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2417 case LyXRC::RC_LANGUAGE_COMMAND_END:
2418 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2419 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2420 case LyXRC::RC_LANGUAGE_PACKAGE:
2421 case LyXRC::RC_LANGUAGE_USE_BABEL:
2422 case LyXRC::RC_MAKE_BACKUP:
2423 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2424 case LyXRC::RC_NUMLASTFILES:
2425 case LyXRC::RC_PATH_PREFIX:
2426 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2427 support::prependEnvPath("PATH", lyxrc.path_prefix);
2429 case LyXRC::RC_PERS_DICT:
2430 case LyXRC::RC_PREVIEW:
2431 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2432 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2433 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2434 case LyXRC::RC_PRINTCOPIESFLAG:
2435 case LyXRC::RC_PRINTER:
2436 case LyXRC::RC_PRINTEVENPAGEFLAG:
2437 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2438 case LyXRC::RC_PRINTFILEEXTENSION:
2439 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2440 case LyXRC::RC_PRINTODDPAGEFLAG:
2441 case LyXRC::RC_PRINTPAGERANGEFLAG:
2442 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2443 case LyXRC::RC_PRINTPAPERFLAG:
2444 case LyXRC::RC_PRINTREVERSEFLAG:
2445 case LyXRC::RC_PRINTSPOOL_COMMAND:
2446 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2447 case LyXRC::RC_PRINTTOFILE:
2448 case LyXRC::RC_PRINTTOPRINTER:
2449 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2450 case LyXRC::RC_PRINT_COMMAND:
2451 case LyXRC::RC_RTL_SUPPORT:
2452 case LyXRC::RC_SCREEN_DPI:
2453 case LyXRC::RC_SCREEN_FONT_ROMAN:
2454 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2455 case LyXRC::RC_SCREEN_FONT_SANS:
2456 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2457 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2458 case LyXRC::RC_SCREEN_FONT_SIZES:
2459 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2460 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2461 case LyXRC::RC_SCREEN_GEOMETRY_HEIGHT:
2462 case LyXRC::RC_SCREEN_GEOMETRY_WIDTH:
2463 case LyXRC::RC_SCREEN_GEOMETRY_XYSAVED:
2464 case LyXRC::RC_SCREEN_ZOOM:
2465 case LyXRC::RC_SERVERPIPE:
2466 case LyXRC::RC_SET_COLOR:
2467 case LyXRC::RC_SHOW_BANNER:
2468 case LyXRC::RC_SPELL_COMMAND:
2469 case LyXRC::RC_TEMPDIRPATH:
2470 case LyXRC::RC_TEMPLATEPATH:
2471 case LyXRC::RC_TEX_ALLOWS_SPACES:
2472 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2473 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2474 support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2476 case LyXRC::RC_UIFILE:
2477 case LyXRC::RC_USER_EMAIL:
2478 case LyXRC::RC_USER_NAME:
2479 case LyXRC::RC_USETEMPDIR:
2480 case LyXRC::RC_USE_ALT_LANG:
2481 case LyXRC::RC_USE_CONVERTER_CACHE:
2482 case LyXRC::RC_USE_ESC_CHARS:
2483 case LyXRC::RC_USE_INP_ENC:
2484 case LyXRC::RC_USE_PERS_DICT:
2485 case LyXRC::RC_USE_SPELL_LIB:
2486 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2487 case LyXRC::RC_VIEWER:
2488 case LyXRC::RC_LAST: