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"
64 #include "insets/InsetBox.h"
65 #include "insets/InsetBranch.h"
66 #include "insets/InsetCommand.h"
67 #include "insets/InsetERT.h"
68 #include "insets/InsetExternal.h"
69 #include "insets/InsetFloat.h"
70 #include "insets/InsetListings.h"
71 #include "insets/InsetGraphics.h"
72 #include "insets/InsetInclude.h"
73 #include "insets/InsetNote.h"
74 #include "insets/InsetTabular.h"
75 #include "insets/InsetVSpace.h"
76 #include "insets/InsetWrap.h"
78 #include "frontends/Application.h"
79 #include "frontends/alert.h"
80 #include "frontends/Dialogs.h"
81 #include "frontends/FileDialog.h"
82 #include "frontends/FontLoader.h"
83 #include "frontends/Gui.h"
84 #include "frontends/KeySymbol.h"
85 #include "frontends/LyXView.h"
86 #include "frontends/Selection.h"
87 #include "frontends/WorkArea.h"
89 #include "support/environment.h"
90 #include "support/FileFilterList.h"
91 #include "support/filetools.h"
92 #include "support/fs_extras.h"
93 #include "support/lstrings.h"
94 #include "support/Path.h"
95 #include "support/Package.h"
96 #include "support/Systemcall.h"
97 #include "support/convert.h"
98 #include "support/os.h"
100 #include <boost/current_function.hpp>
101 #include <boost/filesystem/operations.hpp>
106 using std::make_pair;
109 using std::istringstream;
110 using std::ostringstream;
112 namespace fs = boost::filesystem;
116 using frontend::LyXView;
118 using support::absolutePath;
119 using support::addName;
120 using support::addPath;
121 using support::bformat;
122 using support::changeExtension;
123 using support::contains;
124 using support::FileFilterList;
125 using support::FileName;
126 using support::fileSearch;
127 using support::i18nLibFileSearch;
128 using support::isDirWriteable;
129 using support::isFileReadable;
130 using support::isStrInt;
131 using support::makeAbsPath;
132 using support::makeDisplayPath;
133 using support::package;
134 using support::quoteName;
135 using support::rtrim;
136 using support::split;
137 using support::subst;
138 using support::Systemcall;
139 using support::token;
141 using support::prefixIs;
143 namespace Alert = frontend::Alert;
145 extern bool quitting;
149 // This function runs "configure" and then rereads lyx.defaults to
150 // reconfigure the automatic settings.
151 void reconfigure(LyXView & lv, string const & option)
153 // emit message signal.
154 lv.message(_("Running configure..."));
156 // Run configure in user lyx directory
157 support::Path p(package().user_support());
158 string configure_command = package().configure_command();
159 configure_command += option;
161 one.startscript(Systemcall::Wait, configure_command);
163 // emit message signal.
164 lv.message(_("Reloading configuration..."));
165 lyxrc.read(support::libFileSearch(string(), "lyxrc.defaults"));
166 // Re-read packages.lst
167 LaTeXFeatures::getAvailable();
169 Alert::information(_("System reconfigured"),
170 _("The system has been reconfigured.\n"
171 "You need to restart LyX to make use of any\n"
172 "updated document class specifications."));
176 bool getLocalStatus(Cursor cursor, FuncRequest const & cmd, FuncStatus & status)
178 // Try to fix cursor in case it is broken.
179 cursor.fixIfBroken();
181 // This is, of course, a mess. Better create a new doc iterator and use
182 // this in Inset::getStatus. This might require an additional
183 // BufferView * arg, though (which should be avoided)
184 //Cursor safe = *this;
186 for ( ; cursor.depth(); cursor.pop()) {
187 //lyxerr << "\nCursor::getStatus: cmd: " << cmd << endl << *this << endl;
188 BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
189 BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
190 BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
192 // The inset's getStatus() will return 'true' if it made
193 // a definitive decision on whether it want to handle the
194 // request or not. The result of this decision is put into
195 // the 'status' parameter.
196 if (cursor.inset().getStatus(cursor, cmd, status)) {
205 /** Return the change status at cursor position, taking in account the
206 * status at each level of the document iterator (a table in a deleted
207 * footnote is deleted).
208 * When \param outer is true, the top slice is not looked at.
210 Change::Type lookupChangeType(DocIterator const & dit, bool outer = false)
212 size_t const depth = dit.depth() - (outer ? 1 : 0);
214 for (size_t i = 0 ; i < depth ; ++i) {
215 CursorSlice const & slice = dit[i];
216 if (!slice.inset().inMathed()
217 && slice.pos() < slice.paragraph().size()) {
218 Change::Type const ch = slice.paragraph().lookupChange(slice.pos()).type;
219 if (ch != Change::UNCHANGED)
223 return Change::UNCHANGED;
230 : lyx_view_(0), encoded_last_key(0), meta_fake_bit(NoModifier)
235 void LyXFunc::initKeySequences(KeyMap * kb)
237 keyseq = KeySequence(kb, kb);
238 cancel_meta_seq = KeySequence(kb, kb);
242 void LyXFunc::setLyXView(LyXView * lv)
244 if (!quitting && lyx_view_ && lyx_view_->view() && lyx_view_ != lv)
245 // save current selection to the selection buffer to allow
246 // middle-button paste in another window
247 cap::saveSelection(lyx_view_->view()->cursor());
252 void LyXFunc::handleKeyFunc(kb_action action)
254 char_type c = encoded_last_key;
259 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
260 lyx_view_->view()->getIntl().getTransManager().deadkey(
261 c, get_accent(action).accent, view()->cursor().innerText(), view()->cursor());
262 // Need to clear, in case the minibuffer calls these
265 // copied verbatim from do_accent_char
266 view()->cursor().resetAnchor();
267 view()->processUpdateFlags(Update::FitCursor);
271 void LyXFunc::gotoBookmark(unsigned int idx, bool openFile, bool switchToBuffer)
273 BOOST_ASSERT(lyx_view_);
274 if (!LyX::ref().session().bookmarks().isValid(idx))
276 BookmarksSection::Bookmark const & bm = LyX::ref().session().bookmarks().bookmark(idx);
277 BOOST_ASSERT(!bm.filename.empty());
278 string const file = bm.filename.absFilename();
279 // if the file is not opened, open it.
280 if (!theBufferList().exists(file)) {
282 dispatch(FuncRequest(LFUN_FILE_OPEN, file));
286 // open may fail, so we need to test it again
287 if (!theBufferList().exists(file))
290 // if the current buffer is not that one, switch to it.
291 if (lyx_view_->buffer()->fileName() != file) {
294 dispatch(FuncRequest(LFUN_BUFFER_SWITCH, file));
296 // moveToPosition try paragraph id first and then paragraph (pit, pos).
297 if (!view()->moveToPosition(bm.bottom_pit, bm.bottom_pos,
298 bm.top_id, bm.top_pos))
301 // Cursor jump succeeded!
302 Cursor const & cur = view()->cursor();
303 pit_type new_pit = cur.pit();
304 pos_type new_pos = cur.pos();
305 int new_id = cur.paragraph().id();
307 // if bottom_pit, bottom_pos or top_id has been changed, update bookmark
308 // see http://bugzilla.lyx.org/show_bug.cgi?id=3092
309 if (bm.bottom_pit != new_pit || bm.bottom_pos != new_pos
310 || bm.top_id != new_id) {
311 const_cast<BookmarksSection::Bookmark &>(bm).updatePos(
312 new_pit, new_pos, new_id);
317 void LyXFunc::processKeySym(KeySymbol const & keysym, KeyModifier state)
319 LYXERR(Debug::KEY) << "KeySym is " << keysym.getSymbolName() << endl;
321 // Do nothing if we have nothing (JMarc)
322 if (!keysym.isOK()) {
323 LYXERR(Debug::KEY) << "Empty kbd action (probably composing)"
328 if (keysym.isModifier()) {
329 LYXERR(Debug::KEY) << "isModifier true" << endl;
333 //Encoding const * encoding = view()->cursor().getEncoding();
334 //encoded_last_key = keysym.getISOEncoded(encoding ? encoding->name() : "");
335 // FIXME: encoded_last_key shadows the member variable of the same
336 // name. Is that intended?
337 char_type encoded_last_key = keysym.getUCSEncoded();
339 // Do a one-deep top-level lookup for
340 // cancel and meta-fake keys. RVDK_PATCH_5
341 cancel_meta_seq.reset();
343 FuncRequest func = cancel_meta_seq.addkey(keysym, state);
344 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
345 << " action first set to [" << func.action << ']'
348 // When not cancel or meta-fake, do the normal lookup.
349 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
350 // Mostly, meta_fake_bit = NoModifier. RVDK_PATCH_5.
351 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_PREFIX)) {
352 // remove Caps Lock and Mod2 as a modifiers
353 func = keyseq.addkey(keysym, (state | meta_fake_bit));
354 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
355 << "action now set to ["
356 << func.action << ']' << endl;
359 // Dont remove this unless you know what you are doing.
360 meta_fake_bit = NoModifier;
362 // Can this happen now ?
363 if (func.action == LFUN_NOACTION)
364 func = FuncRequest(LFUN_COMMAND_PREFIX);
366 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
368 << func.action << "]["
369 << to_utf8(keyseq.print(false)) << ']'
372 // already here we know if it any point in going further
373 // why not return already here if action == -1 and
374 // num_bytes == 0? (Lgb)
376 if (keyseq.length() > 1)
377 lyx_view_->message(keyseq.print(true));
380 // Maybe user can only reach the key via holding down shift.
381 // Let's see. But only if shift is the only modifier
382 if (func.action == LFUN_UNKNOWN_ACTION && state == ShiftModifier) {
383 LYXERR(Debug::KEY) << "Trying without shift" << endl;
384 func = keyseq.addkey(keysym, NoModifier);
385 LYXERR(Debug::KEY) << "Action now " << func.action << endl;
388 if (func.action == LFUN_UNKNOWN_ACTION) {
389 // Hmm, we didn't match any of the keysequences. See
390 // if it's normal insertable text not already covered
392 if (keysym.isText() && keyseq.length() == 1) {
393 LYXERR(Debug::KEY) << "isText() is true, inserting." << endl;
394 func = FuncRequest(LFUN_SELF_INSERT,
395 FuncRequest::KEYBOARD);
397 LYXERR(Debug::KEY) << "Unknown, !isText() - giving up" << endl;
398 lyx_view_->message(_("Unknown function."));
403 if (func.action == LFUN_SELF_INSERT) {
404 if (encoded_last_key != 0) {
405 docstring const arg(1, encoded_last_key);
406 dispatch(FuncRequest(LFUN_SELF_INSERT, arg,
407 FuncRequest::KEYBOARD));
409 << "SelfInsert arg[`" << to_utf8(arg) << "']" << endl;
417 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
419 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
422 /* In LyX/Mac, when a dialog is open, the menus of the
423 application can still be accessed without giving focus to
424 the main window. In this case, we want to disable the menu
425 entries that are buffer-related.
427 Note that this code is not perfect, as bug 1941 attests:
428 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
430 Buffer * buf = lyx_view_? lyx_view_->buffer() : 0;
431 if (lyx_view_ && cmd.origin == FuncRequest::MENU && !lyx_view_->hasFocus())
434 if (cmd.action == LFUN_NOACTION) {
435 flag.message(from_utf8(N_("Nothing to do")));
440 switch (cmd.action) {
441 case LFUN_UNKNOWN_ACTION:
442 #ifndef HAVE_LIBAIKSAURUS
443 case LFUN_THESAURUS_ENTRY:
453 if (flag.unknown()) {
454 flag.message(from_utf8(N_("Unknown action")));
458 if (!flag.enabled()) {
459 if (flag.message().empty())
460 flag.message(from_utf8(N_("Command disabled")));
464 // Check whether we need a buffer
465 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
467 flag.message(from_utf8(N_("Command not allowed with"
468 "out any document open")));
473 Cursor * cur = view()? &view()->cursor(): 0;
475 // I would really like to avoid having this switch and rather try to
476 // encode this in the function itself.
477 // -- And I'd rather let an inset decide which LFUNs it is willing
478 // to handle (Andre')
480 switch (cmd.action) {
481 case LFUN_BUFFER_TOGGLE_READ_ONLY:
482 flag.setOnOff(buf->isReadonly());
485 case LFUN_BUFFER_SWITCH:
486 // toggle on the current buffer, but do not toggle off
487 // the other ones (is that a good idea?)
488 if (buf && to_utf8(cmd.argument()) == buf->fileName())
492 case LFUN_BUFFER_EXPORT:
493 enable = cmd.argument() == "custom"
494 || Exporter::isExportable(*buf, to_utf8(cmd.argument()));
497 case LFUN_BUFFER_CHKTEX:
498 enable = buf->isLatex() && !lyxrc.chktex_command.empty();
501 case LFUN_BUILD_PROGRAM:
502 enable = Exporter::isExportable(*buf, "program");
505 case LFUN_LAYOUT_TABULAR:
506 enable = cur? cur->innerInsetOfType(Inset::TABULAR_CODE) : false;
510 case LFUN_LAYOUT_PARAGRAPH:
511 enable = cur? !cur->inset().forceDefaultParagraphs(cur->idx()) : false;
514 case LFUN_VC_REGISTER:
515 enable = !buf->lyxvc().inUse();
517 case LFUN_VC_CHECK_IN:
518 enable = buf->lyxvc().inUse() && !buf->isReadonly();
520 case LFUN_VC_CHECK_OUT:
521 enable = buf->lyxvc().inUse() && buf->isReadonly();
524 case LFUN_VC_UNDO_LAST:
525 enable = buf->lyxvc().inUse();
527 case LFUN_BUFFER_RELOAD:
528 enable = !buf->isUnnamed() && fs::exists(buf->fileName())
529 && (!buf->isClean() || buf->isExternallyModified(Buffer::timestamp_method));
532 case LFUN_INSET_SETTINGS: {
537 Inset::Code code = cur->inset().lyxCode();
539 case Inset::TABULAR_CODE:
540 enable = cmd.argument() == "tabular";
542 case Inset::ERT_CODE:
543 enable = cmd.argument() == "ert";
545 case Inset::FLOAT_CODE:
546 enable = cmd.argument() == "float";
548 case Inset::WRAP_CODE:
549 enable = cmd.argument() == "wrap";
551 case Inset::NOTE_CODE:
552 enable = cmd.argument() == "note";
554 case Inset::BRANCH_CODE:
555 enable = cmd.argument() == "branch";
557 case Inset::BOX_CODE:
558 enable = cmd.argument() == "box";
560 case Inset::LISTINGS_CODE:
561 enable = cmd.argument() == "listings";
569 case LFUN_INSET_APPLY: {
574 string const name = cmd.getArg(0);
575 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
577 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
579 if (!inset->getStatus(*cur, fr, fs)) {
580 // Every inset is supposed to handle this
585 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
586 flag |= getStatus(fr);
588 enable = flag.enabled();
592 case LFUN_DIALOG_TOGGLE:
593 flag.setOnOff(lyx_view_->getDialogs().visible(cmd.getArg(0)));
594 // fall through to set "enable"
595 case LFUN_DIALOG_SHOW: {
600 string const name = cmd.getArg(0);
602 enable = name == "aboutlyx"
603 || name == "file" //FIXME: should be removed.
605 || name == "texinfo";
606 else if (name == "print")
607 enable = Exporter::isExportable(*buf, "dvi")
608 && lyxrc.print_command != "none";
609 else if (name == "character")
610 enable = cur->inset().lyxCode() != Inset::ERT_CODE &&
611 cur->inset().lyxCode() != Inset::LISTINGS_CODE;
612 else if (name == "latexlog")
613 enable = isFileReadable(FileName(buf->getLogName().second));
614 else if (name == "spellchecker")
615 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
616 enable = !buf->isReadonly();
620 else if (name == "vclog")
621 enable = buf->lyxvc().inUse();
625 case LFUN_DIALOG_SHOW_NEW_INSET:
630 enable = cur->inset().lyxCode() != Inset::ERT_CODE &&
631 cur->inset().lyxCode() != Inset::LISTINGS_CODE;
632 if (cur->inset().lyxCode() == Inset::CAPTION_CODE) {
634 if (cur->inset().getStatus(*cur, cmd, flag))
639 case LFUN_DIALOG_UPDATE: {
640 string const name = cmd.getArg(0);
642 enable = name == "prefs";
646 case LFUN_CITATION_INSERT: {
647 FuncRequest fr(LFUN_INSET_INSERT, "citation");
648 enable = getStatus(fr).enabled();
652 case LFUN_BUFFER_WRITE: {
653 enable = lyx_view_->buffer()->isUnnamed()
654 || !lyx_view_->buffer()->isClean();
659 case LFUN_BUFFER_WRITE_ALL: {
660 // We enable the command only if there are some modified buffers
661 Buffer * first = theBufferList().first();
662 bool modified = false;
666 // We cannot use a for loop as the buffer list is a cycle.
672 b = theBufferList().next(b);
673 } while (b != first);
681 case LFUN_BOOKMARK_GOTO: {
682 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
683 enable = LyX::ref().session().bookmarks().isValid(num);
687 case LFUN_BOOKMARK_CLEAR:
688 enable = LyX::ref().session().bookmarks().size() > 0;
691 case LFUN_TOOLBAR_TOGGLE: {
692 bool const current = lyx_view_->isToolbarVisible(cmd.getArg(0));
693 flag.setOnOff(current);
696 case LFUN_WINDOW_CLOSE: {
697 enable = (theApp()->gui().viewIds().size() > 1);
701 // this one is difficult to get right. As a half-baked
702 // solution, we consider only the first action of the sequence
703 case LFUN_COMMAND_SEQUENCE: {
704 // argument contains ';'-terminated commands
705 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
706 FuncRequest func(lyxaction.lookupFunc(firstcmd));
707 func.origin = cmd.origin;
708 flag = getStatus(func);
711 case LFUN_BUFFER_NEW:
712 case LFUN_BUFFER_NEW_TEMPLATE:
713 case LFUN_WORD_FIND_FORWARD:
714 case LFUN_WORD_FIND_BACKWARD:
715 case LFUN_COMMAND_PREFIX:
716 case LFUN_COMMAND_EXECUTE:
718 case LFUN_META_PREFIX:
719 case LFUN_BUFFER_CLOSE:
720 case LFUN_BUFFER_WRITE_AS:
721 case LFUN_BUFFER_UPDATE:
722 case LFUN_BUFFER_VIEW:
723 case LFUN_MASTER_BUFFER_UPDATE:
724 case LFUN_MASTER_BUFFER_VIEW:
725 case LFUN_BUFFER_IMPORT:
726 case LFUN_BUFFER_AUTO_SAVE:
727 case LFUN_RECONFIGURE:
731 case LFUN_DROP_LAYOUTS_CHOICE:
733 case LFUN_SERVER_GET_NAME:
734 case LFUN_SERVER_NOTIFY:
735 case LFUN_SERVER_GOTO_FILE_ROW:
736 case LFUN_DIALOG_HIDE:
737 case LFUN_DIALOG_DISCONNECT_INSET:
738 case LFUN_BUFFER_CHILD_OPEN:
739 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
740 case LFUN_KEYMAP_OFF:
741 case LFUN_KEYMAP_PRIMARY:
742 case LFUN_KEYMAP_SECONDARY:
743 case LFUN_KEYMAP_TOGGLE:
745 case LFUN_BUFFER_EXPORT_CUSTOM:
746 case LFUN_BUFFER_PRINT:
747 case LFUN_PREFERENCES_SAVE:
748 case LFUN_SCREEN_FONT_UPDATE:
751 case LFUN_EXTERNAL_EDIT:
752 case LFUN_GRAPHICS_EDIT:
753 case LFUN_ALL_INSETS_TOGGLE:
754 case LFUN_BUFFER_LANGUAGE:
755 case LFUN_TEXTCLASS_APPLY:
756 case LFUN_TEXTCLASS_LOAD:
757 case LFUN_BUFFER_SAVE_AS_DEFAULT:
758 case LFUN_BUFFER_PARAMS_APPLY:
759 case LFUN_LAYOUT_MODULES_CLEAR:
760 case LFUN_LAYOUT_MODULE_ADD:
761 case LFUN_LAYOUT_RELOAD:
762 case LFUN_LYXRC_APPLY:
763 case LFUN_BUFFER_NEXT:
764 case LFUN_BUFFER_PREVIOUS:
765 case LFUN_WINDOW_NEW:
767 // these are handled in our dispatch()
775 if (!getLocalStatus(*cur, cmd, flag))
776 flag = view()->getStatus(cmd);
782 // Can we use a readonly buffer?
783 if (buf && buf->isReadonly()
784 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
785 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
786 flag.message(from_utf8(N_("Document is read-only")));
790 // Are we in a DELETED change-tracking region?
792 && lookupChangeType(*cur, true) == Change::DELETED
793 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
794 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
795 flag.message(from_utf8(N_("This portion of the document is deleted.")));
799 // the default error message if we disable the command
800 if (!flag.enabled() && flag.message().empty())
801 flag.message(from_utf8(N_("Command disabled")));
807 bool LyXFunc::ensureBufferClean(BufferView * bv)
809 Buffer & buf = bv->buffer();
813 docstring const file = makeDisplayPath(buf.fileName(), 30);
814 docstring text = bformat(_("The document %1$s has unsaved "
815 "changes.\n\nDo you want to save "
816 "the document?"), file);
817 int const ret = Alert::prompt(_("Save changed document?"),
818 text, 0, 1, _("&Save"),
822 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
824 return buf.isClean();
830 void showPrintError(string const & name)
832 docstring str = bformat(_("Could not print the document %1$s.\n"
833 "Check that your printer is set up correctly."),
834 makeDisplayPath(name, 50));
835 Alert::error(_("Print document failed"), str);
839 void loadTextClass(string const & name)
841 std::pair<bool, textclass_type> const tc_pair =
842 textclasslist.numberOfClass(name);
844 if (!tc_pair.first) {
845 lyxerr << "Document class \"" << name
846 << "\" does not exist."
851 textclass_type const tc = tc_pair.second;
853 if (!textclasslist[tc].load()) {
854 docstring s = bformat(_("The document class %1$s."
855 "could not be loaded."),
856 from_utf8(textclasslist[tc].name()));
857 Alert::error(_("Could not load class"), s);
862 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
867 void LyXFunc::dispatch(FuncRequest const & cmd)
869 string const argument = to_utf8(cmd.argument());
870 kb_action const action = cmd.action;
872 LYXERR(Debug::ACTION) << endl << "LyXFunc::dispatch: cmd: " << cmd << endl;
873 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
875 // we have not done anything wrong yet.
877 dispatch_buffer.erase();
879 // redraw the screen at the end (first of the two drawing steps).
880 //This is done unless explicitely requested otherwise
881 Update::flags updateFlags = Update::FitCursor;
883 FuncStatus const flag = getStatus(cmd);
884 if (!flag.enabled()) {
885 // We cannot use this function here
886 LYXERR(Debug::ACTION) << "LyXFunc::dispatch: "
887 << lyxaction.getActionName(action)
888 << " [" << action << "] is disabled at this location"
890 setErrorMessage(flag.message());
894 case LFUN_WORD_FIND_FORWARD:
895 case LFUN_WORD_FIND_BACKWARD: {
896 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
897 static docstring last_search;
898 docstring searched_string;
900 if (!cmd.argument().empty()) {
901 last_search = cmd.argument();
902 searched_string = cmd.argument();
904 searched_string = last_search;
907 if (searched_string.empty())
910 bool const fw = action == LFUN_WORD_FIND_FORWARD;
911 docstring const data =
912 find2string(searched_string, true, false, fw);
913 find(view(), FuncRequest(LFUN_WORD_FIND, data));
917 case LFUN_COMMAND_PREFIX:
918 BOOST_ASSERT(lyx_view_);
919 lyx_view_->message(keyseq.printOptions(true));
922 case LFUN_COMMAND_EXECUTE:
923 BOOST_ASSERT(lyx_view_);
924 lyx_view_->showMiniBuffer(true);
928 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
930 meta_fake_bit = NoModifier;
931 if (lyx_view_->buffer())
932 // cancel any selection
933 dispatch(FuncRequest(LFUN_MARK_OFF));
934 setMessage(from_ascii(N_("Cancel")));
937 case LFUN_META_PREFIX:
938 meta_fake_bit = AltModifier;
939 setMessage(keyseq.print(true));
942 case LFUN_BUFFER_TOGGLE_READ_ONLY: {
943 BOOST_ASSERT(lyx_view_ && lyx_view_->view() && lyx_view_->buffer());
944 Buffer * buf = lyx_view_->buffer();
945 if (buf->lyxvc().inUse())
946 buf->lyxvc().toggleReadOnly();
948 buf->setReadonly(!lyx_view_->buffer()->isReadonly());
952 // --- Menus -----------------------------------------------
953 case LFUN_BUFFER_NEW:
954 menuNew(argument, false);
955 updateFlags = Update::None;
958 case LFUN_BUFFER_NEW_TEMPLATE:
959 menuNew(argument, true);
960 updateFlags = Update::None;
963 case LFUN_BUFFER_CLOSE:
965 updateFlags = Update::None;
968 case LFUN_BUFFER_WRITE:
969 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
970 if (!lyx_view_->buffer()->isUnnamed()) {
971 docstring const str = bformat(_("Saving document %1$s..."),
972 makeDisplayPath(lyx_view_->buffer()->fileName()));
973 lyx_view_->message(str);
974 lyx_view_->buffer()->menuWrite();
975 lyx_view_->message(str + _(" done."));
977 lyx_view_->buffer()->writeAs();
979 updateFlags = Update::None;
982 case LFUN_BUFFER_WRITE_AS:
983 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
984 lyx_view_->buffer()->writeAs(argument);
985 updateFlags = Update::None;
988 case LFUN_BUFFER_WRITE_ALL: {
989 Buffer * first = theBufferList().first();
992 lyx_view_->message(_("Saving all documents..."));
994 // We cannot use a for loop as the buffer list cycles.
997 if (!b->isUnnamed()) {
999 lyxerr[Debug::ACTION] << "Saved " << b->fileName() << endl;
1003 b = theBufferList().next(b);
1004 } while (b != first);
1005 lyx_view_->message(_("All documents saved."));
1008 updateFlags = Update::None;
1012 case LFUN_BUFFER_RELOAD: {
1013 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1014 docstring const file = makeDisplayPath(lyx_view_->buffer()->fileName(), 20);
1015 docstring text = bformat(_("Any changes will be lost. Are you sure "
1016 "you want to revert to the saved version of the document %1$s?"), file);
1017 int const ret = Alert::prompt(_("Revert to saved document?"),
1018 text, 1, 1, _("&Revert"), _("&Cancel"));
1025 case LFUN_BUFFER_UPDATE:
1026 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1027 Exporter::Export(lyx_view_->buffer(), argument, true);
1030 case LFUN_BUFFER_VIEW:
1031 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1032 Exporter::preview(lyx_view_->buffer(), argument);
1035 case LFUN_MASTER_BUFFER_UPDATE:
1036 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->getMasterBuffer());
1037 Exporter::Export(lyx_view_->buffer()->getMasterBuffer(), argument, true);
1040 case LFUN_MASTER_BUFFER_VIEW:
1041 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->getMasterBuffer());
1042 Exporter::preview(lyx_view_->buffer()->getMasterBuffer(), argument);
1045 case LFUN_BUILD_PROGRAM:
1046 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1047 Exporter::Export(lyx_view_->buffer(), "program", true);
1050 case LFUN_BUFFER_CHKTEX:
1051 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1052 lyx_view_->buffer()->runChktex();
1055 case LFUN_BUFFER_EXPORT:
1056 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1057 if (argument == "custom")
1058 lyx_view_->getDialogs().show("sendto");
1060 Exporter::Export(lyx_view_->buffer(), argument, false);
1064 case LFUN_BUFFER_EXPORT_CUSTOM: {
1065 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1067 string command = split(argument, format_name, ' ');
1068 Format const * format = formats.getFormat(format_name);
1070 lyxerr << "Format \"" << format_name
1071 << "\" not recognized!"
1076 Buffer * buffer = lyx_view_->buffer();
1078 // The name of the file created by the conversion process
1081 // Output to filename
1082 if (format->name() == "lyx") {
1083 string const latexname =
1084 buffer->getLatexName(false);
1085 filename = changeExtension(latexname,
1086 format->extension());
1087 filename = addName(buffer->temppath(), filename);
1089 if (!buffer->writeFile(FileName(filename)))
1093 Exporter::Export(buffer, format_name, true, filename);
1096 // Substitute $$FName for filename
1097 if (!contains(command, "$$FName"))
1098 command = "( " + command + " ) < $$FName";
1099 command = subst(command, "$$FName", filename);
1101 // Execute the command in the background
1103 call.startscript(Systemcall::DontWait, command);
1107 case LFUN_BUFFER_PRINT: {
1108 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1109 // FIXME: cmd.getArg() might fail if one of the arguments
1110 // contains double quotes
1111 string target = cmd.getArg(0);
1112 string target_name = cmd.getArg(1);
1113 string command = cmd.getArg(2);
1116 || target_name.empty()
1117 || command.empty()) {
1118 lyxerr << "Unable to parse \""
1119 << argument << '"' << endl;
1122 if (target != "printer" && target != "file") {
1123 lyxerr << "Unrecognized target \""
1124 << target << '"' << endl;
1128 Buffer * buffer = lyx_view_->buffer();
1130 if (!Exporter::Export(buffer, "dvi", true)) {
1131 showPrintError(buffer->fileName());
1135 // Push directory path.
1136 string const path = buffer->temppath();
1137 // Prevent the compiler from optimizing away p
1139 support::Path p(pp);
1141 // there are three cases here:
1142 // 1. we print to a file
1143 // 2. we print directly to a printer
1144 // 3. we print using a spool command (print to file first)
1147 string const dviname =
1148 changeExtension(buffer->getLatexName(true),
1151 if (target == "printer") {
1152 if (!lyxrc.print_spool_command.empty()) {
1153 // case 3: print using a spool
1154 string const psname =
1155 changeExtension(dviname,".ps");
1156 command += ' ' + lyxrc.print_to_file
1159 + quoteName(dviname);
1162 lyxrc.print_spool_command + ' ';
1163 if (target_name != "default") {
1164 command2 += lyxrc.print_spool_printerprefix
1168 command2 += quoteName(psname);
1170 // If successful, then spool command
1171 res = one.startscript(
1176 res = one.startscript(
1177 Systemcall::DontWait,
1180 // case 2: print directly to a printer
1181 if (target_name != "default")
1182 command += ' ' + lyxrc.print_to_printer + target_name + ' ';
1183 res = one.startscript(
1184 Systemcall::DontWait,
1185 command + quoteName(dviname));
1189 // case 1: print to a file
1190 FileName const filename(makeAbsPath(target_name,
1191 lyx_view_->buffer()->filePath()));
1192 FileName const dvifile(makeAbsPath(dviname, path));
1193 if (fs::exists(filename.toFilesystemEncoding())) {
1194 docstring text = bformat(
1195 _("The file %1$s already exists.\n\n"
1196 "Do you want to overwrite that file?"),
1197 makeDisplayPath(filename.absFilename()));
1198 if (Alert::prompt(_("Overwrite file?"),
1199 text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
1202 command += ' ' + lyxrc.print_to_file
1203 + quoteName(filename.toFilesystemEncoding())
1205 + quoteName(dvifile.toFilesystemEncoding());
1206 res = one.startscript(Systemcall::DontWait,
1211 showPrintError(buffer->fileName());
1215 case LFUN_BUFFER_IMPORT:
1220 // quitting is triggered by the gui code
1221 // (leaving the event loop).
1222 lyx_view_->message(from_utf8(N_("Exiting.")));
1223 if (theBufferList().quitWriteAll())
1224 theApp()->gui().closeAllViews();
1227 case LFUN_BUFFER_AUTO_SAVE:
1228 lyx_view_->buffer()->autoSave();
1231 case LFUN_RECONFIGURE:
1232 BOOST_ASSERT(lyx_view_);
1233 // argument is any additional parameter to the configure.py command
1234 reconfigure(*lyx_view_, argument);
1237 case LFUN_HELP_OPEN: {
1238 BOOST_ASSERT(lyx_view_);
1239 string const arg = argument;
1241 setErrorMessage(from_ascii(N_("Missing argument")));
1244 FileName const fname = i18nLibFileSearch("doc", arg, "lyx");
1245 if (fname.empty()) {
1246 lyxerr << "LyX: unable to find documentation file `"
1247 << arg << "'. Bad installation?" << endl;
1250 lyx_view_->message(bformat(_("Opening help file %1$s..."),
1251 makeDisplayPath(fname.absFilename())));
1252 Buffer * buf = lyx_view_->loadLyXFile(fname, false);
1255 lyx_view_->setBuffer(buf);
1256 lyx_view_->showErrorList("Parse");
1258 updateFlags = Update::None;
1262 // --- version control -------------------------------
1263 case LFUN_VC_REGISTER:
1264 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1265 if (!ensureBufferClean(view()))
1267 if (!lyx_view_->buffer()->lyxvc().inUse()) {
1268 lyx_view_->buffer()->lyxvc().registrer();
1271 updateFlags = Update::Force;
1274 case LFUN_VC_CHECK_IN:
1275 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1276 if (!ensureBufferClean(view()))
1278 if (lyx_view_->buffer()->lyxvc().inUse()
1279 && !lyx_view_->buffer()->isReadonly()) {
1280 lyx_view_->buffer()->lyxvc().checkIn();
1285 case LFUN_VC_CHECK_OUT:
1286 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1287 if (!ensureBufferClean(view()))
1289 if (lyx_view_->buffer()->lyxvc().inUse()
1290 && lyx_view_->buffer()->isReadonly()) {
1291 lyx_view_->buffer()->lyxvc().checkOut();
1296 case LFUN_VC_REVERT:
1297 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1298 lyx_view_->buffer()->lyxvc().revert();
1302 case LFUN_VC_UNDO_LAST:
1303 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1304 lyx_view_->buffer()->lyxvc().undoLast();
1308 // --- buffers ----------------------------------------
1309 case LFUN_BUFFER_SWITCH:
1310 BOOST_ASSERT(lyx_view_);
1311 lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1312 updateFlags = Update::None;
1315 case LFUN_BUFFER_NEXT:
1316 BOOST_ASSERT(lyx_view_);
1317 lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer()));
1318 updateFlags = Update::None;
1321 case LFUN_BUFFER_PREVIOUS:
1322 BOOST_ASSERT(lyx_view_);
1323 lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer()));
1324 updateFlags = Update::None;
1327 case LFUN_FILE_NEW: {
1328 BOOST_ASSERT(lyx_view_);
1330 string tmpname = split(argument, name, ':'); // Split filename
1331 Buffer * const b = newFile(name, tmpname);
1333 lyx_view_->setBuffer(b);
1334 updateFlags = Update::None;
1338 case LFUN_FILE_OPEN:
1339 BOOST_ASSERT(lyx_view_);
1341 updateFlags = Update::None;
1344 case LFUN_DROP_LAYOUTS_CHOICE:
1345 BOOST_ASSERT(lyx_view_);
1346 lyx_view_->openLayoutList();
1349 case LFUN_MENU_OPEN:
1350 BOOST_ASSERT(lyx_view_);
1351 lyx_view_->openMenu(from_utf8(argument));
1354 // --- lyxserver commands ----------------------------
1355 case LFUN_SERVER_GET_NAME:
1356 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1357 setMessage(from_utf8(lyx_view_->buffer()->fileName()));
1358 LYXERR(Debug::INFO) << "FNAME["
1359 << lyx_view_->buffer()->fileName()
1363 case LFUN_SERVER_NOTIFY:
1364 dispatch_buffer = keyseq.print(false);
1365 theServer().notifyClient(to_utf8(dispatch_buffer));
1368 case LFUN_SERVER_GOTO_FILE_ROW: {
1369 BOOST_ASSERT(lyx_view_);
1372 istringstream is(argument);
1373 is >> file_name >> row;
1375 bool loaded = false;
1376 if (prefixIs(file_name, package().temp_dir().absFilename()))
1377 // Needed by inverse dvi search. If it is a file
1378 // in tmpdir, call the apropriated function
1379 buf = theBufferList().getBufferFromTmp(file_name);
1381 // Must replace extension of the file to be .lyx
1382 // and get full path
1383 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1384 // Either change buffer or load the file
1385 if (theBufferList().exists(s.absFilename()))
1386 buf = theBufferList().getBuffer(s.absFilename());
1388 buf = lyx_view_->loadLyXFile(s);
1394 updateFlags = Update::None;
1399 lyx_view_->setBuffer(buf);
1400 view()->setCursorFromRow(row);
1402 lyx_view_->showErrorList("Parse");
1403 updateFlags = Update::FitCursor;
1407 case LFUN_DIALOG_SHOW: {
1408 BOOST_ASSERT(lyx_view_);
1409 string const name = cmd.getArg(0);
1410 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1412 if (name == "character") {
1413 data = freefont2string();
1415 lyx_view_->getDialogs().show("character", data);
1416 } else if (name == "latexlog") {
1417 pair<Buffer::LogType, string> const logfile =
1418 lyx_view_->buffer()->getLogName();
1419 switch (logfile.first) {
1420 case Buffer::latexlog:
1423 case Buffer::buildlog:
1427 data += Lexer::quoteString(logfile.second);
1428 lyx_view_->getDialogs().show("log", data);
1429 } else if (name == "vclog") {
1430 string const data = "vc " +
1431 Lexer::quoteString(lyx_view_->buffer()->lyxvc().getLogFile());
1432 lyx_view_->getDialogs().show("log", data);
1434 lyx_view_->getDialogs().show(name, data);
1438 case LFUN_DIALOG_SHOW_NEW_INSET: {
1439 BOOST_ASSERT(lyx_view_);
1440 string const name = cmd.getArg(0);
1441 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1442 if (name == "bibitem" ||
1446 name == "nomenclature" ||
1450 InsetCommandParams p(name);
1451 data = InsetCommandMailer::params2string(name, p);
1452 } else if (name == "include") {
1453 // data is the include type: one of "include",
1454 // "input", "verbatiminput" or "verbatiminput*"
1456 // default type is requested
1458 InsetCommandParams p(data);
1459 data = InsetIncludeMailer::params2string(p);
1460 } else if (name == "box") {
1461 // \c data == "Boxed" || "Frameless" etc
1462 InsetBoxParams p(data);
1463 data = InsetBoxMailer::params2string(p);
1464 } else if (name == "branch") {
1465 InsetBranchParams p;
1466 data = InsetBranchMailer::params2string(p);
1467 } else if (name == "citation") {
1468 InsetCommandParams p("citation");
1469 data = InsetCommandMailer::params2string(name, p);
1470 } else if (name == "ert") {
1471 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1472 } else if (name == "external") {
1473 InsetExternalParams p;
1474 Buffer const & buffer = *lyx_view_->buffer();
1475 data = InsetExternalMailer::params2string(p, buffer);
1476 } else if (name == "float") {
1478 data = InsetFloatMailer::params2string(p);
1479 } else if (name == "listings") {
1480 InsetListingsParams p;
1481 data = InsetListingsMailer::params2string(p);
1482 } else if (name == "graphics") {
1483 InsetGraphicsParams p;
1484 Buffer const & buffer = *lyx_view_->buffer();
1485 data = InsetGraphicsMailer::params2string(p, buffer);
1486 } else if (name == "note") {
1488 data = InsetNoteMailer::params2string(p);
1489 } else if (name == "vspace") {
1491 data = InsetVSpaceMailer::params2string(space);
1492 } else if (name == "wrap") {
1494 data = InsetWrapMailer::params2string(p);
1496 lyx_view_->getDialogs().show(name, data, 0);
1500 case LFUN_DIALOG_UPDATE: {
1501 BOOST_ASSERT(lyx_view_);
1502 string const & name = argument;
1503 // Can only update a dialog connected to an existing inset
1504 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1506 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1507 inset->dispatch(view()->cursor(), fr);
1508 } else if (name == "paragraph") {
1509 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1510 } else if (name == "prefs") {
1511 lyx_view_->getDialogs().update(name, string());
1516 case LFUN_DIALOG_HIDE:
1517 LyX::cref().hideDialogs(argument, 0);
1520 case LFUN_DIALOG_TOGGLE: {
1521 BOOST_ASSERT(lyx_view_);
1522 if (lyx_view_->getDialogs().visible(cmd.getArg(0)))
1523 dispatch(FuncRequest(LFUN_DIALOG_HIDE, argument));
1525 dispatch(FuncRequest(LFUN_DIALOG_SHOW, argument));
1529 case LFUN_DIALOG_DISCONNECT_INSET:
1530 BOOST_ASSERT(lyx_view_);
1531 lyx_view_->getDialogs().disconnect(argument);
1535 case LFUN_CITATION_INSERT: {
1536 BOOST_ASSERT(lyx_view_);
1537 if (!argument.empty()) {
1538 // we can have one optional argument, delimited by '|'
1539 // citation-insert <key>|<text_before>
1540 // this should be enhanced to also support text_after
1541 // and citation style
1542 string arg = argument;
1544 if (contains(argument, "|")) {
1545 arg = token(argument, '|', 0);
1546 opt1 = token(argument, '|', 1);
1548 InsetCommandParams icp("citation");
1549 icp["key"] = from_utf8(arg);
1551 icp["before"] = from_utf8(opt1);
1552 string icstr = InsetCommandMailer::params2string("citation", icp);
1553 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1556 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1560 case LFUN_BUFFER_CHILD_OPEN: {
1561 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1562 Buffer * parent = lyx_view_->buffer();
1563 FileName filename = makeAbsPath(argument, parent->filePath());
1564 view()->saveBookmark(false);
1566 bool parsed = false;
1567 if (theBufferList().exists(filename.absFilename())) {
1568 child = theBufferList().getBuffer(filename.absFilename());
1570 setMessage(bformat(_("Opening child document %1$s..."),
1571 makeDisplayPath(filename.absFilename())));
1572 child = lyx_view_->loadLyXFile(filename, true);
1576 // Set the parent name of the child document.
1577 // This makes insertion of citations and references in the child work,
1578 // when the target is in the parent or another child document.
1579 child->setParentName(parent->fileName());
1580 updateLabels(*child->getMasterBuffer());
1581 lyx_view_->setBuffer(child);
1583 lyx_view_->showErrorList("Parse");
1586 // If a screen update is required (in case where auto_open is false),
1587 // setBuffer() would have taken care of it already. Otherwise we shall
1588 // reset the update flag because it can cause a circular problem.
1590 updateFlags = Update::None;
1594 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1595 BOOST_ASSERT(lyx_view_);
1596 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1599 case LFUN_KEYMAP_OFF:
1600 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1601 lyx_view_->view()->getIntl().keyMapOn(false);
1604 case LFUN_KEYMAP_PRIMARY:
1605 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1606 lyx_view_->view()->getIntl().keyMapPrim();
1609 case LFUN_KEYMAP_SECONDARY:
1610 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1611 lyx_view_->view()->getIntl().keyMapSec();
1614 case LFUN_KEYMAP_TOGGLE:
1615 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1616 lyx_view_->view()->getIntl().toggleKeyMap();
1622 string rest = split(argument, countstr, ' ');
1623 istringstream is(countstr);
1626 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1627 for (int i = 0; i < count; ++i)
1628 dispatch(lyxaction.lookupFunc(rest));
1632 case LFUN_COMMAND_SEQUENCE: {
1633 // argument contains ';'-terminated commands
1634 string arg = argument;
1635 while (!arg.empty()) {
1637 arg = split(arg, first, ';');
1638 FuncRequest func(lyxaction.lookupFunc(first));
1639 func.origin = cmd.origin;
1645 case LFUN_PREFERENCES_SAVE: {
1646 lyxrc.write(makeAbsPath("preferences",
1647 package().user_support().absFilename()),
1652 case LFUN_SCREEN_FONT_UPDATE:
1653 BOOST_ASSERT(lyx_view_);
1654 // handle the screen font changes.
1655 theFontLoader().update();
1656 /// FIXME: only the current view will be updated. the Gui
1657 /// class is able to furnish the list of views.
1658 updateFlags = Update::Force;
1661 case LFUN_SET_COLOR: {
1663 string const x11_name = split(argument, lyx_name, ' ');
1664 if (lyx_name.empty() || x11_name.empty()) {
1665 setErrorMessage(from_ascii(N_(
1666 "Syntax: set-color <lyx_name>"
1671 bool const graphicsbg_changed =
1672 (lyx_name == lcolor.getLyXName(Color::graphicsbg) &&
1673 x11_name != lcolor.getX11Name(Color::graphicsbg));
1675 if (!lcolor.setColor(lyx_name, x11_name)) {
1677 bformat(_("Set-color \"%1$s\" failed "
1678 "- color is undefined or "
1679 "may not be redefined"),
1680 from_utf8(lyx_name)));
1684 theApp()->updateColor(lcolor.getFromLyXName(lyx_name));
1686 if (graphicsbg_changed) {
1687 // FIXME: The graphics cache no longer has a changeDisplay method.
1689 graphics::GCache::get().changeDisplay(true);
1696 BOOST_ASSERT(lyx_view_);
1697 lyx_view_->message(from_utf8(argument));
1700 case LFUN_EXTERNAL_EDIT: {
1701 BOOST_ASSERT(lyx_view_);
1702 FuncRequest fr(action, argument);
1703 InsetExternal().dispatch(view()->cursor(), fr);
1707 case LFUN_GRAPHICS_EDIT: {
1708 FuncRequest fr(action, argument);
1709 InsetGraphics().dispatch(view()->cursor(), fr);
1713 case LFUN_INSET_APPLY: {
1714 BOOST_ASSERT(lyx_view_);
1715 string const name = cmd.getArg(0);
1716 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1718 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1719 inset->dispatch(view()->cursor(), fr);
1721 FuncRequest fr(LFUN_INSET_INSERT, argument);
1724 // ideally, the update flag should be set by the insets,
1725 // but this is not possible currently
1726 updateFlags = Update::Force | Update::FitCursor;
1730 case LFUN_ALL_INSETS_TOGGLE: {
1731 BOOST_ASSERT(lyx_view_);
1733 string const name = split(argument, action, ' ');
1734 Inset::Code const inset_code =
1735 Inset::translate(name);
1737 Cursor & cur = view()->cursor();
1738 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1740 Inset & inset = lyx_view_->buffer()->inset();
1741 InsetIterator it = inset_iterator_begin(inset);
1742 InsetIterator const end = inset_iterator_end(inset);
1743 for (; it != end; ++it) {
1744 if (!it->asInsetMath()
1745 && (inset_code == Inset::NO_CODE
1746 || inset_code == it->lyxCode())) {
1747 Cursor tmpcur = cur;
1748 tmpcur.pushLeft(*it);
1749 it->dispatch(tmpcur, fr);
1752 updateFlags = Update::Force | Update::FitCursor;
1756 case LFUN_BUFFER_LANGUAGE: {
1757 BOOST_ASSERT(lyx_view_);
1758 Buffer & buffer = *lyx_view_->buffer();
1759 Language const * oldL = buffer.params().language;
1760 Language const * newL = languages.getLanguage(argument);
1761 if (!newL || oldL == newL)
1764 if (oldL->rightToLeft() == newL->rightToLeft()
1765 && !buffer.isMultiLingual())
1766 buffer.changeLanguage(oldL, newL);
1770 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1771 string const fname =
1772 addName(addPath(package().user_support().absFilename(), "templates/"),
1774 Buffer defaults(fname);
1776 istringstream ss(argument);
1779 int const unknown_tokens = defaults.readHeader(lex);
1781 if (unknown_tokens != 0) {
1782 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1783 << unknown_tokens << " unknown token"
1784 << (unknown_tokens == 1 ? "" : "s")
1788 if (defaults.writeFile(FileName(defaults.fileName())))
1789 setMessage(bformat(_("Document defaults saved in %1$s"),
1790 makeDisplayPath(fname)));
1792 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1796 case LFUN_BUFFER_PARAMS_APPLY: {
1797 BOOST_ASSERT(lyx_view_);
1798 biblio::CiteEngine const oldEngine =
1799 lyx_view_->buffer()->params().getEngine();
1801 Buffer * buffer = lyx_view_->buffer();
1803 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1804 recordUndoFullDocument(view());
1806 istringstream ss(argument);
1809 int const unknown_tokens = buffer->readHeader(lex);
1811 if (unknown_tokens != 0) {
1812 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1813 << unknown_tokens << " unknown token"
1814 << (unknown_tokens == 1 ? "" : "s")
1818 updateLayout(oldClass, buffer);
1820 biblio::CiteEngine const newEngine =
1821 lyx_view_->buffer()->params().getEngine();
1823 if (oldEngine != newEngine) {
1824 Cursor & cur = view()->cursor();
1825 FuncRequest fr(LFUN_INSET_REFRESH);
1827 Inset & inset = lyx_view_->buffer()->inset();
1828 InsetIterator it = inset_iterator_begin(inset);
1829 InsetIterator const end = inset_iterator_end(inset);
1830 for (; it != end; ++it)
1831 if (it->lyxCode() == Inset::CITE_CODE)
1832 it->dispatch(cur, fr);
1835 updateFlags = Update::Force | Update::FitCursor;
1839 case LFUN_LAYOUT_MODULES_CLEAR: {
1840 BOOST_ASSERT(lyx_view_);
1841 Buffer * buffer = lyx_view_->buffer();
1842 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1843 recordUndoFullDocument(view());
1844 buffer->params().clearLayoutModules();
1845 updateLayout(oldClass, buffer);
1846 updateFlags = Update::Force | Update::FitCursor;
1850 case LFUN_LAYOUT_MODULE_ADD: {
1851 BOOST_ASSERT(lyx_view_);
1852 Buffer * buffer = lyx_view_->buffer();
1853 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1854 recordUndoFullDocument(view());
1855 buffer->params().addLayoutModule(argument);
1856 updateLayout(oldClass, buffer);
1857 updateFlags = Update::Force | Update::FitCursor;
1861 case LFUN_TEXTCLASS_APPLY: {
1862 BOOST_ASSERT(lyx_view_);
1863 Buffer * buffer = lyx_view_->buffer();
1865 loadTextClass(argument);
1867 std::pair<bool, textclass_type> const tc_pair =
1868 textclasslist.numberOfClass(argument);
1873 textclass_type const old_class = buffer->params().getBaseClass();
1874 textclass_type const new_class = tc_pair.second;
1876 if (old_class == new_class)
1880 //Save the old, possibly modular, layout for use in conversion.
1881 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1882 recordUndoFullDocument(view());
1883 buffer->params().setBaseClass(new_class);
1884 updateLayout(oldClass, buffer);
1885 updateFlags = Update::Force | Update::FitCursor;
1889 case LFUN_LAYOUT_RELOAD: {
1890 BOOST_ASSERT(lyx_view_);
1891 Buffer * buffer = lyx_view_->buffer();
1892 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1893 textclass_type const tc = buffer->params().getBaseClass();
1894 textclasslist.reset(tc);
1895 buffer->params().setBaseClass(tc);
1896 updateLayout(oldClass, buffer);
1897 updateFlags = Update::Force | Update::FitCursor;
1901 case LFUN_TEXTCLASS_LOAD:
1902 loadTextClass(argument);
1905 case LFUN_LYXRC_APPLY: {
1906 LyXRC const lyxrc_orig = lyxrc;
1908 istringstream ss(argument);
1909 bool const success = lyxrc.read(ss) == 0;
1912 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1913 << "Unable to read lyxrc data"
1918 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1920 /// We force the redraw in any case because there might be
1921 /// some screen font changes.
1922 /// FIXME: only the current view will be updated. the Gui
1923 /// class is able to furnish the list of views.
1924 updateFlags = Update::Force;
1928 case LFUN_WINDOW_NEW:
1929 LyX::ref().newLyXView();
1932 case LFUN_WINDOW_CLOSE:
1933 BOOST_ASSERT(lyx_view_);
1934 BOOST_ASSERT(theApp());
1935 // update bookmark pit of the current buffer before window close
1936 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1937 gotoBookmark(i+1, false, false);
1938 // ask the user for saving changes or cancel quit
1939 if (!theBufferList().quitWriteAll())
1944 case LFUN_BOOKMARK_GOTO:
1945 // go to bookmark, open unopened file and switch to buffer if necessary
1946 gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
1949 case LFUN_BOOKMARK_CLEAR:
1950 LyX::ref().session().bookmarks().clear();
1953 case LFUN_TOOLBAR_TOGGLE: {
1954 BOOST_ASSERT(lyx_view_);
1955 string const name = cmd.getArg(0);
1956 bool const allowauto = cmd.getArg(1) == "allowauto";
1957 lyx_view_->toggleToolbarState(name, allowauto);
1958 ToolbarInfo * tbi = lyx_view_->getToolbarInfo(name);
1960 setMessage(bformat(_("Unknown toolbar \"%1$s\""),
1965 if (tbi->flags & ToolbarInfo::ON)
1967 else if (tbi->flags & ToolbarInfo::OFF)
1969 else if (tbi->flags & ToolbarInfo::AUTO)
1972 setMessage(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1973 _(tbi->gui_name), state));
1978 BOOST_ASSERT(lyx_view_);
1979 view()->cursor().dispatch(cmd);
1980 updateFlags = view()->cursor().result().update();
1981 if (!view()->cursor().result().dispatched())
1982 updateFlags = view()->dispatch(cmd);
1987 if (lyx_view_ && lyx_view_->buffer()) {
1988 // BufferView::update() updates the ViewMetricsInfo and
1989 // also initializes the position cache for all insets in
1990 // (at least partially) visible top-level paragraphs.
1991 // We will redraw the screen only if needed.
1992 view()->processUpdateFlags(updateFlags);
1993 lyx_view_->updateStatusBar();
1995 // if we executed a mutating lfun, mark the buffer as dirty
1997 && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
1998 && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
1999 lyx_view_->buffer()->markDirty();
2001 //Do we have a selection?
2002 theSelection().haveSelection(view()->cursor().selection());
2004 if (view()->cursor().inTexted()) {
2005 lyx_view_->updateLayoutChoice();
2009 if (!quitting && lyx_view_) {
2010 lyx_view_->updateToolbars();
2011 // Some messages may already be translated, so we cannot use _()
2012 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
2017 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
2019 const bool verbose = (cmd.origin == FuncRequest::MENU
2020 || cmd.origin == FuncRequest::TOOLBAR
2021 || cmd.origin == FuncRequest::COMMANDBUFFER);
2023 if (cmd.action == LFUN_SELF_INSERT || !verbose) {
2024 LYXERR(Debug::ACTION) << "dispatch msg is " << to_utf8(msg) << endl;
2026 lyx_view_->message(msg);
2030 docstring dispatch_msg = msg;
2031 if (!dispatch_msg.empty())
2032 dispatch_msg += ' ';
2034 docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
2036 bool argsadded = false;
2038 if (!cmd.argument().empty()) {
2039 if (cmd.action != LFUN_UNKNOWN_ACTION) {
2040 comname += ' ' + cmd.argument();
2045 docstring const shortcuts = theTopLevelKeymap().printbindings(cmd);
2047 if (!shortcuts.empty())
2048 comname += ": " + shortcuts;
2049 else if (!argsadded && !cmd.argument().empty())
2050 comname += ' ' + cmd.argument();
2052 if (!comname.empty()) {
2053 comname = rtrim(comname);
2054 dispatch_msg += '(' + rtrim(comname) + ')';
2057 LYXERR(Debug::ACTION) << "verbose dispatch msg "
2058 << to_utf8(dispatch_msg) << endl;
2059 if (!dispatch_msg.empty())
2060 lyx_view_->message(dispatch_msg);
2064 void LyXFunc::menuNew(string const & name, bool fromTemplate)
2066 // FIXME: initpath is not used. What to do?
2067 string initpath = lyxrc.document_path;
2068 string filename(name);
2070 if (lyx_view_->buffer()) {
2071 string const trypath = lyx_view_->buffer()->filePath();
2072 // If directory is writeable, use this as default.
2073 if (isDirWriteable(FileName(trypath)))
2077 static int newfile_number;
2079 if (filename.empty()) {
2080 filename = addName(lyxrc.document_path,
2081 "newfile" + convert<string>(++newfile_number) + ".lyx");
2082 while (theBufferList().exists(filename) ||
2083 fs::is_readable(FileName(filename).toFilesystemEncoding())) {
2085 filename = addName(lyxrc.document_path,
2086 "newfile" + convert<string>(newfile_number) +
2091 // The template stuff
2094 FileDialog fileDlg(_("Select template file"),
2095 LFUN_SELECT_FILE_SYNC,
2096 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2097 make_pair(_("Templates|#T#t"), from_utf8(lyxrc.template_path)));
2099 FileDialog::Result result =
2100 fileDlg.open(from_utf8(lyxrc.template_path),
2101 FileFilterList(_("LyX Documents (*.lyx)")),
2104 if (result.first == FileDialog::Later)
2106 if (result.second.empty())
2108 templname = to_utf8(result.second);
2111 Buffer * const b = newFile(filename, templname, !name.empty());
2113 lyx_view_->setBuffer(b);
2117 void LyXFunc::open(string const & fname)
2119 string initpath = lyxrc.document_path;
2121 if (lyx_view_->buffer()) {
2122 string const trypath = lyx_view_->buffer()->filePath();
2123 // If directory is writeable, use this as default.
2124 if (isDirWriteable(FileName(trypath)))
2130 if (fname.empty()) {
2131 FileDialog fileDlg(_("Select document to open"),
2133 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2134 make_pair(_("Examples|#E#e"), from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2136 FileDialog::Result result =
2137 fileDlg.open(from_utf8(initpath),
2138 FileFilterList(_("LyX Documents (*.lyx)")),
2141 if (result.first == FileDialog::Later)
2144 filename = to_utf8(result.second);
2146 // check selected filename
2147 if (filename.empty()) {
2148 lyx_view_->message(_("Canceled."));
2154 // get absolute path of file and add ".lyx" to the filename if
2156 FileName const fullname = fileSearch(string(), filename, "lyx");
2157 if (!fullname.empty())
2158 filename = fullname.absFilename();
2160 // if the file doesn't exist, let the user create one
2161 if (!fs::exists(fullname.toFilesystemEncoding())) {
2162 // the user specifically chose this name. Believe him.
2163 Buffer * const b = newFile(filename, string(), true);
2165 lyx_view_->setBuffer(b);
2169 docstring const disp_fn = makeDisplayPath(filename);
2170 lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
2173 Buffer * buf = lyx_view_->loadLyXFile(fullname);
2176 lyx_view_->setBuffer(buf);
2177 lyx_view_->showErrorList("Parse");
2178 str2 = bformat(_("Document %1$s opened."), disp_fn);
2180 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2182 lyx_view_->message(str2);
2186 void LyXFunc::doImport(string const & argument)
2189 string filename = split(argument, format, ' ');
2191 LYXERR(Debug::INFO) << "LyXFunc::doImport: " << format
2192 << " file: " << filename << endl;
2194 // need user interaction
2195 if (filename.empty()) {
2196 string initpath = lyxrc.document_path;
2198 if (lyx_view_->buffer()) {
2199 string const trypath = lyx_view_->buffer()->filePath();
2200 // If directory is writeable, use this as default.
2201 if (isDirWriteable(FileName(trypath)))
2205 docstring const text = bformat(_("Select %1$s file to import"),
2206 formats.prettyName(format));
2208 FileDialog fileDlg(text,
2210 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2211 make_pair(_("Examples|#E#e"),
2212 from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2214 docstring filter = formats.prettyName(format);
2217 filter += from_utf8(formats.extension(format));
2220 FileDialog::Result result =
2221 fileDlg.open(from_utf8(initpath),
2222 FileFilterList(filter),
2225 if (result.first == FileDialog::Later)
2228 filename = to_utf8(result.second);
2230 // check selected filename
2231 if (filename.empty())
2232 lyx_view_->message(_("Canceled."));
2235 if (filename.empty())
2238 // get absolute path of file
2239 FileName const fullname(makeAbsPath(filename));
2241 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
2243 // Check if the document already is open
2244 if (use_gui && theBufferList().exists(lyxfile.absFilename())) {
2245 if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) {
2246 lyx_view_->message(_("Canceled."));
2251 // if the file exists already, and we didn't do
2252 // -i lyx thefile.lyx, warn
2253 if (fs::exists(lyxfile.toFilesystemEncoding()) && fullname != lyxfile) {
2254 docstring const file = makeDisplayPath(lyxfile.absFilename(), 30);
2256 docstring text = bformat(_("The document %1$s already exists.\n\n"
2257 "Do you want to overwrite that document?"), file);
2258 int const ret = Alert::prompt(_("Overwrite document?"),
2259 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2262 lyx_view_->message(_("Canceled."));
2267 ErrorList errorList;
2268 Importer::Import(lyx_view_, fullname, format, errorList);
2269 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2273 void LyXFunc::closeBuffer()
2275 // goto bookmark to update bookmark pit.
2276 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2277 gotoBookmark(i+1, false, false);
2279 theBufferList().close(lyx_view_->buffer(), true);
2283 void LyXFunc::reloadBuffer()
2285 FileName filename(lyx_view_->buffer()->fileName());
2286 docstring const disp_fn = makeDisplayPath(filename.absFilename());
2289 Buffer * buf = lyx_view_->loadLyXFile(filename);
2292 lyx_view_->setBuffer(buf);
2293 lyx_view_->showErrorList("Parse");
2294 str = bformat(_("Document %1$s reloaded."), disp_fn);
2296 str = bformat(_("Could not reload document %1$s"), disp_fn);
2298 lyx_view_->message(str);
2301 // Each "lyx_view_" should have it's own message method. lyxview and
2302 // the minibuffer would use the minibuffer, but lyxserver would
2303 // send an ERROR signal to its client. Alejandro 970603
2304 // This function is bit problematic when it comes to NLS, to make the
2305 // lyx servers client be language indepenent we must not translate
2306 // strings sent to this func.
2307 void LyXFunc::setErrorMessage(docstring const & m) const
2309 dispatch_buffer = m;
2314 void LyXFunc::setMessage(docstring const & m) const
2316 dispatch_buffer = m;
2320 docstring const LyXFunc::viewStatusMessage()
2322 // When meta-fake key is pressed, show the key sequence so far + "M-".
2324 return keyseq.print(true) + "M-";
2326 // Else, when a non-complete key sequence is pressed,
2327 // show the available options.
2328 if (keyseq.length() > 0 && !keyseq.deleted())
2329 return keyseq.printOptions(true);
2331 BOOST_ASSERT(lyx_view_);
2332 if (!lyx_view_->buffer())
2333 return _("Welcome to LyX!");
2335 return view()->cursor().currentState();
2339 BufferView * LyXFunc::view() const
2341 BOOST_ASSERT(lyx_view_);
2342 return lyx_view_->view();
2346 bool LyXFunc::wasMetaKey() const
2348 return (meta_fake_bit != NoModifier);
2352 void LyXFunc::updateLayout(TextClassPtr const & oldlayout,
2355 lyx_view_->message(_("Converting document to new document class..."));
2357 StableDocIterator backcur(view()->cursor());
2358 ErrorList & el = buffer->errorList("Class Switch");
2359 cap::switchBetweenClasses(
2360 oldlayout, buffer->params().getTextClassPtr(),
2361 static_cast<InsetText &>(buffer->inset()), el);
2363 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
2365 buffer->errors("Class Switch");
2366 updateLabels(*buffer);
2372 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2374 // Why the switch you might ask. It is a trick to ensure that all
2375 // the elements in the LyXRCTags enum is handled. As you can see
2376 // there are no breaks at all. So it is just a huge fall-through.
2377 // The nice thing is that we will get a warning from the compiler
2378 // if we forget an element.
2379 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2381 case LyXRC::RC_ACCEPT_COMPOUND:
2382 case LyXRC::RC_ALT_LANG:
2383 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
2384 case LyXRC::RC_PLAINTEXT_LINELEN:
2385 case LyXRC::RC_AUTOREGIONDELETE:
2386 case LyXRC::RC_AUTORESET_OPTIONS:
2387 case LyXRC::RC_AUTOSAVE:
2388 case LyXRC::RC_AUTO_NUMBER:
2389 case LyXRC::RC_BACKUPDIR_PATH:
2390 case LyXRC::RC_BIBTEX_COMMAND:
2391 case LyXRC::RC_BINDFILE:
2392 case LyXRC::RC_CHECKLASTFILES:
2393 case LyXRC::RC_USELASTFILEPOS:
2394 case LyXRC::RC_LOADSESSION:
2395 case LyXRC::RC_CHKTEX_COMMAND:
2396 case LyXRC::RC_CONVERTER:
2397 case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
2398 case LyXRC::RC_COPIER:
2399 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2400 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2401 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2402 case LyXRC::RC_DATE_INSERT_FORMAT:
2403 case LyXRC::RC_DEFAULT_LANGUAGE:
2404 case LyXRC::RC_DEFAULT_PAPERSIZE:
2405 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2406 case LyXRC::RC_DISPLAY_GRAPHICS:
2407 case LyXRC::RC_DOCUMENTPATH:
2408 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2409 string const encoded = FileName(
2410 lyxrc_new.document_path).toFilesystemEncoding();
2411 if (fs::exists(encoded) && fs::is_directory(encoded))
2412 support::package().document_dir() = FileName(lyxrc.document_path);
2414 case LyXRC::RC_ESC_CHARS:
2415 case LyXRC::RC_FONT_ENCODING:
2416 case LyXRC::RC_FORMAT:
2417 case LyXRC::RC_INDEX_COMMAND:
2418 case LyXRC::RC_INPUT:
2419 case LyXRC::RC_KBMAP:
2420 case LyXRC::RC_KBMAP_PRIMARY:
2421 case LyXRC::RC_KBMAP_SECONDARY:
2422 case LyXRC::RC_LABEL_INIT_LENGTH:
2423 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2424 case LyXRC::RC_LANGUAGE_AUTO_END:
2425 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2426 case LyXRC::RC_LANGUAGE_COMMAND_END:
2427 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2428 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2429 case LyXRC::RC_LANGUAGE_PACKAGE:
2430 case LyXRC::RC_LANGUAGE_USE_BABEL:
2431 case LyXRC::RC_MAKE_BACKUP:
2432 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2433 case LyXRC::RC_NUMLASTFILES:
2434 case LyXRC::RC_PATH_PREFIX:
2435 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2436 support::prependEnvPath("PATH", lyxrc.path_prefix);
2438 case LyXRC::RC_PERS_DICT:
2439 case LyXRC::RC_PREVIEW:
2440 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2441 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2442 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2443 case LyXRC::RC_PRINTCOPIESFLAG:
2444 case LyXRC::RC_PRINTER:
2445 case LyXRC::RC_PRINTEVENPAGEFLAG:
2446 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2447 case LyXRC::RC_PRINTFILEEXTENSION:
2448 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2449 case LyXRC::RC_PRINTODDPAGEFLAG:
2450 case LyXRC::RC_PRINTPAGERANGEFLAG:
2451 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2452 case LyXRC::RC_PRINTPAPERFLAG:
2453 case LyXRC::RC_PRINTREVERSEFLAG:
2454 case LyXRC::RC_PRINTSPOOL_COMMAND:
2455 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2456 case LyXRC::RC_PRINTTOFILE:
2457 case LyXRC::RC_PRINTTOPRINTER:
2458 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2459 case LyXRC::RC_PRINT_COMMAND:
2460 case LyXRC::RC_RTL_SUPPORT:
2461 case LyXRC::RC_SCREEN_DPI:
2462 case LyXRC::RC_SCREEN_FONT_ROMAN:
2463 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2464 case LyXRC::RC_SCREEN_FONT_SANS:
2465 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2466 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2467 case LyXRC::RC_SCREEN_FONT_SIZES:
2468 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2469 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2470 case LyXRC::RC_SCREEN_GEOMETRY_HEIGHT:
2471 case LyXRC::RC_SCREEN_GEOMETRY_WIDTH:
2472 case LyXRC::RC_SCREEN_GEOMETRY_XYSAVED:
2473 case LyXRC::RC_SCREEN_ZOOM:
2474 case LyXRC::RC_SERVERPIPE:
2475 case LyXRC::RC_SET_COLOR:
2476 case LyXRC::RC_SHOW_BANNER:
2477 case LyXRC::RC_SPELL_COMMAND:
2478 case LyXRC::RC_TEMPDIRPATH:
2479 case LyXRC::RC_TEMPLATEPATH:
2480 case LyXRC::RC_TEX_ALLOWS_SPACES:
2481 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2482 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2483 support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2485 case LyXRC::RC_UIFILE:
2486 case LyXRC::RC_USER_EMAIL:
2487 case LyXRC::RC_USER_NAME:
2488 case LyXRC::RC_USETEMPDIR:
2489 case LyXRC::RC_USE_ALT_LANG:
2490 case LyXRC::RC_USE_CONVERTER_CACHE:
2491 case LyXRC::RC_USE_ESC_CHARS:
2492 case LyXRC::RC_USE_INP_ENC:
2493 case LyXRC::RC_USE_PERS_DICT:
2494 case LyXRC::RC_USE_SPELL_LIB:
2495 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2496 case LyXRC::RC_VIEWER:
2497 case LyXRC::RC_LAST: