3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Alfredo Braunstein
7 * \author Lars Gullik Bjønnes
8 * \author Jean-Marc Lasgouttes
9 * \author Angus Leeming
11 * \author André Pönitz
14 * \author Martin Vermeer
15 * \author Jürgen Vigna
17 * Full author contact details are available in file CREDITS.
25 #include "BranchList.h"
26 #include "buffer_funcs.h"
28 #include "BufferList.h"
29 #include "BufferParams.h"
30 #include "BufferView.h"
33 #include "CutAndPaste.h"
35 #include "DispatchResult.h"
37 #include "ErrorList.h"
40 #include "FuncRequest.h"
41 #include "FuncStatus.h"
44 #include "InsetIterator.h"
49 #include "LyXAction.h"
54 #include "Paragraph.h"
55 #include "ParagraphParameters.h"
56 #include "ParIterator.h"
60 #include "TextClassList.h"
61 #include "ToolbarBackend.h"
64 #include "insets/InsetBox.h"
65 #include "insets/InsetBranch.h"
66 #include "insets/InsetCommand.h"
67 #include "insets/InsetERT.h"
68 #include "insets/InsetExternal.h"
69 #include "insets/InsetFloat.h"
70 #include "insets/InsetListings.h"
71 #include "insets/InsetGraphics.h"
72 #include "insets/InsetInclude.h"
73 #include "insets/InsetNote.h"
74 #include "insets/InsetTabular.h"
75 #include "insets/InsetVSpace.h"
76 #include "insets/InsetWrap.h"
78 #include "frontends/Application.h"
79 #include "frontends/alert.h"
80 #include "frontends/Dialogs.h"
81 #include "frontends/FileDialog.h"
82 #include "frontends/FontLoader.h"
83 #include "frontends/Gui.h"
84 #include "frontends/KeySymbol.h"
85 #include "frontends/LyXView.h"
86 #include "frontends/Selection.h"
87 #include "frontends/WorkArea.h"
89 #include "support/environment.h"
90 #include "support/FileFilterList.h"
91 #include "support/filetools.h"
92 #include "support/fs_extras.h"
93 #include "support/lstrings.h"
94 #include "support/Path.h"
95 #include "support/Package.h"
96 #include "support/Systemcall.h"
97 #include "support/convert.h"
98 #include "support/os.h"
100 #include <boost/current_function.hpp>
101 #include <boost/filesystem/operations.hpp>
106 using std::make_pair;
109 using std::istringstream;
110 using std::ostringstream;
112 namespace fs = boost::filesystem;
116 using frontend::LyXView;
118 using support::absolutePath;
119 using support::addName;
120 using support::addPath;
121 using support::bformat;
122 using support::changeExtension;
123 using support::contains;
124 using support::FileFilterList;
125 using support::FileName;
126 using support::fileSearch;
127 using support::i18nLibFileSearch;
128 using support::isDirWriteable;
129 using support::isFileReadable;
130 using support::isStrInt;
131 using support::makeAbsPath;
132 using support::makeDisplayPath;
133 using support::package;
134 using support::quoteName;
135 using support::rtrim;
136 using support::split;
137 using support::subst;
138 using support::Systemcall;
139 using support::token;
141 using support::prefixIs;
143 namespace Alert = frontend::Alert;
145 extern bool quitting;
149 // This function runs "configure" and then rereads lyx.defaults to
150 // reconfigure the automatic settings.
151 void reconfigure(LyXView & lv, string const & option)
153 // emit message signal.
154 lv.message(_("Running configure..."));
156 // Run configure in user lyx directory
157 support::Path p(package().user_support());
158 string configure_command = package().configure_command();
159 configure_command += option;
161 one.startscript(Systemcall::Wait, configure_command);
163 // emit message signal.
164 lv.message(_("Reloading configuration..."));
165 lyxrc.read(support::libFileSearch(string(), "lyxrc.defaults"));
166 // Re-read packages.lst
167 LaTeXFeatures::getAvailable();
169 Alert::information(_("System reconfigured"),
170 _("The system has been reconfigured.\n"
171 "You need to restart LyX to make use of any\n"
172 "updated document class specifications."));
176 bool getLocalStatus(Cursor cursor, FuncRequest const & cmd, FuncStatus & status)
178 // Try to fix cursor in case it is broken.
179 cursor.fixIfBroken();
181 // This is, of course, a mess. Better create a new doc iterator and use
182 // this in Inset::getStatus. This might require an additional
183 // BufferView * arg, though (which should be avoided)
184 //Cursor safe = *this;
186 for ( ; cursor.depth(); cursor.pop()) {
187 //lyxerr << "\nCursor::getStatus: cmd: " << cmd << endl << *this << endl;
188 BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
189 BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
190 BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
192 // The inset's getStatus() will return 'true' if it made
193 // a definitive decision on whether it want to handle the
194 // request or not. The result of this decision is put into
195 // the 'status' parameter.
196 if (cursor.inset().getStatus(cursor, cmd, status)) {
205 /** Return the change status at cursor position, taking in account the
206 * status at each level of the document iterator (a table in a deleted
207 * footnote is deleted).
208 * When \param outer is true, the top slice is not looked at.
210 Change::Type lookupChangeType(DocIterator const & dit, bool outer = false)
212 size_t const depth = dit.depth() - (outer ? 1 : 0);
214 for (size_t i = 0 ; i < depth ; ++i) {
215 CursorSlice const & slice = dit[i];
216 if (!slice.inset().inMathed()
217 && slice.pos() < slice.paragraph().size()) {
218 Change::Type const ch = slice.paragraph().lookupChange(slice.pos()).type;
219 if (ch != Change::UNCHANGED)
223 return Change::UNCHANGED;
230 : lyx_view_(0), encoded_last_key(0), meta_fake_bit(NoModifier)
235 void LyXFunc::initKeySequences(KeyMap * kb)
237 keyseq = KeySequence(kb, kb);
238 cancel_meta_seq = KeySequence(kb, kb);
242 void LyXFunc::setLyXView(LyXView * lv)
244 if (!quitting && lyx_view_ && lyx_view_->view() && lyx_view_ != lv)
245 // save current selection to the selection buffer to allow
246 // middle-button paste in another window
247 cap::saveSelection(lyx_view_->view()->cursor());
252 void LyXFunc::handleKeyFunc(kb_action action)
254 char_type c = encoded_last_key;
259 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
260 lyx_view_->view()->getIntl().getTransManager().deadkey(
261 c, get_accent(action).accent, view()->cursor().innerText(), view()->cursor());
262 // Need to clear, in case the minibuffer calls these
265 // copied verbatim from do_accent_char
266 view()->cursor().resetAnchor();
267 view()->processUpdateFlags(Update::FitCursor);
271 void LyXFunc::gotoBookmark(unsigned int idx, bool openFile, bool switchToBuffer)
273 BOOST_ASSERT(lyx_view_);
274 if (!LyX::ref().session().bookmarks().isValid(idx))
276 BookmarksSection::Bookmark const & bm = LyX::ref().session().bookmarks().bookmark(idx);
277 BOOST_ASSERT(!bm.filename.empty());
278 string const file = bm.filename.absFilename();
279 // if the file is not opened, open it.
280 if (!theBufferList().exists(file)) {
282 dispatch(FuncRequest(LFUN_FILE_OPEN, file));
286 // open may fail, so we need to test it again
287 if (!theBufferList().exists(file))
290 // if the current buffer is not that one, switch to it.
291 if (lyx_view_->buffer()->fileName() != file) {
294 dispatch(FuncRequest(LFUN_BUFFER_SWITCH, file));
296 // moveToPosition try paragraph id first and then paragraph (pit, pos).
297 if (!view()->moveToPosition(bm.bottom_pit, bm.bottom_pos,
298 bm.top_id, bm.top_pos))
301 // Cursor jump succeeded!
302 Cursor const & cur = view()->cursor();
303 pit_type new_pit = cur.pit();
304 pos_type new_pos = cur.pos();
305 int new_id = cur.paragraph().id();
307 // if bottom_pit, bottom_pos or top_id has been changed, update bookmark
308 // see http://bugzilla.lyx.org/show_bug.cgi?id=3092
309 if (bm.bottom_pit != new_pit || bm.bottom_pos != new_pos
310 || bm.top_id != new_id) {
311 const_cast<BookmarksSection::Bookmark &>(bm).updatePos(
312 new_pit, new_pos, new_id);
317 void LyXFunc::processKeySym(KeySymbol const & keysym, KeyModifier state)
319 LYXERR(Debug::KEY) << "KeySym is " << keysym.getSymbolName() << endl;
321 // Do nothing if we have nothing (JMarc)
322 if (!keysym.isOK()) {
323 LYXERR(Debug::KEY) << "Empty kbd action (probably composing)"
328 if (keysym.isModifier()) {
329 LYXERR(Debug::KEY) << "isModifier true" << endl;
333 //Encoding const * encoding = view()->cursor().getEncoding();
334 //encoded_last_key = keysym.getISOEncoded(encoding ? encoding->name() : "");
335 // FIXME: encoded_last_key shadows the member variable of the same
336 // name. Is that intended?
337 char_type encoded_last_key = keysym.getUCSEncoded();
339 // Do a one-deep top-level lookup for
340 // cancel and meta-fake keys. RVDK_PATCH_5
341 cancel_meta_seq.reset();
343 FuncRequest func = cancel_meta_seq.addkey(keysym, state);
344 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
345 << " action first set to [" << func.action << ']'
348 // When not cancel or meta-fake, do the normal lookup.
349 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
350 // Mostly, meta_fake_bit = NoModifier. RVDK_PATCH_5.
351 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_PREFIX)) {
352 // remove Caps Lock and Mod2 as a modifiers
353 func = keyseq.addkey(keysym, (state | meta_fake_bit));
354 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
355 << "action now set to ["
356 << func.action << ']' << endl;
359 // Dont remove this unless you know what you are doing.
360 meta_fake_bit = NoModifier;
362 // Can this happen now ?
363 if (func.action == LFUN_NOACTION)
364 func = FuncRequest(LFUN_COMMAND_PREFIX);
366 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
368 << func.action << "]["
369 << to_utf8(keyseq.print(false)) << ']'
372 // already here we know if it any point in going further
373 // why not return already here if action == -1 and
374 // num_bytes == 0? (Lgb)
376 if (keyseq.length() > 1)
377 lyx_view_->message(keyseq.print(true));
380 // Maybe user can only reach the key via holding down shift.
381 // Let's see. But only if shift is the only modifier
382 if (func.action == LFUN_UNKNOWN_ACTION && state == ShiftModifier) {
383 LYXERR(Debug::KEY) << "Trying without shift" << endl;
384 func = keyseq.addkey(keysym, NoModifier);
385 LYXERR(Debug::KEY) << "Action now " << func.action << endl;
388 if (func.action == LFUN_UNKNOWN_ACTION) {
389 // Hmm, we didn't match any of the keysequences. See
390 // if it's normal insertable text not already covered
392 if (keysym.isText() && keyseq.length() == 1) {
393 LYXERR(Debug::KEY) << "isText() is true, inserting." << endl;
394 func = FuncRequest(LFUN_SELF_INSERT,
395 FuncRequest::KEYBOARD);
397 LYXERR(Debug::KEY) << "Unknown, !isText() - giving up" << endl;
398 lyx_view_->message(_("Unknown function."));
403 if (func.action == LFUN_SELF_INSERT) {
404 if (encoded_last_key != 0) {
405 docstring const arg(1, encoded_last_key);
406 dispatch(FuncRequest(LFUN_SELF_INSERT, arg,
407 FuncRequest::KEYBOARD));
409 << "SelfInsert arg[`" << to_utf8(arg) << "']" << endl;
417 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
419 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
422 /* In LyX/Mac, when a dialog is open, the menus of the
423 application can still be accessed without giving focus to
424 the main window. In this case, we want to disable the menu
425 entries that are buffer-related.
427 Note that this code is not perfect, as bug 1941 attests:
428 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
430 Buffer * buf = lyx_view_? lyx_view_->buffer() : 0;
431 if (lyx_view_ && cmd.origin == FuncRequest::MENU && !lyx_view_->hasFocus())
434 if (cmd.action == LFUN_NOACTION) {
435 flag.message(from_utf8(N_("Nothing to do")));
440 switch (cmd.action) {
441 case LFUN_UNKNOWN_ACTION:
442 #ifndef HAVE_LIBAIKSAURUS
443 case LFUN_THESAURUS_ENTRY:
453 if (flag.unknown()) {
454 flag.message(from_utf8(N_("Unknown action")));
458 if (!flag.enabled()) {
459 if (flag.message().empty())
460 flag.message(from_utf8(N_("Command disabled")));
464 // Check whether we need a buffer
465 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
467 flag.message(from_utf8(N_("Command not allowed with"
468 "out any document open")));
473 Cursor * cur = view()? &view()->cursor(): 0;
475 // I would really like to avoid having this switch and rather try to
476 // encode this in the function itself.
477 // -- And I'd rather let an inset decide which LFUNs it is willing
478 // to handle (Andre')
480 switch (cmd.action) {
481 case LFUN_BUFFER_TOGGLE_READ_ONLY:
482 flag.setOnOff(buf->isReadonly());
485 case LFUN_BUFFER_SWITCH:
486 // toggle on the current buffer, but do not toggle off
487 // the other ones (is that a good idea?)
488 if (buf && to_utf8(cmd.argument()) == buf->fileName())
492 case LFUN_BUFFER_EXPORT:
493 enable = cmd.argument() == "custom"
494 || Exporter::isExportable(*buf, to_utf8(cmd.argument()));
497 case LFUN_BUFFER_CHKTEX:
498 enable = buf->isLatex() && !lyxrc.chktex_command.empty();
501 case LFUN_BUILD_PROGRAM:
502 enable = Exporter::isExportable(*buf, "program");
505 case LFUN_LAYOUT_TABULAR:
506 enable = cur? cur->innerInsetOfType(Inset::TABULAR_CODE) : false;
510 case LFUN_LAYOUT_PARAGRAPH:
511 enable = cur? !cur->inset().forceDefaultParagraphs(cur->idx()) : false;
514 case LFUN_VC_REGISTER:
515 enable = !buf->lyxvc().inUse();
517 case LFUN_VC_CHECK_IN:
518 enable = buf->lyxvc().inUse() && !buf->isReadonly();
520 case LFUN_VC_CHECK_OUT:
521 enable = buf->lyxvc().inUse() && buf->isReadonly();
524 case LFUN_VC_UNDO_LAST:
525 enable = buf->lyxvc().inUse();
527 case LFUN_BUFFER_RELOAD:
528 enable = !buf->isUnnamed() && fs::exists(buf->fileName())
529 && (!buf->isClean() || buf->isExternallyModified(Buffer::timestamp_method));
532 case LFUN_INSET_SETTINGS: {
536 Inset::Code code = cur->inset().lyxCode();
538 case Inset::TABULAR_CODE:
539 enable = cmd.argument() == "tabular";
541 case Inset::ERT_CODE:
542 enable = cmd.argument() == "ert";
544 case Inset::FLOAT_CODE:
545 enable = cmd.argument() == "float";
547 case Inset::WRAP_CODE:
548 enable = cmd.argument() == "wrap";
550 case Inset::NOTE_CODE:
551 enable = cmd.argument() == "note";
553 case Inset::BRANCH_CODE:
554 enable = cmd.argument() == "branch";
556 case Inset::BOX_CODE:
557 enable = cmd.argument() == "box";
559 case Inset::LISTINGS_CODE:
560 enable = cmd.argument() == "listings";
568 case LFUN_INSET_APPLY: {
572 string const name = cmd.getArg(0);
573 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
575 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
577 if (!inset->getStatus(*cur, fr, fs)) {
578 // Every inset is supposed to handle this
583 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
584 flag |= getStatus(fr);
586 enable = flag.enabled();
590 case LFUN_DIALOG_TOGGLE:
591 flag.setOnOff(lyx_view_->getDialogs().visible(cmd.getArg(0)));
592 // fall through to set "enable"
593 case LFUN_DIALOG_SHOW: {
597 string const name = cmd.getArg(0);
599 enable = name == "aboutlyx"
600 || name == "file" //FIXME: should be removed.
602 || name == "texinfo";
603 else if (name == "print")
604 enable = Exporter::isExportable(*buf, "dvi")
605 && lyxrc.print_command != "none";
606 else if (name == "character")
607 enable = cur->inset().lyxCode() != Inset::ERT_CODE &&
608 cur->inset().lyxCode() != Inset::LISTINGS_CODE;
609 else if (name == "latexlog")
610 enable = isFileReadable(FileName(buf->getLogName().second));
611 else if (name == "spellchecker")
612 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
613 enable = !buf->isReadonly();
617 else if (name == "vclog")
618 enable = buf->lyxvc().inUse();
622 case LFUN_DIALOG_SHOW_NEW_INSET:
626 enable = cur->inset().lyxCode() != Inset::ERT_CODE &&
627 cur->inset().lyxCode() != Inset::LISTINGS_CODE;
628 if (cur->inset().lyxCode() == Inset::CAPTION_CODE) {
630 if (cur->inset().getStatus(*cur, cmd, flag))
635 case LFUN_DIALOG_UPDATE: {
636 string const name = cmd.getArg(0);
638 enable = name == "prefs";
642 case LFUN_CITATION_INSERT: {
643 FuncRequest fr(LFUN_INSET_INSERT, "citation");
644 enable = getStatus(fr).enabled();
648 case LFUN_BUFFER_WRITE: {
649 enable = lyx_view_->buffer()->isUnnamed()
650 || !lyx_view_->buffer()->isClean();
655 case LFUN_BUFFER_WRITE_ALL: {
656 // We enable the command only if there are some modified buffers
657 Buffer * first = theBufferList().first();
658 bool modified = false;
662 // We cannot use a for loop as the buffer list is a cycle.
668 b = theBufferList().next(b);
669 } while (b != first);
677 case LFUN_BOOKMARK_GOTO: {
678 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
679 enable = LyX::ref().session().bookmarks().isValid(num);
683 case LFUN_BOOKMARK_CLEAR:
684 enable = LyX::ref().session().bookmarks().size() > 0;
687 case LFUN_TOOLBAR_TOGGLE: {
688 bool const current = lyx_view_->isToolbarVisible(cmd.getArg(0));
689 flag.setOnOff(current);
692 case LFUN_WINDOW_CLOSE: {
693 enable = (theApp()->gui().viewIds().size() > 1);
697 // this one is difficult to get right. As a half-baked
698 // solution, we consider only the first action of the sequence
699 case LFUN_COMMAND_SEQUENCE: {
700 // argument contains ';'-terminated commands
701 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
702 FuncRequest func(lyxaction.lookupFunc(firstcmd));
703 func.origin = cmd.origin;
704 flag = getStatus(func);
707 case LFUN_BUFFER_NEW:
708 case LFUN_BUFFER_NEW_TEMPLATE:
709 case LFUN_WORD_FIND_FORWARD:
710 case LFUN_WORD_FIND_BACKWARD:
711 case LFUN_COMMAND_PREFIX:
712 case LFUN_COMMAND_EXECUTE:
714 case LFUN_META_PREFIX:
715 case LFUN_BUFFER_CLOSE:
716 case LFUN_BUFFER_WRITE_AS:
717 case LFUN_BUFFER_UPDATE:
718 case LFUN_BUFFER_VIEW:
719 case LFUN_MASTER_BUFFER_UPDATE:
720 case LFUN_MASTER_BUFFER_VIEW:
721 case LFUN_BUFFER_IMPORT:
722 case LFUN_BUFFER_AUTO_SAVE:
723 case LFUN_RECONFIGURE:
727 case LFUN_DROP_LAYOUTS_CHOICE:
729 case LFUN_SERVER_GET_NAME:
730 case LFUN_SERVER_NOTIFY:
731 case LFUN_SERVER_GOTO_FILE_ROW:
732 case LFUN_DIALOG_HIDE:
733 case LFUN_DIALOG_DISCONNECT_INSET:
734 case LFUN_BUFFER_CHILD_OPEN:
735 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
736 case LFUN_KEYMAP_OFF:
737 case LFUN_KEYMAP_PRIMARY:
738 case LFUN_KEYMAP_SECONDARY:
739 case LFUN_KEYMAP_TOGGLE:
741 case LFUN_BUFFER_EXPORT_CUSTOM:
742 case LFUN_BUFFER_PRINT:
743 case LFUN_PREFERENCES_SAVE:
744 case LFUN_SCREEN_FONT_UPDATE:
747 case LFUN_EXTERNAL_EDIT:
748 case LFUN_GRAPHICS_EDIT:
749 case LFUN_ALL_INSETS_TOGGLE:
750 case LFUN_BUFFER_LANGUAGE:
751 case LFUN_TEXTCLASS_APPLY:
752 case LFUN_TEXTCLASS_LOAD:
753 case LFUN_BUFFER_SAVE_AS_DEFAULT:
754 case LFUN_BUFFER_PARAMS_APPLY:
755 case LFUN_LAYOUT_MODULES_CLEAR:
756 case LFUN_LAYOUT_MODULE_ADD:
757 case LFUN_LAYOUT_RELOAD:
758 case LFUN_LYXRC_APPLY:
759 case LFUN_BUFFER_NEXT:
760 case LFUN_BUFFER_PREVIOUS:
761 case LFUN_WINDOW_NEW:
763 // these are handled in our dispatch()
770 if (!getLocalStatus(*cur, cmd, flag))
771 flag = view()->getStatus(cmd);
777 // Can we use a readonly buffer?
778 if (buf && buf->isReadonly()
779 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
780 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
781 flag.message(from_utf8(N_("Document is read-only")));
785 // Are we in a DELETED change-tracking region?
787 && lookupChangeType(*cur, true) == Change::DELETED
788 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
789 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
790 flag.message(from_utf8(N_("This portion of the document is deleted.")));
794 // the default error message if we disable the command
795 if (!flag.enabled() && flag.message().empty())
796 flag.message(from_utf8(N_("Command disabled")));
802 bool LyXFunc::ensureBufferClean(BufferView * bv)
804 Buffer & buf = bv->buffer();
808 docstring const file = makeDisplayPath(buf.fileName(), 30);
809 docstring text = bformat(_("The document %1$s has unsaved "
810 "changes.\n\nDo you want to save "
811 "the document?"), file);
812 int const ret = Alert::prompt(_("Save changed document?"),
813 text, 0, 1, _("&Save"),
817 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
819 return buf.isClean();
825 void showPrintError(string const & name)
827 docstring str = bformat(_("Could not print the document %1$s.\n"
828 "Check that your printer is set up correctly."),
829 makeDisplayPath(name, 50));
830 Alert::error(_("Print document failed"), str);
834 void loadTextClass(string const & name)
836 std::pair<bool, textclass_type> const tc_pair =
837 textclasslist.numberOfClass(name);
839 if (!tc_pair.first) {
840 lyxerr << "Document class \"" << name
841 << "\" does not exist."
846 textclass_type const tc = tc_pair.second;
848 if (!textclasslist[tc].load()) {
849 docstring s = bformat(_("The document class %1$s."
850 "could not be loaded."),
851 from_utf8(textclasslist[tc].name()));
852 Alert::error(_("Could not load class"), s);
857 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
862 void LyXFunc::dispatch(FuncRequest const & cmd)
864 string const argument = to_utf8(cmd.argument());
865 kb_action const action = cmd.action;
867 LYXERR(Debug::ACTION) << endl << "LyXFunc::dispatch: cmd: " << cmd << endl;
868 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
870 // we have not done anything wrong yet.
872 dispatch_buffer.erase();
874 // redraw the screen at the end (first of the two drawing steps).
875 //This is done unless explicitely requested otherwise
876 Update::flags updateFlags = Update::FitCursor;
878 FuncStatus const flag = getStatus(cmd);
879 if (!flag.enabled()) {
880 // We cannot use this function here
881 LYXERR(Debug::ACTION) << "LyXFunc::dispatch: "
882 << lyxaction.getActionName(action)
883 << " [" << action << "] is disabled at this location"
885 setErrorMessage(flag.message());
889 case LFUN_WORD_FIND_FORWARD:
890 case LFUN_WORD_FIND_BACKWARD: {
891 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
892 static docstring last_search;
893 docstring searched_string;
895 if (!cmd.argument().empty()) {
896 last_search = cmd.argument();
897 searched_string = cmd.argument();
899 searched_string = last_search;
902 if (searched_string.empty())
905 bool const fw = action == LFUN_WORD_FIND_FORWARD;
906 docstring const data =
907 find2string(searched_string, true, false, fw);
908 find(view(), FuncRequest(LFUN_WORD_FIND, data));
912 case LFUN_COMMAND_PREFIX:
913 BOOST_ASSERT(lyx_view_);
914 lyx_view_->message(keyseq.printOptions(true));
917 case LFUN_COMMAND_EXECUTE:
918 BOOST_ASSERT(lyx_view_);
919 lyx_view_->showMiniBuffer(true);
923 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
925 meta_fake_bit = NoModifier;
926 if (lyx_view_->buffer())
927 // cancel any selection
928 dispatch(FuncRequest(LFUN_MARK_OFF));
929 setMessage(from_ascii(N_("Cancel")));
932 case LFUN_META_PREFIX:
933 meta_fake_bit = AltModifier;
934 setMessage(keyseq.print(true));
937 case LFUN_BUFFER_TOGGLE_READ_ONLY: {
938 BOOST_ASSERT(lyx_view_ && lyx_view_->view() && lyx_view_->buffer());
939 Buffer * buf = lyx_view_->buffer();
940 if (buf->lyxvc().inUse())
941 buf->lyxvc().toggleReadOnly();
943 buf->setReadonly(!lyx_view_->buffer()->isReadonly());
947 // --- Menus -----------------------------------------------
948 case LFUN_BUFFER_NEW:
949 menuNew(argument, false);
950 updateFlags = Update::None;
953 case LFUN_BUFFER_NEW_TEMPLATE:
954 menuNew(argument, true);
955 updateFlags = Update::None;
958 case LFUN_BUFFER_CLOSE:
960 updateFlags = Update::None;
963 case LFUN_BUFFER_WRITE:
964 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
965 if (!lyx_view_->buffer()->isUnnamed()) {
966 docstring const str = bformat(_("Saving document %1$s..."),
967 makeDisplayPath(lyx_view_->buffer()->fileName()));
968 lyx_view_->message(str);
969 lyx_view_->buffer()->menuWrite();
970 lyx_view_->message(str + _(" done."));
972 lyx_view_->buffer()->writeAs();
974 updateFlags = Update::None;
977 case LFUN_BUFFER_WRITE_AS:
978 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
979 lyx_view_->buffer()->writeAs(argument);
980 updateFlags = Update::None;
983 case LFUN_BUFFER_WRITE_ALL: {
984 Buffer * first = theBufferList().first();
987 lyx_view_->message(_("Saving all documents..."));
989 // We cannot use a for loop as the buffer list cycles.
992 if (!b->isUnnamed()) {
994 lyxerr[Debug::ACTION] << "Saved " << b->fileName() << endl;
998 b = theBufferList().next(b);
999 } while (b != first);
1000 lyx_view_->message(_("All documents saved."));
1003 updateFlags = Update::None;
1007 case LFUN_BUFFER_RELOAD: {
1008 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1009 docstring const file = makeDisplayPath(lyx_view_->buffer()->fileName(), 20);
1010 docstring text = bformat(_("Any changes will be lost. Are you sure "
1011 "you want to revert to the saved version of the document %1$s?"), file);
1012 int const ret = Alert::prompt(_("Revert to saved document?"),
1013 text, 1, 1, _("&Revert"), _("&Cancel"));
1020 case LFUN_BUFFER_UPDATE:
1021 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1022 Exporter::Export(lyx_view_->buffer(), argument, true);
1025 case LFUN_BUFFER_VIEW:
1026 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1027 Exporter::preview(lyx_view_->buffer(), argument);
1030 case LFUN_MASTER_BUFFER_UPDATE:
1031 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->getMasterBuffer());
1032 Exporter::Export(lyx_view_->buffer()->getMasterBuffer(), argument, true);
1035 case LFUN_MASTER_BUFFER_VIEW:
1036 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->getMasterBuffer());
1037 Exporter::preview(lyx_view_->buffer()->getMasterBuffer(), argument);
1040 case LFUN_BUILD_PROGRAM:
1041 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1042 Exporter::Export(lyx_view_->buffer(), "program", true);
1045 case LFUN_BUFFER_CHKTEX:
1046 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1047 lyx_view_->buffer()->runChktex();
1050 case LFUN_BUFFER_EXPORT:
1051 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1052 if (argument == "custom")
1053 lyx_view_->getDialogs().show("sendto");
1055 Exporter::Export(lyx_view_->buffer(), argument, false);
1059 case LFUN_BUFFER_EXPORT_CUSTOM: {
1060 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1062 string command = split(argument, format_name, ' ');
1063 Format const * format = formats.getFormat(format_name);
1065 lyxerr << "Format \"" << format_name
1066 << "\" not recognized!"
1071 Buffer * buffer = lyx_view_->buffer();
1073 // The name of the file created by the conversion process
1076 // Output to filename
1077 if (format->name() == "lyx") {
1078 string const latexname =
1079 buffer->getLatexName(false);
1080 filename = changeExtension(latexname,
1081 format->extension());
1082 filename = addName(buffer->temppath(), filename);
1084 if (!buffer->writeFile(FileName(filename)))
1088 Exporter::Export(buffer, format_name, true, filename);
1091 // Substitute $$FName for filename
1092 if (!contains(command, "$$FName"))
1093 command = "( " + command + " ) < $$FName";
1094 command = subst(command, "$$FName", filename);
1096 // Execute the command in the background
1098 call.startscript(Systemcall::DontWait, command);
1102 case LFUN_BUFFER_PRINT: {
1103 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1104 // FIXME: cmd.getArg() might fail if one of the arguments
1105 // contains double quotes
1106 string target = cmd.getArg(0);
1107 string target_name = cmd.getArg(1);
1108 string command = cmd.getArg(2);
1111 || target_name.empty()
1112 || command.empty()) {
1113 lyxerr << "Unable to parse \""
1114 << argument << '"' << endl;
1117 if (target != "printer" && target != "file") {
1118 lyxerr << "Unrecognized target \""
1119 << target << '"' << endl;
1123 Buffer * buffer = lyx_view_->buffer();
1125 if (!Exporter::Export(buffer, "dvi", true)) {
1126 showPrintError(buffer->fileName());
1130 // Push directory path.
1131 string const path = buffer->temppath();
1132 // Prevent the compiler from optimizing away p
1134 support::Path p(pp);
1136 // there are three cases here:
1137 // 1. we print to a file
1138 // 2. we print directly to a printer
1139 // 3. we print using a spool command (print to file first)
1142 string const dviname =
1143 changeExtension(buffer->getLatexName(true),
1146 if (target == "printer") {
1147 if (!lyxrc.print_spool_command.empty()) {
1148 // case 3: print using a spool
1149 string const psname =
1150 changeExtension(dviname,".ps");
1151 command += ' ' + lyxrc.print_to_file
1154 + quoteName(dviname);
1157 lyxrc.print_spool_command + ' ';
1158 if (target_name != "default") {
1159 command2 += lyxrc.print_spool_printerprefix
1163 command2 += quoteName(psname);
1165 // If successful, then spool command
1166 res = one.startscript(
1171 res = one.startscript(
1172 Systemcall::DontWait,
1175 // case 2: print directly to a printer
1176 if (target_name != "default")
1177 command += ' ' + lyxrc.print_to_printer + target_name + ' ';
1178 res = one.startscript(
1179 Systemcall::DontWait,
1180 command + quoteName(dviname));
1184 // case 1: print to a file
1185 FileName const filename(makeAbsPath(target_name,
1186 lyx_view_->buffer()->filePath()));
1187 FileName const dvifile(makeAbsPath(dviname, path));
1188 if (fs::exists(filename.toFilesystemEncoding())) {
1189 docstring text = bformat(
1190 _("The file %1$s already exists.\n\n"
1191 "Do you want to overwrite that file?"),
1192 makeDisplayPath(filename.absFilename()));
1193 if (Alert::prompt(_("Overwrite file?"),
1194 text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
1197 command += ' ' + lyxrc.print_to_file
1198 + quoteName(filename.toFilesystemEncoding())
1200 + quoteName(dvifile.toFilesystemEncoding());
1201 res = one.startscript(Systemcall::DontWait,
1206 showPrintError(buffer->fileName());
1210 case LFUN_BUFFER_IMPORT:
1215 // quitting is triggered by the gui code
1216 // (leaving the event loop).
1217 lyx_view_->message(from_utf8(N_("Exiting.")));
1218 if (theBufferList().quitWriteAll())
1219 theApp()->gui().closeAllViews();
1222 case LFUN_BUFFER_AUTO_SAVE:
1223 lyx_view_->buffer()->autoSave();
1226 case LFUN_RECONFIGURE:
1227 BOOST_ASSERT(lyx_view_);
1228 // argument is any additional parameter to the configure.py command
1229 reconfigure(*lyx_view_, argument);
1232 case LFUN_HELP_OPEN: {
1233 BOOST_ASSERT(lyx_view_);
1234 string const arg = argument;
1236 setErrorMessage(from_ascii(N_("Missing argument")));
1239 FileName const fname = i18nLibFileSearch("doc", arg, "lyx");
1240 if (fname.empty()) {
1241 lyxerr << "LyX: unable to find documentation file `"
1242 << arg << "'. Bad installation?" << endl;
1245 lyx_view_->message(bformat(_("Opening help file %1$s..."),
1246 makeDisplayPath(fname.absFilename())));
1247 Buffer * buf = lyx_view_->loadLyXFile(fname, false);
1250 lyx_view_->setBuffer(buf);
1251 lyx_view_->showErrorList("Parse");
1253 updateFlags = Update::None;
1257 // --- version control -------------------------------
1258 case LFUN_VC_REGISTER:
1259 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1260 if (!ensureBufferClean(view()))
1262 if (!lyx_view_->buffer()->lyxvc().inUse()) {
1263 lyx_view_->buffer()->lyxvc().registrer();
1266 updateFlags = Update::Force;
1269 case LFUN_VC_CHECK_IN:
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().checkIn();
1280 case LFUN_VC_CHECK_OUT:
1281 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1282 if (!ensureBufferClean(view()))
1284 if (lyx_view_->buffer()->lyxvc().inUse()
1285 && lyx_view_->buffer()->isReadonly()) {
1286 lyx_view_->buffer()->lyxvc().checkOut();
1291 case LFUN_VC_REVERT:
1292 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1293 lyx_view_->buffer()->lyxvc().revert();
1297 case LFUN_VC_UNDO_LAST:
1298 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1299 lyx_view_->buffer()->lyxvc().undoLast();
1303 // --- buffers ----------------------------------------
1304 case LFUN_BUFFER_SWITCH:
1305 BOOST_ASSERT(lyx_view_);
1306 lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1307 updateFlags = Update::None;
1310 case LFUN_BUFFER_NEXT:
1311 BOOST_ASSERT(lyx_view_);
1312 lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer()));
1313 updateFlags = Update::None;
1316 case LFUN_BUFFER_PREVIOUS:
1317 BOOST_ASSERT(lyx_view_);
1318 lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer()));
1319 updateFlags = Update::None;
1322 case LFUN_FILE_NEW: {
1323 BOOST_ASSERT(lyx_view_);
1325 string tmpname = split(argument, name, ':'); // Split filename
1326 Buffer * const b = newFile(name, tmpname);
1328 lyx_view_->setBuffer(b);
1329 updateFlags = Update::None;
1333 case LFUN_FILE_OPEN:
1334 BOOST_ASSERT(lyx_view_);
1336 updateFlags = Update::None;
1339 case LFUN_DROP_LAYOUTS_CHOICE:
1340 BOOST_ASSERT(lyx_view_);
1341 lyx_view_->openLayoutList();
1344 case LFUN_MENU_OPEN:
1345 BOOST_ASSERT(lyx_view_);
1346 lyx_view_->openMenu(from_utf8(argument));
1349 // --- lyxserver commands ----------------------------
1350 case LFUN_SERVER_GET_NAME:
1351 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1352 setMessage(from_utf8(lyx_view_->buffer()->fileName()));
1353 LYXERR(Debug::INFO) << "FNAME["
1354 << lyx_view_->buffer()->fileName()
1358 case LFUN_SERVER_NOTIFY:
1359 dispatch_buffer = keyseq.print(false);
1360 theServer().notifyClient(to_utf8(dispatch_buffer));
1363 case LFUN_SERVER_GOTO_FILE_ROW: {
1364 BOOST_ASSERT(lyx_view_);
1367 istringstream is(argument);
1368 is >> file_name >> row;
1370 bool loaded = false;
1371 if (prefixIs(file_name, package().temp_dir().absFilename()))
1372 // Needed by inverse dvi search. If it is a file
1373 // in tmpdir, call the apropriated function
1374 buf = theBufferList().getBufferFromTmp(file_name);
1376 // Must replace extension of the file to be .lyx
1377 // and get full path
1378 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1379 // Either change buffer or load the file
1380 if (theBufferList().exists(s.absFilename()))
1381 buf = theBufferList().getBuffer(s.absFilename());
1383 buf = lyx_view_->loadLyXFile(s);
1389 updateFlags = Update::None;
1394 lyx_view_->setBuffer(buf);
1395 view()->setCursorFromRow(row);
1397 lyx_view_->showErrorList("Parse");
1398 updateFlags = Update::FitCursor;
1402 case LFUN_DIALOG_SHOW: {
1403 BOOST_ASSERT(lyx_view_);
1404 string const name = cmd.getArg(0);
1405 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1407 if (name == "character") {
1408 data = freefont2string();
1410 lyx_view_->getDialogs().show("character", data);
1411 } else if (name == "latexlog") {
1412 pair<Buffer::LogType, string> const logfile =
1413 lyx_view_->buffer()->getLogName();
1414 switch (logfile.first) {
1415 case Buffer::latexlog:
1418 case Buffer::buildlog:
1422 data += Lexer::quoteString(logfile.second);
1423 lyx_view_->getDialogs().show("log", data);
1424 } else if (name == "vclog") {
1425 string const data = "vc " +
1426 Lexer::quoteString(lyx_view_->buffer()->lyxvc().getLogFile());
1427 lyx_view_->getDialogs().show("log", data);
1429 lyx_view_->getDialogs().show(name, data);
1433 case LFUN_DIALOG_SHOW_NEW_INSET: {
1434 BOOST_ASSERT(lyx_view_);
1435 string const name = cmd.getArg(0);
1436 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1437 if (name == "bibitem" ||
1441 name == "nomenclature" ||
1445 InsetCommandParams p(name);
1446 data = InsetCommandMailer::params2string(name, p);
1447 } else if (name == "include") {
1448 // data is the include type: one of "include",
1449 // "input", "verbatiminput" or "verbatiminput*"
1451 // default type is requested
1453 InsetCommandParams p(data);
1454 data = InsetIncludeMailer::params2string(p);
1455 } else if (name == "box") {
1456 // \c data == "Boxed" || "Frameless" etc
1457 InsetBoxParams p(data);
1458 data = InsetBoxMailer::params2string(p);
1459 } else if (name == "branch") {
1460 InsetBranchParams p;
1461 data = InsetBranchMailer::params2string(p);
1462 } else if (name == "citation") {
1463 InsetCommandParams p("citation");
1464 data = InsetCommandMailer::params2string(name, p);
1465 } else if (name == "ert") {
1466 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1467 } else if (name == "external") {
1468 InsetExternalParams p;
1469 Buffer const & buffer = *lyx_view_->buffer();
1470 data = InsetExternalMailer::params2string(p, buffer);
1471 } else if (name == "float") {
1473 data = InsetFloatMailer::params2string(p);
1474 } else if (name == "listings") {
1475 InsetListingsParams p;
1476 data = InsetListingsMailer::params2string(p);
1477 } else if (name == "graphics") {
1478 InsetGraphicsParams p;
1479 Buffer const & buffer = *lyx_view_->buffer();
1480 data = InsetGraphicsMailer::params2string(p, buffer);
1481 } else if (name == "note") {
1483 data = InsetNoteMailer::params2string(p);
1484 } else if (name == "vspace") {
1486 data = InsetVSpaceMailer::params2string(space);
1487 } else if (name == "wrap") {
1489 data = InsetWrapMailer::params2string(p);
1491 lyx_view_->getDialogs().show(name, data, 0);
1495 case LFUN_DIALOG_UPDATE: {
1496 BOOST_ASSERT(lyx_view_);
1497 string const & name = argument;
1498 // Can only update a dialog connected to an existing inset
1499 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1501 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1502 inset->dispatch(view()->cursor(), fr);
1503 } else if (name == "paragraph") {
1504 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1505 } else if (name == "prefs") {
1506 lyx_view_->getDialogs().update(name, string());
1511 case LFUN_DIALOG_HIDE:
1512 LyX::cref().hideDialogs(argument, 0);
1515 case LFUN_DIALOG_TOGGLE: {
1516 BOOST_ASSERT(lyx_view_);
1517 if (lyx_view_->getDialogs().visible(cmd.getArg(0)))
1518 dispatch(FuncRequest(LFUN_DIALOG_HIDE, argument));
1520 dispatch(FuncRequest(LFUN_DIALOG_SHOW, argument));
1524 case LFUN_DIALOG_DISCONNECT_INSET:
1525 BOOST_ASSERT(lyx_view_);
1526 lyx_view_->getDialogs().disconnect(argument);
1530 case LFUN_CITATION_INSERT: {
1531 BOOST_ASSERT(lyx_view_);
1532 if (!argument.empty()) {
1533 // we can have one optional argument, delimited by '|'
1534 // citation-insert <key>|<text_before>
1535 // this should be enhanced to also support text_after
1536 // and citation style
1537 string arg = argument;
1539 if (contains(argument, "|")) {
1540 arg = token(argument, '|', 0);
1541 opt1 = token(argument, '|', 1);
1543 InsetCommandParams icp("citation");
1544 icp["key"] = from_utf8(arg);
1546 icp["before"] = from_utf8(opt1);
1547 string icstr = InsetCommandMailer::params2string("citation", icp);
1548 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1551 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1555 case LFUN_BUFFER_CHILD_OPEN: {
1556 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1557 Buffer * parent = lyx_view_->buffer();
1558 FileName filename = makeAbsPath(argument, parent->filePath());
1559 view()->saveBookmark(false);
1561 bool parsed = false;
1562 if (theBufferList().exists(filename.absFilename())) {
1563 child = theBufferList().getBuffer(filename.absFilename());
1565 setMessage(bformat(_("Opening child document %1$s..."),
1566 makeDisplayPath(filename.absFilename())));
1567 child = lyx_view_->loadLyXFile(filename, true);
1571 // Set the parent name of the child document.
1572 // This makes insertion of citations and references in the child work,
1573 // when the target is in the parent or another child document.
1574 child->setParentName(parent->fileName());
1575 updateLabels(*child->getMasterBuffer());
1576 lyx_view_->setBuffer(child);
1578 lyx_view_->showErrorList("Parse");
1581 // If a screen update is required (in case where auto_open is false),
1582 // setBuffer() would have taken care of it already. Otherwise we shall
1583 // reset the update flag because it can cause a circular problem.
1585 updateFlags = Update::None;
1589 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1590 BOOST_ASSERT(lyx_view_);
1591 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1594 case LFUN_KEYMAP_OFF:
1595 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1596 lyx_view_->view()->getIntl().keyMapOn(false);
1599 case LFUN_KEYMAP_PRIMARY:
1600 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1601 lyx_view_->view()->getIntl().keyMapPrim();
1604 case LFUN_KEYMAP_SECONDARY:
1605 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1606 lyx_view_->view()->getIntl().keyMapSec();
1609 case LFUN_KEYMAP_TOGGLE:
1610 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1611 lyx_view_->view()->getIntl().toggleKeyMap();
1617 string rest = split(argument, countstr, ' ');
1618 istringstream is(countstr);
1621 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1622 for (int i = 0; i < count; ++i)
1623 dispatch(lyxaction.lookupFunc(rest));
1627 case LFUN_COMMAND_SEQUENCE: {
1628 // argument contains ';'-terminated commands
1629 string arg = argument;
1630 while (!arg.empty()) {
1632 arg = split(arg, first, ';');
1633 FuncRequest func(lyxaction.lookupFunc(first));
1634 func.origin = cmd.origin;
1640 case LFUN_PREFERENCES_SAVE: {
1641 lyxrc.write(makeAbsPath("preferences",
1642 package().user_support().absFilename()),
1647 case LFUN_SCREEN_FONT_UPDATE:
1648 BOOST_ASSERT(lyx_view_);
1649 // handle the screen font changes.
1650 theFontLoader().update();
1651 /// FIXME: only the current view will be updated. the Gui
1652 /// class is able to furnish the list of views.
1653 updateFlags = Update::Force;
1656 case LFUN_SET_COLOR: {
1658 string const x11_name = split(argument, lyx_name, ' ');
1659 if (lyx_name.empty() || x11_name.empty()) {
1660 setErrorMessage(from_ascii(N_(
1661 "Syntax: set-color <lyx_name>"
1666 bool const graphicsbg_changed =
1667 (lyx_name == lcolor.getLyXName(Color::graphicsbg) &&
1668 x11_name != lcolor.getX11Name(Color::graphicsbg));
1670 if (!lcolor.setColor(lyx_name, x11_name)) {
1672 bformat(_("Set-color \"%1$s\" failed "
1673 "- color is undefined or "
1674 "may not be redefined"),
1675 from_utf8(lyx_name)));
1679 theApp()->updateColor(lcolor.getFromLyXName(lyx_name));
1681 if (graphicsbg_changed) {
1682 // FIXME: The graphics cache no longer has a changeDisplay method.
1684 graphics::GCache::get().changeDisplay(true);
1691 BOOST_ASSERT(lyx_view_);
1692 lyx_view_->message(from_utf8(argument));
1695 case LFUN_EXTERNAL_EDIT: {
1696 BOOST_ASSERT(lyx_view_);
1697 FuncRequest fr(action, argument);
1698 InsetExternal().dispatch(view()->cursor(), fr);
1702 case LFUN_GRAPHICS_EDIT: {
1703 FuncRequest fr(action, argument);
1704 InsetGraphics().dispatch(view()->cursor(), fr);
1708 case LFUN_INSET_APPLY: {
1709 BOOST_ASSERT(lyx_view_);
1710 string const name = cmd.getArg(0);
1711 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1713 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1714 inset->dispatch(view()->cursor(), fr);
1716 FuncRequest fr(LFUN_INSET_INSERT, argument);
1719 // ideally, the update flag should be set by the insets,
1720 // but this is not possible currently
1721 updateFlags = Update::Force | Update::FitCursor;
1725 case LFUN_ALL_INSETS_TOGGLE: {
1726 BOOST_ASSERT(lyx_view_);
1728 string const name = split(argument, action, ' ');
1729 Inset::Code const inset_code =
1730 Inset::translate(name);
1732 Cursor & cur = view()->cursor();
1733 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1735 Inset & inset = lyx_view_->buffer()->inset();
1736 InsetIterator it = inset_iterator_begin(inset);
1737 InsetIterator const end = inset_iterator_end(inset);
1738 for (; it != end; ++it) {
1739 if (!it->asInsetMath()
1740 && (inset_code == Inset::NO_CODE
1741 || inset_code == it->lyxCode())) {
1742 Cursor tmpcur = cur;
1743 tmpcur.pushLeft(*it);
1744 it->dispatch(tmpcur, fr);
1747 updateFlags = Update::Force | Update::FitCursor;
1751 case LFUN_BUFFER_LANGUAGE: {
1752 BOOST_ASSERT(lyx_view_);
1753 Buffer & buffer = *lyx_view_->buffer();
1754 Language const * oldL = buffer.params().language;
1755 Language const * newL = languages.getLanguage(argument);
1756 if (!newL || oldL == newL)
1759 if (oldL->rightToLeft() == newL->rightToLeft()
1760 && !buffer.isMultiLingual())
1761 buffer.changeLanguage(oldL, newL);
1765 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1766 string const fname =
1767 addName(addPath(package().user_support().absFilename(), "templates/"),
1769 Buffer defaults(fname);
1771 istringstream ss(argument);
1774 int const unknown_tokens = defaults.readHeader(lex);
1776 if (unknown_tokens != 0) {
1777 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1778 << unknown_tokens << " unknown token"
1779 << (unknown_tokens == 1 ? "" : "s")
1783 if (defaults.writeFile(FileName(defaults.fileName())))
1784 setMessage(bformat(_("Document defaults saved in %1$s"),
1785 makeDisplayPath(fname)));
1787 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1791 case LFUN_BUFFER_PARAMS_APPLY: {
1792 BOOST_ASSERT(lyx_view_);
1793 biblio::CiteEngine const oldEngine =
1794 lyx_view_->buffer()->params().getEngine();
1796 Buffer * buffer = lyx_view_->buffer();
1798 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1799 recordUndoFullDocument(view());
1801 istringstream ss(argument);
1804 int const unknown_tokens = buffer->readHeader(lex);
1806 if (unknown_tokens != 0) {
1807 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1808 << unknown_tokens << " unknown token"
1809 << (unknown_tokens == 1 ? "" : "s")
1813 updateLayout(oldClass, buffer);
1815 biblio::CiteEngine const newEngine =
1816 lyx_view_->buffer()->params().getEngine();
1818 if (oldEngine != newEngine) {
1819 Cursor & cur = view()->cursor();
1820 FuncRequest fr(LFUN_INSET_REFRESH);
1822 Inset & inset = lyx_view_->buffer()->inset();
1823 InsetIterator it = inset_iterator_begin(inset);
1824 InsetIterator const end = inset_iterator_end(inset);
1825 for (; it != end; ++it)
1826 if (it->lyxCode() == Inset::CITE_CODE)
1827 it->dispatch(cur, fr);
1830 updateFlags = Update::Force | Update::FitCursor;
1834 case LFUN_LAYOUT_MODULES_CLEAR: {
1835 BOOST_ASSERT(lyx_view_);
1836 Buffer * buffer = lyx_view_->buffer();
1837 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1838 recordUndoFullDocument(view());
1839 buffer->params().clearLayoutModules();
1840 updateLayout(oldClass, buffer);
1841 updateFlags = Update::Force | Update::FitCursor;
1845 case LFUN_LAYOUT_MODULE_ADD: {
1846 BOOST_ASSERT(lyx_view_);
1847 Buffer * buffer = lyx_view_->buffer();
1848 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1849 recordUndoFullDocument(view());
1850 buffer->params().addLayoutModule(argument);
1851 updateLayout(oldClass, buffer);
1852 updateFlags = Update::Force | Update::FitCursor;
1856 case LFUN_TEXTCLASS_APPLY: {
1857 BOOST_ASSERT(lyx_view_);
1858 Buffer * buffer = lyx_view_->buffer();
1860 loadTextClass(argument);
1862 std::pair<bool, textclass_type> const tc_pair =
1863 textclasslist.numberOfClass(argument);
1868 textclass_type const old_class = buffer->params().getBaseClass();
1869 textclass_type const new_class = tc_pair.second;
1871 if (old_class == new_class)
1875 //Save the old, possibly modular, layout for use in conversion.
1876 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1877 recordUndoFullDocument(view());
1878 buffer->params().setBaseClass(new_class);
1879 updateLayout(oldClass, buffer);
1880 updateFlags = Update::Force | Update::FitCursor;
1884 case LFUN_LAYOUT_RELOAD: {
1885 BOOST_ASSERT(lyx_view_);
1886 Buffer * buffer = lyx_view_->buffer();
1887 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1888 textclass_type const tc = buffer->params().getBaseClass();
1889 textclasslist.reset(tc);
1890 buffer->params().setBaseClass(tc);
1891 updateLayout(oldClass, buffer);
1892 updateFlags = Update::Force | Update::FitCursor;
1896 case LFUN_TEXTCLASS_LOAD:
1897 loadTextClass(argument);
1900 case LFUN_LYXRC_APPLY: {
1901 LyXRC const lyxrc_orig = lyxrc;
1903 istringstream ss(argument);
1904 bool const success = lyxrc.read(ss) == 0;
1907 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1908 << "Unable to read lyxrc data"
1913 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1915 /// We force the redraw in any case because there might be
1916 /// some screen font changes.
1917 /// FIXME: only the current view will be updated. the Gui
1918 /// class is able to furnish the list of views.
1919 updateFlags = Update::Force;
1923 case LFUN_WINDOW_NEW:
1924 LyX::ref().newLyXView();
1927 case LFUN_WINDOW_CLOSE:
1928 BOOST_ASSERT(lyx_view_);
1929 BOOST_ASSERT(theApp());
1930 // update bookmark pit of the current buffer before window close
1931 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1932 gotoBookmark(i+1, false, false);
1933 // ask the user for saving changes or cancel quit
1934 if (!theBufferList().quitWriteAll())
1939 case LFUN_BOOKMARK_GOTO:
1940 // go to bookmark, open unopened file and switch to buffer if necessary
1941 gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
1944 case LFUN_BOOKMARK_CLEAR:
1945 LyX::ref().session().bookmarks().clear();
1948 case LFUN_TOOLBAR_TOGGLE: {
1949 BOOST_ASSERT(lyx_view_);
1950 string const name = cmd.getArg(0);
1951 bool const allowauto = cmd.getArg(1) == "allowauto";
1952 lyx_view_->toggleToolbarState(name, allowauto);
1953 ToolbarInfo * tbi = lyx_view_->getToolbarInfo(name);
1955 setMessage(bformat(_("Unknown toolbar \"%1$s\""),
1960 if (tbi->flags & ToolbarInfo::ON)
1962 else if (tbi->flags & ToolbarInfo::OFF)
1964 else if (tbi->flags & ToolbarInfo::AUTO)
1967 setMessage(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1968 _(tbi->gui_name), state));
1973 BOOST_ASSERT(lyx_view_);
1974 view()->cursor().dispatch(cmd);
1975 updateFlags = view()->cursor().result().update();
1976 if (!view()->cursor().result().dispatched())
1977 updateFlags = view()->dispatch(cmd);
1982 if (lyx_view_ && lyx_view_->buffer()) {
1983 // BufferView::update() updates the ViewMetricsInfo and
1984 // also initializes the position cache for all insets in
1985 // (at least partially) visible top-level paragraphs.
1986 // We will redraw the screen only if needed.
1987 view()->processUpdateFlags(updateFlags);
1988 lyx_view_->updateStatusBar();
1990 // if we executed a mutating lfun, mark the buffer as dirty
1992 && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
1993 && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
1994 lyx_view_->buffer()->markDirty();
1996 //Do we have a selection?
1997 theSelection().haveSelection(view()->cursor().selection());
1999 if (view()->cursor().inTexted()) {
2000 lyx_view_->updateLayoutChoice();
2004 if (!quitting && lyx_view_) {
2005 lyx_view_->updateToolbars();
2006 // Some messages may already be translated, so we cannot use _()
2007 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
2012 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
2014 const bool verbose = (cmd.origin == FuncRequest::MENU
2015 || cmd.origin == FuncRequest::TOOLBAR
2016 || cmd.origin == FuncRequest::COMMANDBUFFER);
2018 if (cmd.action == LFUN_SELF_INSERT || !verbose) {
2019 LYXERR(Debug::ACTION) << "dispatch msg is " << to_utf8(msg) << endl;
2021 lyx_view_->message(msg);
2025 docstring dispatch_msg = msg;
2026 if (!dispatch_msg.empty())
2027 dispatch_msg += ' ';
2029 docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
2031 bool argsadded = false;
2033 if (!cmd.argument().empty()) {
2034 if (cmd.action != LFUN_UNKNOWN_ACTION) {
2035 comname += ' ' + cmd.argument();
2040 docstring const shortcuts = theTopLevelKeymap().printbindings(cmd);
2042 if (!shortcuts.empty())
2043 comname += ": " + shortcuts;
2044 else if (!argsadded && !cmd.argument().empty())
2045 comname += ' ' + cmd.argument();
2047 if (!comname.empty()) {
2048 comname = rtrim(comname);
2049 dispatch_msg += '(' + rtrim(comname) + ')';
2052 LYXERR(Debug::ACTION) << "verbose dispatch msg "
2053 << to_utf8(dispatch_msg) << endl;
2054 if (!dispatch_msg.empty())
2055 lyx_view_->message(dispatch_msg);
2059 void LyXFunc::menuNew(string const & name, bool fromTemplate)
2061 // FIXME: initpath is not used. What to do?
2062 string initpath = lyxrc.document_path;
2063 string filename(name);
2065 if (lyx_view_->buffer()) {
2066 string const trypath = lyx_view_->buffer()->filePath();
2067 // If directory is writeable, use this as default.
2068 if (isDirWriteable(FileName(trypath)))
2072 static int newfile_number;
2074 if (filename.empty()) {
2075 filename = addName(lyxrc.document_path,
2076 "newfile" + convert<string>(++newfile_number) + ".lyx");
2077 while (theBufferList().exists(filename) ||
2078 fs::is_readable(FileName(filename).toFilesystemEncoding())) {
2080 filename = addName(lyxrc.document_path,
2081 "newfile" + convert<string>(newfile_number) +
2086 // The template stuff
2089 FileDialog fileDlg(_("Select template file"),
2090 LFUN_SELECT_FILE_SYNC,
2091 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2092 make_pair(_("Templates|#T#t"), from_utf8(lyxrc.template_path)));
2094 FileDialog::Result result =
2095 fileDlg.open(from_utf8(lyxrc.template_path),
2096 FileFilterList(_("LyX Documents (*.lyx)")),
2099 if (result.first == FileDialog::Later)
2101 if (result.second.empty())
2103 templname = to_utf8(result.second);
2106 Buffer * const b = newFile(filename, templname, !name.empty());
2108 lyx_view_->setBuffer(b);
2112 void LyXFunc::open(string const & fname)
2114 string initpath = lyxrc.document_path;
2116 if (lyx_view_->buffer()) {
2117 string const trypath = lyx_view_->buffer()->filePath();
2118 // If directory is writeable, use this as default.
2119 if (isDirWriteable(FileName(trypath)))
2125 if (fname.empty()) {
2126 FileDialog fileDlg(_("Select document to open"),
2128 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2129 make_pair(_("Examples|#E#e"), from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2131 FileDialog::Result result =
2132 fileDlg.open(from_utf8(initpath),
2133 FileFilterList(_("LyX Documents (*.lyx)")),
2136 if (result.first == FileDialog::Later)
2139 filename = to_utf8(result.second);
2141 // check selected filename
2142 if (filename.empty()) {
2143 lyx_view_->message(_("Canceled."));
2149 // get absolute path of file and add ".lyx" to the filename if
2151 FileName const fullname = fileSearch(string(), filename, "lyx");
2152 if (!fullname.empty())
2153 filename = fullname.absFilename();
2155 // if the file doesn't exist, let the user create one
2156 if (!fs::exists(fullname.toFilesystemEncoding())) {
2157 // the user specifically chose this name. Believe him.
2158 Buffer * const b = newFile(filename, string(), true);
2160 lyx_view_->setBuffer(b);
2164 docstring const disp_fn = makeDisplayPath(filename);
2165 lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
2168 Buffer * buf = lyx_view_->loadLyXFile(fullname);
2171 lyx_view_->setBuffer(buf);
2172 lyx_view_->showErrorList("Parse");
2173 str2 = bformat(_("Document %1$s opened."), disp_fn);
2175 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2177 lyx_view_->message(str2);
2181 void LyXFunc::doImport(string const & argument)
2184 string filename = split(argument, format, ' ');
2186 LYXERR(Debug::INFO) << "LyXFunc::doImport: " << format
2187 << " file: " << filename << endl;
2189 // need user interaction
2190 if (filename.empty()) {
2191 string initpath = lyxrc.document_path;
2193 if (lyx_view_->buffer()) {
2194 string const trypath = lyx_view_->buffer()->filePath();
2195 // If directory is writeable, use this as default.
2196 if (isDirWriteable(FileName(trypath)))
2200 docstring const text = bformat(_("Select %1$s file to import"),
2201 formats.prettyName(format));
2203 FileDialog fileDlg(text,
2205 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2206 make_pair(_("Examples|#E#e"),
2207 from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2209 docstring filter = formats.prettyName(format);
2212 filter += from_utf8(formats.extension(format));
2215 FileDialog::Result result =
2216 fileDlg.open(from_utf8(initpath),
2217 FileFilterList(filter),
2220 if (result.first == FileDialog::Later)
2223 filename = to_utf8(result.second);
2225 // check selected filename
2226 if (filename.empty())
2227 lyx_view_->message(_("Canceled."));
2230 if (filename.empty())
2233 // get absolute path of file
2234 FileName const fullname(makeAbsPath(filename));
2236 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
2238 // Check if the document already is open
2239 if (use_gui && theBufferList().exists(lyxfile.absFilename())) {
2240 if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) {
2241 lyx_view_->message(_("Canceled."));
2246 // if the file exists already, and we didn't do
2247 // -i lyx thefile.lyx, warn
2248 if (fs::exists(lyxfile.toFilesystemEncoding()) && fullname != lyxfile) {
2249 docstring const file = makeDisplayPath(lyxfile.absFilename(), 30);
2251 docstring text = bformat(_("The document %1$s already exists.\n\n"
2252 "Do you want to overwrite that document?"), file);
2253 int const ret = Alert::prompt(_("Overwrite document?"),
2254 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2257 lyx_view_->message(_("Canceled."));
2262 ErrorList errorList;
2263 Importer::Import(lyx_view_, fullname, format, errorList);
2264 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2268 void LyXFunc::closeBuffer()
2270 // goto bookmark to update bookmark pit.
2271 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2272 gotoBookmark(i+1, false, false);
2274 theBufferList().close(lyx_view_->buffer(), true);
2278 void LyXFunc::reloadBuffer()
2280 FileName filename(lyx_view_->buffer()->fileName());
2281 docstring const disp_fn = makeDisplayPath(filename.absFilename());
2284 Buffer * buf = lyx_view_->loadLyXFile(filename);
2287 lyx_view_->setBuffer(buf);
2288 lyx_view_->showErrorList("Parse");
2289 str = bformat(_("Document %1$s reloaded."), disp_fn);
2291 str = bformat(_("Could not reload document %1$s"), disp_fn);
2293 lyx_view_->message(str);
2296 // Each "lyx_view_" should have it's own message method. lyxview and
2297 // the minibuffer would use the minibuffer, but lyxserver would
2298 // send an ERROR signal to its client. Alejandro 970603
2299 // This function is bit problematic when it comes to NLS, to make the
2300 // lyx servers client be language indepenent we must not translate
2301 // strings sent to this func.
2302 void LyXFunc::setErrorMessage(docstring const & m) const
2304 dispatch_buffer = m;
2309 void LyXFunc::setMessage(docstring const & m) const
2311 dispatch_buffer = m;
2315 docstring const LyXFunc::viewStatusMessage()
2317 // When meta-fake key is pressed, show the key sequence so far + "M-".
2319 return keyseq.print(true) + "M-";
2321 // Else, when a non-complete key sequence is pressed,
2322 // show the available options.
2323 if (keyseq.length() > 0 && !keyseq.deleted())
2324 return keyseq.printOptions(true);
2326 BOOST_ASSERT(lyx_view_);
2327 if (!lyx_view_->buffer())
2328 return _("Welcome to LyX!");
2330 return view()->cursor().currentState();
2334 BufferView * LyXFunc::view() const
2336 BOOST_ASSERT(lyx_view_);
2337 return lyx_view_->view();
2341 bool LyXFunc::wasMetaKey() const
2343 return (meta_fake_bit != NoModifier);
2347 void LyXFunc::updateLayout(TextClassPtr const & oldlayout,
2350 lyx_view_->message(_("Converting document to new document class..."));
2352 StableDocIterator backcur(view()->cursor());
2353 ErrorList & el = buffer->errorList("Class Switch");
2354 cap::switchBetweenClasses(
2355 oldlayout, buffer->params().getTextClassPtr(),
2356 static_cast<InsetText &>(buffer->inset()), el);
2358 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
2360 buffer->errors("Class Switch");
2361 updateLabels(*buffer);
2367 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2369 // Why the switch you might ask. It is a trick to ensure that all
2370 // the elements in the LyXRCTags enum is handled. As you can see
2371 // there are no breaks at all. So it is just a huge fall-through.
2372 // The nice thing is that we will get a warning from the compiler
2373 // if we forget an element.
2374 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2376 case LyXRC::RC_ACCEPT_COMPOUND:
2377 case LyXRC::RC_ALT_LANG:
2378 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
2379 case LyXRC::RC_PLAINTEXT_LINELEN:
2380 case LyXRC::RC_AUTOREGIONDELETE:
2381 case LyXRC::RC_AUTORESET_OPTIONS:
2382 case LyXRC::RC_AUTOSAVE:
2383 case LyXRC::RC_AUTO_NUMBER:
2384 case LyXRC::RC_BACKUPDIR_PATH:
2385 case LyXRC::RC_BIBTEX_COMMAND:
2386 case LyXRC::RC_BINDFILE:
2387 case LyXRC::RC_CHECKLASTFILES:
2388 case LyXRC::RC_USELASTFILEPOS:
2389 case LyXRC::RC_LOADSESSION:
2390 case LyXRC::RC_CHKTEX_COMMAND:
2391 case LyXRC::RC_CONVERTER:
2392 case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
2393 case LyXRC::RC_COPIER:
2394 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2395 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2396 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2397 case LyXRC::RC_DATE_INSERT_FORMAT:
2398 case LyXRC::RC_DEFAULT_LANGUAGE:
2399 case LyXRC::RC_DEFAULT_PAPERSIZE:
2400 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2401 case LyXRC::RC_DISPLAY_GRAPHICS:
2402 case LyXRC::RC_DOCUMENTPATH:
2403 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2404 string const encoded = FileName(
2405 lyxrc_new.document_path).toFilesystemEncoding();
2406 if (fs::exists(encoded) && fs::is_directory(encoded))
2407 support::package().document_dir() = FileName(lyxrc.document_path);
2409 case LyXRC::RC_ESC_CHARS:
2410 case LyXRC::RC_FONT_ENCODING:
2411 case LyXRC::RC_FORMAT:
2412 case LyXRC::RC_INDEX_COMMAND:
2413 case LyXRC::RC_INPUT:
2414 case LyXRC::RC_KBMAP:
2415 case LyXRC::RC_KBMAP_PRIMARY:
2416 case LyXRC::RC_KBMAP_SECONDARY:
2417 case LyXRC::RC_LABEL_INIT_LENGTH:
2418 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2419 case LyXRC::RC_LANGUAGE_AUTO_END:
2420 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2421 case LyXRC::RC_LANGUAGE_COMMAND_END:
2422 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2423 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2424 case LyXRC::RC_LANGUAGE_PACKAGE:
2425 case LyXRC::RC_LANGUAGE_USE_BABEL:
2426 case LyXRC::RC_MAKE_BACKUP:
2427 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2428 case LyXRC::RC_NUMLASTFILES:
2429 case LyXRC::RC_PATH_PREFIX:
2430 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2431 support::prependEnvPath("PATH", lyxrc.path_prefix);
2433 case LyXRC::RC_PERS_DICT:
2434 case LyXRC::RC_PREVIEW:
2435 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2436 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2437 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2438 case LyXRC::RC_PRINTCOPIESFLAG:
2439 case LyXRC::RC_PRINTER:
2440 case LyXRC::RC_PRINTEVENPAGEFLAG:
2441 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2442 case LyXRC::RC_PRINTFILEEXTENSION:
2443 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2444 case LyXRC::RC_PRINTODDPAGEFLAG:
2445 case LyXRC::RC_PRINTPAGERANGEFLAG:
2446 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2447 case LyXRC::RC_PRINTPAPERFLAG:
2448 case LyXRC::RC_PRINTREVERSEFLAG:
2449 case LyXRC::RC_PRINTSPOOL_COMMAND:
2450 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2451 case LyXRC::RC_PRINTTOFILE:
2452 case LyXRC::RC_PRINTTOPRINTER:
2453 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2454 case LyXRC::RC_PRINT_COMMAND:
2455 case LyXRC::RC_RTL_SUPPORT:
2456 case LyXRC::RC_SCREEN_DPI:
2457 case LyXRC::RC_SCREEN_FONT_ROMAN:
2458 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2459 case LyXRC::RC_SCREEN_FONT_SANS:
2460 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2461 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2462 case LyXRC::RC_SCREEN_FONT_SIZES:
2463 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2464 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2465 case LyXRC::RC_SCREEN_GEOMETRY_HEIGHT:
2466 case LyXRC::RC_SCREEN_GEOMETRY_WIDTH:
2467 case LyXRC::RC_SCREEN_GEOMETRY_XYSAVED:
2468 case LyXRC::RC_SCREEN_ZOOM:
2469 case LyXRC::RC_SERVERPIPE:
2470 case LyXRC::RC_SET_COLOR:
2471 case LyXRC::RC_SHOW_BANNER:
2472 case LyXRC::RC_SPELL_COMMAND:
2473 case LyXRC::RC_TEMPDIRPATH:
2474 case LyXRC::RC_TEMPLATEPATH:
2475 case LyXRC::RC_TEX_ALLOWS_SPACES:
2476 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2477 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2478 support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2480 case LyXRC::RC_UIFILE:
2481 case LyXRC::RC_USER_EMAIL:
2482 case LyXRC::RC_USER_NAME:
2483 case LyXRC::RC_USETEMPDIR:
2484 case LyXRC::RC_USE_ALT_LANG:
2485 case LyXRC::RC_USE_CONVERTER_CACHE:
2486 case LyXRC::RC_USE_ESC_CHARS:
2487 case LyXRC::RC_USE_INP_ENC:
2488 case LyXRC::RC_USE_PERS_DICT:
2489 case LyXRC::RC_USE_SPELL_LIB:
2490 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2491 case LyXRC::RC_VIEWER:
2492 case LyXRC::RC_LAST: