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/ForkedcallsController.h"
93 #include "support/fs_extras.h"
94 #include "support/lstrings.h"
95 #include "support/Path.h"
96 #include "support/Package.h"
97 #include "support/Systemcall.h"
98 #include "support/convert.h"
99 #include "support/os.h"
101 #include <boost/current_function.hpp>
102 #include <boost/filesystem/operations.hpp>
107 using std::make_pair;
110 using std::istringstream;
111 using std::ostringstream;
113 namespace fs = boost::filesystem;
117 using frontend::LyXView;
119 using support::absolutePath;
120 using support::addName;
121 using support::addPath;
122 using support::bformat;
123 using support::changeExtension;
124 using support::contains;
125 using support::FileFilterList;
126 using support::FileName;
127 using support::fileSearch;
128 using support::ForkedcallsController;
129 using support::i18nLibFileSearch;
130 using support::isDirWriteable;
131 using support::isFileReadable;
132 using support::isStrInt;
133 using support::makeAbsPath;
134 using support::makeDisplayPath;
135 using support::package;
136 using support::quoteName;
137 using support::rtrim;
138 using support::split;
139 using support::subst;
140 using support::Systemcall;
141 using support::token;
143 using support::prefixIs;
145 namespace Alert = frontend::Alert;
147 extern bool quitting;
151 // This function runs "configure" and then rereads lyx.defaults to
152 // reconfigure the automatic settings.
153 void reconfigure(LyXView & lv, string const & option)
155 // emit message signal.
156 lv.message(_("Running configure..."));
158 // Run configure in user lyx directory
159 support::Path p(package().user_support());
160 string configure_command = package().configure_command();
161 configure_command += option;
163 one.startscript(Systemcall::Wait, configure_command);
165 // emit message signal.
166 lv.message(_("Reloading configuration..."));
167 lyxrc.read(support::libFileSearch(string(), "lyxrc.defaults"));
168 // Re-read packages.lst
169 LaTeXFeatures::getAvailable();
171 Alert::information(_("System reconfigured"),
172 _("The system has been reconfigured.\n"
173 "You need to restart LyX to make use of any\n"
174 "updated document class specifications."));
178 bool getLocalStatus(Cursor cursor, FuncRequest const & cmd, FuncStatus & status)
180 // Try to fix cursor in case it is broken.
181 cursor.fixIfBroken();
183 // This is, of course, a mess. Better create a new doc iterator and use
184 // this in Inset::getStatus. This might require an additional
185 // BufferView * arg, though (which should be avoided)
186 //Cursor safe = *this;
188 for ( ; cursor.depth(); cursor.pop()) {
189 //lyxerr << "\nCursor::getStatus: cmd: " << cmd << endl << *this << endl;
190 BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
191 BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
192 BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
194 // The inset's getStatus() will return 'true' if it made
195 // a definitive decision on whether it want to handle the
196 // request or not. The result of this decision is put into
197 // the 'status' parameter.
198 if (cursor.inset().getStatus(cursor, cmd, status)) {
207 /** Return the change status at cursor position, taking in account the
208 * status at each level of the document iterator (a table in a deleted
209 * footnote is deleted).
210 * When \param outer is true, the top slice is not looked at.
212 Change::Type lookupChangeType(DocIterator const & dit, bool outer = false)
214 size_t const depth = dit.depth() - (outer ? 1 : 0);
216 for (size_t i = 0 ; i < depth ; ++i) {
217 CursorSlice const & slice = dit[i];
218 if (!slice.inset().inMathed()
219 && slice.pos() < slice.paragraph().size()) {
220 Change::Type const ch = slice.paragraph().lookupChange(slice.pos()).type;
221 if (ch != Change::UNCHANGED)
225 return Change::UNCHANGED;
232 : lyx_view_(0), encoded_last_key(0), meta_fake_bit(NoModifier)
237 void LyXFunc::initKeySequences(KeyMap * kb)
239 keyseq = KeySequence(kb, kb);
240 cancel_meta_seq = KeySequence(kb, kb);
244 void LyXFunc::setLyXView(LyXView * lv)
246 if (!quitting && lyx_view_ && lyx_view_->view() && lyx_view_ != lv)
247 // save current selection to the selection buffer to allow
248 // middle-button paste in another window
249 cap::saveSelection(lyx_view_->view()->cursor());
254 void LyXFunc::handleKeyFunc(kb_action action)
256 char_type c = encoded_last_key;
261 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
262 lyx_view_->view()->getIntl().getTransManager().deadkey(
263 c, get_accent(action).accent, view()->cursor().innerText(), view()->cursor());
264 // Need to clear, in case the minibuffer calls these
267 // copied verbatim from do_accent_char
268 view()->cursor().resetAnchor();
269 view()->processUpdateFlags(Update::FitCursor);
273 void LyXFunc::gotoBookmark(unsigned int idx, bool openFile, bool switchToBuffer)
275 BOOST_ASSERT(lyx_view_);
276 if (!LyX::ref().session().bookmarks().isValid(idx))
278 BookmarksSection::Bookmark const & bm = LyX::ref().session().bookmarks().bookmark(idx);
279 BOOST_ASSERT(!bm.filename.empty());
280 string const file = bm.filename.absFilename();
281 // if the file is not opened, open it.
282 if (!theBufferList().exists(file)) {
284 dispatch(FuncRequest(LFUN_FILE_OPEN, file));
288 // open may fail, so we need to test it again
289 if (!theBufferList().exists(file))
292 // if the current buffer is not that one, switch to it.
293 if (lyx_view_->buffer()->fileName() != file) {
296 dispatch(FuncRequest(LFUN_BUFFER_SWITCH, file));
298 // moveToPosition try paragraph id first and then paragraph (pit, pos).
299 if (!view()->moveToPosition(bm.bottom_pit, bm.bottom_pos,
300 bm.top_id, bm.top_pos))
303 // Cursor jump succeeded!
304 Cursor const & cur = view()->cursor();
305 pit_type new_pit = cur.pit();
306 pos_type new_pos = cur.pos();
307 int new_id = cur.paragraph().id();
309 // if bottom_pit, bottom_pos or top_id has been changed, update bookmark
310 // see http://bugzilla.lyx.org/show_bug.cgi?id=3092
311 if (bm.bottom_pit != new_pit || bm.bottom_pos != new_pos
312 || bm.top_id != new_id) {
313 const_cast<BookmarksSection::Bookmark &>(bm).updatePos(
314 new_pit, new_pos, new_id);
319 void LyXFunc::processKeySym(KeySymbol const & keysym, KeyModifier state)
321 LYXERR(Debug::KEY) << "KeySym is " << keysym.getSymbolName() << endl;
323 // Do nothing if we have nothing (JMarc)
324 if (!keysym.isOK()) {
325 LYXERR(Debug::KEY) << "Empty kbd action (probably composing)"
330 if (keysym.isModifier()) {
331 LYXERR(Debug::KEY) << "isModifier true" << endl;
335 //Encoding const * encoding = view()->cursor().getEncoding();
336 //encoded_last_key = keysym.getISOEncoded(encoding ? encoding->name() : "");
337 // FIXME: encoded_last_key shadows the member variable of the same
338 // name. Is that intended?
339 char_type encoded_last_key = keysym.getUCSEncoded();
341 // Do a one-deep top-level lookup for
342 // cancel and meta-fake keys. RVDK_PATCH_5
343 cancel_meta_seq.reset();
345 FuncRequest func = cancel_meta_seq.addkey(keysym, state);
346 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
347 << " action first set to [" << func.action << ']'
350 // When not cancel or meta-fake, do the normal lookup.
351 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
352 // Mostly, meta_fake_bit = NoModifier. RVDK_PATCH_5.
353 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_PREFIX)) {
354 // remove Caps Lock and Mod2 as a modifiers
355 func = keyseq.addkey(keysym, (state | meta_fake_bit));
356 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
357 << "action now set to ["
358 << func.action << ']' << endl;
361 // Dont remove this unless you know what you are doing.
362 meta_fake_bit = NoModifier;
364 // Can this happen now ?
365 if (func.action == LFUN_NOACTION)
366 func = FuncRequest(LFUN_COMMAND_PREFIX);
368 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
370 << func.action << "]["
371 << to_utf8(keyseq.print(false)) << ']'
374 // already here we know if it any point in going further
375 // why not return already here if action == -1 and
376 // num_bytes == 0? (Lgb)
378 if (keyseq.length() > 1)
379 lyx_view_->message(keyseq.print(true));
382 // Maybe user can only reach the key via holding down shift.
383 // Let's see. But only if shift is the only modifier
384 if (func.action == LFUN_UNKNOWN_ACTION && state == ShiftModifier) {
385 LYXERR(Debug::KEY) << "Trying without shift" << endl;
386 func = keyseq.addkey(keysym, NoModifier);
387 LYXERR(Debug::KEY) << "Action now " << func.action << endl;
390 if (func.action == LFUN_UNKNOWN_ACTION) {
391 // Hmm, we didn't match any of the keysequences. See
392 // if it's normal insertable text not already covered
394 if (keysym.isText() && keyseq.length() == 1) {
395 LYXERR(Debug::KEY) << "isText() is true, inserting." << endl;
396 func = FuncRequest(LFUN_SELF_INSERT,
397 FuncRequest::KEYBOARD);
399 LYXERR(Debug::KEY) << "Unknown, !isText() - giving up" << endl;
400 lyx_view_->message(_("Unknown function."));
405 if (func.action == LFUN_SELF_INSERT) {
406 if (encoded_last_key != 0) {
407 docstring const arg(1, encoded_last_key);
408 dispatch(FuncRequest(LFUN_SELF_INSERT, arg,
409 FuncRequest::KEYBOARD));
411 << "SelfInsert arg[`" << to_utf8(arg) << "']" << endl;
419 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
421 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
424 Cursor & cur = view()->cursor();
426 /* In LyX/Mac, when a dialog is open, the menus of the
427 application can still be accessed without giving focus to
428 the main window. In this case, we want to disable the menu
429 entries that are buffer-related.
431 Note that this code is not perfect, as bug 1941 attests:
432 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
434 Buffer * buf = lyx_view_? lyx_view_->buffer() : 0;
435 if (lyx_view_ && cmd.origin == FuncRequest::MENU && !lyx_view_->hasFocus())
438 if (cmd.action == LFUN_NOACTION) {
439 flag.message(from_utf8(N_("Nothing to do")));
444 switch (cmd.action) {
445 case LFUN_UNKNOWN_ACTION:
446 #ifndef HAVE_LIBAIKSAURUS
447 case LFUN_THESAURUS_ENTRY:
457 if (flag.unknown()) {
458 flag.message(from_utf8(N_("Unknown action")));
462 if (!flag.enabled()) {
463 if (flag.message().empty())
464 flag.message(from_utf8(N_("Command disabled")));
468 // Check whether we need a buffer
469 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
471 flag.message(from_utf8(N_("Command not allowed with"
472 "out any document open")));
477 // I would really like to avoid having this switch and rather try to
478 // encode this in the function itself.
479 // -- And I'd rather let an inset decide which LFUNs it is willing
480 // to handle (Andre')
482 switch (cmd.action) {
483 case LFUN_BUFFER_TOGGLE_READ_ONLY:
484 flag.setOnOff(buf->isReadonly());
487 case LFUN_BUFFER_SWITCH:
488 // toggle on the current buffer, but do not toggle off
489 // the other ones (is that a good idea?)
490 if (buf && to_utf8(cmd.argument()) == buf->fileName())
494 case LFUN_BUFFER_EXPORT:
495 enable = cmd.argument() == "custom"
496 || Exporter::isExportable(*buf, to_utf8(cmd.argument()));
499 case LFUN_BUFFER_CHKTEX:
500 enable = buf->isLatex() && !lyxrc.chktex_command.empty();
503 case LFUN_BUILD_PROGRAM:
504 enable = Exporter::isExportable(*buf, "program");
507 case LFUN_LAYOUT_TABULAR:
508 enable = cur.innerInsetOfType(Inset::TABULAR_CODE);
512 case LFUN_LAYOUT_PARAGRAPH:
513 enable = !cur.inset().forceDefaultParagraphs(cur.idx());
516 case LFUN_VC_REGISTER:
517 enable = !buf->lyxvc().inUse();
519 case LFUN_VC_CHECK_IN:
520 enable = buf->lyxvc().inUse() && !buf->isReadonly();
522 case LFUN_VC_CHECK_OUT:
523 enable = buf->lyxvc().inUse() && buf->isReadonly();
526 case LFUN_VC_UNDO_LAST:
527 enable = buf->lyxvc().inUse();
529 case LFUN_BUFFER_RELOAD:
530 enable = !buf->isUnnamed() && fs::exists(buf->fileName())
531 && (!buf->isClean() || buf->isExternallyModified(Buffer::timestamp_method));
534 case LFUN_INSET_SETTINGS: {
538 Inset::Code code = cur.inset().lyxCode();
540 case Inset::TABULAR_CODE:
541 enable = cmd.argument() == "tabular";
543 case Inset::ERT_CODE:
544 enable = cmd.argument() == "ert";
546 case Inset::FLOAT_CODE:
547 enable = cmd.argument() == "float";
549 case Inset::WRAP_CODE:
550 enable = cmd.argument() == "wrap";
552 case Inset::NOTE_CODE:
553 enable = cmd.argument() == "note";
555 case Inset::BRANCH_CODE:
556 enable = cmd.argument() == "branch";
558 case Inset::BOX_CODE:
559 enable = cmd.argument() == "box";
561 case Inset::LISTINGS_CODE:
562 enable = cmd.argument() == "listings";
570 case LFUN_INSET_APPLY: {
571 string const name = cmd.getArg(0);
572 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
574 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
576 if (!inset->getStatus(cur, fr, fs)) {
577 // Every inset is supposed to handle this
582 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
583 flag |= getStatus(fr);
585 enable = flag.enabled();
589 case LFUN_DIALOG_TOGGLE:
590 flag.setOnOff(lyx_view_->getDialogs().visible(cmd.getArg(0)));
591 // fall through to set "enable"
592 case LFUN_DIALOG_SHOW: {
593 string const name = cmd.getArg(0);
595 enable = name == "aboutlyx"
596 || name == "file" //FIXME: should be removed.
598 || name == "texinfo";
599 else if (name == "print")
600 enable = Exporter::isExportable(*buf, "dvi")
601 && lyxrc.print_command != "none";
602 else if (name == "character")
603 enable = cur.inset().lyxCode() != Inset::ERT_CODE &&
604 cur.inset().lyxCode() != Inset::LISTINGS_CODE;
605 else if (name == "latexlog")
606 enable = isFileReadable(FileName(buf->getLogName().second));
607 else if (name == "spellchecker")
608 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
609 enable = !buf->isReadonly();
613 else if (name == "vclog")
614 enable = buf->lyxvc().inUse();
618 case LFUN_DIALOG_SHOW_NEW_INSET:
619 enable = cur.inset().lyxCode() != Inset::ERT_CODE &&
620 cur.inset().lyxCode() != Inset::LISTINGS_CODE;
621 if (cur.inset().lyxCode() == Inset::CAPTION_CODE) {
623 if (cur.inset().getStatus(cur, cmd, flag))
628 case LFUN_DIALOG_UPDATE: {
629 string const name = cmd.getArg(0);
631 enable = name == "prefs";
635 case LFUN_CITATION_INSERT: {
636 FuncRequest fr(LFUN_INSET_INSERT, "citation");
637 enable = getStatus(fr).enabled();
641 case LFUN_BUFFER_WRITE: {
642 enable = lyx_view_->buffer()->isUnnamed()
643 || !lyx_view_->buffer()->isClean();
648 case LFUN_BUFFER_WRITE_ALL: {
649 // We enable the command only if there are some modified buffers
650 Buffer * first = theBufferList().first();
651 bool modified = false;
655 // We cannot use a for loop as the buffer list is a cycle.
661 b = theBufferList().next(b);
662 } while (b != first);
670 case LFUN_BOOKMARK_GOTO: {
671 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
672 enable = LyX::ref().session().bookmarks().isValid(num);
676 case LFUN_BOOKMARK_CLEAR:
677 enable = LyX::ref().session().bookmarks().size() > 0;
680 case LFUN_TOOLBAR_TOGGLE: {
681 bool const current = lyx_view_->isToolbarVisible(cmd.getArg(0));
682 flag.setOnOff(current);
685 case LFUN_WINDOW_CLOSE: {
686 enable = (theApp()->gui().viewIds().size() > 1);
690 // this one is difficult to get right. As a half-baked
691 // solution, we consider only the first action of the sequence
692 case LFUN_COMMAND_SEQUENCE: {
693 // argument contains ';'-terminated commands
694 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
695 FuncRequest func(lyxaction.lookupFunc(firstcmd));
696 func.origin = cmd.origin;
697 flag = getStatus(func);
700 case LFUN_BUFFER_NEW:
701 case LFUN_BUFFER_NEW_TEMPLATE:
702 case LFUN_WORD_FIND_FORWARD:
703 case LFUN_WORD_FIND_BACKWARD:
704 case LFUN_COMMAND_PREFIX:
705 case LFUN_COMMAND_EXECUTE:
707 case LFUN_META_PREFIX:
708 case LFUN_BUFFER_CLOSE:
709 case LFUN_BUFFER_WRITE_AS:
710 case LFUN_BUFFER_UPDATE:
711 case LFUN_BUFFER_VIEW:
712 case LFUN_MASTER_BUFFER_UPDATE:
713 case LFUN_MASTER_BUFFER_VIEW:
714 case LFUN_BUFFER_IMPORT:
715 case LFUN_BUFFER_AUTO_SAVE:
716 case LFUN_RECONFIGURE:
720 case LFUN_DROP_LAYOUTS_CHOICE:
722 case LFUN_SERVER_GET_NAME:
723 case LFUN_SERVER_NOTIFY:
724 case LFUN_SERVER_GOTO_FILE_ROW:
725 case LFUN_DIALOG_HIDE:
726 case LFUN_DIALOG_DISCONNECT_INSET:
727 case LFUN_BUFFER_CHILD_OPEN:
728 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
729 case LFUN_KEYMAP_OFF:
730 case LFUN_KEYMAP_PRIMARY:
731 case LFUN_KEYMAP_SECONDARY:
732 case LFUN_KEYMAP_TOGGLE:
734 case LFUN_BUFFER_EXPORT_CUSTOM:
735 case LFUN_BUFFER_PRINT:
736 case LFUN_PREFERENCES_SAVE:
737 case LFUN_SCREEN_FONT_UPDATE:
740 case LFUN_EXTERNAL_EDIT:
741 case LFUN_GRAPHICS_EDIT:
742 case LFUN_ALL_INSETS_TOGGLE:
743 case LFUN_BUFFER_LANGUAGE:
744 case LFUN_TEXTCLASS_APPLY:
745 case LFUN_TEXTCLASS_LOAD:
746 case LFUN_BUFFER_SAVE_AS_DEFAULT:
747 case LFUN_BUFFER_PARAMS_APPLY:
748 case LFUN_LAYOUT_MODULES_CLEAR:
749 case LFUN_LAYOUT_MODULE_ADD:
750 case LFUN_LAYOUT_RELOAD:
751 case LFUN_LYXRC_APPLY:
752 case LFUN_BUFFER_NEXT:
753 case LFUN_BUFFER_PREVIOUS:
754 case LFUN_WINDOW_NEW:
756 // these are handled in our dispatch()
760 if (!getLocalStatus(cur, cmd, flag))
761 flag = view()->getStatus(cmd);
767 // Can we use a readonly buffer?
768 if (buf && buf->isReadonly()
769 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
770 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
771 flag.message(from_utf8(N_("Document is read-only")));
775 // Are we in a DELETED change-tracking region?
776 if (buf && lookupChangeType(cur, true) == Change::DELETED
777 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
778 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
779 flag.message(from_utf8(N_("This portion of the document is deleted.")));
783 // the default error message if we disable the command
784 if (!flag.enabled() && flag.message().empty())
785 flag.message(from_utf8(N_("Command disabled")));
791 bool LyXFunc::ensureBufferClean(BufferView * bv)
793 Buffer & buf = bv->buffer();
797 docstring const file = makeDisplayPath(buf.fileName(), 30);
798 docstring text = bformat(_("The document %1$s has unsaved "
799 "changes.\n\nDo you want to save "
800 "the document?"), file);
801 int const ret = Alert::prompt(_("Save changed document?"),
802 text, 0, 1, _("&Save"),
806 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
808 return buf.isClean();
814 void showPrintError(string const & name)
816 docstring str = bformat(_("Could not print the document %1$s.\n"
817 "Check that your printer is set up correctly."),
818 makeDisplayPath(name, 50));
819 Alert::error(_("Print document failed"), str);
823 void loadTextClass(string const & name)
825 std::pair<bool, textclass_type> const tc_pair =
826 textclasslist.numberOfClass(name);
828 if (!tc_pair.first) {
829 lyxerr << "Document class \"" << name
830 << "\" does not exist."
835 textclass_type const tc = tc_pair.second;
837 if (!textclasslist[tc].load()) {
838 docstring s = bformat(_("The document class %1$s."
839 "could not be loaded."),
840 from_utf8(textclasslist[tc].name()));
841 Alert::error(_("Could not load class"), s);
846 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
851 void LyXFunc::dispatch(FuncRequest const & cmd)
853 string const argument = to_utf8(cmd.argument());
854 kb_action const action = cmd.action;
856 LYXERR(Debug::ACTION) << endl << "LyXFunc::dispatch: cmd: " << cmd << endl;
857 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
859 // we have not done anything wrong yet.
861 dispatch_buffer.erase();
863 // redraw the screen at the end (first of the two drawing steps).
864 //This is done unless explicitely requested otherwise
865 Update::flags updateFlags = Update::FitCursor;
867 FuncStatus const flag = getStatus(cmd);
868 if (!flag.enabled()) {
869 // We cannot use this function here
870 LYXERR(Debug::ACTION) << "LyXFunc::dispatch: "
871 << lyxaction.getActionName(action)
872 << " [" << action << "] is disabled at this location"
874 setErrorMessage(flag.message());
878 case LFUN_WORD_FIND_FORWARD:
879 case LFUN_WORD_FIND_BACKWARD: {
880 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
881 static docstring last_search;
882 docstring searched_string;
884 if (!cmd.argument().empty()) {
885 last_search = cmd.argument();
886 searched_string = cmd.argument();
888 searched_string = last_search;
891 if (searched_string.empty())
894 bool const fw = action == LFUN_WORD_FIND_FORWARD;
895 docstring const data =
896 find2string(searched_string, true, false, fw);
897 find(view(), FuncRequest(LFUN_WORD_FIND, data));
901 case LFUN_COMMAND_PREFIX:
902 BOOST_ASSERT(lyx_view_);
903 lyx_view_->message(keyseq.printOptions(true));
906 case LFUN_COMMAND_EXECUTE:
907 BOOST_ASSERT(lyx_view_);
908 lyx_view_->showMiniBuffer(true);
912 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
914 meta_fake_bit = NoModifier;
915 if (lyx_view_->buffer())
916 // cancel any selection
917 dispatch(FuncRequest(LFUN_MARK_OFF));
918 setMessage(from_ascii(N_("Cancel")));
921 case LFUN_META_PREFIX:
922 meta_fake_bit = AltModifier;
923 setMessage(keyseq.print(true));
926 case LFUN_BUFFER_TOGGLE_READ_ONLY: {
927 BOOST_ASSERT(lyx_view_ && lyx_view_->view() && lyx_view_->buffer());
928 Buffer * buf = lyx_view_->buffer();
929 if (buf->lyxvc().inUse())
930 buf->lyxvc().toggleReadOnly();
932 buf->setReadonly(!lyx_view_->buffer()->isReadonly());
936 // --- Menus -----------------------------------------------
937 case LFUN_BUFFER_NEW:
938 menuNew(argument, false);
939 updateFlags = Update::None;
942 case LFUN_BUFFER_NEW_TEMPLATE:
943 menuNew(argument, true);
944 updateFlags = Update::None;
947 case LFUN_BUFFER_CLOSE:
949 updateFlags = Update::None;
952 case LFUN_BUFFER_WRITE:
953 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
954 if (!lyx_view_->buffer()->isUnnamed()) {
955 docstring const str = bformat(_("Saving document %1$s..."),
956 makeDisplayPath(lyx_view_->buffer()->fileName()));
957 lyx_view_->message(str);
958 lyx_view_->buffer()->menuWrite();
959 lyx_view_->message(str + _(" done."));
961 lyx_view_->buffer()->writeAs();
963 updateFlags = Update::None;
966 case LFUN_BUFFER_WRITE_AS:
967 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
968 lyx_view_->buffer()->writeAs(argument);
969 updateFlags = Update::None;
972 case LFUN_BUFFER_WRITE_ALL: {
973 Buffer * first = theBufferList().first();
976 lyx_view_->message(_("Saving all documents..."));
978 // We cannot use a for loop as the buffer list cycles.
981 if (!b->isUnnamed()) {
983 lyxerr[Debug::ACTION] << "Saved " << b->fileName() << endl;
987 b = theBufferList().next(b);
988 } while (b != first);
989 lyx_view_->message(_("All documents saved."));
992 updateFlags = Update::None;
996 case LFUN_BUFFER_RELOAD: {
997 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
998 docstring const file = makeDisplayPath(lyx_view_->buffer()->fileName(), 20);
999 docstring text = bformat(_("Any changes will be lost. Are you sure "
1000 "you want to revert to the saved version of the document %1$s?"), file);
1001 int const ret = Alert::prompt(_("Revert to saved document?"),
1002 text, 1, 1, _("&Revert"), _("&Cancel"));
1009 case LFUN_BUFFER_UPDATE:
1010 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1011 Exporter::Export(lyx_view_->buffer(), argument, true);
1014 case LFUN_BUFFER_VIEW:
1015 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1016 Exporter::preview(lyx_view_->buffer(), argument);
1019 case LFUN_MASTER_BUFFER_UPDATE:
1020 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->getMasterBuffer());
1021 Exporter::Export(lyx_view_->buffer()->getMasterBuffer(), argument, true);
1024 case LFUN_MASTER_BUFFER_VIEW:
1025 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->getMasterBuffer());
1026 Exporter::preview(lyx_view_->buffer()->getMasterBuffer(), argument);
1029 case LFUN_BUILD_PROGRAM:
1030 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1031 Exporter::Export(lyx_view_->buffer(), "program", true);
1034 case LFUN_BUFFER_CHKTEX:
1035 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1036 lyx_view_->buffer()->runChktex();
1039 case LFUN_BUFFER_EXPORT:
1040 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1041 if (argument == "custom")
1042 lyx_view_->getDialogs().show("sendto");
1044 Exporter::Export(lyx_view_->buffer(), argument, false);
1048 case LFUN_BUFFER_EXPORT_CUSTOM: {
1049 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1051 string command = split(argument, format_name, ' ');
1052 Format const * format = formats.getFormat(format_name);
1054 lyxerr << "Format \"" << format_name
1055 << "\" not recognized!"
1060 Buffer * buffer = lyx_view_->buffer();
1062 // The name of the file created by the conversion process
1065 // Output to filename
1066 if (format->name() == "lyx") {
1067 string const latexname =
1068 buffer->getLatexName(false);
1069 filename = changeExtension(latexname,
1070 format->extension());
1071 filename = addName(buffer->temppath(), filename);
1073 if (!buffer->writeFile(FileName(filename)))
1077 Exporter::Export(buffer, format_name, true, filename);
1080 // Substitute $$FName for filename
1081 if (!contains(command, "$$FName"))
1082 command = "( " + command + " ) < $$FName";
1083 command = subst(command, "$$FName", filename);
1085 // Execute the command in the background
1087 call.startscript(Systemcall::DontWait, command);
1091 case LFUN_BUFFER_PRINT: {
1092 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1093 // FIXME: cmd.getArg() might fail if one of the arguments
1094 // contains double quotes
1095 string target = cmd.getArg(0);
1096 string target_name = cmd.getArg(1);
1097 string command = cmd.getArg(2);
1100 || target_name.empty()
1101 || command.empty()) {
1102 lyxerr << "Unable to parse \""
1103 << argument << '"' << endl;
1106 if (target != "printer" && target != "file") {
1107 lyxerr << "Unrecognized target \""
1108 << target << '"' << endl;
1112 Buffer * buffer = lyx_view_->buffer();
1114 if (!Exporter::Export(buffer, "dvi", true)) {
1115 showPrintError(buffer->fileName());
1119 // Push directory path.
1120 string const path = buffer->temppath();
1121 // Prevent the compiler from optimizing away p
1123 support::Path p(pp);
1125 // there are three cases here:
1126 // 1. we print to a file
1127 // 2. we print directly to a printer
1128 // 3. we print using a spool command (print to file first)
1131 string const dviname =
1132 changeExtension(buffer->getLatexName(true),
1135 if (target == "printer") {
1136 if (!lyxrc.print_spool_command.empty()) {
1137 // case 3: print using a spool
1138 string const psname =
1139 changeExtension(dviname,".ps");
1140 command += ' ' + lyxrc.print_to_file
1143 + quoteName(dviname);
1146 lyxrc.print_spool_command + ' ';
1147 if (target_name != "default") {
1148 command2 += lyxrc.print_spool_printerprefix
1152 command2 += quoteName(psname);
1154 // If successful, then spool command
1155 res = one.startscript(
1160 res = one.startscript(
1161 Systemcall::DontWait,
1164 // case 2: print directly to a printer
1165 if (target_name != "default")
1166 command += ' ' + lyxrc.print_to_printer + target_name + ' ';
1167 res = one.startscript(
1168 Systemcall::DontWait,
1169 command + quoteName(dviname));
1173 // case 1: print to a file
1174 FileName const filename(makeAbsPath(target_name,
1175 lyx_view_->buffer()->filePath()));
1176 FileName const dvifile(makeAbsPath(dviname, path));
1177 if (fs::exists(filename.toFilesystemEncoding())) {
1178 docstring text = bformat(
1179 _("The file %1$s already exists.\n\n"
1180 "Do you want to overwrite that file?"),
1181 makeDisplayPath(filename.absFilename()));
1182 if (Alert::prompt(_("Overwrite file?"),
1183 text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
1186 command += ' ' + lyxrc.print_to_file
1187 + quoteName(filename.toFilesystemEncoding())
1189 + quoteName(dvifile.toFilesystemEncoding());
1190 res = one.startscript(Systemcall::DontWait,
1195 showPrintError(buffer->fileName());
1199 case LFUN_BUFFER_IMPORT:
1204 // quitting is triggered by the gui code
1205 // (leaving the event loop).
1206 lyx_view_->message(from_utf8(N_("Exiting.")));
1207 if (theBufferList().quitWriteAll())
1208 theApp()->gui().closeAllViews();
1211 case LFUN_BUFFER_AUTO_SAVE:
1212 lyx_view_->buffer()->autoSave();
1215 case LFUN_RECONFIGURE:
1216 BOOST_ASSERT(lyx_view_);
1217 // argument is any additional parameter to the configure.py command
1218 reconfigure(*lyx_view_, argument);
1221 case LFUN_HELP_OPEN: {
1222 BOOST_ASSERT(lyx_view_);
1223 string const arg = argument;
1225 setErrorMessage(from_ascii(N_("Missing argument")));
1228 FileName const fname = i18nLibFileSearch("doc", arg, "lyx");
1229 if (fname.empty()) {
1230 lyxerr << "LyX: unable to find documentation file `"
1231 << arg << "'. Bad installation?" << endl;
1234 lyx_view_->message(bformat(_("Opening help file %1$s..."),
1235 makeDisplayPath(fname.absFilename())));
1236 Buffer * buf = lyx_view_->loadLyXFile(fname, false);
1239 lyx_view_->setBuffer(buf);
1240 lyx_view_->showErrorList("Parse");
1242 updateFlags = Update::None;
1246 // --- version control -------------------------------
1247 case LFUN_VC_REGISTER:
1248 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1249 if (!ensureBufferClean(view()))
1251 if (!lyx_view_->buffer()->lyxvc().inUse()) {
1252 lyx_view_->buffer()->lyxvc().registrer();
1255 updateFlags = Update::Force;
1258 case LFUN_VC_CHECK_IN:
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().checkIn();
1269 case LFUN_VC_CHECK_OUT:
1270 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1271 if (!ensureBufferClean(view()))
1273 if (lyx_view_->buffer()->lyxvc().inUse()
1274 && lyx_view_->buffer()->isReadonly()) {
1275 lyx_view_->buffer()->lyxvc().checkOut();
1280 case LFUN_VC_REVERT:
1281 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1282 lyx_view_->buffer()->lyxvc().revert();
1286 case LFUN_VC_UNDO_LAST:
1287 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1288 lyx_view_->buffer()->lyxvc().undoLast();
1292 // --- buffers ----------------------------------------
1293 case LFUN_BUFFER_SWITCH:
1294 BOOST_ASSERT(lyx_view_);
1295 lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1296 updateFlags = Update::None;
1299 case LFUN_BUFFER_NEXT:
1300 BOOST_ASSERT(lyx_view_);
1301 lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer()));
1302 updateFlags = Update::None;
1305 case LFUN_BUFFER_PREVIOUS:
1306 BOOST_ASSERT(lyx_view_);
1307 lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer()));
1308 updateFlags = Update::None;
1311 case LFUN_FILE_NEW: {
1312 BOOST_ASSERT(lyx_view_);
1314 string tmpname = split(argument, name, ':'); // Split filename
1315 Buffer * const b = newFile(name, tmpname);
1317 lyx_view_->setBuffer(b);
1318 updateFlags = Update::None;
1322 case LFUN_FILE_OPEN:
1323 BOOST_ASSERT(lyx_view_);
1325 updateFlags = Update::None;
1328 case LFUN_DROP_LAYOUTS_CHOICE:
1329 BOOST_ASSERT(lyx_view_);
1330 lyx_view_->openLayoutList();
1333 case LFUN_MENU_OPEN:
1334 BOOST_ASSERT(lyx_view_);
1335 lyx_view_->openMenu(from_utf8(argument));
1338 // --- lyxserver commands ----------------------------
1339 case LFUN_SERVER_GET_NAME:
1340 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1341 setMessage(from_utf8(lyx_view_->buffer()->fileName()));
1342 LYXERR(Debug::INFO) << "FNAME["
1343 << lyx_view_->buffer()->fileName()
1347 case LFUN_SERVER_NOTIFY:
1348 dispatch_buffer = keyseq.print(false);
1349 theServer().notifyClient(to_utf8(dispatch_buffer));
1352 case LFUN_SERVER_GOTO_FILE_ROW: {
1353 BOOST_ASSERT(lyx_view_);
1356 istringstream is(argument);
1357 is >> file_name >> row;
1359 bool loaded = false;
1360 if (prefixIs(file_name, package().temp_dir().absFilename()))
1361 // Needed by inverse dvi search. If it is a file
1362 // in tmpdir, call the apropriated function
1363 buf = theBufferList().getBufferFromTmp(file_name);
1365 // Must replace extension of the file to be .lyx
1366 // and get full path
1367 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1368 // Either change buffer or load the file
1369 if (theBufferList().exists(s.absFilename()))
1370 buf = theBufferList().getBuffer(s.absFilename());
1372 buf = lyx_view_->loadLyXFile(s);
1378 updateFlags = Update::None;
1383 lyx_view_->setBuffer(buf);
1384 view()->setCursorFromRow(row);
1386 lyx_view_->showErrorList("Parse");
1387 updateFlags = Update::FitCursor;
1391 case LFUN_DIALOG_SHOW: {
1392 BOOST_ASSERT(lyx_view_);
1393 string const name = cmd.getArg(0);
1394 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1396 if (name == "character") {
1397 data = freefont2string();
1399 lyx_view_->getDialogs().show("character", data);
1400 } else if (name == "latexlog") {
1401 pair<Buffer::LogType, string> const logfile =
1402 lyx_view_->buffer()->getLogName();
1403 switch (logfile.first) {
1404 case Buffer::latexlog:
1407 case Buffer::buildlog:
1411 data += Lexer::quoteString(logfile.second);
1412 lyx_view_->getDialogs().show("log", data);
1413 } else if (name == "vclog") {
1414 string const data = "vc " +
1415 Lexer::quoteString(lyx_view_->buffer()->lyxvc().getLogFile());
1416 lyx_view_->getDialogs().show("log", data);
1418 lyx_view_->getDialogs().show(name, data);
1422 case LFUN_DIALOG_SHOW_NEW_INSET: {
1423 BOOST_ASSERT(lyx_view_);
1424 string const name = cmd.getArg(0);
1425 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1426 if (name == "bibitem" ||
1430 name == "nomenclature" ||
1434 InsetCommandParams p(name);
1435 data = InsetCommandMailer::params2string(name, p);
1436 } else if (name == "include") {
1437 // data is the include type: one of "include",
1438 // "input", "verbatiminput" or "verbatiminput*"
1440 // default type is requested
1442 InsetCommandParams p(data);
1443 data = InsetIncludeMailer::params2string(p);
1444 } else if (name == "box") {
1445 // \c data == "Boxed" || "Frameless" etc
1446 InsetBoxParams p(data);
1447 data = InsetBoxMailer::params2string(p);
1448 } else if (name == "branch") {
1449 InsetBranchParams p;
1450 data = InsetBranchMailer::params2string(p);
1451 } else if (name == "citation") {
1452 InsetCommandParams p("citation");
1453 data = InsetCommandMailer::params2string(name, p);
1454 } else if (name == "ert") {
1455 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1456 } else if (name == "external") {
1457 InsetExternalParams p;
1458 Buffer const & buffer = *lyx_view_->buffer();
1459 data = InsetExternalMailer::params2string(p, buffer);
1460 } else if (name == "float") {
1462 data = InsetFloatMailer::params2string(p);
1463 } else if (name == "listings") {
1464 InsetListingsParams p;
1465 data = InsetListingsMailer::params2string(p);
1466 } else if (name == "graphics") {
1467 InsetGraphicsParams p;
1468 Buffer const & buffer = *lyx_view_->buffer();
1469 data = InsetGraphicsMailer::params2string(p, buffer);
1470 } else if (name == "note") {
1472 data = InsetNoteMailer::params2string(p);
1473 } else if (name == "vspace") {
1475 data = InsetVSpaceMailer::params2string(space);
1476 } else if (name == "wrap") {
1478 data = InsetWrapMailer::params2string(p);
1480 lyx_view_->getDialogs().show(name, data, 0);
1484 case LFUN_DIALOG_UPDATE: {
1485 BOOST_ASSERT(lyx_view_);
1486 string const & name = argument;
1487 // Can only update a dialog connected to an existing inset
1488 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1490 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1491 inset->dispatch(view()->cursor(), fr);
1492 } else if (name == "paragraph") {
1493 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1494 } else if (name == "prefs") {
1495 lyx_view_->getDialogs().update(name, string());
1500 case LFUN_DIALOG_HIDE:
1501 LyX::cref().hideDialogs(argument, 0);
1504 case LFUN_DIALOG_TOGGLE: {
1505 BOOST_ASSERT(lyx_view_);
1506 if (lyx_view_->getDialogs().visible(cmd.getArg(0)))
1507 dispatch(FuncRequest(LFUN_DIALOG_HIDE, argument));
1509 dispatch(FuncRequest(LFUN_DIALOG_SHOW, argument));
1513 case LFUN_DIALOG_DISCONNECT_INSET:
1514 BOOST_ASSERT(lyx_view_);
1515 lyx_view_->getDialogs().disconnect(argument);
1519 case LFUN_CITATION_INSERT: {
1520 BOOST_ASSERT(lyx_view_);
1521 if (!argument.empty()) {
1522 // we can have one optional argument, delimited by '|'
1523 // citation-insert <key>|<text_before>
1524 // this should be enhanced to also support text_after
1525 // and citation style
1526 string arg = argument;
1528 if (contains(argument, "|")) {
1529 arg = token(argument, '|', 0);
1530 opt1 = token(argument, '|', 1);
1532 InsetCommandParams icp("citation");
1533 icp["key"] = from_utf8(arg);
1535 icp["before"] = from_utf8(opt1);
1536 string icstr = InsetCommandMailer::params2string("citation", icp);
1537 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1540 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1544 case LFUN_BUFFER_CHILD_OPEN: {
1545 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1546 Buffer * parent = lyx_view_->buffer();
1547 FileName filename = makeAbsPath(argument, parent->filePath());
1548 view()->saveBookmark(false);
1550 bool parsed = false;
1551 if (theBufferList().exists(filename.absFilename())) {
1552 child = theBufferList().getBuffer(filename.absFilename());
1554 setMessage(bformat(_("Opening child document %1$s..."),
1555 makeDisplayPath(filename.absFilename())));
1556 child = lyx_view_->loadLyXFile(filename, true);
1560 // Set the parent name of the child document.
1561 // This makes insertion of citations and references in the child work,
1562 // when the target is in the parent or another child document.
1563 child->setParentName(parent->fileName());
1564 updateLabels(*child->getMasterBuffer());
1565 lyx_view_->setBuffer(child);
1567 lyx_view_->showErrorList("Parse");
1570 // If a screen update is required (in case where auto_open is false),
1571 // setBuffer() would have taken care of it already. Otherwise we shall
1572 // reset the update flag because it can cause a circular problem.
1574 updateFlags = Update::None;
1578 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1579 BOOST_ASSERT(lyx_view_);
1580 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1583 case LFUN_KEYMAP_OFF:
1584 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1585 lyx_view_->view()->getIntl().keyMapOn(false);
1588 case LFUN_KEYMAP_PRIMARY:
1589 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1590 lyx_view_->view()->getIntl().keyMapPrim();
1593 case LFUN_KEYMAP_SECONDARY:
1594 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1595 lyx_view_->view()->getIntl().keyMapSec();
1598 case LFUN_KEYMAP_TOGGLE:
1599 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1600 lyx_view_->view()->getIntl().toggleKeyMap();
1606 string rest = split(argument, countstr, ' ');
1607 istringstream is(countstr);
1610 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1611 for (int i = 0; i < count; ++i)
1612 dispatch(lyxaction.lookupFunc(rest));
1616 case LFUN_COMMAND_SEQUENCE: {
1617 // argument contains ';'-terminated commands
1618 string arg = argument;
1619 while (!arg.empty()) {
1621 arg = split(arg, first, ';');
1622 FuncRequest func(lyxaction.lookupFunc(first));
1623 func.origin = cmd.origin;
1629 case LFUN_PREFERENCES_SAVE: {
1630 lyxrc.write(makeAbsPath("preferences",
1631 package().user_support().absFilename()),
1636 case LFUN_SCREEN_FONT_UPDATE:
1637 BOOST_ASSERT(lyx_view_);
1638 // handle the screen font changes.
1639 theFontLoader().update();
1640 /// FIXME: only the current view will be updated. the Gui
1641 /// class is able to furnish the list of views.
1642 updateFlags = Update::Force;
1645 case LFUN_SET_COLOR: {
1647 string const x11_name = split(argument, lyx_name, ' ');
1648 if (lyx_name.empty() || x11_name.empty()) {
1649 setErrorMessage(from_ascii(N_(
1650 "Syntax: set-color <lyx_name>"
1655 bool const graphicsbg_changed =
1656 (lyx_name == lcolor.getLyXName(Color::graphicsbg) &&
1657 x11_name != lcolor.getX11Name(Color::graphicsbg));
1659 if (!lcolor.setColor(lyx_name, x11_name)) {
1661 bformat(_("Set-color \"%1$s\" failed "
1662 "- color is undefined or "
1663 "may not be redefined"),
1664 from_utf8(lyx_name)));
1668 theApp()->updateColor(lcolor.getFromLyXName(lyx_name));
1670 if (graphicsbg_changed) {
1671 // FIXME: The graphics cache no longer has a changeDisplay method.
1673 graphics::GCache::get().changeDisplay(true);
1680 BOOST_ASSERT(lyx_view_);
1681 lyx_view_->message(from_utf8(argument));
1684 case LFUN_EXTERNAL_EDIT: {
1685 BOOST_ASSERT(lyx_view_);
1686 FuncRequest fr(action, argument);
1687 InsetExternal().dispatch(view()->cursor(), fr);
1691 case LFUN_GRAPHICS_EDIT: {
1692 FuncRequest fr(action, argument);
1693 InsetGraphics().dispatch(view()->cursor(), fr);
1697 case LFUN_INSET_APPLY: {
1698 BOOST_ASSERT(lyx_view_);
1699 string const name = cmd.getArg(0);
1700 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1702 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1703 inset->dispatch(view()->cursor(), fr);
1705 FuncRequest fr(LFUN_INSET_INSERT, argument);
1708 // ideally, the update flag should be set by the insets,
1709 // but this is not possible currently
1710 updateFlags = Update::Force | Update::FitCursor;
1714 case LFUN_ALL_INSETS_TOGGLE: {
1715 BOOST_ASSERT(lyx_view_);
1717 string const name = split(argument, action, ' ');
1718 Inset::Code const inset_code =
1719 Inset::translate(name);
1721 Cursor & cur = view()->cursor();
1722 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1724 Inset & inset = lyx_view_->buffer()->inset();
1725 InsetIterator it = inset_iterator_begin(inset);
1726 InsetIterator const end = inset_iterator_end(inset);
1727 for (; it != end; ++it) {
1728 if (!it->asInsetMath()
1729 && (inset_code == Inset::NO_CODE
1730 || inset_code == it->lyxCode())) {
1731 Cursor tmpcur = cur;
1732 tmpcur.pushLeft(*it);
1733 it->dispatch(tmpcur, fr);
1736 updateFlags = Update::Force | Update::FitCursor;
1740 case LFUN_BUFFER_LANGUAGE: {
1741 BOOST_ASSERT(lyx_view_);
1742 Buffer & buffer = *lyx_view_->buffer();
1743 Language const * oldL = buffer.params().language;
1744 Language const * newL = languages.getLanguage(argument);
1745 if (!newL || oldL == newL)
1748 if (oldL->rightToLeft() == newL->rightToLeft()
1749 && !buffer.isMultiLingual())
1750 buffer.changeLanguage(oldL, newL);
1754 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1755 string const fname =
1756 addName(addPath(package().user_support().absFilename(), "templates/"),
1758 Buffer defaults(fname);
1760 istringstream ss(argument);
1763 int const unknown_tokens = defaults.readHeader(lex);
1765 if (unknown_tokens != 0) {
1766 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1767 << unknown_tokens << " unknown token"
1768 << (unknown_tokens == 1 ? "" : "s")
1772 if (defaults.writeFile(FileName(defaults.fileName())))
1773 setMessage(bformat(_("Document defaults saved in %1$s"),
1774 makeDisplayPath(fname)));
1776 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1780 case LFUN_BUFFER_PARAMS_APPLY: {
1781 BOOST_ASSERT(lyx_view_);
1782 biblio::CiteEngine const oldEngine =
1783 lyx_view_->buffer()->params().getEngine();
1785 Buffer * buffer = lyx_view_->buffer();
1787 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1788 recordUndoFullDocument(view());
1790 istringstream ss(argument);
1793 int const unknown_tokens = buffer->readHeader(lex);
1795 if (unknown_tokens != 0) {
1796 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1797 << unknown_tokens << " unknown token"
1798 << (unknown_tokens == 1 ? "" : "s")
1802 updateLayout(oldClass, buffer);
1804 biblio::CiteEngine const newEngine =
1805 lyx_view_->buffer()->params().getEngine();
1807 if (oldEngine != newEngine) {
1808 Cursor & cur = view()->cursor();
1809 FuncRequest fr(LFUN_INSET_REFRESH);
1811 Inset & inset = lyx_view_->buffer()->inset();
1812 InsetIterator it = inset_iterator_begin(inset);
1813 InsetIterator const end = inset_iterator_end(inset);
1814 for (; it != end; ++it)
1815 if (it->lyxCode() == Inset::CITE_CODE)
1816 it->dispatch(cur, fr);
1819 updateFlags = Update::Force | Update::FitCursor;
1823 case LFUN_LAYOUT_MODULES_CLEAR: {
1824 BOOST_ASSERT(lyx_view_);
1825 Buffer * buffer = lyx_view_->buffer();
1826 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1827 recordUndoFullDocument(view());
1828 buffer->params().clearLayoutModules();
1829 updateLayout(oldClass, buffer);
1830 updateFlags = Update::Force | Update::FitCursor;
1834 case LFUN_LAYOUT_MODULE_ADD: {
1835 BOOST_ASSERT(lyx_view_);
1836 Buffer * buffer = lyx_view_->buffer();
1837 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1838 recordUndoFullDocument(view());
1839 buffer->params().addLayoutModule(argument);
1840 updateLayout(oldClass, buffer);
1841 updateFlags = Update::Force | Update::FitCursor;
1845 case LFUN_TEXTCLASS_APPLY: {
1846 BOOST_ASSERT(lyx_view_);
1847 Buffer * buffer = lyx_view_->buffer();
1849 loadTextClass(argument);
1851 std::pair<bool, textclass_type> const tc_pair =
1852 textclasslist.numberOfClass(argument);
1857 textclass_type const old_class = buffer->params().getBaseClass();
1858 textclass_type const new_class = tc_pair.second;
1860 if (old_class == new_class)
1864 //Save the old, possibly modular, layout for use in conversion.
1865 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1866 recordUndoFullDocument(view());
1867 buffer->params().setBaseClass(new_class);
1868 updateLayout(oldClass, buffer);
1869 updateFlags = Update::Force | Update::FitCursor;
1873 case LFUN_LAYOUT_RELOAD: {
1874 BOOST_ASSERT(lyx_view_);
1875 Buffer * buffer = lyx_view_->buffer();
1876 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1877 textclass_type const tc = buffer->params().getBaseClass();
1878 textclasslist.reset(tc);
1879 buffer->params().setBaseClass(tc);
1880 updateLayout(oldClass, buffer);
1881 updateFlags = Update::Force | Update::FitCursor;
1885 case LFUN_TEXTCLASS_LOAD:
1886 loadTextClass(argument);
1889 case LFUN_LYXRC_APPLY: {
1890 LyXRC const lyxrc_orig = lyxrc;
1892 istringstream ss(argument);
1893 bool const success = lyxrc.read(ss) == 0;
1896 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1897 << "Unable to read lyxrc data"
1902 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1904 /// We force the redraw in any case because there might be
1905 /// some screen font changes.
1906 /// FIXME: only the current view will be updated. the Gui
1907 /// class is able to furnish the list of views.
1908 updateFlags = Update::Force;
1912 case LFUN_WINDOW_NEW:
1913 LyX::ref().newLyXView();
1916 case LFUN_WINDOW_CLOSE:
1917 BOOST_ASSERT(lyx_view_);
1918 BOOST_ASSERT(theApp());
1919 // update bookmark pit of the current buffer before window close
1920 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1921 gotoBookmark(i+1, false, false);
1922 // ask the user for saving changes or cancel quit
1923 if (!theBufferList().quitWriteAll())
1928 case LFUN_BOOKMARK_GOTO:
1929 // go to bookmark, open unopened file and switch to buffer if necessary
1930 gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
1933 case LFUN_BOOKMARK_CLEAR:
1934 LyX::ref().session().bookmarks().clear();
1937 case LFUN_TOOLBAR_TOGGLE: {
1938 BOOST_ASSERT(lyx_view_);
1939 string const name = cmd.getArg(0);
1940 bool const allowauto = cmd.getArg(1) == "allowauto";
1941 lyx_view_->toggleToolbarState(name, allowauto);
1942 ToolbarInfo * tbi = lyx_view_->getToolbarInfo(name);
1944 setMessage(bformat(_("Unknown toolbar \"%1$s\""),
1949 if (tbi->flags & ToolbarInfo::ON)
1951 else if (tbi->flags & ToolbarInfo::OFF)
1953 else if (tbi->flags & ToolbarInfo::AUTO)
1956 setMessage(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1957 _(tbi->gui_name), state));
1962 BOOST_ASSERT(lyx_view_);
1963 view()->cursor().dispatch(cmd);
1964 updateFlags = view()->cursor().result().update();
1965 if (!view()->cursor().result().dispatched())
1966 updateFlags = view()->dispatch(cmd);
1971 if (lyx_view_ && lyx_view_->buffer()) {
1972 // BufferView::update() updates the ViewMetricsInfo and
1973 // also initializes the position cache for all insets in
1974 // (at least partially) visible top-level paragraphs.
1975 // We will redraw the screen only if needed.
1976 view()->processUpdateFlags(updateFlags);
1977 lyx_view_->updateStatusBar();
1979 // if we executed a mutating lfun, mark the buffer as dirty
1981 && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
1982 && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
1983 lyx_view_->buffer()->markDirty();
1985 //Do we have a selection?
1986 theSelection().haveSelection(view()->cursor().selection());
1988 if (view()->cursor().inTexted()) {
1989 lyx_view_->updateLayoutChoice();
1993 if (!quitting && lyx_view_) {
1994 lyx_view_->updateToolbars();
1995 // Some messages may already be translated, so we cannot use _()
1996 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
2001 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
2003 const bool verbose = (cmd.origin == FuncRequest::MENU
2004 || cmd.origin == FuncRequest::TOOLBAR
2005 || cmd.origin == FuncRequest::COMMANDBUFFER);
2007 if (cmd.action == LFUN_SELF_INSERT || !verbose) {
2008 LYXERR(Debug::ACTION) << "dispatch msg is " << to_utf8(msg) << endl;
2010 lyx_view_->message(msg);
2014 docstring dispatch_msg = msg;
2015 if (!dispatch_msg.empty())
2016 dispatch_msg += ' ';
2018 docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
2020 bool argsadded = false;
2022 if (!cmd.argument().empty()) {
2023 if (cmd.action != LFUN_UNKNOWN_ACTION) {
2024 comname += ' ' + cmd.argument();
2029 docstring const shortcuts = theTopLevelKeymap().printbindings(cmd);
2031 if (!shortcuts.empty())
2032 comname += ": " + shortcuts;
2033 else if (!argsadded && !cmd.argument().empty())
2034 comname += ' ' + cmd.argument();
2036 if (!comname.empty()) {
2037 comname = rtrim(comname);
2038 dispatch_msg += '(' + rtrim(comname) + ')';
2041 LYXERR(Debug::ACTION) << "verbose dispatch msg "
2042 << to_utf8(dispatch_msg) << endl;
2043 if (!dispatch_msg.empty())
2044 lyx_view_->message(dispatch_msg);
2048 void LyXFunc::menuNew(string const & name, bool fromTemplate)
2050 // FIXME: initpath is not used. What to do?
2051 string initpath = lyxrc.document_path;
2052 string filename(name);
2054 if (lyx_view_->buffer()) {
2055 string const trypath = lyx_view_->buffer()->filePath();
2056 // If directory is writeable, use this as default.
2057 if (isDirWriteable(FileName(trypath)))
2061 static int newfile_number;
2063 if (filename.empty()) {
2064 filename = addName(lyxrc.document_path,
2065 "newfile" + convert<string>(++newfile_number) + ".lyx");
2066 while (theBufferList().exists(filename) ||
2067 fs::is_readable(FileName(filename).toFilesystemEncoding())) {
2069 filename = addName(lyxrc.document_path,
2070 "newfile" + convert<string>(newfile_number) +
2075 // The template stuff
2078 FileDialog fileDlg(_("Select template file"),
2079 LFUN_SELECT_FILE_SYNC,
2080 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2081 make_pair(_("Templates|#T#t"), from_utf8(lyxrc.template_path)));
2083 FileDialog::Result result =
2084 fileDlg.open(from_utf8(lyxrc.template_path),
2085 FileFilterList(_("LyX Documents (*.lyx)")),
2088 if (result.first == FileDialog::Later)
2090 if (result.second.empty())
2092 templname = to_utf8(result.second);
2095 Buffer * const b = newFile(filename, templname, !name.empty());
2097 lyx_view_->setBuffer(b);
2101 void LyXFunc::open(string const & fname)
2103 string initpath = lyxrc.document_path;
2105 if (lyx_view_->buffer()) {
2106 string const trypath = lyx_view_->buffer()->filePath();
2107 // If directory is writeable, use this as default.
2108 if (isDirWriteable(FileName(trypath)))
2114 if (fname.empty()) {
2115 FileDialog fileDlg(_("Select document to open"),
2117 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2118 make_pair(_("Examples|#E#e"), from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2120 FileDialog::Result result =
2121 fileDlg.open(from_utf8(initpath),
2122 FileFilterList(_("LyX Documents (*.lyx)")),
2125 if (result.first == FileDialog::Later)
2128 filename = to_utf8(result.second);
2130 // check selected filename
2131 if (filename.empty()) {
2132 lyx_view_->message(_("Canceled."));
2138 // get absolute path of file and add ".lyx" to the filename if
2140 FileName const fullname = fileSearch(string(), filename, "lyx");
2141 if (!fullname.empty())
2142 filename = fullname.absFilename();
2144 // if the file doesn't exist, let the user create one
2145 if (!fs::exists(fullname.toFilesystemEncoding())) {
2146 // the user specifically chose this name. Believe him.
2147 Buffer * const b = newFile(filename, string(), true);
2149 lyx_view_->setBuffer(b);
2153 docstring const disp_fn = makeDisplayPath(filename);
2154 lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
2157 Buffer * buf = lyx_view_->loadLyXFile(fullname);
2160 lyx_view_->setBuffer(buf);
2161 lyx_view_->showErrorList("Parse");
2162 str2 = bformat(_("Document %1$s opened."), disp_fn);
2164 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2166 lyx_view_->message(str2);
2170 void LyXFunc::doImport(string const & argument)
2173 string filename = split(argument, format, ' ');
2175 LYXERR(Debug::INFO) << "LyXFunc::doImport: " << format
2176 << " file: " << filename << endl;
2178 // need user interaction
2179 if (filename.empty()) {
2180 string initpath = lyxrc.document_path;
2182 if (lyx_view_->buffer()) {
2183 string const trypath = lyx_view_->buffer()->filePath();
2184 // If directory is writeable, use this as default.
2185 if (isDirWriteable(FileName(trypath)))
2189 docstring const text = bformat(_("Select %1$s file to import"),
2190 formats.prettyName(format));
2192 FileDialog fileDlg(text,
2194 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2195 make_pair(_("Examples|#E#e"),
2196 from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2198 docstring filter = formats.prettyName(format);
2201 filter += from_utf8(formats.extension(format));
2204 FileDialog::Result result =
2205 fileDlg.open(from_utf8(initpath),
2206 FileFilterList(filter),
2209 if (result.first == FileDialog::Later)
2212 filename = to_utf8(result.second);
2214 // check selected filename
2215 if (filename.empty())
2216 lyx_view_->message(_("Canceled."));
2219 if (filename.empty())
2222 // get absolute path of file
2223 FileName const fullname(makeAbsPath(filename));
2225 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
2227 // Check if the document already is open
2228 if (use_gui && theBufferList().exists(lyxfile.absFilename())) {
2229 if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) {
2230 lyx_view_->message(_("Canceled."));
2235 // if the file exists already, and we didn't do
2236 // -i lyx thefile.lyx, warn
2237 if (fs::exists(lyxfile.toFilesystemEncoding()) && fullname != lyxfile) {
2238 docstring const file = makeDisplayPath(lyxfile.absFilename(), 30);
2240 docstring text = bformat(_("The document %1$s already exists.\n\n"
2241 "Do you want to overwrite that document?"), file);
2242 int const ret = Alert::prompt(_("Overwrite document?"),
2243 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2246 lyx_view_->message(_("Canceled."));
2251 ErrorList errorList;
2252 Importer::Import(lyx_view_, fullname, format, errorList);
2253 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2257 void LyXFunc::closeBuffer()
2259 // goto bookmark to update bookmark pit.
2260 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2261 gotoBookmark(i+1, false, false);
2263 theBufferList().close(lyx_view_->buffer(), true);
2267 void LyXFunc::reloadBuffer()
2269 FileName filename(lyx_view_->buffer()->fileName());
2270 docstring const disp_fn = makeDisplayPath(filename.absFilename());
2273 Buffer * buf = lyx_view_->loadLyXFile(filename);
2276 lyx_view_->setBuffer(buf);
2277 lyx_view_->showErrorList("Parse");
2278 str = bformat(_("Document %1$s reloaded."), disp_fn);
2280 str = bformat(_("Could not reload document %1$s"), disp_fn);
2282 lyx_view_->message(str);
2285 // Each "lyx_view_" should have it's own message method. lyxview and
2286 // the minibuffer would use the minibuffer, but lyxserver would
2287 // send an ERROR signal to its client. Alejandro 970603
2288 // This function is bit problematic when it comes to NLS, to make the
2289 // lyx servers client be language indepenent we must not translate
2290 // strings sent to this func.
2291 void LyXFunc::setErrorMessage(docstring const & m) const
2293 dispatch_buffer = m;
2298 void LyXFunc::setMessage(docstring const & m) const
2300 dispatch_buffer = m;
2304 docstring const LyXFunc::viewStatusMessage()
2306 // When meta-fake key is pressed, show the key sequence so far + "M-".
2308 return keyseq.print(true) + "M-";
2310 // Else, when a non-complete key sequence is pressed,
2311 // show the available options.
2312 if (keyseq.length() > 0 && !keyseq.deleted())
2313 return keyseq.printOptions(true);
2315 BOOST_ASSERT(lyx_view_);
2316 if (!lyx_view_->buffer())
2317 return _("Welcome to LyX!");
2319 return view()->cursor().currentState();
2323 BufferView * LyXFunc::view() const
2325 BOOST_ASSERT(lyx_view_);
2326 return lyx_view_->view();
2330 bool LyXFunc::wasMetaKey() const
2332 return (meta_fake_bit != NoModifier);
2336 void LyXFunc::updateLayout(TextClassPtr const & oldlayout,
2339 lyx_view_->message(_("Converting document to new document class..."));
2341 StableDocIterator backcur(view()->cursor());
2342 ErrorList & el = buffer->errorList("Class Switch");
2343 cap::switchBetweenClasses(
2344 oldlayout, buffer->params().getTextClassPtr(),
2345 static_cast<InsetText &>(buffer->inset()), el);
2347 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
2349 buffer->errors("Class Switch");
2350 updateLabels(*buffer);
2356 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2358 // Why the switch you might ask. It is a trick to ensure that all
2359 // the elements in the LyXRCTags enum is handled. As you can see
2360 // there are no breaks at all. So it is just a huge fall-through.
2361 // The nice thing is that we will get a warning from the compiler
2362 // if we forget an element.
2363 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2365 case LyXRC::RC_ACCEPT_COMPOUND:
2366 case LyXRC::RC_ALT_LANG:
2367 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
2368 case LyXRC::RC_PLAINTEXT_LINELEN:
2369 case LyXRC::RC_AUTOREGIONDELETE:
2370 case LyXRC::RC_AUTORESET_OPTIONS:
2371 case LyXRC::RC_AUTOSAVE:
2372 case LyXRC::RC_AUTO_NUMBER:
2373 case LyXRC::RC_BACKUPDIR_PATH:
2374 case LyXRC::RC_BIBTEX_COMMAND:
2375 case LyXRC::RC_BINDFILE:
2376 case LyXRC::RC_CHECKLASTFILES:
2377 case LyXRC::RC_USELASTFILEPOS:
2378 case LyXRC::RC_LOADSESSION:
2379 case LyXRC::RC_CHKTEX_COMMAND:
2380 case LyXRC::RC_CONVERTER:
2381 case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
2382 case LyXRC::RC_COPIER:
2383 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2384 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2385 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2386 case LyXRC::RC_DATE_INSERT_FORMAT:
2387 case LyXRC::RC_DEFAULT_LANGUAGE:
2388 case LyXRC::RC_DEFAULT_PAPERSIZE:
2389 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2390 case LyXRC::RC_DISPLAY_GRAPHICS:
2391 case LyXRC::RC_DOCUMENTPATH:
2392 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2393 string const encoded = FileName(
2394 lyxrc_new.document_path).toFilesystemEncoding();
2395 if (fs::exists(encoded) && fs::is_directory(encoded))
2396 support::package().document_dir() = FileName(lyxrc.document_path);
2398 case LyXRC::RC_ESC_CHARS:
2399 case LyXRC::RC_FONT_ENCODING:
2400 case LyXRC::RC_FORMAT:
2401 case LyXRC::RC_INDEX_COMMAND:
2402 case LyXRC::RC_INPUT:
2403 case LyXRC::RC_KBMAP:
2404 case LyXRC::RC_KBMAP_PRIMARY:
2405 case LyXRC::RC_KBMAP_SECONDARY:
2406 case LyXRC::RC_LABEL_INIT_LENGTH:
2407 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2408 case LyXRC::RC_LANGUAGE_AUTO_END:
2409 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2410 case LyXRC::RC_LANGUAGE_COMMAND_END:
2411 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2412 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2413 case LyXRC::RC_LANGUAGE_PACKAGE:
2414 case LyXRC::RC_LANGUAGE_USE_BABEL:
2415 case LyXRC::RC_MAKE_BACKUP:
2416 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2417 case LyXRC::RC_NUMLASTFILES:
2418 case LyXRC::RC_PATH_PREFIX:
2419 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2420 support::prependEnvPath("PATH", lyxrc.path_prefix);
2422 case LyXRC::RC_PERS_DICT:
2423 case LyXRC::RC_PREVIEW:
2424 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2425 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2426 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2427 case LyXRC::RC_PRINTCOPIESFLAG:
2428 case LyXRC::RC_PRINTER:
2429 case LyXRC::RC_PRINTEVENPAGEFLAG:
2430 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2431 case LyXRC::RC_PRINTFILEEXTENSION:
2432 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2433 case LyXRC::RC_PRINTODDPAGEFLAG:
2434 case LyXRC::RC_PRINTPAGERANGEFLAG:
2435 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2436 case LyXRC::RC_PRINTPAPERFLAG:
2437 case LyXRC::RC_PRINTREVERSEFLAG:
2438 case LyXRC::RC_PRINTSPOOL_COMMAND:
2439 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2440 case LyXRC::RC_PRINTTOFILE:
2441 case LyXRC::RC_PRINTTOPRINTER:
2442 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2443 case LyXRC::RC_PRINT_COMMAND:
2444 case LyXRC::RC_RTL_SUPPORT:
2445 case LyXRC::RC_SCREEN_DPI:
2446 case LyXRC::RC_SCREEN_FONT_ROMAN:
2447 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2448 case LyXRC::RC_SCREEN_FONT_SANS:
2449 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2450 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2451 case LyXRC::RC_SCREEN_FONT_SIZES:
2452 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2453 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2454 case LyXRC::RC_SCREEN_GEOMETRY_HEIGHT:
2455 case LyXRC::RC_SCREEN_GEOMETRY_WIDTH:
2456 case LyXRC::RC_SCREEN_GEOMETRY_XYSAVED:
2457 case LyXRC::RC_SCREEN_ZOOM:
2458 case LyXRC::RC_SERVERPIPE:
2459 case LyXRC::RC_SET_COLOR:
2460 case LyXRC::RC_SHOW_BANNER:
2461 case LyXRC::RC_SPELL_COMMAND:
2462 case LyXRC::RC_TEMPDIRPATH:
2463 case LyXRC::RC_TEMPLATEPATH:
2464 case LyXRC::RC_TEX_ALLOWS_SPACES:
2465 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2466 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2467 support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2469 case LyXRC::RC_UIFILE:
2470 case LyXRC::RC_USER_EMAIL:
2471 case LyXRC::RC_USER_NAME:
2472 case LyXRC::RC_USETEMPDIR:
2473 case LyXRC::RC_USE_ALT_LANG:
2474 case LyXRC::RC_USE_CONVERTER_CACHE:
2475 case LyXRC::RC_USE_ESC_CHARS:
2476 case LyXRC::RC_USE_INP_ENC:
2477 case LyXRC::RC_USE_PERS_DICT:
2478 case LyXRC::RC_USE_SPELL_LIB:
2479 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2480 case LyXRC::RC_VIEWER:
2481 case LyXRC::RC_LAST: