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;
417 /* When we move around, or type, it's nice to be able to see
418 * the cursor immediately after the keypress.
420 if (lyx_view_ && lyx_view_->currentWorkArea())
421 lyx_view_->currentWorkArea()->startBlinkingCursor();
425 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
427 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
430 Cursor & cur = view()->cursor();
432 /* In LyX/Mac, when a dialog is open, the menus of the
433 application can still be accessed without giving focus to
434 the main window. In this case, we want to disable the menu
435 entries that are buffer-related.
437 Note that this code is not perfect, as bug 1941 attests:
438 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
440 Buffer * buf = lyx_view_? lyx_view_->buffer() : 0;
441 if (lyx_view_ && cmd.origin == FuncRequest::MENU && !lyx_view_->hasFocus())
444 if (cmd.action == LFUN_NOACTION) {
445 flag.message(from_utf8(N_("Nothing to do")));
450 switch (cmd.action) {
451 case LFUN_UNKNOWN_ACTION:
452 #ifndef HAVE_LIBAIKSAURUS
453 case LFUN_THESAURUS_ENTRY:
463 if (flag.unknown()) {
464 flag.message(from_utf8(N_("Unknown action")));
468 if (!flag.enabled()) {
469 if (flag.message().empty())
470 flag.message(from_utf8(N_("Command disabled")));
474 // Check whether we need a buffer
475 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
477 flag.message(from_utf8(N_("Command not allowed with"
478 "out any document open")));
483 // I would really like to avoid having this switch and rather try to
484 // encode this in the function itself.
485 // -- And I'd rather let an inset decide which LFUNs it is willing
486 // to handle (Andre')
488 switch (cmd.action) {
489 case LFUN_BUFFER_TOGGLE_READ_ONLY:
490 flag.setOnOff(buf->isReadonly());
493 case LFUN_BUFFER_SWITCH:
494 // toggle on the current buffer, but do not toggle off
495 // the other ones (is that a good idea?)
496 if (buf && to_utf8(cmd.argument()) == buf->fileName())
500 case LFUN_BUFFER_EXPORT:
501 enable = cmd.argument() == "custom"
502 || Exporter::isExportable(*buf, to_utf8(cmd.argument()));
505 case LFUN_BUFFER_CHKTEX:
506 enable = buf->isLatex() && !lyxrc.chktex_command.empty();
509 case LFUN_BUILD_PROGRAM:
510 enable = Exporter::isExportable(*buf, "program");
513 case LFUN_LAYOUT_TABULAR:
514 enable = cur.innerInsetOfType(Inset::TABULAR_CODE);
518 case LFUN_LAYOUT_PARAGRAPH:
519 enable = !cur.inset().forceDefaultParagraphs(cur.idx());
522 case LFUN_VC_REGISTER:
523 enable = !buf->lyxvc().inUse();
525 case LFUN_VC_CHECK_IN:
526 enable = buf->lyxvc().inUse() && !buf->isReadonly();
528 case LFUN_VC_CHECK_OUT:
529 enable = buf->lyxvc().inUse() && buf->isReadonly();
532 case LFUN_VC_UNDO_LAST:
533 enable = buf->lyxvc().inUse();
535 case LFUN_BUFFER_RELOAD:
536 enable = !buf->isUnnamed() && fs::exists(buf->fileName())
537 && (!buf->isClean() || buf->isExternallyModified(Buffer::timestamp_method));
540 case LFUN_INSET_SETTINGS: {
544 Inset::Code code = cur.inset().lyxCode();
546 case Inset::TABULAR_CODE:
547 enable = cmd.argument() == "tabular";
549 case Inset::ERT_CODE:
550 enable = cmd.argument() == "ert";
552 case Inset::FLOAT_CODE:
553 enable = cmd.argument() == "float";
555 case Inset::WRAP_CODE:
556 enable = cmd.argument() == "wrap";
558 case Inset::NOTE_CODE:
559 enable = cmd.argument() == "note";
561 case Inset::BRANCH_CODE:
562 enable = cmd.argument() == "branch";
564 case Inset::BOX_CODE:
565 enable = cmd.argument() == "box";
567 case Inset::LISTINGS_CODE:
568 enable = cmd.argument() == "listings";
576 case LFUN_INSET_APPLY: {
577 string const name = cmd.getArg(0);
578 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
580 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
582 if (!inset->getStatus(cur, fr, fs)) {
583 // Every inset is supposed to handle this
588 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
589 flag |= getStatus(fr);
591 enable = flag.enabled();
595 case LFUN_DIALOG_TOGGLE:
596 flag.setOnOff(lyx_view_->getDialogs().visible(cmd.getArg(0)));
597 // fall through to set "enable"
598 case LFUN_DIALOG_SHOW: {
599 string const name = cmd.getArg(0);
601 enable = name == "aboutlyx"
602 || name == "file" //FIXME: should be removed.
604 || name == "texinfo";
605 else if (name == "print")
606 enable = Exporter::isExportable(*buf, "dvi")
607 && lyxrc.print_command != "none";
608 else if (name == "character")
609 enable = cur.inset().lyxCode() != Inset::ERT_CODE &&
610 cur.inset().lyxCode() != Inset::LISTINGS_CODE;
611 else if (name == "latexlog")
612 enable = isFileReadable(FileName(buf->getLogName().second));
613 else if (name == "spellchecker")
614 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
615 enable = !buf->isReadonly();
619 else if (name == "vclog")
620 enable = buf->lyxvc().inUse();
624 case LFUN_DIALOG_SHOW_NEW_INSET:
625 enable = cur.inset().lyxCode() != Inset::ERT_CODE &&
626 cur.inset().lyxCode() != Inset::LISTINGS_CODE;
627 if (cur.inset().lyxCode() == Inset::CAPTION_CODE) {
629 if (cur.inset().getStatus(cur, cmd, flag))
634 case LFUN_DIALOG_UPDATE: {
635 string const name = cmd.getArg(0);
637 enable = name == "prefs";
641 case LFUN_CITATION_INSERT: {
642 FuncRequest fr(LFUN_INSET_INSERT, "citation");
643 enable = getStatus(fr).enabled();
647 case LFUN_BUFFER_WRITE: {
648 enable = lyx_view_->buffer()->isUnnamed()
649 || !lyx_view_->buffer()->isClean();
654 case LFUN_BUFFER_WRITE_ALL: {
655 // We enable the command only if there are some modified buffers
656 Buffer * first = theBufferList().first();
657 bool modified = false;
661 // We cannot use a for loop as the buffer list is a cycle.
667 b = theBufferList().next(b);
668 } while (b != first);
676 case LFUN_BOOKMARK_GOTO: {
677 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
678 enable = LyX::ref().session().bookmarks().isValid(num);
682 case LFUN_BOOKMARK_CLEAR:
683 enable = LyX::ref().session().bookmarks().size() > 0;
686 case LFUN_TOOLBAR_TOGGLE: {
687 bool const current = lyx_view_->isToolbarVisible(cmd.getArg(0));
688 flag.setOnOff(current);
691 case LFUN_WINDOW_CLOSE: {
692 enable = (theApp()->gui().viewIds().size() > 1);
696 // this one is difficult to get right. As a half-baked
697 // solution, we consider only the first action of the sequence
698 case LFUN_COMMAND_SEQUENCE: {
699 // argument contains ';'-terminated commands
700 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
701 FuncRequest func(lyxaction.lookupFunc(firstcmd));
702 func.origin = cmd.origin;
703 flag = getStatus(func);
706 case LFUN_BUFFER_NEW:
707 case LFUN_BUFFER_NEW_TEMPLATE:
708 case LFUN_WORD_FIND_FORWARD:
709 case LFUN_WORD_FIND_BACKWARD:
710 case LFUN_COMMAND_PREFIX:
711 case LFUN_COMMAND_EXECUTE:
713 case LFUN_META_PREFIX:
714 case LFUN_BUFFER_CLOSE:
715 case LFUN_BUFFER_WRITE_AS:
716 case LFUN_BUFFER_UPDATE:
717 case LFUN_BUFFER_VIEW:
718 case LFUN_MASTER_BUFFER_UPDATE:
719 case LFUN_MASTER_BUFFER_VIEW:
720 case LFUN_BUFFER_IMPORT:
721 case LFUN_BUFFER_AUTO_SAVE:
722 case LFUN_RECONFIGURE:
726 case LFUN_DROP_LAYOUTS_CHOICE:
728 case LFUN_SERVER_GET_NAME:
729 case LFUN_SERVER_NOTIFY:
730 case LFUN_SERVER_GOTO_FILE_ROW:
731 case LFUN_DIALOG_HIDE:
732 case LFUN_DIALOG_DISCONNECT_INSET:
733 case LFUN_BUFFER_CHILD_OPEN:
734 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
735 case LFUN_KEYMAP_OFF:
736 case LFUN_KEYMAP_PRIMARY:
737 case LFUN_KEYMAP_SECONDARY:
738 case LFUN_KEYMAP_TOGGLE:
740 case LFUN_BUFFER_EXPORT_CUSTOM:
741 case LFUN_BUFFER_PRINT:
742 case LFUN_PREFERENCES_SAVE:
743 case LFUN_SCREEN_FONT_UPDATE:
746 case LFUN_EXTERNAL_EDIT:
747 case LFUN_GRAPHICS_EDIT:
748 case LFUN_ALL_INSETS_TOGGLE:
749 case LFUN_BUFFER_LANGUAGE:
750 case LFUN_TEXTCLASS_APPLY:
751 case LFUN_TEXTCLASS_LOAD:
752 case LFUN_BUFFER_SAVE_AS_DEFAULT:
753 case LFUN_BUFFER_PARAMS_APPLY:
754 case LFUN_LAYOUT_MODULES_CLEAR:
755 case LFUN_LAYOUT_MODULE_ADD:
756 case LFUN_LAYOUT_RELOAD:
757 case LFUN_LYXRC_APPLY:
758 case LFUN_BUFFER_NEXT:
759 case LFUN_BUFFER_PREVIOUS:
760 case LFUN_WINDOW_NEW:
762 // these are handled in our dispatch()
766 if (!getLocalStatus(cur, cmd, flag))
767 flag = view()->getStatus(cmd);
773 // Can we use a readonly buffer?
774 if (buf && buf->isReadonly()
775 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
776 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
777 flag.message(from_utf8(N_("Document is read-only")));
781 // Are we in a DELETED change-tracking region?
782 if (buf && lookupChangeType(cur, true) == Change::DELETED
783 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
784 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
785 flag.message(from_utf8(N_("This portion of the document is deleted.")));
789 // the default error message if we disable the command
790 if (!flag.enabled() && flag.message().empty())
791 flag.message(from_utf8(N_("Command disabled")));
797 bool LyXFunc::ensureBufferClean(BufferView * bv)
799 Buffer & buf = bv->buffer();
803 docstring const file = makeDisplayPath(buf.fileName(), 30);
804 docstring text = bformat(_("The document %1$s has unsaved "
805 "changes.\n\nDo you want to save "
806 "the document?"), file);
807 int const ret = Alert::prompt(_("Save changed document?"),
808 text, 0, 1, _("&Save"),
812 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
814 return buf.isClean();
820 void showPrintError(string const & name)
822 docstring str = bformat(_("Could not print the document %1$s.\n"
823 "Check that your printer is set up correctly."),
824 makeDisplayPath(name, 50));
825 Alert::error(_("Print document failed"), str);
829 void loadTextClass(string const & name)
831 std::pair<bool, textclass_type> const tc_pair =
832 textclasslist.numberOfClass(name);
834 if (!tc_pair.first) {
835 lyxerr << "Document class \"" << name
836 << "\" does not exist."
841 textclass_type const tc = tc_pair.second;
843 if (!textclasslist[tc].load()) {
844 docstring s = bformat(_("The document class %1$s."
845 "could not be loaded."),
846 from_utf8(textclasslist[tc].name()));
847 Alert::error(_("Could not load class"), s);
852 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
857 void LyXFunc::dispatch(FuncRequest const & cmd)
859 string const argument = to_utf8(cmd.argument());
860 kb_action const action = cmd.action;
862 LYXERR(Debug::ACTION) << endl << "LyXFunc::dispatch: cmd: " << cmd << endl;
863 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
865 // we have not done anything wrong yet.
867 dispatch_buffer.erase();
869 // redraw the screen at the end (first of the two drawing steps).
870 //This is done unless explicitely requested otherwise
871 Update::flags updateFlags = Update::FitCursor;
873 FuncStatus const flag = getStatus(cmd);
874 if (!flag.enabled()) {
875 // We cannot use this function here
876 LYXERR(Debug::ACTION) << "LyXFunc::dispatch: "
877 << lyxaction.getActionName(action)
878 << " [" << action << "] is disabled at this location"
880 setErrorMessage(flag.message());
884 case LFUN_WORD_FIND_FORWARD:
885 case LFUN_WORD_FIND_BACKWARD: {
886 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
887 static docstring last_search;
888 docstring searched_string;
890 if (!cmd.argument().empty()) {
891 last_search = cmd.argument();
892 searched_string = cmd.argument();
894 searched_string = last_search;
897 if (searched_string.empty())
900 bool const fw = action == LFUN_WORD_FIND_FORWARD;
901 docstring const data =
902 find2string(searched_string, true, false, fw);
903 find(view(), FuncRequest(LFUN_WORD_FIND, data));
907 case LFUN_COMMAND_PREFIX:
908 BOOST_ASSERT(lyx_view_);
909 lyx_view_->message(keyseq.printOptions(true));
912 case LFUN_COMMAND_EXECUTE:
913 BOOST_ASSERT(lyx_view_);
914 lyx_view_->showMiniBuffer(true);
918 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
920 meta_fake_bit = NoModifier;
921 if (lyx_view_->buffer())
922 // cancel any selection
923 dispatch(FuncRequest(LFUN_MARK_OFF));
924 setMessage(from_ascii(N_("Cancel")));
927 case LFUN_META_PREFIX:
928 meta_fake_bit = AltModifier;
929 setMessage(keyseq.print(true));
932 case LFUN_BUFFER_TOGGLE_READ_ONLY: {
933 BOOST_ASSERT(lyx_view_ && lyx_view_->view() && lyx_view_->buffer());
934 Buffer * buf = lyx_view_->buffer();
935 if (buf->lyxvc().inUse())
936 buf->lyxvc().toggleReadOnly();
938 buf->setReadonly(!lyx_view_->buffer()->isReadonly());
942 // --- Menus -----------------------------------------------
943 case LFUN_BUFFER_NEW:
944 menuNew(argument, false);
945 updateFlags = Update::None;
948 case LFUN_BUFFER_NEW_TEMPLATE:
949 menuNew(argument, true);
950 updateFlags = Update::None;
953 case LFUN_BUFFER_CLOSE:
955 updateFlags = Update::None;
958 case LFUN_BUFFER_WRITE:
959 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
960 if (!lyx_view_->buffer()->isUnnamed()) {
961 docstring const str = bformat(_("Saving document %1$s..."),
962 makeDisplayPath(lyx_view_->buffer()->fileName()));
963 lyx_view_->message(str);
964 lyx_view_->buffer()->menuWrite();
965 lyx_view_->message(str + _(" done."));
967 lyx_view_->buffer()->writeAs();
969 updateFlags = Update::None;
972 case LFUN_BUFFER_WRITE_AS:
973 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
974 lyx_view_->buffer()->writeAs(argument);
975 updateFlags = Update::None;
978 case LFUN_BUFFER_WRITE_ALL: {
979 Buffer * first = theBufferList().first();
982 lyx_view_->message(_("Saving all documents..."));
984 // We cannot use a for loop as the buffer list cycles.
987 if (!b->isUnnamed()) {
989 lyxerr[Debug::ACTION] << "Saved " << b->fileName() << endl;
993 b = theBufferList().next(b);
994 } while (b != first);
995 lyx_view_->message(_("All documents saved."));
998 updateFlags = Update::None;
1002 case LFUN_BUFFER_RELOAD: {
1003 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1004 docstring const file = makeDisplayPath(lyx_view_->buffer()->fileName(), 20);
1005 docstring text = bformat(_("Any changes will be lost. Are you sure "
1006 "you want to revert to the saved version of the document %1$s?"), file);
1007 int const ret = Alert::prompt(_("Revert to saved document?"),
1008 text, 1, 1, _("&Revert"), _("&Cancel"));
1015 case LFUN_BUFFER_UPDATE:
1016 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1017 Exporter::Export(lyx_view_->buffer(), argument, true);
1020 case LFUN_BUFFER_VIEW:
1021 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1022 Exporter::preview(lyx_view_->buffer(), argument);
1025 case LFUN_MASTER_BUFFER_UPDATE:
1026 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->getMasterBuffer());
1027 Exporter::Export(lyx_view_->buffer()->getMasterBuffer(), argument, true);
1030 case LFUN_MASTER_BUFFER_VIEW:
1031 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->getMasterBuffer());
1032 Exporter::preview(lyx_view_->buffer()->getMasterBuffer(), argument);
1035 case LFUN_BUILD_PROGRAM:
1036 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1037 Exporter::Export(lyx_view_->buffer(), "program", true);
1040 case LFUN_BUFFER_CHKTEX:
1041 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1042 lyx_view_->buffer()->runChktex();
1045 case LFUN_BUFFER_EXPORT:
1046 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1047 if (argument == "custom")
1048 lyx_view_->getDialogs().show("sendto");
1050 Exporter::Export(lyx_view_->buffer(), argument, false);
1054 case LFUN_BUFFER_EXPORT_CUSTOM: {
1055 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1057 string command = split(argument, format_name, ' ');
1058 Format const * format = formats.getFormat(format_name);
1060 lyxerr << "Format \"" << format_name
1061 << "\" not recognized!"
1066 Buffer * buffer = lyx_view_->buffer();
1068 // The name of the file created by the conversion process
1071 // Output to filename
1072 if (format->name() == "lyx") {
1073 string const latexname =
1074 buffer->getLatexName(false);
1075 filename = changeExtension(latexname,
1076 format->extension());
1077 filename = addName(buffer->temppath(), filename);
1079 if (!buffer->writeFile(FileName(filename)))
1083 Exporter::Export(buffer, format_name, true, filename);
1086 // Substitute $$FName for filename
1087 if (!contains(command, "$$FName"))
1088 command = "( " + command + " ) < $$FName";
1089 command = subst(command, "$$FName", filename);
1091 // Execute the command in the background
1093 call.startscript(Systemcall::DontWait, command);
1097 case LFUN_BUFFER_PRINT: {
1098 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1099 // FIXME: cmd.getArg() might fail if one of the arguments
1100 // contains double quotes
1101 string target = cmd.getArg(0);
1102 string target_name = cmd.getArg(1);
1103 string command = cmd.getArg(2);
1106 || target_name.empty()
1107 || command.empty()) {
1108 lyxerr << "Unable to parse \""
1109 << argument << '"' << endl;
1112 if (target != "printer" && target != "file") {
1113 lyxerr << "Unrecognized target \""
1114 << target << '"' << endl;
1118 Buffer * buffer = lyx_view_->buffer();
1120 if (!Exporter::Export(buffer, "dvi", true)) {
1121 showPrintError(buffer->fileName());
1125 // Push directory path.
1126 string const path = buffer->temppath();
1127 // Prevent the compiler from optimizing away p
1129 support::Path p(pp);
1131 // there are three cases here:
1132 // 1. we print to a file
1133 // 2. we print directly to a printer
1134 // 3. we print using a spool command (print to file first)
1137 string const dviname =
1138 changeExtension(buffer->getLatexName(true),
1141 if (target == "printer") {
1142 if (!lyxrc.print_spool_command.empty()) {
1143 // case 3: print using a spool
1144 string const psname =
1145 changeExtension(dviname,".ps");
1146 command += ' ' + lyxrc.print_to_file
1149 + quoteName(dviname);
1152 lyxrc.print_spool_command + ' ';
1153 if (target_name != "default") {
1154 command2 += lyxrc.print_spool_printerprefix
1158 command2 += quoteName(psname);
1160 // If successful, then spool command
1161 res = one.startscript(
1166 res = one.startscript(
1167 Systemcall::DontWait,
1170 // case 2: print directly to a printer
1171 if (target_name != "default")
1172 command += ' ' + lyxrc.print_to_printer + target_name + ' ';
1173 res = one.startscript(
1174 Systemcall::DontWait,
1175 command + quoteName(dviname));
1179 // case 1: print to a file
1180 FileName const filename(makeAbsPath(target_name,
1181 lyx_view_->buffer()->filePath()));
1182 FileName const dvifile(makeAbsPath(dviname, path));
1183 if (fs::exists(filename.toFilesystemEncoding())) {
1184 docstring text = bformat(
1185 _("The file %1$s already exists.\n\n"
1186 "Do you want to overwrite that file?"),
1187 makeDisplayPath(filename.absFilename()));
1188 if (Alert::prompt(_("Overwrite file?"),
1189 text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
1192 command += ' ' + lyxrc.print_to_file
1193 + quoteName(filename.toFilesystemEncoding())
1195 + quoteName(dvifile.toFilesystemEncoding());
1196 res = one.startscript(Systemcall::DontWait,
1201 showPrintError(buffer->fileName());
1205 case LFUN_BUFFER_IMPORT:
1210 // quitting is triggered by the gui code
1211 // (leaving the event loop).
1212 lyx_view_->message(from_utf8(N_("Exiting.")));
1213 if (theBufferList().quitWriteAll())
1214 theApp()->gui().closeAllViews();
1217 case LFUN_BUFFER_AUTO_SAVE:
1218 lyx_view_->buffer()->autoSave();
1221 case LFUN_RECONFIGURE:
1222 BOOST_ASSERT(lyx_view_);
1223 // argument is any additional parameter to the configure.py command
1224 reconfigure(*lyx_view_, argument);
1227 case LFUN_HELP_OPEN: {
1228 BOOST_ASSERT(lyx_view_);
1229 string const arg = argument;
1231 setErrorMessage(from_ascii(N_("Missing argument")));
1234 FileName const fname = i18nLibFileSearch("doc", arg, "lyx");
1235 if (fname.empty()) {
1236 lyxerr << "LyX: unable to find documentation file `"
1237 << arg << "'. Bad installation?" << endl;
1240 lyx_view_->message(bformat(_("Opening help file %1$s..."),
1241 makeDisplayPath(fname.absFilename())));
1242 Buffer * buf = lyx_view_->loadLyXFile(fname, false);
1245 lyx_view_->setBuffer(buf);
1246 lyx_view_->showErrorList("Parse");
1248 updateFlags = Update::None;
1252 // --- version control -------------------------------
1253 case LFUN_VC_REGISTER:
1254 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1255 if (!ensureBufferClean(view()))
1257 if (!lyx_view_->buffer()->lyxvc().inUse()) {
1258 lyx_view_->buffer()->lyxvc().registrer();
1261 updateFlags = Update::Force;
1264 case LFUN_VC_CHECK_IN:
1265 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1266 if (!ensureBufferClean(view()))
1268 if (lyx_view_->buffer()->lyxvc().inUse()
1269 && !lyx_view_->buffer()->isReadonly()) {
1270 lyx_view_->buffer()->lyxvc().checkIn();
1275 case LFUN_VC_CHECK_OUT:
1276 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1277 if (!ensureBufferClean(view()))
1279 if (lyx_view_->buffer()->lyxvc().inUse()
1280 && lyx_view_->buffer()->isReadonly()) {
1281 lyx_view_->buffer()->lyxvc().checkOut();
1286 case LFUN_VC_REVERT:
1287 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1288 lyx_view_->buffer()->lyxvc().revert();
1292 case LFUN_VC_UNDO_LAST:
1293 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1294 lyx_view_->buffer()->lyxvc().undoLast();
1298 // --- buffers ----------------------------------------
1299 case LFUN_BUFFER_SWITCH:
1300 BOOST_ASSERT(lyx_view_);
1301 lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1302 updateFlags = Update::None;
1305 case LFUN_BUFFER_NEXT:
1306 BOOST_ASSERT(lyx_view_);
1307 lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer()));
1308 updateFlags = Update::None;
1311 case LFUN_BUFFER_PREVIOUS:
1312 BOOST_ASSERT(lyx_view_);
1313 lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer()));
1314 updateFlags = Update::None;
1317 case LFUN_FILE_NEW: {
1318 BOOST_ASSERT(lyx_view_);
1320 string tmpname = split(argument, name, ':'); // Split filename
1321 Buffer * const b = newFile(name, tmpname);
1323 lyx_view_->setBuffer(b);
1324 updateFlags = Update::None;
1328 case LFUN_FILE_OPEN:
1329 BOOST_ASSERT(lyx_view_);
1331 updateFlags = Update::None;
1334 case LFUN_DROP_LAYOUTS_CHOICE:
1335 BOOST_ASSERT(lyx_view_);
1336 lyx_view_->openLayoutList();
1339 case LFUN_MENU_OPEN:
1340 BOOST_ASSERT(lyx_view_);
1341 lyx_view_->openMenu(from_utf8(argument));
1344 // --- lyxserver commands ----------------------------
1345 case LFUN_SERVER_GET_NAME:
1346 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1347 setMessage(from_utf8(lyx_view_->buffer()->fileName()));
1348 LYXERR(Debug::INFO) << "FNAME["
1349 << lyx_view_->buffer()->fileName()
1353 case LFUN_SERVER_NOTIFY:
1354 dispatch_buffer = keyseq.print(false);
1355 theServer().notifyClient(to_utf8(dispatch_buffer));
1358 case LFUN_SERVER_GOTO_FILE_ROW: {
1359 BOOST_ASSERT(lyx_view_);
1362 istringstream is(argument);
1363 is >> file_name >> row;
1365 bool loaded = false;
1366 if (prefixIs(file_name, package().temp_dir().absFilename()))
1367 // Needed by inverse dvi search. If it is a file
1368 // in tmpdir, call the apropriated function
1369 buf = theBufferList().getBufferFromTmp(file_name);
1371 // Must replace extension of the file to be .lyx
1372 // and get full path
1373 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1374 // Either change buffer or load the file
1375 if (theBufferList().exists(s.absFilename()))
1376 buf = theBufferList().getBuffer(s.absFilename());
1378 buf = lyx_view_->loadLyXFile(s);
1384 updateFlags = Update::None;
1389 lyx_view_->setBuffer(buf);
1390 view()->setCursorFromRow(row);
1392 lyx_view_->showErrorList("Parse");
1393 updateFlags = Update::FitCursor;
1397 case LFUN_DIALOG_SHOW: {
1398 BOOST_ASSERT(lyx_view_);
1399 string const name = cmd.getArg(0);
1400 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1402 if (name == "character") {
1403 data = freefont2string();
1405 lyx_view_->getDialogs().show("character", data);
1406 } else if (name == "latexlog") {
1407 pair<Buffer::LogType, string> const logfile =
1408 lyx_view_->buffer()->getLogName();
1409 switch (logfile.first) {
1410 case Buffer::latexlog:
1413 case Buffer::buildlog:
1417 data += Lexer::quoteString(logfile.second);
1418 lyx_view_->getDialogs().show("log", data);
1419 } else if (name == "vclog") {
1420 string const data = "vc " +
1421 Lexer::quoteString(lyx_view_->buffer()->lyxvc().getLogFile());
1422 lyx_view_->getDialogs().show("log", data);
1424 lyx_view_->getDialogs().show(name, data);
1428 case LFUN_DIALOG_SHOW_NEW_INSET: {
1429 BOOST_ASSERT(lyx_view_);
1430 string const name = cmd.getArg(0);
1431 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1432 if (name == "bibitem" ||
1436 name == "nomenclature" ||
1440 InsetCommandParams p(name);
1441 data = InsetCommandMailer::params2string(name, p);
1442 } else if (name == "include") {
1443 // data is the include type: one of "include",
1444 // "input", "verbatiminput" or "verbatiminput*"
1446 // default type is requested
1448 InsetCommandParams p(data);
1449 data = InsetIncludeMailer::params2string(p);
1450 } else if (name == "box") {
1451 // \c data == "Boxed" || "Frameless" etc
1452 InsetBoxParams p(data);
1453 data = InsetBoxMailer::params2string(p);
1454 } else if (name == "branch") {
1455 InsetBranchParams p;
1456 data = InsetBranchMailer::params2string(p);
1457 } else if (name == "citation") {
1458 InsetCommandParams p("citation");
1459 data = InsetCommandMailer::params2string(name, p);
1460 } else if (name == "ert") {
1461 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1462 } else if (name == "external") {
1463 InsetExternalParams p;
1464 Buffer const & buffer = *lyx_view_->buffer();
1465 data = InsetExternalMailer::params2string(p, buffer);
1466 } else if (name == "float") {
1468 data = InsetFloatMailer::params2string(p);
1469 } else if (name == "listings") {
1470 InsetListingsParams p;
1471 data = InsetListingsMailer::params2string(p);
1472 } else if (name == "graphics") {
1473 InsetGraphicsParams p;
1474 Buffer const & buffer = *lyx_view_->buffer();
1475 data = InsetGraphicsMailer::params2string(p, buffer);
1476 } else if (name == "note") {
1478 data = InsetNoteMailer::params2string(p);
1479 } else if (name == "vspace") {
1481 data = InsetVSpaceMailer::params2string(space);
1482 } else if (name == "wrap") {
1484 data = InsetWrapMailer::params2string(p);
1486 lyx_view_->getDialogs().show(name, data, 0);
1490 case LFUN_DIALOG_UPDATE: {
1491 BOOST_ASSERT(lyx_view_);
1492 string const & name = argument;
1493 // Can only update a dialog connected to an existing inset
1494 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1496 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1497 inset->dispatch(view()->cursor(), fr);
1498 } else if (name == "paragraph") {
1499 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1500 } else if (name == "prefs") {
1501 lyx_view_->getDialogs().update(name, string());
1506 case LFUN_DIALOG_HIDE:
1507 LyX::cref().hideDialogs(argument, 0);
1510 case LFUN_DIALOG_TOGGLE: {
1511 BOOST_ASSERT(lyx_view_);
1512 if (lyx_view_->getDialogs().visible(cmd.getArg(0)))
1513 dispatch(FuncRequest(LFUN_DIALOG_HIDE, argument));
1515 dispatch(FuncRequest(LFUN_DIALOG_SHOW, argument));
1519 case LFUN_DIALOG_DISCONNECT_INSET:
1520 BOOST_ASSERT(lyx_view_);
1521 lyx_view_->getDialogs().disconnect(argument);
1525 case LFUN_CITATION_INSERT: {
1526 BOOST_ASSERT(lyx_view_);
1527 if (!argument.empty()) {
1528 // we can have one optional argument, delimited by '|'
1529 // citation-insert <key>|<text_before>
1530 // this should be enhanced to also support text_after
1531 // and citation style
1532 string arg = argument;
1534 if (contains(argument, "|")) {
1535 arg = token(argument, '|', 0);
1536 opt1 = token(argument, '|', 1);
1538 InsetCommandParams icp("citation");
1539 icp["key"] = from_utf8(arg);
1541 icp["before"] = from_utf8(opt1);
1542 string icstr = InsetCommandMailer::params2string("citation", icp);
1543 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1546 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1550 case LFUN_BUFFER_CHILD_OPEN: {
1551 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1552 Buffer * parent = lyx_view_->buffer();
1553 FileName filename = makeAbsPath(argument, parent->filePath());
1554 view()->saveBookmark(false);
1556 bool parsed = false;
1557 if (theBufferList().exists(filename.absFilename())) {
1558 child = theBufferList().getBuffer(filename.absFilename());
1560 setMessage(bformat(_("Opening child document %1$s..."),
1561 makeDisplayPath(filename.absFilename())));
1562 child = lyx_view_->loadLyXFile(filename, true);
1566 // Set the parent name of the child document.
1567 // This makes insertion of citations and references in the child work,
1568 // when the target is in the parent or another child document.
1569 child->setParentName(parent->fileName());
1570 updateLabels(*child->getMasterBuffer());
1571 lyx_view_->setBuffer(child);
1573 lyx_view_->showErrorList("Parse");
1576 // If a screen update is required (in case where auto_open is false),
1577 // setBuffer() would have taken care of it already. Otherwise we shall
1578 // reset the update flag because it can cause a circular problem.
1580 updateFlags = Update::None;
1584 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1585 BOOST_ASSERT(lyx_view_);
1586 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1589 case LFUN_KEYMAP_OFF:
1590 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1591 lyx_view_->view()->getIntl().keyMapOn(false);
1594 case LFUN_KEYMAP_PRIMARY:
1595 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1596 lyx_view_->view()->getIntl().keyMapPrim();
1599 case LFUN_KEYMAP_SECONDARY:
1600 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1601 lyx_view_->view()->getIntl().keyMapSec();
1604 case LFUN_KEYMAP_TOGGLE:
1605 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1606 lyx_view_->view()->getIntl().toggleKeyMap();
1612 string rest = split(argument, countstr, ' ');
1613 istringstream is(countstr);
1616 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1617 for (int i = 0; i < count; ++i)
1618 dispatch(lyxaction.lookupFunc(rest));
1622 case LFUN_COMMAND_SEQUENCE: {
1623 // argument contains ';'-terminated commands
1624 string arg = argument;
1625 while (!arg.empty()) {
1627 arg = split(arg, first, ';');
1628 FuncRequest func(lyxaction.lookupFunc(first));
1629 func.origin = cmd.origin;
1635 case LFUN_PREFERENCES_SAVE: {
1636 lyxrc.write(makeAbsPath("preferences",
1637 package().user_support().absFilename()),
1642 case LFUN_SCREEN_FONT_UPDATE:
1643 BOOST_ASSERT(lyx_view_);
1644 // handle the screen font changes.
1645 theFontLoader().update();
1646 /// FIXME: only the current view will be updated. the Gui
1647 /// class is able to furnish the list of views.
1648 updateFlags = Update::Force;
1651 case LFUN_SET_COLOR: {
1653 string const x11_name = split(argument, lyx_name, ' ');
1654 if (lyx_name.empty() || x11_name.empty()) {
1655 setErrorMessage(from_ascii(N_(
1656 "Syntax: set-color <lyx_name>"
1661 bool const graphicsbg_changed =
1662 (lyx_name == lcolor.getLyXName(Color::graphicsbg) &&
1663 x11_name != lcolor.getX11Name(Color::graphicsbg));
1665 if (!lcolor.setColor(lyx_name, x11_name)) {
1667 bformat(_("Set-color \"%1$s\" failed "
1668 "- color is undefined or "
1669 "may not be redefined"),
1670 from_utf8(lyx_name)));
1674 theApp()->updateColor(lcolor.getFromLyXName(lyx_name));
1676 if (graphicsbg_changed) {
1677 // FIXME: The graphics cache no longer has a changeDisplay method.
1679 graphics::GCache::get().changeDisplay(true);
1686 BOOST_ASSERT(lyx_view_);
1687 lyx_view_->message(from_utf8(argument));
1690 case LFUN_EXTERNAL_EDIT: {
1691 BOOST_ASSERT(lyx_view_);
1692 FuncRequest fr(action, argument);
1693 InsetExternal().dispatch(view()->cursor(), fr);
1697 case LFUN_GRAPHICS_EDIT: {
1698 FuncRequest fr(action, argument);
1699 InsetGraphics().dispatch(view()->cursor(), fr);
1703 case LFUN_INSET_APPLY: {
1704 BOOST_ASSERT(lyx_view_);
1705 string const name = cmd.getArg(0);
1706 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1708 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1709 inset->dispatch(view()->cursor(), fr);
1711 FuncRequest fr(LFUN_INSET_INSERT, argument);
1714 // ideally, the update flag should be set by the insets,
1715 // but this is not possible currently
1716 updateFlags = Update::Force | Update::FitCursor;
1720 case LFUN_ALL_INSETS_TOGGLE: {
1721 BOOST_ASSERT(lyx_view_);
1723 string const name = split(argument, action, ' ');
1724 Inset::Code const inset_code =
1725 Inset::translate(name);
1727 Cursor & cur = view()->cursor();
1728 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1730 Inset & inset = lyx_view_->buffer()->inset();
1731 InsetIterator it = inset_iterator_begin(inset);
1732 InsetIterator const end = inset_iterator_end(inset);
1733 for (; it != end; ++it) {
1734 if (!it->asInsetMath()
1735 && (inset_code == Inset::NO_CODE
1736 || inset_code == it->lyxCode())) {
1737 Cursor tmpcur = cur;
1738 tmpcur.pushLeft(*it);
1739 it->dispatch(tmpcur, fr);
1742 updateFlags = Update::Force | Update::FitCursor;
1746 case LFUN_BUFFER_LANGUAGE: {
1747 BOOST_ASSERT(lyx_view_);
1748 Buffer & buffer = *lyx_view_->buffer();
1749 Language const * oldL = buffer.params().language;
1750 Language const * newL = languages.getLanguage(argument);
1751 if (!newL || oldL == newL)
1754 if (oldL->rightToLeft() == newL->rightToLeft()
1755 && !buffer.isMultiLingual())
1756 buffer.changeLanguage(oldL, newL);
1760 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1761 string const fname =
1762 addName(addPath(package().user_support().absFilename(), "templates/"),
1764 Buffer defaults(fname);
1766 istringstream ss(argument);
1769 int const unknown_tokens = defaults.readHeader(lex);
1771 if (unknown_tokens != 0) {
1772 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1773 << unknown_tokens << " unknown token"
1774 << (unknown_tokens == 1 ? "" : "s")
1778 if (defaults.writeFile(FileName(defaults.fileName())))
1779 setMessage(bformat(_("Document defaults saved in %1$s"),
1780 makeDisplayPath(fname)));
1782 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1786 case LFUN_BUFFER_PARAMS_APPLY: {
1787 BOOST_ASSERT(lyx_view_);
1788 biblio::CiteEngine const oldEngine =
1789 lyx_view_->buffer()->params().getEngine();
1791 Buffer * buffer = lyx_view_->buffer();
1793 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1794 recordUndoFullDocument(view());
1796 istringstream ss(argument);
1799 int const unknown_tokens = buffer->readHeader(lex);
1801 if (unknown_tokens != 0) {
1802 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1803 << unknown_tokens << " unknown token"
1804 << (unknown_tokens == 1 ? "" : "s")
1808 updateLayout(oldClass, buffer);
1810 biblio::CiteEngine const newEngine =
1811 lyx_view_->buffer()->params().getEngine();
1813 if (oldEngine != newEngine) {
1814 Cursor & cur = view()->cursor();
1815 FuncRequest fr(LFUN_INSET_REFRESH);
1817 Inset & inset = lyx_view_->buffer()->inset();
1818 InsetIterator it = inset_iterator_begin(inset);
1819 InsetIterator const end = inset_iterator_end(inset);
1820 for (; it != end; ++it)
1821 if (it->lyxCode() == Inset::CITE_CODE)
1822 it->dispatch(cur, fr);
1825 updateFlags = Update::Force | Update::FitCursor;
1829 case LFUN_LAYOUT_MODULES_CLEAR: {
1830 BOOST_ASSERT(lyx_view_);
1831 Buffer * buffer = lyx_view_->buffer();
1832 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1833 recordUndoFullDocument(view());
1834 buffer->params().clearLayoutModules();
1835 updateLayout(oldClass, buffer);
1836 updateFlags = Update::Force | Update::FitCursor;
1840 case LFUN_LAYOUT_MODULE_ADD: {
1841 BOOST_ASSERT(lyx_view_);
1842 Buffer * buffer = lyx_view_->buffer();
1843 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1844 recordUndoFullDocument(view());
1845 buffer->params().addLayoutModule(argument);
1846 updateLayout(oldClass, buffer);
1847 updateFlags = Update::Force | Update::FitCursor;
1851 case LFUN_TEXTCLASS_APPLY: {
1852 BOOST_ASSERT(lyx_view_);
1853 Buffer * buffer = lyx_view_->buffer();
1855 loadTextClass(argument);
1857 std::pair<bool, textclass_type> const tc_pair =
1858 textclasslist.numberOfClass(argument);
1863 textclass_type const old_class = buffer->params().getBaseClass();
1864 textclass_type const new_class = tc_pair.second;
1866 if (old_class == new_class)
1870 //Save the old, possibly modular, layout for use in conversion.
1871 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1872 recordUndoFullDocument(view());
1873 buffer->params().setBaseClass(new_class);
1874 updateLayout(oldClass, buffer);
1875 updateFlags = Update::Force | Update::FitCursor;
1879 case LFUN_LAYOUT_RELOAD: {
1880 BOOST_ASSERT(lyx_view_);
1881 Buffer * buffer = lyx_view_->buffer();
1882 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1883 textclass_type const tc = buffer->params().getBaseClass();
1884 textclasslist.reset(tc);
1885 buffer->params().setBaseClass(tc);
1886 updateLayout(oldClass, buffer);
1887 updateFlags = Update::Force | Update::FitCursor;
1891 case LFUN_TEXTCLASS_LOAD:
1892 loadTextClass(argument);
1895 case LFUN_LYXRC_APPLY: {
1896 LyXRC const lyxrc_orig = lyxrc;
1898 istringstream ss(argument);
1899 bool const success = lyxrc.read(ss) == 0;
1902 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1903 << "Unable to read lyxrc data"
1908 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1910 /// We force the redraw in any case because there might be
1911 /// some screen font changes.
1912 /// FIXME: only the current view will be updated. the Gui
1913 /// class is able to furnish the list of views.
1914 updateFlags = Update::Force;
1918 case LFUN_WINDOW_NEW:
1919 LyX::ref().newLyXView();
1922 case LFUN_WINDOW_CLOSE:
1923 BOOST_ASSERT(lyx_view_);
1924 BOOST_ASSERT(theApp());
1925 // update bookmark pit of the current buffer before window close
1926 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1927 gotoBookmark(i+1, false, false);
1928 // ask the user for saving changes or cancel quit
1929 if (!theBufferList().quitWriteAll())
1934 case LFUN_BOOKMARK_GOTO:
1935 // go to bookmark, open unopened file and switch to buffer if necessary
1936 gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
1939 case LFUN_BOOKMARK_CLEAR:
1940 LyX::ref().session().bookmarks().clear();
1943 case LFUN_TOOLBAR_TOGGLE: {
1944 BOOST_ASSERT(lyx_view_);
1945 string const name = cmd.getArg(0);
1946 bool const allowauto = cmd.getArg(1) == "allowauto";
1947 lyx_view_->toggleToolbarState(name, allowauto);
1948 ToolbarInfo * tbi = lyx_view_->getToolbarInfo(name);
1950 setMessage(bformat(_("Unknown toolbar \"%1$s\""),
1955 if (tbi->flags & ToolbarInfo::ON)
1957 else if (tbi->flags & ToolbarInfo::OFF)
1959 else if (tbi->flags & ToolbarInfo::AUTO)
1962 setMessage(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1963 _(tbi->gui_name), state));
1968 BOOST_ASSERT(lyx_view_);
1969 view()->cursor().dispatch(cmd);
1970 updateFlags = view()->cursor().result().update();
1971 if (!view()->cursor().result().dispatched())
1972 updateFlags = view()->dispatch(cmd);
1977 if (lyx_view_ && lyx_view_->buffer()) {
1978 // BufferView::update() updates the ViewMetricsInfo and
1979 // also initializes the position cache for all insets in
1980 // (at least partially) visible top-level paragraphs.
1981 // We will redraw the screen only if needed.
1982 view()->processUpdateFlags(updateFlags);
1983 lyx_view_->updateStatusBar();
1985 // if we executed a mutating lfun, mark the buffer as dirty
1987 && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
1988 && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
1989 lyx_view_->buffer()->markDirty();
1991 //Do we have a selection?
1992 theSelection().haveSelection(view()->cursor().selection());
1994 if (view()->cursor().inTexted()) {
1995 lyx_view_->updateLayoutChoice();
1999 if (!quitting && lyx_view_) {
2000 lyx_view_->updateToolbars();
2001 // Some messages may already be translated, so we cannot use _()
2002 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
2007 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
2009 const bool verbose = (cmd.origin == FuncRequest::MENU
2010 || cmd.origin == FuncRequest::TOOLBAR
2011 || cmd.origin == FuncRequest::COMMANDBUFFER);
2013 if (cmd.action == LFUN_SELF_INSERT || !verbose) {
2014 LYXERR(Debug::ACTION) << "dispatch msg is " << to_utf8(msg) << endl;
2016 lyx_view_->message(msg);
2020 docstring dispatch_msg = msg;
2021 if (!dispatch_msg.empty())
2022 dispatch_msg += ' ';
2024 docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
2026 bool argsadded = false;
2028 if (!cmd.argument().empty()) {
2029 if (cmd.action != LFUN_UNKNOWN_ACTION) {
2030 comname += ' ' + cmd.argument();
2035 docstring const shortcuts = theTopLevelKeymap().printbindings(cmd);
2037 if (!shortcuts.empty())
2038 comname += ": " + shortcuts;
2039 else if (!argsadded && !cmd.argument().empty())
2040 comname += ' ' + cmd.argument();
2042 if (!comname.empty()) {
2043 comname = rtrim(comname);
2044 dispatch_msg += '(' + rtrim(comname) + ')';
2047 LYXERR(Debug::ACTION) << "verbose dispatch msg "
2048 << to_utf8(dispatch_msg) << endl;
2049 if (!dispatch_msg.empty())
2050 lyx_view_->message(dispatch_msg);
2054 void LyXFunc::menuNew(string const & name, bool fromTemplate)
2056 // FIXME: initpath is not used. What to do?
2057 string initpath = lyxrc.document_path;
2058 string filename(name);
2060 if (lyx_view_->buffer()) {
2061 string const trypath = lyx_view_->buffer()->filePath();
2062 // If directory is writeable, use this as default.
2063 if (isDirWriteable(FileName(trypath)))
2067 static int newfile_number;
2069 if (filename.empty()) {
2070 filename = addName(lyxrc.document_path,
2071 "newfile" + convert<string>(++newfile_number) + ".lyx");
2072 while (theBufferList().exists(filename) ||
2073 fs::is_readable(FileName(filename).toFilesystemEncoding())) {
2075 filename = addName(lyxrc.document_path,
2076 "newfile" + convert<string>(newfile_number) +
2081 // The template stuff
2084 FileDialog fileDlg(_("Select template file"),
2085 LFUN_SELECT_FILE_SYNC,
2086 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2087 make_pair(_("Templates|#T#t"), from_utf8(lyxrc.template_path)));
2089 FileDialog::Result result =
2090 fileDlg.open(from_utf8(lyxrc.template_path),
2091 FileFilterList(_("LyX Documents (*.lyx)")),
2094 if (result.first == FileDialog::Later)
2096 if (result.second.empty())
2098 templname = to_utf8(result.second);
2101 Buffer * const b = newFile(filename, templname, !name.empty());
2103 lyx_view_->setBuffer(b);
2107 void LyXFunc::open(string const & fname)
2109 string initpath = lyxrc.document_path;
2111 if (lyx_view_->buffer()) {
2112 string const trypath = lyx_view_->buffer()->filePath();
2113 // If directory is writeable, use this as default.
2114 if (isDirWriteable(FileName(trypath)))
2120 if (fname.empty()) {
2121 FileDialog fileDlg(_("Select document to open"),
2123 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2124 make_pair(_("Examples|#E#e"), from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2126 FileDialog::Result result =
2127 fileDlg.open(from_utf8(initpath),
2128 FileFilterList(_("LyX Documents (*.lyx)")),
2131 if (result.first == FileDialog::Later)
2134 filename = to_utf8(result.second);
2136 // check selected filename
2137 if (filename.empty()) {
2138 lyx_view_->message(_("Canceled."));
2144 // get absolute path of file and add ".lyx" to the filename if
2146 FileName const fullname = fileSearch(string(), filename, "lyx");
2147 if (!fullname.empty())
2148 filename = fullname.absFilename();
2150 // if the file doesn't exist, let the user create one
2151 if (!fs::exists(fullname.toFilesystemEncoding())) {
2152 // the user specifically chose this name. Believe him.
2153 Buffer * const b = newFile(filename, string(), true);
2155 lyx_view_->setBuffer(b);
2159 docstring const disp_fn = makeDisplayPath(filename);
2160 lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
2163 Buffer * buf = lyx_view_->loadLyXFile(fullname);
2166 lyx_view_->setBuffer(buf);
2167 lyx_view_->showErrorList("Parse");
2168 str2 = bformat(_("Document %1$s opened."), disp_fn);
2170 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2172 lyx_view_->message(str2);
2176 void LyXFunc::doImport(string const & argument)
2179 string filename = split(argument, format, ' ');
2181 LYXERR(Debug::INFO) << "LyXFunc::doImport: " << format
2182 << " file: " << filename << endl;
2184 // need user interaction
2185 if (filename.empty()) {
2186 string initpath = lyxrc.document_path;
2188 if (lyx_view_->buffer()) {
2189 string const trypath = lyx_view_->buffer()->filePath();
2190 // If directory is writeable, use this as default.
2191 if (isDirWriteable(FileName(trypath)))
2195 docstring const text = bformat(_("Select %1$s file to import"),
2196 formats.prettyName(format));
2198 FileDialog fileDlg(text,
2200 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2201 make_pair(_("Examples|#E#e"),
2202 from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2204 docstring filter = formats.prettyName(format);
2207 filter += from_utf8(formats.extension(format));
2210 FileDialog::Result result =
2211 fileDlg.open(from_utf8(initpath),
2212 FileFilterList(filter),
2215 if (result.first == FileDialog::Later)
2218 filename = to_utf8(result.second);
2220 // check selected filename
2221 if (filename.empty())
2222 lyx_view_->message(_("Canceled."));
2225 if (filename.empty())
2228 // get absolute path of file
2229 FileName const fullname(makeAbsPath(filename));
2231 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
2233 // Check if the document already is open
2234 if (use_gui && theBufferList().exists(lyxfile.absFilename())) {
2235 if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) {
2236 lyx_view_->message(_("Canceled."));
2241 // if the file exists already, and we didn't do
2242 // -i lyx thefile.lyx, warn
2243 if (fs::exists(lyxfile.toFilesystemEncoding()) && fullname != lyxfile) {
2244 docstring const file = makeDisplayPath(lyxfile.absFilename(), 30);
2246 docstring text = bformat(_("The document %1$s already exists.\n\n"
2247 "Do you want to overwrite that document?"), file);
2248 int const ret = Alert::prompt(_("Overwrite document?"),
2249 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2252 lyx_view_->message(_("Canceled."));
2257 ErrorList errorList;
2258 Importer::Import(lyx_view_, fullname, format, errorList);
2259 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2263 void LyXFunc::closeBuffer()
2265 // goto bookmark to update bookmark pit.
2266 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2267 gotoBookmark(i+1, false, false);
2269 theBufferList().close(lyx_view_->buffer(), true);
2273 void LyXFunc::reloadBuffer()
2275 FileName filename(lyx_view_->buffer()->fileName());
2276 docstring const disp_fn = makeDisplayPath(filename.absFilename());
2279 Buffer * buf = lyx_view_->loadLyXFile(filename);
2282 lyx_view_->setBuffer(buf);
2283 lyx_view_->showErrorList("Parse");
2284 str = bformat(_("Document %1$s reloaded."), disp_fn);
2286 str = bformat(_("Could not reload document %1$s"), disp_fn);
2288 lyx_view_->message(str);
2291 // Each "lyx_view_" should have it's own message method. lyxview and
2292 // the minibuffer would use the minibuffer, but lyxserver would
2293 // send an ERROR signal to its client. Alejandro 970603
2294 // This function is bit problematic when it comes to NLS, to make the
2295 // lyx servers client be language indepenent we must not translate
2296 // strings sent to this func.
2297 void LyXFunc::setErrorMessage(docstring const & m) const
2299 dispatch_buffer = m;
2304 void LyXFunc::setMessage(docstring const & m) const
2306 dispatch_buffer = m;
2310 docstring const LyXFunc::viewStatusMessage()
2312 // When meta-fake key is pressed, show the key sequence so far + "M-".
2314 return keyseq.print(true) + "M-";
2316 // Else, when a non-complete key sequence is pressed,
2317 // show the available options.
2318 if (keyseq.length() > 0 && !keyseq.deleted())
2319 return keyseq.printOptions(true);
2321 BOOST_ASSERT(lyx_view_);
2322 if (!lyx_view_->buffer())
2323 return _("Welcome to LyX!");
2325 return view()->cursor().currentState();
2329 BufferView * LyXFunc::view() const
2331 BOOST_ASSERT(lyx_view_);
2332 return lyx_view_->view();
2336 bool LyXFunc::wasMetaKey() const
2338 return (meta_fake_bit != NoModifier);
2342 void LyXFunc::updateLayout(TextClassPtr const & oldlayout,
2345 lyx_view_->message(_("Converting document to new document class..."));
2347 StableDocIterator backcur(view()->cursor());
2348 ErrorList & el = buffer->errorList("Class Switch");
2349 cap::switchBetweenClasses(
2350 oldlayout, buffer->params().getTextClassPtr(),
2351 static_cast<InsetText &>(buffer->inset()), el);
2353 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
2355 buffer->errors("Class Switch");
2356 updateLabels(*buffer);
2362 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2364 // Why the switch you might ask. It is a trick to ensure that all
2365 // the elements in the LyXRCTags enum is handled. As you can see
2366 // there are no breaks at all. So it is just a huge fall-through.
2367 // The nice thing is that we will get a warning from the compiler
2368 // if we forget an element.
2369 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2371 case LyXRC::RC_ACCEPT_COMPOUND:
2372 case LyXRC::RC_ALT_LANG:
2373 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
2374 case LyXRC::RC_PLAINTEXT_LINELEN:
2375 case LyXRC::RC_AUTOREGIONDELETE:
2376 case LyXRC::RC_AUTORESET_OPTIONS:
2377 case LyXRC::RC_AUTOSAVE:
2378 case LyXRC::RC_AUTO_NUMBER:
2379 case LyXRC::RC_BACKUPDIR_PATH:
2380 case LyXRC::RC_BIBTEX_COMMAND:
2381 case LyXRC::RC_BINDFILE:
2382 case LyXRC::RC_CHECKLASTFILES:
2383 case LyXRC::RC_USELASTFILEPOS:
2384 case LyXRC::RC_LOADSESSION:
2385 case LyXRC::RC_CHKTEX_COMMAND:
2386 case LyXRC::RC_CONVERTER:
2387 case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
2388 case LyXRC::RC_COPIER:
2389 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2390 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2391 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2392 case LyXRC::RC_DATE_INSERT_FORMAT:
2393 case LyXRC::RC_DEFAULT_LANGUAGE:
2394 case LyXRC::RC_DEFAULT_PAPERSIZE:
2395 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2396 case LyXRC::RC_DISPLAY_GRAPHICS:
2397 case LyXRC::RC_DOCUMENTPATH:
2398 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2399 string const encoded = FileName(
2400 lyxrc_new.document_path).toFilesystemEncoding();
2401 if (fs::exists(encoded) && fs::is_directory(encoded))
2402 support::package().document_dir() = FileName(lyxrc.document_path);
2404 case LyXRC::RC_ESC_CHARS:
2405 case LyXRC::RC_FONT_ENCODING:
2406 case LyXRC::RC_FORMAT:
2407 case LyXRC::RC_INDEX_COMMAND:
2408 case LyXRC::RC_INPUT:
2409 case LyXRC::RC_KBMAP:
2410 case LyXRC::RC_KBMAP_PRIMARY:
2411 case LyXRC::RC_KBMAP_SECONDARY:
2412 case LyXRC::RC_LABEL_INIT_LENGTH:
2413 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2414 case LyXRC::RC_LANGUAGE_AUTO_END:
2415 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2416 case LyXRC::RC_LANGUAGE_COMMAND_END:
2417 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2418 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2419 case LyXRC::RC_LANGUAGE_PACKAGE:
2420 case LyXRC::RC_LANGUAGE_USE_BABEL:
2421 case LyXRC::RC_MAKE_BACKUP:
2422 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2423 case LyXRC::RC_NUMLASTFILES:
2424 case LyXRC::RC_PATH_PREFIX:
2425 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2426 support::prependEnvPath("PATH", lyxrc.path_prefix);
2428 case LyXRC::RC_PERS_DICT:
2429 case LyXRC::RC_PREVIEW:
2430 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2431 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2432 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2433 case LyXRC::RC_PRINTCOPIESFLAG:
2434 case LyXRC::RC_PRINTER:
2435 case LyXRC::RC_PRINTEVENPAGEFLAG:
2436 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2437 case LyXRC::RC_PRINTFILEEXTENSION:
2438 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2439 case LyXRC::RC_PRINTODDPAGEFLAG:
2440 case LyXRC::RC_PRINTPAGERANGEFLAG:
2441 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2442 case LyXRC::RC_PRINTPAPERFLAG:
2443 case LyXRC::RC_PRINTREVERSEFLAG:
2444 case LyXRC::RC_PRINTSPOOL_COMMAND:
2445 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2446 case LyXRC::RC_PRINTTOFILE:
2447 case LyXRC::RC_PRINTTOPRINTER:
2448 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2449 case LyXRC::RC_PRINT_COMMAND:
2450 case LyXRC::RC_RTL_SUPPORT:
2451 case LyXRC::RC_SCREEN_DPI:
2452 case LyXRC::RC_SCREEN_FONT_ROMAN:
2453 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2454 case LyXRC::RC_SCREEN_FONT_SANS:
2455 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2456 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2457 case LyXRC::RC_SCREEN_FONT_SIZES:
2458 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2459 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2460 case LyXRC::RC_SCREEN_GEOMETRY_HEIGHT:
2461 case LyXRC::RC_SCREEN_GEOMETRY_WIDTH:
2462 case LyXRC::RC_SCREEN_GEOMETRY_XYSAVED:
2463 case LyXRC::RC_SCREEN_ZOOM:
2464 case LyXRC::RC_SERVERPIPE:
2465 case LyXRC::RC_SET_COLOR:
2466 case LyXRC::RC_SHOW_BANNER:
2467 case LyXRC::RC_SPELL_COMMAND:
2468 case LyXRC::RC_TEMPDIRPATH:
2469 case LyXRC::RC_TEMPLATEPATH:
2470 case LyXRC::RC_TEX_ALLOWS_SPACES:
2471 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2472 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2473 support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2475 case LyXRC::RC_UIFILE:
2476 case LyXRC::RC_USER_EMAIL:
2477 case LyXRC::RC_USER_NAME:
2478 case LyXRC::RC_USETEMPDIR:
2479 case LyXRC::RC_USE_ALT_LANG:
2480 case LyXRC::RC_USE_CONVERTER_CACHE:
2481 case LyXRC::RC_USE_ESC_CHARS:
2482 case LyXRC::RC_USE_INP_ENC:
2483 case LyXRC::RC_USE_PERS_DICT:
2484 case LyXRC::RC_USE_SPELL_LIB:
2485 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2486 case LyXRC::RC_VIEWER:
2487 case LyXRC::RC_LAST: