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"
34 #include "CutAndPaste.h"
36 #include "DispatchResult.h"
38 #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(KeySequence::Portable)) << ']'
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(KeySequence::ForGui));
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 || buf->isExportable(to_utf8(cmd.argument()));
515 case LFUN_BUFFER_CHKTEX:
516 enable = buf->isLatex() && !lyxrc.chktex_command.empty();
519 case LFUN_BUILD_PROGRAM:
520 enable = buf->isExportable("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 = buf->isExportable("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);
673 std::string name(to_utf8(cmd.argument()));
674 if (LyX::ref().topLevelCmdDef().lock(name, func)) {
675 func.origin = cmd.origin;
676 flag = getStatus(func);
677 LyX::ref().topLevelCmdDef().release(name);
679 // catch recursion or unknown command definiton
680 // all operations until the recursion or unknown command
681 // definiton occures are performed, so set the state to enabled
687 case LFUN_BUFFER_NEW:
688 case LFUN_BUFFER_NEW_TEMPLATE:
689 case LFUN_WORD_FIND_FORWARD:
690 case LFUN_WORD_FIND_BACKWARD:
691 case LFUN_COMMAND_PREFIX:
692 case LFUN_COMMAND_EXECUTE:
694 case LFUN_META_PREFIX:
695 case LFUN_BUFFER_CLOSE:
696 case LFUN_BUFFER_WRITE_AS:
697 case LFUN_BUFFER_UPDATE:
698 case LFUN_BUFFER_VIEW:
699 case LFUN_MASTER_BUFFER_UPDATE:
700 case LFUN_MASTER_BUFFER_VIEW:
701 case LFUN_BUFFER_IMPORT:
702 case LFUN_BUFFER_AUTO_SAVE:
703 case LFUN_RECONFIGURE:
707 case LFUN_DROP_LAYOUTS_CHOICE:
709 case LFUN_SERVER_GET_NAME:
710 case LFUN_SERVER_NOTIFY:
711 case LFUN_SERVER_GOTO_FILE_ROW:
712 case LFUN_DIALOG_HIDE:
713 case LFUN_DIALOG_DISCONNECT_INSET:
714 case LFUN_BUFFER_CHILD_OPEN:
715 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
716 case LFUN_KEYMAP_OFF:
717 case LFUN_KEYMAP_PRIMARY:
718 case LFUN_KEYMAP_SECONDARY:
719 case LFUN_KEYMAP_TOGGLE:
721 case LFUN_BUFFER_EXPORT_CUSTOM:
722 case LFUN_BUFFER_PRINT:
723 case LFUN_PREFERENCES_SAVE:
724 case LFUN_SCREEN_FONT_UPDATE:
727 case LFUN_EXTERNAL_EDIT:
728 case LFUN_GRAPHICS_EDIT:
729 case LFUN_ALL_INSETS_TOGGLE:
730 case LFUN_BUFFER_LANGUAGE:
731 case LFUN_TEXTCLASS_APPLY:
732 case LFUN_TEXTCLASS_LOAD:
733 case LFUN_BUFFER_SAVE_AS_DEFAULT:
734 case LFUN_BUFFER_PARAMS_APPLY:
735 case LFUN_LAYOUT_MODULES_CLEAR:
736 case LFUN_LAYOUT_MODULE_ADD:
737 case LFUN_LAYOUT_RELOAD:
738 case LFUN_LYXRC_APPLY:
739 case LFUN_BUFFER_NEXT:
740 case LFUN_BUFFER_PREVIOUS:
741 case LFUN_WINDOW_NEW:
743 // these are handled in our dispatch()
751 if (!getLocalStatus(view()->cursor(), cmd, flag))
752 flag = view()->getStatus(cmd);
758 // Can we use a readonly buffer?
759 if (buf && buf->isReadonly()
760 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
761 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
762 flag.message(from_utf8(N_("Document is read-only")));
766 // Are we in a DELETED change-tracking region?
768 && lookupChangeType(view()->cursor(), true) == Change::DELETED
769 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
770 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
771 flag.message(from_utf8(N_("This portion of the document is deleted.")));
775 // the default error message if we disable the command
776 if (!flag.enabled() && flag.message().empty())
777 flag.message(from_utf8(N_("Command disabled")));
783 bool LyXFunc::ensureBufferClean(BufferView * bv)
785 Buffer & buf = bv->buffer();
789 docstring const file = makeDisplayPath(buf.absFileName(), 30);
790 docstring text = bformat(_("The document %1$s has unsaved "
791 "changes.\n\nDo you want to save "
792 "the document?"), file);
793 int const ret = Alert::prompt(_("Save changed document?"),
794 text, 0, 1, _("&Save"),
798 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
800 return buf.isClean();
806 void showPrintError(string const & name)
808 docstring str = bformat(_("Could not print the document %1$s.\n"
809 "Check that your printer is set up correctly."),
810 makeDisplayPath(name, 50));
811 Alert::error(_("Print document failed"), str);
815 void loadTextClass(string const & name)
817 std::pair<bool, textclass_type> const tc_pair =
818 textclasslist.numberOfClass(name);
820 if (!tc_pair.first) {
821 lyxerr << "Document class \"" << name
822 << "\" does not exist."
827 textclass_type const tc = tc_pair.second;
829 if (!textclasslist[tc].load()) {
830 docstring s = bformat(_("The document class %1$s."
831 "could not be loaded."),
832 from_utf8(textclasslist[tc].name()));
833 Alert::error(_("Could not load class"), s);
838 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
843 void LyXFunc::dispatch(FuncRequest const & cmd)
845 string const argument = to_utf8(cmd.argument());
846 kb_action const action = cmd.action;
848 LYXERR(Debug::ACTION) << endl << "LyXFunc::dispatch: cmd: " << cmd << endl;
849 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
851 // we have not done anything wrong yet.
853 dispatch_buffer.erase();
855 // redraw the screen at the end (first of the two drawing steps).
856 //This is done unless explicitely requested otherwise
857 Update::flags updateFlags = Update::FitCursor;
859 FuncStatus const flag = getStatus(cmd);
860 if (!flag.enabled()) {
861 // We cannot use this function here
862 LYXERR(Debug::ACTION) << "LyXFunc::dispatch: "
863 << lyxaction.getActionName(action)
864 << " [" << action << "] is disabled at this location"
866 setErrorMessage(flag.message());
870 case LFUN_WORD_FIND_FORWARD:
871 case LFUN_WORD_FIND_BACKWARD: {
872 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
873 static docstring last_search;
874 docstring searched_string;
876 if (!cmd.argument().empty()) {
877 last_search = cmd.argument();
878 searched_string = cmd.argument();
880 searched_string = last_search;
883 if (searched_string.empty())
886 bool const fw = action == LFUN_WORD_FIND_FORWARD;
887 docstring const data =
888 find2string(searched_string, true, false, fw);
889 find(view(), FuncRequest(LFUN_WORD_FIND, data));
893 case LFUN_COMMAND_PREFIX:
894 BOOST_ASSERT(lyx_view_);
895 lyx_view_->message(keyseq.printOptions(true));
898 case LFUN_COMMAND_EXECUTE:
899 BOOST_ASSERT(lyx_view_);
900 lyx_view_->showMiniBuffer(true);
904 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
906 meta_fake_bit = NoModifier;
907 if (lyx_view_->buffer())
908 // cancel any selection
909 dispatch(FuncRequest(LFUN_MARK_OFF));
910 setMessage(from_ascii(N_("Cancel")));
913 case LFUN_META_PREFIX:
914 meta_fake_bit = AltModifier;
915 setMessage(keyseq.print(KeySequence::ForGui));
918 case LFUN_BUFFER_TOGGLE_READ_ONLY: {
919 BOOST_ASSERT(lyx_view_ && lyx_view_->view() && lyx_view_->buffer());
920 Buffer * buf = lyx_view_->buffer();
921 if (buf->lyxvc().inUse())
922 buf->lyxvc().toggleReadOnly();
924 buf->setReadonly(!lyx_view_->buffer()->isReadonly());
928 // --- Menus -----------------------------------------------
929 case LFUN_BUFFER_NEW:
930 menuNew(argument, false);
931 updateFlags = Update::None;
934 case LFUN_BUFFER_NEW_TEMPLATE:
935 menuNew(argument, true);
936 updateFlags = Update::None;
939 case LFUN_BUFFER_CLOSE:
941 updateFlags = Update::None;
944 case LFUN_BUFFER_WRITE:
945 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
946 if (!lyx_view_->buffer()->isUnnamed()) {
947 docstring const str = bformat(_("Saving document %1$s..."),
948 makeDisplayPath(lyx_view_->buffer()->absFileName()));
949 lyx_view_->message(str);
950 lyx_view_->buffer()->menuWrite();
951 lyx_view_->message(str + _(" done."));
953 lyx_view_->buffer()->writeAs();
955 updateFlags = Update::None;
958 case LFUN_BUFFER_WRITE_AS:
959 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
960 lyx_view_->buffer()->writeAs(argument);
961 updateFlags = Update::None;
964 case LFUN_BUFFER_WRITE_ALL: {
965 Buffer * first = theBufferList().first();
968 lyx_view_->message(_("Saving all documents..."));
970 // We cannot use a for loop as the buffer list cycles.
973 if (!b->isUnnamed()) {
975 lyxerr[Debug::ACTION] << "Saved " << b->absFileName() << endl;
979 b = theBufferList().next(b);
980 } while (b != first);
981 lyx_view_->message(_("All documents saved."));
984 updateFlags = Update::None;
988 case LFUN_BUFFER_RELOAD: {
989 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
990 docstring const file = makeDisplayPath(lyx_view_->buffer()->absFileName(), 20);
991 docstring text = bformat(_("Any changes will be lost. Are you sure "
992 "you want to revert to the saved version of the document %1$s?"), file);
993 int const ret = Alert::prompt(_("Revert to saved document?"),
994 text, 1, 1, _("&Revert"), _("&Cancel"));
1001 case LFUN_BUFFER_UPDATE:
1002 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1003 lyx_view_->buffer()->doExport(argument, true);
1006 case LFUN_BUFFER_VIEW:
1007 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1008 lyx_view_->buffer()->preview(argument);
1011 case LFUN_MASTER_BUFFER_UPDATE:
1012 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->masterBuffer());
1013 lyx_view_->buffer()->masterBuffer()->doExport(argument, true);
1016 case LFUN_MASTER_BUFFER_VIEW:
1017 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->masterBuffer());
1018 lyx_view_->buffer()->masterBuffer()->preview(argument);
1021 case LFUN_BUILD_PROGRAM:
1022 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1023 lyx_view_->buffer()->doExport("program", true);
1026 case LFUN_BUFFER_CHKTEX:
1027 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1028 lyx_view_->buffer()->runChktex();
1031 case LFUN_BUFFER_EXPORT:
1032 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1033 if (argument == "custom")
1034 lyx_view_->getDialogs().show("sendto");
1036 lyx_view_->buffer()->doExport(argument, false);
1039 case LFUN_BUFFER_EXPORT_CUSTOM: {
1040 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1042 string command = split(argument, format_name, ' ');
1043 Format const * format = formats.getFormat(format_name);
1045 lyxerr << "Format \"" << format_name
1046 << "\" not recognized!"
1051 Buffer * buffer = lyx_view_->buffer();
1053 // The name of the file created by the conversion process
1056 // Output to filename
1057 if (format->name() == "lyx") {
1058 string const latexname = buffer->latexName(false);
1059 filename = changeExtension(latexname,
1060 format->extension());
1061 filename = addName(buffer->temppath(), filename);
1063 if (!buffer->writeFile(FileName(filename)))
1067 buffer->doExport(format_name, true, filename);
1070 // Substitute $$FName for filename
1071 if (!contains(command, "$$FName"))
1072 command = "( " + command + " ) < $$FName";
1073 command = subst(command, "$$FName", filename);
1075 // Execute the command in the background
1077 call.startscript(Systemcall::DontWait, command);
1081 case LFUN_BUFFER_PRINT: {
1082 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1083 // FIXME: cmd.getArg() might fail if one of the arguments
1084 // contains double quotes
1085 string target = cmd.getArg(0);
1086 string target_name = cmd.getArg(1);
1087 string command = cmd.getArg(2);
1090 || target_name.empty()
1091 || command.empty()) {
1092 lyxerr << "Unable to parse \""
1093 << argument << '"' << endl;
1096 if (target != "printer" && target != "file") {
1097 lyxerr << "Unrecognized target \""
1098 << target << '"' << endl;
1102 Buffer * buffer = lyx_view_->buffer();
1104 if (!buffer->doExport("dvi", true)) {
1105 showPrintError(buffer->absFileName());
1109 // Push directory path.
1110 string const path = buffer->temppath();
1111 // Prevent the compiler from optimizing away p
1113 support::Path p(pp);
1115 // there are three cases here:
1116 // 1. we print to a file
1117 // 2. we print directly to a printer
1118 // 3. we print using a spool command (print to file first)
1121 string const dviname =
1122 changeExtension(buffer->latexName(true), "dvi");
1124 if (target == "printer") {
1125 if (!lyxrc.print_spool_command.empty()) {
1126 // case 3: print using a spool
1127 string const psname =
1128 changeExtension(dviname,".ps");
1129 command += ' ' + lyxrc.print_to_file
1132 + quoteName(dviname);
1135 lyxrc.print_spool_command + ' ';
1136 if (target_name != "default") {
1137 command2 += lyxrc.print_spool_printerprefix
1141 command2 += quoteName(psname);
1143 // If successful, then spool command
1144 res = one.startscript(
1149 res = one.startscript(
1150 Systemcall::DontWait,
1153 // case 2: print directly to a printer
1154 if (target_name != "default")
1155 command += ' ' + lyxrc.print_to_printer + target_name + ' ';
1156 res = one.startscript(
1157 Systemcall::DontWait,
1158 command + quoteName(dviname));
1162 // case 1: print to a file
1163 FileName const filename(makeAbsPath(target_name,
1164 lyx_view_->buffer()->filePath()));
1165 FileName const dvifile(makeAbsPath(dviname, path));
1166 if (filename.exists()) {
1167 docstring text = bformat(
1168 _("The file %1$s already exists.\n\n"
1169 "Do you want to overwrite that file?"),
1170 makeDisplayPath(filename.absFilename()));
1171 if (Alert::prompt(_("Overwrite file?"),
1172 text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
1175 command += ' ' + lyxrc.print_to_file
1176 + quoteName(filename.toFilesystemEncoding())
1178 + quoteName(dvifile.toFilesystemEncoding());
1179 res = one.startscript(Systemcall::DontWait,
1184 showPrintError(buffer->absFileName());
1188 case LFUN_BUFFER_IMPORT:
1193 // quitting is triggered by the gui code
1194 // (leaving the event loop).
1195 lyx_view_->message(from_utf8(N_("Exiting.")));
1196 if (theBufferList().quitWriteAll())
1197 theApp()->gui().closeAllViews();
1200 case LFUN_BUFFER_AUTO_SAVE:
1201 lyx_view_->buffer()->autoSave();
1204 case LFUN_RECONFIGURE:
1205 BOOST_ASSERT(lyx_view_);
1206 // argument is any additional parameter to the configure.py command
1207 reconfigure(*lyx_view_, argument);
1210 case LFUN_HELP_OPEN: {
1211 BOOST_ASSERT(lyx_view_);
1212 string const arg = argument;
1214 setErrorMessage(from_ascii(N_("Missing argument")));
1217 FileName const fname = i18nLibFileSearch("doc", arg, "lyx");
1218 if (fname.empty()) {
1219 lyxerr << "LyX: unable to find documentation file `"
1220 << arg << "'. Bad installation?" << endl;
1223 lyx_view_->message(bformat(_("Opening help file %1$s..."),
1224 makeDisplayPath(fname.absFilename())));
1225 Buffer * buf = lyx_view_->loadLyXFile(fname, false);
1228 lyx_view_->setBuffer(buf);
1229 lyx_view_->showErrorList("Parse");
1231 updateFlags = Update::None;
1235 // --- version control -------------------------------
1236 case LFUN_VC_REGISTER:
1237 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1238 if (!ensureBufferClean(view()))
1240 if (!lyx_view_->buffer()->lyxvc().inUse()) {
1241 lyx_view_->buffer()->lyxvc().registrer();
1244 updateFlags = Update::Force;
1247 case LFUN_VC_CHECK_IN:
1248 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1249 if (!ensureBufferClean(view()))
1251 if (lyx_view_->buffer()->lyxvc().inUse()
1252 && !lyx_view_->buffer()->isReadonly()) {
1253 lyx_view_->buffer()->lyxvc().checkIn();
1258 case LFUN_VC_CHECK_OUT:
1259 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1260 if (!ensureBufferClean(view()))
1262 if (lyx_view_->buffer()->lyxvc().inUse()
1263 && lyx_view_->buffer()->isReadonly()) {
1264 lyx_view_->buffer()->lyxvc().checkOut();
1269 case LFUN_VC_REVERT:
1270 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1271 lyx_view_->buffer()->lyxvc().revert();
1275 case LFUN_VC_UNDO_LAST:
1276 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1277 lyx_view_->buffer()->lyxvc().undoLast();
1281 // --- buffers ----------------------------------------
1282 case LFUN_BUFFER_SWITCH:
1283 BOOST_ASSERT(lyx_view_);
1284 lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1285 updateFlags = Update::None;
1288 case LFUN_BUFFER_NEXT:
1289 BOOST_ASSERT(lyx_view_);
1290 lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer()));
1291 updateFlags = Update::None;
1294 case LFUN_BUFFER_PREVIOUS:
1295 BOOST_ASSERT(lyx_view_);
1296 lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer()));
1297 updateFlags = Update::None;
1300 case LFUN_FILE_NEW: {
1301 BOOST_ASSERT(lyx_view_);
1303 string tmpname = split(argument, name, ':'); // Split filename
1304 Buffer * const b = newFile(name, tmpname);
1306 lyx_view_->setBuffer(b);
1307 updateFlags = Update::None;
1311 case LFUN_FILE_OPEN:
1312 BOOST_ASSERT(lyx_view_);
1314 updateFlags = Update::None;
1317 case LFUN_DROP_LAYOUTS_CHOICE:
1318 BOOST_ASSERT(lyx_view_);
1319 lyx_view_->openLayoutList();
1322 case LFUN_MENU_OPEN:
1323 BOOST_ASSERT(lyx_view_);
1324 lyx_view_->openMenu(from_utf8(argument));
1327 // --- lyxserver commands ----------------------------
1328 case LFUN_SERVER_GET_NAME:
1329 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1330 setMessage(from_utf8(lyx_view_->buffer()->absFileName()));
1331 LYXERR(Debug::INFO) << "FNAME["
1332 << lyx_view_->buffer()->absFileName()
1336 case LFUN_SERVER_NOTIFY:
1337 dispatch_buffer = keyseq.print(KeySequence::Portable);
1338 theServer().notifyClient(to_utf8(dispatch_buffer));
1341 case LFUN_SERVER_GOTO_FILE_ROW: {
1342 BOOST_ASSERT(lyx_view_);
1345 istringstream is(argument);
1346 is >> file_name >> row;
1348 bool loaded = false;
1349 if (prefixIs(file_name, package().temp_dir().absFilename()))
1350 // Needed by inverse dvi search. If it is a file
1351 // in tmpdir, call the apropriated function
1352 buf = theBufferList().getBufferFromTmp(file_name);
1354 // Must replace extension of the file to be .lyx
1355 // and get full path
1356 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1357 // Either change buffer or load the file
1358 if (theBufferList().exists(s.absFilename()))
1359 buf = theBufferList().getBuffer(s.absFilename());
1361 buf = lyx_view_->loadLyXFile(s);
1367 updateFlags = Update::None;
1372 lyx_view_->setBuffer(buf);
1373 view()->setCursorFromRow(row);
1375 lyx_view_->showErrorList("Parse");
1376 updateFlags = Update::FitCursor;
1380 case LFUN_DIALOG_SHOW: {
1381 BOOST_ASSERT(lyx_view_);
1382 string const name = cmd.getArg(0);
1383 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1385 if (name == "character") {
1386 data = freefont2string();
1388 lyx_view_->getDialogs().show("character", data);
1389 } else if (name == "latexlog") {
1390 pair<Buffer::LogType, string> const logfile =
1391 lyx_view_->buffer()->logName();
1392 switch (logfile.first) {
1393 case Buffer::latexlog:
1396 case Buffer::buildlog:
1400 data += Lexer::quoteString(logfile.second);
1401 lyx_view_->getDialogs().show("log", data);
1402 } else if (name == "vclog") {
1403 string const data = "vc " +
1404 Lexer::quoteString(lyx_view_->buffer()->lyxvc().getLogFile());
1405 lyx_view_->getDialogs().show("log", data);
1407 lyx_view_->getDialogs().show(name, data);
1411 case LFUN_DIALOG_SHOW_NEW_INSET: {
1412 BOOST_ASSERT(lyx_view_);
1413 string const name = cmd.getArg(0);
1414 InsetCode code = insetCode(name);
1415 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1416 bool insetCodeOK = true;
1425 case HYPERLINK_CODE: {
1426 InsetCommandParams p(code);
1427 data = InsetCommandMailer::params2string(name, p);
1430 case INCLUDE_CODE: {
1431 // data is the include type: one of "include",
1432 // "input", "verbatiminput" or "verbatiminput*"
1434 // default type is requested
1436 InsetCommandParams p(INCLUDE_CODE, data);
1437 data = InsetIncludeMailer::params2string(p);
1441 // \c data == "Boxed" || "Frameless" etc
1442 InsetBoxParams p(data);
1443 data = InsetBoxMailer::params2string(p);
1447 InsetBranchParams p;
1448 data = InsetBranchMailer::params2string(p);
1452 InsetCommandParams p(CITE_CODE);
1453 data = InsetCommandMailer::params2string(name, p);
1457 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1460 case EXTERNAL_CODE: {
1461 InsetExternalParams p;
1462 Buffer const & buffer = *lyx_view_->buffer();
1463 data = InsetExternalMailer::params2string(p, buffer);
1468 data = InsetFloatMailer::params2string(p);
1471 case LISTINGS_CODE: {
1472 InsetListingsParams p;
1473 data = InsetListingsMailer::params2string(p);
1476 case GRAPHICS_CODE: {
1477 InsetGraphicsParams p;
1478 Buffer const & buffer = *lyx_view_->buffer();
1479 data = InsetGraphicsMailer::params2string(p, buffer);
1484 data = InsetNoteMailer::params2string(p);
1489 data = InsetVSpaceMailer::params2string(space);
1494 data = InsetWrapMailer::params2string(p);
1498 lyxerr << "Inset type '" << name <<
1499 "' not recognized in LFUN_DIALOG_SHOW_NEW_INSET" << std:: endl;
1500 insetCodeOK = false;
1502 } // end switch(code)
1504 lyx_view_->getDialogs().show(name, data, 0);
1508 case LFUN_DIALOG_UPDATE: {
1509 BOOST_ASSERT(lyx_view_);
1510 string const & name = argument;
1511 // Can only update a dialog connected to an existing inset
1512 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1514 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1515 inset->dispatch(view()->cursor(), fr);
1516 } else if (name == "paragraph") {
1517 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1518 } else if (name == "prefs") {
1519 lyx_view_->getDialogs().update(name, string());
1524 case LFUN_DIALOG_HIDE:
1525 LyX::cref().hideDialogs(argument, 0);
1528 case LFUN_DIALOG_TOGGLE: {
1529 BOOST_ASSERT(lyx_view_);
1530 if (lyx_view_->getDialogs().visible(cmd.getArg(0)))
1531 dispatch(FuncRequest(LFUN_DIALOG_HIDE, argument));
1533 dispatch(FuncRequest(LFUN_DIALOG_SHOW, argument));
1537 case LFUN_DIALOG_DISCONNECT_INSET:
1538 BOOST_ASSERT(lyx_view_);
1539 lyx_view_->getDialogs().disconnect(argument);
1543 case LFUN_CITATION_INSERT: {
1544 BOOST_ASSERT(lyx_view_);
1545 if (!argument.empty()) {
1546 // we can have one optional argument, delimited by '|'
1547 // citation-insert <key>|<text_before>
1548 // this should be enhanced to also support text_after
1549 // and citation style
1550 string arg = argument;
1552 if (contains(argument, "|")) {
1553 arg = token(argument, '|', 0);
1554 opt1 = token(argument, '|', 1);
1556 InsetCommandParams icp(CITE_CODE);
1557 icp["key"] = from_utf8(arg);
1559 icp["before"] = from_utf8(opt1);
1560 string icstr = InsetCommandMailer::params2string("citation", icp);
1561 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1564 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1568 case LFUN_BUFFER_CHILD_OPEN: {
1569 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1570 Buffer * parent = lyx_view_->buffer();
1571 FileName filename = makeAbsPath(argument, parent->filePath());
1572 view()->saveBookmark(false);
1574 bool parsed = false;
1575 if (theBufferList().exists(filename.absFilename())) {
1576 child = theBufferList().getBuffer(filename.absFilename());
1578 setMessage(bformat(_("Opening child document %1$s..."),
1579 makeDisplayPath(filename.absFilename())));
1580 child = lyx_view_->loadLyXFile(filename, true);
1584 // Set the parent name of the child document.
1585 // This makes insertion of citations and references in the child work,
1586 // when the target is in the parent or another child document.
1587 child->setParentName(parent->absFileName());
1588 updateLabels(*child->masterBuffer());
1589 lyx_view_->setBuffer(child);
1591 lyx_view_->showErrorList("Parse");
1594 // If a screen update is required (in case where auto_open is false),
1595 // setBuffer() would have taken care of it already. Otherwise we shall
1596 // reset the update flag because it can cause a circular problem.
1598 updateFlags = Update::None;
1602 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1603 BOOST_ASSERT(lyx_view_);
1604 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1607 case LFUN_KEYMAP_OFF:
1608 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1609 lyx_view_->view()->getIntl().keyMapOn(false);
1612 case LFUN_KEYMAP_PRIMARY:
1613 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1614 lyx_view_->view()->getIntl().keyMapPrim();
1617 case LFUN_KEYMAP_SECONDARY:
1618 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1619 lyx_view_->view()->getIntl().keyMapSec();
1622 case LFUN_KEYMAP_TOGGLE:
1623 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1624 lyx_view_->view()->getIntl().toggleKeyMap();
1630 string rest = split(argument, countstr, ' ');
1631 istringstream is(countstr);
1634 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1635 for (int i = 0; i < count; ++i)
1636 dispatch(lyxaction.lookupFunc(rest));
1640 case LFUN_COMMAND_SEQUENCE: {
1641 // argument contains ';'-terminated commands
1642 string arg = argument;
1643 while (!arg.empty()) {
1645 arg = split(arg, first, ';');
1646 FuncRequest func(lyxaction.lookupFunc(first));
1647 func.origin = cmd.origin;
1655 if (LyX::ref().topLevelCmdDef().lock(argument, func)) {
1656 func.origin = cmd.origin;
1658 LyX::ref().topLevelCmdDef().release(argument);
1660 if (func.action == LFUN_UNKNOWN_ACTION) {
1661 // unknown command definition
1662 lyxerr << "Warning: unknown command definition `"
1666 // recursion detected
1667 lyxerr << "Warning: Recursion in the command definition `"
1668 << argument << "' detected"
1675 case LFUN_PREFERENCES_SAVE: {
1676 lyxrc.write(makeAbsPath("preferences",
1677 package().user_support().absFilename()),
1682 case LFUN_SCREEN_FONT_UPDATE:
1683 BOOST_ASSERT(lyx_view_);
1684 // handle the screen font changes.
1685 theFontLoader().update();
1686 /// FIXME: only the current view will be updated. the Gui
1687 /// class is able to furnish the list of views.
1688 updateFlags = Update::Force;
1691 case LFUN_SET_COLOR: {
1693 string const x11_name = split(argument, lyx_name, ' ');
1694 if (lyx_name.empty() || x11_name.empty()) {
1695 setErrorMessage(from_ascii(N_(
1696 "Syntax: set-color <lyx_name>"
1701 bool const graphicsbg_changed =
1702 (lyx_name == lcolor.getLyXName(Color::graphicsbg) &&
1703 x11_name != lcolor.getX11Name(Color::graphicsbg));
1705 if (!lcolor.setColor(lyx_name, x11_name)) {
1707 bformat(_("Set-color \"%1$s\" failed "
1708 "- color is undefined or "
1709 "may not be redefined"),
1710 from_utf8(lyx_name)));
1714 theApp()->updateColor(lcolor.getFromLyXName(lyx_name));
1716 if (graphicsbg_changed) {
1717 // FIXME: The graphics cache no longer has a changeDisplay method.
1719 graphics::GCache::get().changeDisplay(true);
1726 BOOST_ASSERT(lyx_view_);
1727 lyx_view_->message(from_utf8(argument));
1730 case LFUN_EXTERNAL_EDIT: {
1731 BOOST_ASSERT(lyx_view_);
1732 FuncRequest fr(action, argument);
1733 InsetExternal().dispatch(view()->cursor(), fr);
1737 case LFUN_GRAPHICS_EDIT: {
1738 FuncRequest fr(action, argument);
1739 InsetGraphics().dispatch(view()->cursor(), fr);
1743 case LFUN_INSET_APPLY: {
1744 BOOST_ASSERT(lyx_view_);
1745 string const name = cmd.getArg(0);
1746 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1748 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1749 inset->dispatch(view()->cursor(), fr);
1751 FuncRequest fr(LFUN_INSET_INSERT, argument);
1754 // ideally, the update flag should be set by the insets,
1755 // but this is not possible currently
1756 updateFlags = Update::Force | Update::FitCursor;
1760 case LFUN_ALL_INSETS_TOGGLE: {
1761 BOOST_ASSERT(lyx_view_);
1763 string const name = split(argument, action, ' ');
1764 InsetCode const inset_code = insetCode(name);
1766 Cursor & cur = view()->cursor();
1767 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1769 Inset & inset = lyx_view_->buffer()->inset();
1770 InsetIterator it = inset_iterator_begin(inset);
1771 InsetIterator const end = inset_iterator_end(inset);
1772 for (; it != end; ++it) {
1773 if (!it->asInsetMath()
1774 && (inset_code == NO_CODE
1775 || inset_code == it->lyxCode())) {
1776 Cursor tmpcur = cur;
1777 tmpcur.pushLeft(*it);
1778 it->dispatch(tmpcur, fr);
1781 updateFlags = Update::Force | Update::FitCursor;
1785 case LFUN_BUFFER_LANGUAGE: {
1786 BOOST_ASSERT(lyx_view_);
1787 Buffer & buffer = *lyx_view_->buffer();
1788 Language const * oldL = buffer.params().language;
1789 Language const * newL = languages.getLanguage(argument);
1790 if (!newL || oldL == newL)
1793 if (oldL->rightToLeft() == newL->rightToLeft()
1794 && !buffer.isMultiLingual())
1795 buffer.changeLanguage(oldL, newL);
1799 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1800 string const fname =
1801 addName(addPath(package().user_support().absFilename(), "templates/"),
1803 Buffer defaults(fname);
1805 istringstream ss(argument);
1808 int const unknown_tokens = defaults.readHeader(lex);
1810 if (unknown_tokens != 0) {
1811 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1812 << unknown_tokens << " unknown token"
1813 << (unknown_tokens == 1 ? "" : "s")
1817 if (defaults.writeFile(FileName(defaults.absFileName())))
1818 setMessage(bformat(_("Document defaults saved in %1$s"),
1819 makeDisplayPath(fname)));
1821 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1825 case LFUN_BUFFER_PARAMS_APPLY: {
1826 BOOST_ASSERT(lyx_view_);
1827 biblio::CiteEngine const oldEngine =
1828 lyx_view_->buffer()->params().getEngine();
1830 Buffer * buffer = lyx_view_->buffer();
1832 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1834 Cursor & cur = view()->cursor();
1835 cur.recordUndoFullDocument();
1837 istringstream ss(argument);
1840 int const unknown_tokens = buffer->readHeader(lex);
1842 if (unknown_tokens != 0) {
1843 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1844 << unknown_tokens << " unknown token"
1845 << (unknown_tokens == 1 ? "" : "s")
1849 updateLayout(oldClass, buffer);
1851 biblio::CiteEngine const newEngine =
1852 lyx_view_->buffer()->params().getEngine();
1854 if (oldEngine != newEngine) {
1855 FuncRequest fr(LFUN_INSET_REFRESH);
1857 Inset & inset = lyx_view_->buffer()->inset();
1858 InsetIterator it = inset_iterator_begin(inset);
1859 InsetIterator const end = inset_iterator_end(inset);
1860 for (; it != end; ++it)
1861 if (it->lyxCode() == CITE_CODE)
1862 it->dispatch(cur, fr);
1865 updateFlags = Update::Force | Update::FitCursor;
1869 case LFUN_LAYOUT_MODULES_CLEAR: {
1870 BOOST_ASSERT(lyx_view_);
1871 Buffer * buffer = lyx_view_->buffer();
1872 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1873 view()->cursor().recordUndoFullDocument();
1874 buffer->params().clearLayoutModules();
1875 updateLayout(oldClass, buffer);
1876 updateFlags = Update::Force | Update::FitCursor;
1880 case LFUN_LAYOUT_MODULE_ADD: {
1881 BOOST_ASSERT(lyx_view_);
1882 Buffer * buffer = lyx_view_->buffer();
1883 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1884 view()->cursor().recordUndoFullDocument();
1885 buffer->params().addLayoutModule(argument);
1886 updateLayout(oldClass, buffer);
1887 updateFlags = Update::Force | Update::FitCursor;
1891 case LFUN_TEXTCLASS_APPLY: {
1892 BOOST_ASSERT(lyx_view_);
1893 Buffer * buffer = lyx_view_->buffer();
1895 loadTextClass(argument);
1897 std::pair<bool, textclass_type> const tc_pair =
1898 textclasslist.numberOfClass(argument);
1903 textclass_type const old_class = buffer->params().getBaseClass();
1904 textclass_type const new_class = tc_pair.second;
1906 if (old_class == new_class)
1910 //Save the old, possibly modular, layout for use in conversion.
1911 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1912 view()->cursor().recordUndoFullDocument();
1913 buffer->params().setBaseClass(new_class);
1914 updateLayout(oldClass, buffer);
1915 updateFlags = Update::Force | Update::FitCursor;
1919 case LFUN_LAYOUT_RELOAD: {
1920 BOOST_ASSERT(lyx_view_);
1921 Buffer * buffer = lyx_view_->buffer();
1922 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1923 textclass_type const tc = buffer->params().getBaseClass();
1924 textclasslist.reset(tc);
1925 buffer->params().setBaseClass(tc);
1926 updateLayout(oldClass, buffer);
1927 updateFlags = Update::Force | Update::FitCursor;
1931 case LFUN_TEXTCLASS_LOAD:
1932 loadTextClass(argument);
1935 case LFUN_LYXRC_APPLY: {
1936 LyXRC const lyxrc_orig = lyxrc;
1938 istringstream ss(argument);
1939 bool const success = lyxrc.read(ss) == 0;
1942 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1943 << "Unable to read lyxrc data"
1948 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1950 /// We force the redraw in any case because there might be
1951 /// some screen font changes.
1952 /// FIXME: only the current view will be updated. the Gui
1953 /// class is able to furnish the list of views.
1954 updateFlags = Update::Force;
1958 case LFUN_WINDOW_NEW:
1959 LyX::ref().newLyXView();
1962 case LFUN_WINDOW_CLOSE:
1963 BOOST_ASSERT(lyx_view_);
1964 BOOST_ASSERT(theApp());
1965 // update bookmark pit of the current buffer before window close
1966 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1967 gotoBookmark(i+1, false, false);
1968 // ask the user for saving changes or cancel quit
1969 if (!theBufferList().quitWriteAll())
1974 case LFUN_BOOKMARK_GOTO:
1975 // go to bookmark, open unopened file and switch to buffer if necessary
1976 gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
1979 case LFUN_BOOKMARK_CLEAR:
1980 LyX::ref().session().bookmarks().clear();
1983 case LFUN_TOOLBAR_TOGGLE: {
1984 BOOST_ASSERT(lyx_view_);
1985 string const name = cmd.getArg(0);
1986 bool const allowauto = cmd.getArg(1) == "allowauto";
1987 lyx_view_->toggleToolbarState(name, allowauto);
1988 ToolbarInfo * tbi = lyx_view_->getToolbarInfo(name);
1990 setMessage(bformat(_("Unknown toolbar \"%1$s\""),
1995 if (tbi->flags & ToolbarInfo::ON)
1997 else if (tbi->flags & ToolbarInfo::OFF)
1999 else if (tbi->flags & ToolbarInfo::AUTO)
2002 setMessage(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
2003 _(tbi->gui_name), state));
2008 BOOST_ASSERT(lyx_view_);
2009 view()->cursor().dispatch(cmd);
2010 updateFlags = view()->cursor().result().update();
2011 if (!view()->cursor().result().dispatched())
2012 updateFlags = view()->dispatch(cmd);
2017 if (lyx_view_ && lyx_view_->buffer()) {
2018 // BufferView::update() updates the ViewMetricsInfo and
2019 // also initializes the position cache for all insets in
2020 // (at least partially) visible top-level paragraphs.
2021 // We will redraw the screen only if needed.
2022 view()->processUpdateFlags(updateFlags);
2023 lyx_view_->updateStatusBar();
2025 // if we executed a mutating lfun, mark the buffer as dirty
2027 && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
2028 && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
2029 lyx_view_->buffer()->markDirty();
2031 //Do we have a selection?
2032 theSelection().haveSelection(view()->cursor().selection());
2034 if (view()->cursor().inTexted()) {
2035 lyx_view_->updateLayoutChoice();
2039 if (!quitting && lyx_view_) {
2040 lyx_view_->updateToolbars();
2041 // Some messages may already be translated, so we cannot use _()
2042 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
2047 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
2049 const bool verbose = (cmd.origin == FuncRequest::MENU
2050 || cmd.origin == FuncRequest::TOOLBAR
2051 || cmd.origin == FuncRequest::COMMANDBUFFER);
2053 if (cmd.action == LFUN_SELF_INSERT || !verbose) {
2054 LYXERR(Debug::ACTION) << "dispatch msg is " << to_utf8(msg) << endl;
2056 lyx_view_->message(msg);
2060 docstring dispatch_msg = msg;
2061 if (!dispatch_msg.empty())
2062 dispatch_msg += ' ';
2064 docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
2066 bool argsadded = false;
2068 if (!cmd.argument().empty()) {
2069 if (cmd.action != LFUN_UNKNOWN_ACTION) {
2070 comname += ' ' + cmd.argument();
2075 docstring const shortcuts = theTopLevelKeymap().printbindings(cmd);
2077 if (!shortcuts.empty())
2078 comname += ": " + shortcuts;
2079 else if (!argsadded && !cmd.argument().empty())
2080 comname += ' ' + cmd.argument();
2082 if (!comname.empty()) {
2083 comname = rtrim(comname);
2084 dispatch_msg += '(' + rtrim(comname) + ')';
2087 LYXERR(Debug::ACTION) << "verbose dispatch msg "
2088 << to_utf8(dispatch_msg) << endl;
2089 if (!dispatch_msg.empty())
2090 lyx_view_->message(dispatch_msg);
2094 void LyXFunc::menuNew(string const & name, bool fromTemplate)
2096 // FIXME: initpath is not used. What to do?
2097 string initpath = lyxrc.document_path;
2098 string filename(name);
2100 if (lyx_view_->buffer()) {
2101 string const trypath = lyx_view_->buffer()->filePath();
2102 // If directory is writeable, use this as default.
2103 if (FileName(trypath).isDirWritable())
2107 static int newfile_number;
2109 if (filename.empty()) {
2110 filename = addName(lyxrc.document_path,
2111 "newfile" + convert<string>(++newfile_number) + ".lyx");
2112 while (theBufferList().exists(filename) ||
2113 FileName(filename).isReadable()) {
2115 filename = addName(lyxrc.document_path,
2116 "newfile" + convert<string>(newfile_number) +
2121 // The template stuff
2124 FileDialog fileDlg(_("Select template file"),
2125 LFUN_SELECT_FILE_SYNC,
2126 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2127 make_pair(_("Templates|#T#t"), from_utf8(lyxrc.template_path)));
2129 FileDialog::Result result =
2130 fileDlg.open(from_utf8(lyxrc.template_path),
2131 FileFilterList(_("LyX Documents (*.lyx)")),
2134 if (result.first == FileDialog::Later)
2136 if (result.second.empty())
2138 templname = to_utf8(result.second);
2141 Buffer * const b = newFile(filename, templname, !name.empty());
2143 lyx_view_->setBuffer(b);
2147 void LyXFunc::open(string const & fname)
2149 string initpath = lyxrc.document_path;
2151 if (lyx_view_->buffer()) {
2152 string const trypath = lyx_view_->buffer()->filePath();
2153 // If directory is writeable, use this as default.
2154 if (FileName(trypath).isDirWritable())
2160 if (fname.empty()) {
2161 FileDialog fileDlg(_("Select document to open"),
2163 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2164 make_pair(_("Examples|#E#e"), from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2166 FileDialog::Result result =
2167 fileDlg.open(from_utf8(initpath),
2168 FileFilterList(_("LyX Documents (*.lyx)")),
2171 if (result.first == FileDialog::Later)
2174 filename = to_utf8(result.second);
2176 // check selected filename
2177 if (filename.empty()) {
2178 lyx_view_->message(_("Canceled."));
2184 // get absolute path of file and add ".lyx" to the filename if
2186 FileName const fullname = fileSearch(string(), filename, "lyx");
2187 if (!fullname.empty())
2188 filename = fullname.absFilename();
2190 // if the file doesn't exist, let the user create one
2191 if (!fullname.exists()) {
2192 // the user specifically chose this name. Believe him.
2193 Buffer * const b = newFile(filename, string(), true);
2195 lyx_view_->setBuffer(b);
2199 docstring const disp_fn = makeDisplayPath(filename);
2200 lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
2203 Buffer * buf = lyx_view_->loadLyXFile(fullname);
2206 lyx_view_->setBuffer(buf);
2207 lyx_view_->showErrorList("Parse");
2208 str2 = bformat(_("Document %1$s opened."), disp_fn);
2210 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2212 lyx_view_->message(str2);
2216 void LyXFunc::doImport(string const & argument)
2219 string filename = split(argument, format, ' ');
2221 LYXERR(Debug::INFO) << "LyXFunc::doImport: " << format
2222 << " file: " << filename << endl;
2224 // need user interaction
2225 if (filename.empty()) {
2226 string initpath = lyxrc.document_path;
2228 if (lyx_view_->buffer()) {
2229 string const trypath = lyx_view_->buffer()->filePath();
2230 // If directory is writeable, use this as default.
2231 if (FileName(trypath).isDirWritable())
2235 docstring const text = bformat(_("Select %1$s file to import"),
2236 formats.prettyName(format));
2238 FileDialog fileDlg(text,
2240 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2241 make_pair(_("Examples|#E#e"),
2242 from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2244 docstring filter = formats.prettyName(format);
2247 filter += from_utf8(formats.extension(format));
2250 FileDialog::Result result =
2251 fileDlg.open(from_utf8(initpath),
2252 FileFilterList(filter),
2255 if (result.first == FileDialog::Later)
2258 filename = to_utf8(result.second);
2260 // check selected filename
2261 if (filename.empty())
2262 lyx_view_->message(_("Canceled."));
2265 if (filename.empty())
2268 // get absolute path of file
2269 FileName const fullname(makeAbsPath(filename));
2271 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
2273 // Check if the document already is open
2274 if (use_gui && theBufferList().exists(lyxfile.absFilename())) {
2275 if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) {
2276 lyx_view_->message(_("Canceled."));
2281 // if the file exists already, and we didn't do
2282 // -i lyx thefile.lyx, warn
2283 if (lyxfile.exists() && fullname != lyxfile) {
2284 docstring const file = makeDisplayPath(lyxfile.absFilename(), 30);
2286 docstring text = bformat(_("The document %1$s already exists.\n\n"
2287 "Do you want to overwrite that document?"), file);
2288 int const ret = Alert::prompt(_("Overwrite document?"),
2289 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2292 lyx_view_->message(_("Canceled."));
2297 ErrorList errorList;
2298 Importer::Import(lyx_view_, fullname, format, errorList);
2299 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2303 void LyXFunc::closeBuffer()
2305 // goto bookmark to update bookmark pit.
2306 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2307 gotoBookmark(i+1, false, false);
2309 theBufferList().close(lyx_view_->buffer(), true);
2313 void LyXFunc::reloadBuffer()
2315 FileName filename(lyx_view_->buffer()->absFileName());
2316 docstring const disp_fn = makeDisplayPath(filename.absFilename());
2319 Buffer * buf = lyx_view_->loadLyXFile(filename);
2322 lyx_view_->setBuffer(buf);
2323 lyx_view_->showErrorList("Parse");
2324 str = bformat(_("Document %1$s reloaded."), disp_fn);
2326 str = bformat(_("Could not reload document %1$s"), disp_fn);
2328 lyx_view_->message(str);
2331 // Each "lyx_view_" should have it's own message method. lyxview and
2332 // the minibuffer would use the minibuffer, but lyxserver would
2333 // send an ERROR signal to its client. Alejandro 970603
2334 // This function is bit problematic when it comes to NLS, to make the
2335 // lyx servers client be language indepenent we must not translate
2336 // strings sent to this func.
2337 void LyXFunc::setErrorMessage(docstring const & m) const
2339 dispatch_buffer = m;
2344 void LyXFunc::setMessage(docstring const & m) const
2346 dispatch_buffer = m;
2350 docstring const LyXFunc::viewStatusMessage()
2352 // When meta-fake key is pressed, show the key sequence so far + "M-".
2354 return keyseq.print(KeySequence::ForGui) + "M-";
2356 // Else, when a non-complete key sequence is pressed,
2357 // show the available options.
2358 if (keyseq.length() > 0 && !keyseq.deleted())
2359 return keyseq.printOptions(true);
2361 BOOST_ASSERT(lyx_view_);
2362 if (!lyx_view_->buffer())
2363 return _("Welcome to LyX!");
2365 return view()->cursor().currentState();
2369 BufferView * LyXFunc::view() const
2371 BOOST_ASSERT(lyx_view_);
2372 return lyx_view_->view();
2376 bool LyXFunc::wasMetaKey() const
2378 return (meta_fake_bit != NoModifier);
2382 void LyXFunc::updateLayout(TextClassPtr const & oldlayout,
2385 lyx_view_->message(_("Converting document to new document class..."));
2387 StableDocIterator backcur(view()->cursor());
2388 ErrorList & el = buffer->errorList("Class Switch");
2389 cap::switchBetweenClasses(
2390 oldlayout, buffer->params().getTextClassPtr(),
2391 static_cast<InsetText &>(buffer->inset()), el);
2393 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
2395 buffer->errors("Class Switch");
2396 updateLabels(*buffer);
2402 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2404 // Why the switch you might ask. It is a trick to ensure that all
2405 // the elements in the LyXRCTags enum is handled. As you can see
2406 // there are no breaks at all. So it is just a huge fall-through.
2407 // The nice thing is that we will get a warning from the compiler
2408 // if we forget an element.
2409 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2411 case LyXRC::RC_ACCEPT_COMPOUND:
2412 case LyXRC::RC_ALT_LANG:
2413 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
2414 case LyXRC::RC_PLAINTEXT_LINELEN:
2415 case LyXRC::RC_AUTOREGIONDELETE:
2416 case LyXRC::RC_AUTORESET_OPTIONS:
2417 case LyXRC::RC_AUTOSAVE:
2418 case LyXRC::RC_AUTO_NUMBER:
2419 case LyXRC::RC_BACKUPDIR_PATH:
2420 case LyXRC::RC_BIBTEX_COMMAND:
2421 case LyXRC::RC_BINDFILE:
2422 case LyXRC::RC_CHECKLASTFILES:
2423 case LyXRC::RC_USELASTFILEPOS:
2424 case LyXRC::RC_LOADSESSION:
2425 case LyXRC::RC_CHKTEX_COMMAND:
2426 case LyXRC::RC_CONVERTER:
2427 case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
2428 case LyXRC::RC_COPIER:
2429 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2430 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2431 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2432 case LyXRC::RC_DATE_INSERT_FORMAT:
2433 case LyXRC::RC_DEFAULT_LANGUAGE:
2434 case LyXRC::RC_DEFAULT_PAPERSIZE:
2435 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2436 case LyXRC::RC_DISPLAY_GRAPHICS:
2437 case LyXRC::RC_DOCUMENTPATH:
2438 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2439 FileName path(lyxrc_new.document_path);
2440 if (path.exists() && path.isDirectory())
2441 support::package().document_dir() = FileName(lyxrc.document_path);
2443 case LyXRC::RC_ESC_CHARS:
2444 case LyXRC::RC_FONT_ENCODING:
2445 case LyXRC::RC_FORMAT:
2446 case LyXRC::RC_INDEX_COMMAND:
2447 case LyXRC::RC_INPUT:
2448 case LyXRC::RC_KBMAP:
2449 case LyXRC::RC_KBMAP_PRIMARY:
2450 case LyXRC::RC_KBMAP_SECONDARY:
2451 case LyXRC::RC_LABEL_INIT_LENGTH:
2452 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2453 case LyXRC::RC_LANGUAGE_AUTO_END:
2454 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2455 case LyXRC::RC_LANGUAGE_COMMAND_END:
2456 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2457 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2458 case LyXRC::RC_LANGUAGE_PACKAGE:
2459 case LyXRC::RC_LANGUAGE_USE_BABEL:
2460 case LyXRC::RC_MAKE_BACKUP:
2461 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2462 case LyXRC::RC_NUMLASTFILES:
2463 case LyXRC::RC_PATH_PREFIX:
2464 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2465 support::prependEnvPath("PATH", lyxrc.path_prefix);
2467 case LyXRC::RC_PERS_DICT:
2468 case LyXRC::RC_PREVIEW:
2469 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2470 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2471 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2472 case LyXRC::RC_PRINTCOPIESFLAG:
2473 case LyXRC::RC_PRINTER:
2474 case LyXRC::RC_PRINTEVENPAGEFLAG:
2475 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2476 case LyXRC::RC_PRINTFILEEXTENSION:
2477 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2478 case LyXRC::RC_PRINTODDPAGEFLAG:
2479 case LyXRC::RC_PRINTPAGERANGEFLAG:
2480 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2481 case LyXRC::RC_PRINTPAPERFLAG:
2482 case LyXRC::RC_PRINTREVERSEFLAG:
2483 case LyXRC::RC_PRINTSPOOL_COMMAND:
2484 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2485 case LyXRC::RC_PRINTTOFILE:
2486 case LyXRC::RC_PRINTTOPRINTER:
2487 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2488 case LyXRC::RC_PRINT_COMMAND:
2489 case LyXRC::RC_RTL_SUPPORT:
2490 case LyXRC::RC_SCREEN_DPI:
2491 case LyXRC::RC_SCREEN_FONT_ROMAN:
2492 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2493 case LyXRC::RC_SCREEN_FONT_SANS:
2494 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2495 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2496 case LyXRC::RC_SCREEN_FONT_SIZES:
2497 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2498 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2499 case LyXRC::RC_SCREEN_GEOMETRY_HEIGHT:
2500 case LyXRC::RC_SCREEN_GEOMETRY_WIDTH:
2501 case LyXRC::RC_SCREEN_GEOMETRY_XYSAVED:
2502 case LyXRC::RC_SCREEN_ZOOM:
2503 case LyXRC::RC_SERVERPIPE:
2504 case LyXRC::RC_SET_COLOR:
2505 case LyXRC::RC_SHOW_BANNER:
2506 case LyXRC::RC_SPELL_COMMAND:
2507 case LyXRC::RC_TEMPDIRPATH:
2508 case LyXRC::RC_TEMPLATEPATH:
2509 case LyXRC::RC_TEX_ALLOWS_SPACES:
2510 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2511 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2512 support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2514 case LyXRC::RC_UIFILE:
2515 case LyXRC::RC_USER_EMAIL:
2516 case LyXRC::RC_USER_NAME:
2517 case LyXRC::RC_USETEMPDIR:
2518 case LyXRC::RC_USE_ALT_LANG:
2519 case LyXRC::RC_USE_CONVERTER_CACHE:
2520 case LyXRC::RC_USE_ESC_CHARS:
2521 case LyXRC::RC_USE_INP_ENC:
2522 case LyXRC::RC_USE_PERS_DICT:
2523 case LyXRC::RC_USE_SPELL_LIB:
2524 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2525 case LyXRC::RC_VIEWER:
2526 case LyXRC::RC_LAST: