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()->fileName() != 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->fileName())
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->fileName())
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->getLogName().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.fileName(), 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()->fileName()));
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->fileName() << 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()->fileName(), 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()->getMasterBuffer());
996 Exporter::Export(lyx_view_->buffer()->getMasterBuffer(), argument, true);
999 case LFUN_MASTER_BUFFER_VIEW:
1000 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->getMasterBuffer());
1001 Exporter::preview(lyx_view_->buffer()->getMasterBuffer(), 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 =
1043 buffer->getLatexName(false);
1044 filename = changeExtension(latexname,
1045 format->extension());
1046 filename = addName(buffer->temppath(), filename);
1048 if (!buffer->writeFile(FileName(filename)))
1052 Exporter::Export(buffer, format_name, true, filename);
1055 // Substitute $$FName for filename
1056 if (!contains(command, "$$FName"))
1057 command = "( " + command + " ) < $$FName";
1058 command = subst(command, "$$FName", filename);
1060 // Execute the command in the background
1062 call.startscript(Systemcall::DontWait, command);
1066 case LFUN_BUFFER_PRINT: {
1067 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1068 // FIXME: cmd.getArg() might fail if one of the arguments
1069 // contains double quotes
1070 string target = cmd.getArg(0);
1071 string target_name = cmd.getArg(1);
1072 string command = cmd.getArg(2);
1075 || target_name.empty()
1076 || command.empty()) {
1077 lyxerr << "Unable to parse \""
1078 << argument << '"' << endl;
1081 if (target != "printer" && target != "file") {
1082 lyxerr << "Unrecognized target \""
1083 << target << '"' << endl;
1087 Buffer * buffer = lyx_view_->buffer();
1089 if (!Exporter::Export(buffer, "dvi", true)) {
1090 showPrintError(buffer->fileName());
1094 // Push directory path.
1095 string const path = buffer->temppath();
1096 // Prevent the compiler from optimizing away p
1098 support::Path p(pp);
1100 // there are three cases here:
1101 // 1. we print to a file
1102 // 2. we print directly to a printer
1103 // 3. we print using a spool command (print to file first)
1106 string const dviname =
1107 changeExtension(buffer->getLatexName(true),
1110 if (target == "printer") {
1111 if (!lyxrc.print_spool_command.empty()) {
1112 // case 3: print using a spool
1113 string const psname =
1114 changeExtension(dviname,".ps");
1115 command += ' ' + lyxrc.print_to_file
1118 + quoteName(dviname);
1121 lyxrc.print_spool_command + ' ';
1122 if (target_name != "default") {
1123 command2 += lyxrc.print_spool_printerprefix
1127 command2 += quoteName(psname);
1129 // If successful, then spool command
1130 res = one.startscript(
1135 res = one.startscript(
1136 Systemcall::DontWait,
1139 // case 2: print directly to a printer
1140 if (target_name != "default")
1141 command += ' ' + lyxrc.print_to_printer + target_name + ' ';
1142 res = one.startscript(
1143 Systemcall::DontWait,
1144 command + quoteName(dviname));
1148 // case 1: print to a file
1149 FileName const filename(makeAbsPath(target_name,
1150 lyx_view_->buffer()->filePath()));
1151 FileName const dvifile(makeAbsPath(dviname, path));
1152 if (filename.exists()) {
1153 docstring text = bformat(
1154 _("The file %1$s already exists.\n\n"
1155 "Do you want to overwrite that file?"),
1156 makeDisplayPath(filename.absFilename()));
1157 if (Alert::prompt(_("Overwrite file?"),
1158 text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
1161 command += ' ' + lyxrc.print_to_file
1162 + quoteName(filename.toFilesystemEncoding())
1164 + quoteName(dvifile.toFilesystemEncoding());
1165 res = one.startscript(Systemcall::DontWait,
1170 showPrintError(buffer->fileName());
1174 case LFUN_BUFFER_IMPORT:
1179 // quitting is triggered by the gui code
1180 // (leaving the event loop).
1181 lyx_view_->message(from_utf8(N_("Exiting.")));
1182 if (theBufferList().quitWriteAll())
1183 theApp()->gui().closeAllViews();
1186 case LFUN_BUFFER_AUTO_SAVE:
1187 lyx_view_->buffer()->autoSave();
1190 case LFUN_RECONFIGURE:
1191 BOOST_ASSERT(lyx_view_);
1192 // argument is any additional parameter to the configure.py command
1193 reconfigure(*lyx_view_, argument);
1196 case LFUN_HELP_OPEN: {
1197 BOOST_ASSERT(lyx_view_);
1198 string const arg = argument;
1200 setErrorMessage(from_ascii(N_("Missing argument")));
1203 FileName const fname = i18nLibFileSearch("doc", arg, "lyx");
1204 if (fname.empty()) {
1205 lyxerr << "LyX: unable to find documentation file `"
1206 << arg << "'. Bad installation?" << endl;
1209 lyx_view_->message(bformat(_("Opening help file %1$s..."),
1210 makeDisplayPath(fname.absFilename())));
1211 Buffer * buf = lyx_view_->loadLyXFile(fname, false);
1214 lyx_view_->setBuffer(buf);
1215 lyx_view_->showErrorList("Parse");
1217 updateFlags = Update::None;
1221 // --- version control -------------------------------
1222 case LFUN_VC_REGISTER:
1223 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1224 if (!ensureBufferClean(view()))
1226 if (!lyx_view_->buffer()->lyxvc().inUse()) {
1227 lyx_view_->buffer()->lyxvc().registrer();
1230 updateFlags = Update::Force;
1233 case LFUN_VC_CHECK_IN:
1234 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1235 if (!ensureBufferClean(view()))
1237 if (lyx_view_->buffer()->lyxvc().inUse()
1238 && !lyx_view_->buffer()->isReadonly()) {
1239 lyx_view_->buffer()->lyxvc().checkIn();
1244 case LFUN_VC_CHECK_OUT:
1245 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1246 if (!ensureBufferClean(view()))
1248 if (lyx_view_->buffer()->lyxvc().inUse()
1249 && lyx_view_->buffer()->isReadonly()) {
1250 lyx_view_->buffer()->lyxvc().checkOut();
1255 case LFUN_VC_REVERT:
1256 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1257 lyx_view_->buffer()->lyxvc().revert();
1261 case LFUN_VC_UNDO_LAST:
1262 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1263 lyx_view_->buffer()->lyxvc().undoLast();
1267 // --- buffers ----------------------------------------
1268 case LFUN_BUFFER_SWITCH:
1269 BOOST_ASSERT(lyx_view_);
1270 lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1271 updateFlags = Update::None;
1274 case LFUN_BUFFER_NEXT:
1275 BOOST_ASSERT(lyx_view_);
1276 lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer()));
1277 updateFlags = Update::None;
1280 case LFUN_BUFFER_PREVIOUS:
1281 BOOST_ASSERT(lyx_view_);
1282 lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer()));
1283 updateFlags = Update::None;
1286 case LFUN_FILE_NEW: {
1287 BOOST_ASSERT(lyx_view_);
1289 string tmpname = split(argument, name, ':'); // Split filename
1290 Buffer * const b = newFile(name, tmpname);
1292 lyx_view_->setBuffer(b);
1293 updateFlags = Update::None;
1297 case LFUN_FILE_OPEN:
1298 BOOST_ASSERT(lyx_view_);
1300 updateFlags = Update::None;
1303 case LFUN_DROP_LAYOUTS_CHOICE:
1304 BOOST_ASSERT(lyx_view_);
1305 lyx_view_->openLayoutList();
1308 case LFUN_MENU_OPEN:
1309 BOOST_ASSERT(lyx_view_);
1310 lyx_view_->openMenu(from_utf8(argument));
1313 // --- lyxserver commands ----------------------------
1314 case LFUN_SERVER_GET_NAME:
1315 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1316 setMessage(from_utf8(lyx_view_->buffer()->fileName()));
1317 LYXERR(Debug::INFO) << "FNAME["
1318 << lyx_view_->buffer()->fileName()
1322 case LFUN_SERVER_NOTIFY:
1323 dispatch_buffer = keyseq.print(false);
1324 theServer().notifyClient(to_utf8(dispatch_buffer));
1327 case LFUN_SERVER_GOTO_FILE_ROW: {
1328 BOOST_ASSERT(lyx_view_);
1331 istringstream is(argument);
1332 is >> file_name >> row;
1334 bool loaded = false;
1335 if (prefixIs(file_name, package().temp_dir().absFilename()))
1336 // Needed by inverse dvi search. If it is a file
1337 // in tmpdir, call the apropriated function
1338 buf = theBufferList().getBufferFromTmp(file_name);
1340 // Must replace extension of the file to be .lyx
1341 // and get full path
1342 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1343 // Either change buffer or load the file
1344 if (theBufferList().exists(s.absFilename()))
1345 buf = theBufferList().getBuffer(s.absFilename());
1347 buf = lyx_view_->loadLyXFile(s);
1353 updateFlags = Update::None;
1358 lyx_view_->setBuffer(buf);
1359 view()->setCursorFromRow(row);
1361 lyx_view_->showErrorList("Parse");
1362 updateFlags = Update::FitCursor;
1366 case LFUN_DIALOG_SHOW: {
1367 BOOST_ASSERT(lyx_view_);
1368 string const name = cmd.getArg(0);
1369 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1371 if (name == "character") {
1372 data = freefont2string();
1374 lyx_view_->getDialogs().show("character", data);
1375 } else if (name == "latexlog") {
1376 pair<Buffer::LogType, string> const logfile =
1377 lyx_view_->buffer()->getLogName();
1378 switch (logfile.first) {
1379 case Buffer::latexlog:
1382 case Buffer::buildlog:
1386 data += Lexer::quoteString(logfile.second);
1387 lyx_view_->getDialogs().show("log", data);
1388 } else if (name == "vclog") {
1389 string const data = "vc " +
1390 Lexer::quoteString(lyx_view_->buffer()->lyxvc().getLogFile());
1391 lyx_view_->getDialogs().show("log", data);
1393 lyx_view_->getDialogs().show(name, data);
1397 case LFUN_DIALOG_SHOW_NEW_INSET: {
1398 BOOST_ASSERT(lyx_view_);
1399 string const name = cmd.getArg(0);
1400 InsetCode code = insetCode(name);
1401 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1402 bool insetCodeOK = true;
1411 case HYPERLINK_CODE: {
1412 InsetCommandParams p(code);
1413 data = InsetCommandMailer::params2string(name, p);
1416 case INCLUDE_CODE: {
1417 // data is the include type: one of "include",
1418 // "input", "verbatiminput" or "verbatiminput*"
1420 // default type is requested
1422 InsetCommandParams p(INCLUDE_CODE, data);
1423 data = InsetIncludeMailer::params2string(p);
1427 // \c data == "Boxed" || "Frameless" etc
1428 InsetBoxParams p(data);
1429 data = InsetBoxMailer::params2string(p);
1433 InsetBranchParams p;
1434 data = InsetBranchMailer::params2string(p);
1438 InsetCommandParams p(CITE_CODE);
1439 data = InsetCommandMailer::params2string(name, p);
1443 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1446 case EXTERNAL_CODE: {
1447 InsetExternalParams p;
1448 Buffer const & buffer = *lyx_view_->buffer();
1449 data = InsetExternalMailer::params2string(p, buffer);
1454 data = InsetFloatMailer::params2string(p);
1457 case LISTINGS_CODE: {
1458 InsetListingsParams p;
1459 data = InsetListingsMailer::params2string(p);
1462 case GRAPHICS_CODE: {
1463 InsetGraphicsParams p;
1464 Buffer const & buffer = *lyx_view_->buffer();
1465 data = InsetGraphicsMailer::params2string(p, buffer);
1470 data = InsetNoteMailer::params2string(p);
1475 data = InsetVSpaceMailer::params2string(space);
1480 data = InsetWrapMailer::params2string(p);
1484 lyxerr << "Inset type '" << name <<
1485 "' not recognized in LFUN_DIALOG_SHOW_NEW_INSET" << std:: endl;
1486 insetCodeOK = false;
1488 } // end switch(code)
1490 lyx_view_->getDialogs().show(name, data, 0);
1494 case LFUN_DIALOG_UPDATE: {
1495 BOOST_ASSERT(lyx_view_);
1496 string const & name = argument;
1497 // Can only update a dialog connected to an existing inset
1498 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1500 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1501 inset->dispatch(view()->cursor(), fr);
1502 } else if (name == "paragraph") {
1503 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1504 } else if (name == "prefs") {
1505 lyx_view_->getDialogs().update(name, string());
1510 case LFUN_DIALOG_HIDE:
1511 LyX::cref().hideDialogs(argument, 0);
1514 case LFUN_DIALOG_TOGGLE: {
1515 BOOST_ASSERT(lyx_view_);
1516 if (lyx_view_->getDialogs().visible(cmd.getArg(0)))
1517 dispatch(FuncRequest(LFUN_DIALOG_HIDE, argument));
1519 dispatch(FuncRequest(LFUN_DIALOG_SHOW, argument));
1523 case LFUN_DIALOG_DISCONNECT_INSET:
1524 BOOST_ASSERT(lyx_view_);
1525 lyx_view_->getDialogs().disconnect(argument);
1529 case LFUN_CITATION_INSERT: {
1530 BOOST_ASSERT(lyx_view_);
1531 if (!argument.empty()) {
1532 // we can have one optional argument, delimited by '|'
1533 // citation-insert <key>|<text_before>
1534 // this should be enhanced to also support text_after
1535 // and citation style
1536 string arg = argument;
1538 if (contains(argument, "|")) {
1539 arg = token(argument, '|', 0);
1540 opt1 = token(argument, '|', 1);
1542 InsetCommandParams icp(CITE_CODE);
1543 icp["key"] = from_utf8(arg);
1545 icp["before"] = from_utf8(opt1);
1546 string icstr = InsetCommandMailer::params2string("citation", icp);
1547 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1550 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1554 case LFUN_BUFFER_CHILD_OPEN: {
1555 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1556 Buffer * parent = lyx_view_->buffer();
1557 FileName filename = makeAbsPath(argument, parent->filePath());
1558 view()->saveBookmark(false);
1560 bool parsed = false;
1561 if (theBufferList().exists(filename.absFilename())) {
1562 child = theBufferList().getBuffer(filename.absFilename());
1564 setMessage(bformat(_("Opening child document %1$s..."),
1565 makeDisplayPath(filename.absFilename())));
1566 child = lyx_view_->loadLyXFile(filename, true);
1570 // Set the parent name of the child document.
1571 // This makes insertion of citations and references in the child work,
1572 // when the target is in the parent or another child document.
1573 child->setParentName(parent->fileName());
1574 updateLabels(*child->getMasterBuffer());
1575 lyx_view_->setBuffer(child);
1577 lyx_view_->showErrorList("Parse");
1580 // If a screen update is required (in case where auto_open is false),
1581 // setBuffer() would have taken care of it already. Otherwise we shall
1582 // reset the update flag because it can cause a circular problem.
1584 updateFlags = Update::None;
1588 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1589 BOOST_ASSERT(lyx_view_);
1590 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1593 case LFUN_KEYMAP_OFF:
1594 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1595 lyx_view_->view()->getIntl().keyMapOn(false);
1598 case LFUN_KEYMAP_PRIMARY:
1599 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1600 lyx_view_->view()->getIntl().keyMapPrim();
1603 case LFUN_KEYMAP_SECONDARY:
1604 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1605 lyx_view_->view()->getIntl().keyMapSec();
1608 case LFUN_KEYMAP_TOGGLE:
1609 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1610 lyx_view_->view()->getIntl().toggleKeyMap();
1616 string rest = split(argument, countstr, ' ');
1617 istringstream is(countstr);
1620 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1621 for (int i = 0; i < count; ++i)
1622 dispatch(lyxaction.lookupFunc(rest));
1626 case LFUN_COMMAND_SEQUENCE: {
1627 // argument contains ';'-terminated commands
1628 string arg = argument;
1629 while (!arg.empty()) {
1631 arg = split(arg, first, ';');
1632 FuncRequest func(lyxaction.lookupFunc(first));
1633 func.origin = cmd.origin;
1639 case LFUN_PREFERENCES_SAVE: {
1640 lyxrc.write(makeAbsPath("preferences",
1641 package().user_support().absFilename()),
1646 case LFUN_SCREEN_FONT_UPDATE:
1647 BOOST_ASSERT(lyx_view_);
1648 // handle the screen font changes.
1649 theFontLoader().update();
1650 /// FIXME: only the current view will be updated. the Gui
1651 /// class is able to furnish the list of views.
1652 updateFlags = Update::Force;
1655 case LFUN_SET_COLOR: {
1657 string const x11_name = split(argument, lyx_name, ' ');
1658 if (lyx_name.empty() || x11_name.empty()) {
1659 setErrorMessage(from_ascii(N_(
1660 "Syntax: set-color <lyx_name>"
1665 bool const graphicsbg_changed =
1666 (lyx_name == lcolor.getLyXName(Color::graphicsbg) &&
1667 x11_name != lcolor.getX11Name(Color::graphicsbg));
1669 if (!lcolor.setColor(lyx_name, x11_name)) {
1671 bformat(_("Set-color \"%1$s\" failed "
1672 "- color is undefined or "
1673 "may not be redefined"),
1674 from_utf8(lyx_name)));
1678 theApp()->updateColor(lcolor.getFromLyXName(lyx_name));
1680 if (graphicsbg_changed) {
1681 // FIXME: The graphics cache no longer has a changeDisplay method.
1683 graphics::GCache::get().changeDisplay(true);
1690 BOOST_ASSERT(lyx_view_);
1691 lyx_view_->message(from_utf8(argument));
1694 case LFUN_EXTERNAL_EDIT: {
1695 BOOST_ASSERT(lyx_view_);
1696 FuncRequest fr(action, argument);
1697 InsetExternal().dispatch(view()->cursor(), fr);
1701 case LFUN_GRAPHICS_EDIT: {
1702 FuncRequest fr(action, argument);
1703 InsetGraphics().dispatch(view()->cursor(), fr);
1707 case LFUN_INSET_APPLY: {
1708 BOOST_ASSERT(lyx_view_);
1709 string const name = cmd.getArg(0);
1710 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1712 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1713 inset->dispatch(view()->cursor(), fr);
1715 FuncRequest fr(LFUN_INSET_INSERT, argument);
1718 // ideally, the update flag should be set by the insets,
1719 // but this is not possible currently
1720 updateFlags = Update::Force | Update::FitCursor;
1724 case LFUN_ALL_INSETS_TOGGLE: {
1725 BOOST_ASSERT(lyx_view_);
1727 string const name = split(argument, action, ' ');
1728 InsetCode const inset_code = insetCode(name);
1730 Cursor & cur = view()->cursor();
1731 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1733 Inset & inset = lyx_view_->buffer()->inset();
1734 InsetIterator it = inset_iterator_begin(inset);
1735 InsetIterator const end = inset_iterator_end(inset);
1736 for (; it != end; ++it) {
1737 if (!it->asInsetMath()
1738 && (inset_code == NO_CODE
1739 || inset_code == it->lyxCode())) {
1740 Cursor tmpcur = cur;
1741 tmpcur.pushLeft(*it);
1742 it->dispatch(tmpcur, fr);
1745 updateFlags = Update::Force | Update::FitCursor;
1749 case LFUN_BUFFER_LANGUAGE: {
1750 BOOST_ASSERT(lyx_view_);
1751 Buffer & buffer = *lyx_view_->buffer();
1752 Language const * oldL = buffer.params().language;
1753 Language const * newL = languages.getLanguage(argument);
1754 if (!newL || oldL == newL)
1757 if (oldL->rightToLeft() == newL->rightToLeft()
1758 && !buffer.isMultiLingual())
1759 buffer.changeLanguage(oldL, newL);
1763 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1764 string const fname =
1765 addName(addPath(package().user_support().absFilename(), "templates/"),
1767 Buffer defaults(fname);
1769 istringstream ss(argument);
1772 int const unknown_tokens = defaults.readHeader(lex);
1774 if (unknown_tokens != 0) {
1775 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1776 << unknown_tokens << " unknown token"
1777 << (unknown_tokens == 1 ? "" : "s")
1781 if (defaults.writeFile(FileName(defaults.fileName())))
1782 setMessage(bformat(_("Document defaults saved in %1$s"),
1783 makeDisplayPath(fname)));
1785 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1789 case LFUN_BUFFER_PARAMS_APPLY: {
1790 BOOST_ASSERT(lyx_view_);
1791 biblio::CiteEngine const oldEngine =
1792 lyx_view_->buffer()->params().getEngine();
1794 Buffer * buffer = lyx_view_->buffer();
1796 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1798 Cursor & cur = view()->cursor();
1799 cur.recordUndoFullDocument();
1801 istringstream ss(argument);
1804 int const unknown_tokens = buffer->readHeader(lex);
1806 if (unknown_tokens != 0) {
1807 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1808 << unknown_tokens << " unknown token"
1809 << (unknown_tokens == 1 ? "" : "s")
1813 updateLayout(oldClass, buffer);
1815 biblio::CiteEngine const newEngine =
1816 lyx_view_->buffer()->params().getEngine();
1818 if (oldEngine != newEngine) {
1819 FuncRequest fr(LFUN_INSET_REFRESH);
1821 Inset & inset = lyx_view_->buffer()->inset();
1822 InsetIterator it = inset_iterator_begin(inset);
1823 InsetIterator const end = inset_iterator_end(inset);
1824 for (; it != end; ++it)
1825 if (it->lyxCode() == CITE_CODE)
1826 it->dispatch(cur, fr);
1829 updateFlags = Update::Force | Update::FitCursor;
1833 case LFUN_LAYOUT_MODULES_CLEAR: {
1834 BOOST_ASSERT(lyx_view_);
1835 Buffer * buffer = lyx_view_->buffer();
1836 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1837 view()->cursor().recordUndoFullDocument();
1838 buffer->params().clearLayoutModules();
1839 updateLayout(oldClass, buffer);
1840 updateFlags = Update::Force | Update::FitCursor;
1844 case LFUN_LAYOUT_MODULE_ADD: {
1845 BOOST_ASSERT(lyx_view_);
1846 Buffer * buffer = lyx_view_->buffer();
1847 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1848 view()->cursor().recordUndoFullDocument();
1849 buffer->params().addLayoutModule(argument);
1850 updateLayout(oldClass, buffer);
1851 updateFlags = Update::Force | Update::FitCursor;
1855 case LFUN_TEXTCLASS_APPLY: {
1856 BOOST_ASSERT(lyx_view_);
1857 Buffer * buffer = lyx_view_->buffer();
1859 loadTextClass(argument);
1861 std::pair<bool, textclass_type> const tc_pair =
1862 textclasslist.numberOfClass(argument);
1867 textclass_type const old_class = buffer->params().getBaseClass();
1868 textclass_type const new_class = tc_pair.second;
1870 if (old_class == new_class)
1874 //Save the old, possibly modular, layout for use in conversion.
1875 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1876 view()->cursor().recordUndoFullDocument();
1877 buffer->params().setBaseClass(new_class);
1878 updateLayout(oldClass, buffer);
1879 updateFlags = Update::Force | Update::FitCursor;
1883 case LFUN_LAYOUT_RELOAD: {
1884 BOOST_ASSERT(lyx_view_);
1885 Buffer * buffer = lyx_view_->buffer();
1886 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1887 textclass_type const tc = buffer->params().getBaseClass();
1888 textclasslist.reset(tc);
1889 buffer->params().setBaseClass(tc);
1890 updateLayout(oldClass, buffer);
1891 updateFlags = Update::Force | Update::FitCursor;
1895 case LFUN_TEXTCLASS_LOAD:
1896 loadTextClass(argument);
1899 case LFUN_LYXRC_APPLY: {
1900 LyXRC const lyxrc_orig = lyxrc;
1902 istringstream ss(argument);
1903 bool const success = lyxrc.read(ss) == 0;
1906 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1907 << "Unable to read lyxrc data"
1912 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1914 /// We force the redraw in any case because there might be
1915 /// some screen font changes.
1916 /// FIXME: only the current view will be updated. the Gui
1917 /// class is able to furnish the list of views.
1918 updateFlags = Update::Force;
1922 case LFUN_WINDOW_NEW:
1923 LyX::ref().newLyXView();
1926 case LFUN_WINDOW_CLOSE:
1927 BOOST_ASSERT(lyx_view_);
1928 BOOST_ASSERT(theApp());
1929 // update bookmark pit of the current buffer before window close
1930 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1931 gotoBookmark(i+1, false, false);
1932 // ask the user for saving changes or cancel quit
1933 if (!theBufferList().quitWriteAll())
1938 case LFUN_BOOKMARK_GOTO:
1939 // go to bookmark, open unopened file and switch to buffer if necessary
1940 gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
1943 case LFUN_BOOKMARK_CLEAR:
1944 LyX::ref().session().bookmarks().clear();
1947 case LFUN_TOOLBAR_TOGGLE: {
1948 BOOST_ASSERT(lyx_view_);
1949 string const name = cmd.getArg(0);
1950 bool const allowauto = cmd.getArg(1) == "allowauto";
1951 lyx_view_->toggleToolbarState(name, allowauto);
1952 ToolbarInfo * tbi = lyx_view_->getToolbarInfo(name);
1954 setMessage(bformat(_("Unknown toolbar \"%1$s\""),
1959 if (tbi->flags & ToolbarInfo::ON)
1961 else if (tbi->flags & ToolbarInfo::OFF)
1963 else if (tbi->flags & ToolbarInfo::AUTO)
1966 setMessage(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1967 _(tbi->gui_name), state));
1972 BOOST_ASSERT(lyx_view_);
1973 view()->cursor().dispatch(cmd);
1974 updateFlags = view()->cursor().result().update();
1975 if (!view()->cursor().result().dispatched())
1976 updateFlags = view()->dispatch(cmd);
1981 if (lyx_view_ && lyx_view_->buffer()) {
1982 // BufferView::update() updates the ViewMetricsInfo and
1983 // also initializes the position cache for all insets in
1984 // (at least partially) visible top-level paragraphs.
1985 // We will redraw the screen only if needed.
1986 view()->processUpdateFlags(updateFlags);
1987 lyx_view_->updateStatusBar();
1989 // if we executed a mutating lfun, mark the buffer as dirty
1991 && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
1992 && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
1993 lyx_view_->buffer()->markDirty();
1995 //Do we have a selection?
1996 theSelection().haveSelection(view()->cursor().selection());
1998 if (view()->cursor().inTexted()) {
1999 lyx_view_->updateLayoutChoice();
2003 if (!quitting && lyx_view_) {
2004 lyx_view_->updateToolbars();
2005 // Some messages may already be translated, so we cannot use _()
2006 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
2011 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
2013 const bool verbose = (cmd.origin == FuncRequest::MENU
2014 || cmd.origin == FuncRequest::TOOLBAR
2015 || cmd.origin == FuncRequest::COMMANDBUFFER);
2017 if (cmd.action == LFUN_SELF_INSERT || !verbose) {
2018 LYXERR(Debug::ACTION) << "dispatch msg is " << to_utf8(msg) << endl;
2020 lyx_view_->message(msg);
2024 docstring dispatch_msg = msg;
2025 if (!dispatch_msg.empty())
2026 dispatch_msg += ' ';
2028 docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
2030 bool argsadded = false;
2032 if (!cmd.argument().empty()) {
2033 if (cmd.action != LFUN_UNKNOWN_ACTION) {
2034 comname += ' ' + cmd.argument();
2039 docstring const shortcuts = theTopLevelKeymap().printbindings(cmd);
2041 if (!shortcuts.empty())
2042 comname += ": " + shortcuts;
2043 else if (!argsadded && !cmd.argument().empty())
2044 comname += ' ' + cmd.argument();
2046 if (!comname.empty()) {
2047 comname = rtrim(comname);
2048 dispatch_msg += '(' + rtrim(comname) + ')';
2051 LYXERR(Debug::ACTION) << "verbose dispatch msg "
2052 << to_utf8(dispatch_msg) << endl;
2053 if (!dispatch_msg.empty())
2054 lyx_view_->message(dispatch_msg);
2058 void LyXFunc::menuNew(string const & name, bool fromTemplate)
2060 // FIXME: initpath is not used. What to do?
2061 string initpath = lyxrc.document_path;
2062 string filename(name);
2064 if (lyx_view_->buffer()) {
2065 string const trypath = lyx_view_->buffer()->filePath();
2066 // If directory is writeable, use this as default.
2067 if (FileName(trypath).isDirWritable())
2071 static int newfile_number;
2073 if (filename.empty()) {
2074 filename = addName(lyxrc.document_path,
2075 "newfile" + convert<string>(++newfile_number) + ".lyx");
2076 while (theBufferList().exists(filename) ||
2077 FileName(filename).isReadable()) {
2079 filename = addName(lyxrc.document_path,
2080 "newfile" + convert<string>(newfile_number) +
2085 // The template stuff
2088 FileDialog fileDlg(_("Select template file"),
2089 LFUN_SELECT_FILE_SYNC,
2090 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2091 make_pair(_("Templates|#T#t"), from_utf8(lyxrc.template_path)));
2093 FileDialog::Result result =
2094 fileDlg.open(from_utf8(lyxrc.template_path),
2095 FileFilterList(_("LyX Documents (*.lyx)")),
2098 if (result.first == FileDialog::Later)
2100 if (result.second.empty())
2102 templname = to_utf8(result.second);
2105 Buffer * const b = newFile(filename, templname, !name.empty());
2107 lyx_view_->setBuffer(b);
2111 void LyXFunc::open(string const & fname)
2113 string initpath = lyxrc.document_path;
2115 if (lyx_view_->buffer()) {
2116 string const trypath = lyx_view_->buffer()->filePath();
2117 // If directory is writeable, use this as default.
2118 if (FileName(trypath).isDirWritable())
2124 if (fname.empty()) {
2125 FileDialog fileDlg(_("Select document to open"),
2127 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2128 make_pair(_("Examples|#E#e"), from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2130 FileDialog::Result result =
2131 fileDlg.open(from_utf8(initpath),
2132 FileFilterList(_("LyX Documents (*.lyx)")),
2135 if (result.first == FileDialog::Later)
2138 filename = to_utf8(result.second);
2140 // check selected filename
2141 if (filename.empty()) {
2142 lyx_view_->message(_("Canceled."));
2148 // get absolute path of file and add ".lyx" to the filename if
2150 FileName const fullname = fileSearch(string(), filename, "lyx");
2151 if (!fullname.empty())
2152 filename = fullname.absFilename();
2154 // if the file doesn't exist, let the user create one
2155 if (!fullname.exists()) {
2156 // the user specifically chose this name. Believe him.
2157 Buffer * const b = newFile(filename, string(), true);
2159 lyx_view_->setBuffer(b);
2163 docstring const disp_fn = makeDisplayPath(filename);
2164 lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
2167 Buffer * buf = lyx_view_->loadLyXFile(fullname);
2170 lyx_view_->setBuffer(buf);
2171 lyx_view_->showErrorList("Parse");
2172 str2 = bformat(_("Document %1$s opened."), disp_fn);
2174 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2176 lyx_view_->message(str2);
2180 void LyXFunc::doImport(string const & argument)
2183 string filename = split(argument, format, ' ');
2185 LYXERR(Debug::INFO) << "LyXFunc::doImport: " << format
2186 << " file: " << filename << endl;
2188 // need user interaction
2189 if (filename.empty()) {
2190 string initpath = lyxrc.document_path;
2192 if (lyx_view_->buffer()) {
2193 string const trypath = lyx_view_->buffer()->filePath();
2194 // If directory is writeable, use this as default.
2195 if (FileName(trypath).isDirWritable())
2199 docstring const text = bformat(_("Select %1$s file to import"),
2200 formats.prettyName(format));
2202 FileDialog fileDlg(text,
2204 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2205 make_pair(_("Examples|#E#e"),
2206 from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2208 docstring filter = formats.prettyName(format);
2211 filter += from_utf8(formats.extension(format));
2214 FileDialog::Result result =
2215 fileDlg.open(from_utf8(initpath),
2216 FileFilterList(filter),
2219 if (result.first == FileDialog::Later)
2222 filename = to_utf8(result.second);
2224 // check selected filename
2225 if (filename.empty())
2226 lyx_view_->message(_("Canceled."));
2229 if (filename.empty())
2232 // get absolute path of file
2233 FileName const fullname(makeAbsPath(filename));
2235 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
2237 // Check if the document already is open
2238 if (use_gui && theBufferList().exists(lyxfile.absFilename())) {
2239 if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) {
2240 lyx_view_->message(_("Canceled."));
2245 // if the file exists already, and we didn't do
2246 // -i lyx thefile.lyx, warn
2247 if (lyxfile.exists() && fullname != lyxfile) {
2248 docstring const file = makeDisplayPath(lyxfile.absFilename(), 30);
2250 docstring text = bformat(_("The document %1$s already exists.\n\n"
2251 "Do you want to overwrite that document?"), file);
2252 int const ret = Alert::prompt(_("Overwrite document?"),
2253 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2256 lyx_view_->message(_("Canceled."));
2261 ErrorList errorList;
2262 Importer::Import(lyx_view_, fullname, format, errorList);
2263 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2267 void LyXFunc::closeBuffer()
2269 // goto bookmark to update bookmark pit.
2270 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2271 gotoBookmark(i+1, false, false);
2273 theBufferList().close(lyx_view_->buffer(), true);
2277 void LyXFunc::reloadBuffer()
2279 FileName filename(lyx_view_->buffer()->fileName());
2280 docstring const disp_fn = makeDisplayPath(filename.absFilename());
2283 Buffer * buf = lyx_view_->loadLyXFile(filename);
2286 lyx_view_->setBuffer(buf);
2287 lyx_view_->showErrorList("Parse");
2288 str = bformat(_("Document %1$s reloaded."), disp_fn);
2290 str = bformat(_("Could not reload document %1$s"), disp_fn);
2292 lyx_view_->message(str);
2295 // Each "lyx_view_" should have it's own message method. lyxview and
2296 // the minibuffer would use the minibuffer, but lyxserver would
2297 // send an ERROR signal to its client. Alejandro 970603
2298 // This function is bit problematic when it comes to NLS, to make the
2299 // lyx servers client be language indepenent we must not translate
2300 // strings sent to this func.
2301 void LyXFunc::setErrorMessage(docstring const & m) const
2303 dispatch_buffer = m;
2308 void LyXFunc::setMessage(docstring const & m) const
2310 dispatch_buffer = m;
2314 docstring const LyXFunc::viewStatusMessage()
2316 // When meta-fake key is pressed, show the key sequence so far + "M-".
2318 return keyseq.print(true) + "M-";
2320 // Else, when a non-complete key sequence is pressed,
2321 // show the available options.
2322 if (keyseq.length() > 0 && !keyseq.deleted())
2323 return keyseq.printOptions(true);
2325 BOOST_ASSERT(lyx_view_);
2326 if (!lyx_view_->buffer())
2327 return _("Welcome to LyX!");
2329 return view()->cursor().currentState();
2333 BufferView * LyXFunc::view() const
2335 BOOST_ASSERT(lyx_view_);
2336 return lyx_view_->view();
2340 bool LyXFunc::wasMetaKey() const
2342 return (meta_fake_bit != NoModifier);
2346 void LyXFunc::updateLayout(TextClassPtr const & oldlayout,
2349 lyx_view_->message(_("Converting document to new document class..."));
2351 StableDocIterator backcur(view()->cursor());
2352 ErrorList & el = buffer->errorList("Class Switch");
2353 cap::switchBetweenClasses(
2354 oldlayout, buffer->params().getTextClassPtr(),
2355 static_cast<InsetText &>(buffer->inset()), el);
2357 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
2359 buffer->errors("Class Switch");
2360 updateLabels(*buffer);
2366 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2368 // Why the switch you might ask. It is a trick to ensure that all
2369 // the elements in the LyXRCTags enum is handled. As you can see
2370 // there are no breaks at all. So it is just a huge fall-through.
2371 // The nice thing is that we will get a warning from the compiler
2372 // if we forget an element.
2373 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2375 case LyXRC::RC_ACCEPT_COMPOUND:
2376 case LyXRC::RC_ALT_LANG:
2377 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
2378 case LyXRC::RC_PLAINTEXT_LINELEN:
2379 case LyXRC::RC_AUTOREGIONDELETE:
2380 case LyXRC::RC_AUTORESET_OPTIONS:
2381 case LyXRC::RC_AUTOSAVE:
2382 case LyXRC::RC_AUTO_NUMBER:
2383 case LyXRC::RC_BACKUPDIR_PATH:
2384 case LyXRC::RC_BIBTEX_COMMAND:
2385 case LyXRC::RC_BINDFILE:
2386 case LyXRC::RC_CHECKLASTFILES:
2387 case LyXRC::RC_USELASTFILEPOS:
2388 case LyXRC::RC_LOADSESSION:
2389 case LyXRC::RC_CHKTEX_COMMAND:
2390 case LyXRC::RC_CONVERTER:
2391 case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
2392 case LyXRC::RC_COPIER:
2393 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2394 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2395 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2396 case LyXRC::RC_DATE_INSERT_FORMAT:
2397 case LyXRC::RC_DEFAULT_LANGUAGE:
2398 case LyXRC::RC_DEFAULT_PAPERSIZE:
2399 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2400 case LyXRC::RC_DISPLAY_GRAPHICS:
2401 case LyXRC::RC_DOCUMENTPATH:
2402 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2403 FileName path(lyxrc_new.document_path);
2404 if (path.exists() && path.isDirectory())
2405 support::package().document_dir() = FileName(lyxrc.document_path);
2407 case LyXRC::RC_ESC_CHARS:
2408 case LyXRC::RC_FONT_ENCODING:
2409 case LyXRC::RC_FORMAT:
2410 case LyXRC::RC_INDEX_COMMAND:
2411 case LyXRC::RC_INPUT:
2412 case LyXRC::RC_KBMAP:
2413 case LyXRC::RC_KBMAP_PRIMARY:
2414 case LyXRC::RC_KBMAP_SECONDARY:
2415 case LyXRC::RC_LABEL_INIT_LENGTH:
2416 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2417 case LyXRC::RC_LANGUAGE_AUTO_END:
2418 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2419 case LyXRC::RC_LANGUAGE_COMMAND_END:
2420 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2421 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2422 case LyXRC::RC_LANGUAGE_PACKAGE:
2423 case LyXRC::RC_LANGUAGE_USE_BABEL:
2424 case LyXRC::RC_MAKE_BACKUP:
2425 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2426 case LyXRC::RC_NUMLASTFILES:
2427 case LyXRC::RC_PATH_PREFIX:
2428 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2429 support::prependEnvPath("PATH", lyxrc.path_prefix);
2431 case LyXRC::RC_PERS_DICT:
2432 case LyXRC::RC_PREVIEW:
2433 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2434 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2435 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2436 case LyXRC::RC_PRINTCOPIESFLAG:
2437 case LyXRC::RC_PRINTER:
2438 case LyXRC::RC_PRINTEVENPAGEFLAG:
2439 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2440 case LyXRC::RC_PRINTFILEEXTENSION:
2441 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2442 case LyXRC::RC_PRINTODDPAGEFLAG:
2443 case LyXRC::RC_PRINTPAGERANGEFLAG:
2444 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2445 case LyXRC::RC_PRINTPAPERFLAG:
2446 case LyXRC::RC_PRINTREVERSEFLAG:
2447 case LyXRC::RC_PRINTSPOOL_COMMAND:
2448 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2449 case LyXRC::RC_PRINTTOFILE:
2450 case LyXRC::RC_PRINTTOPRINTER:
2451 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2452 case LyXRC::RC_PRINT_COMMAND:
2453 case LyXRC::RC_RTL_SUPPORT:
2454 case LyXRC::RC_SCREEN_DPI:
2455 case LyXRC::RC_SCREEN_FONT_ROMAN:
2456 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2457 case LyXRC::RC_SCREEN_FONT_SANS:
2458 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2459 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2460 case LyXRC::RC_SCREEN_FONT_SIZES:
2461 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2462 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2463 case LyXRC::RC_SCREEN_GEOMETRY_HEIGHT:
2464 case LyXRC::RC_SCREEN_GEOMETRY_WIDTH:
2465 case LyXRC::RC_SCREEN_GEOMETRY_XYSAVED:
2466 case LyXRC::RC_SCREEN_ZOOM:
2467 case LyXRC::RC_SERVERPIPE:
2468 case LyXRC::RC_SET_COLOR:
2469 case LyXRC::RC_SHOW_BANNER:
2470 case LyXRC::RC_SPELL_COMMAND:
2471 case LyXRC::RC_TEMPDIRPATH:
2472 case LyXRC::RC_TEMPLATEPATH:
2473 case LyXRC::RC_TEX_ALLOWS_SPACES:
2474 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2475 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2476 support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2478 case LyXRC::RC_UIFILE:
2479 case LyXRC::RC_USER_EMAIL:
2480 case LyXRC::RC_USER_NAME:
2481 case LyXRC::RC_USETEMPDIR:
2482 case LyXRC::RC_USE_ALT_LANG:
2483 case LyXRC::RC_USE_CONVERTER_CACHE:
2484 case LyXRC::RC_USE_ESC_CHARS:
2485 case LyXRC::RC_USE_INP_ENC:
2486 case LyXRC::RC_USE_PERS_DICT:
2487 case LyXRC::RC_USE_SPELL_LIB:
2488 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2489 case LyXRC::RC_VIEWER:
2490 case LyXRC::RC_LAST: