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 Cursor & cur = view()->cursor();
424 /* In LyX/Mac, when a dialog is open, the menus of the
425 application can still be accessed without giving focus to
426 the main window. In this case, we want to disable the menu
427 entries that are buffer-related.
429 Note that this code is not perfect, as bug 1941 attests:
430 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
432 Buffer * buf = lyx_view_? lyx_view_->buffer() : 0;
433 if (lyx_view_ && cmd.origin == FuncRequest::MENU && !lyx_view_->hasFocus())
436 if (cmd.action == LFUN_NOACTION) {
437 flag.message(from_utf8(N_("Nothing to do")));
442 switch (cmd.action) {
443 case LFUN_UNKNOWN_ACTION:
444 #ifndef HAVE_LIBAIKSAURUS
445 case LFUN_THESAURUS_ENTRY:
455 if (flag.unknown()) {
456 flag.message(from_utf8(N_("Unknown action")));
460 if (!flag.enabled()) {
461 if (flag.message().empty())
462 flag.message(from_utf8(N_("Command disabled")));
466 // Check whether we need a buffer
467 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
469 flag.message(from_utf8(N_("Command not allowed with"
470 "out any document open")));
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.innerInsetOfType(Inset::TABULAR_CODE);
510 case LFUN_LAYOUT_PARAGRAPH:
511 enable = !cur.inset().forceDefaultParagraphs(cur.idx());
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: {
569 string const name = cmd.getArg(0);
570 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
572 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
574 if (!inset->getStatus(cur, fr, fs)) {
575 // Every inset is supposed to handle this
580 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
581 flag |= getStatus(fr);
583 enable = flag.enabled();
587 case LFUN_DIALOG_TOGGLE:
588 flag.setOnOff(lyx_view_->getDialogs().visible(cmd.getArg(0)));
589 // fall through to set "enable"
590 case LFUN_DIALOG_SHOW: {
591 string const name = cmd.getArg(0);
593 enable = name == "aboutlyx"
594 || name == "file" //FIXME: should be removed.
596 || name == "texinfo";
597 else if (name == "print")
598 enable = Exporter::isExportable(*buf, "dvi")
599 && lyxrc.print_command != "none";
600 else if (name == "character")
601 enable = cur.inset().lyxCode() != Inset::ERT_CODE &&
602 cur.inset().lyxCode() != Inset::LISTINGS_CODE;
603 else if (name == "latexlog")
604 enable = isFileReadable(FileName(buf->getLogName().second));
605 else if (name == "spellchecker")
606 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
607 enable = !buf->isReadonly();
611 else if (name == "vclog")
612 enable = buf->lyxvc().inUse();
616 case LFUN_DIALOG_SHOW_NEW_INSET:
617 enable = cur.inset().lyxCode() != Inset::ERT_CODE &&
618 cur.inset().lyxCode() != Inset::LISTINGS_CODE;
619 if (cur.inset().lyxCode() == Inset::CAPTION_CODE) {
621 if (cur.inset().getStatus(cur, cmd, flag))
626 case LFUN_DIALOG_UPDATE: {
627 string const name = cmd.getArg(0);
629 enable = name == "prefs";
633 case LFUN_CITATION_INSERT: {
634 FuncRequest fr(LFUN_INSET_INSERT, "citation");
635 enable = getStatus(fr).enabled();
639 case LFUN_BUFFER_WRITE: {
640 enable = lyx_view_->buffer()->isUnnamed()
641 || !lyx_view_->buffer()->isClean();
646 case LFUN_BUFFER_WRITE_ALL: {
647 // We enable the command only if there are some modified buffers
648 Buffer * first = theBufferList().first();
649 bool modified = false;
653 // We cannot use a for loop as the buffer list is a cycle.
659 b = theBufferList().next(b);
660 } while (b != first);
668 case LFUN_BOOKMARK_GOTO: {
669 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
670 enable = LyX::ref().session().bookmarks().isValid(num);
674 case LFUN_BOOKMARK_CLEAR:
675 enable = LyX::ref().session().bookmarks().size() > 0;
678 case LFUN_TOOLBAR_TOGGLE: {
679 bool const current = lyx_view_->isToolbarVisible(cmd.getArg(0));
680 flag.setOnOff(current);
683 case LFUN_WINDOW_CLOSE: {
684 enable = (theApp()->gui().viewIds().size() > 1);
688 // this one is difficult to get right. As a half-baked
689 // solution, we consider only the first action of the sequence
690 case LFUN_COMMAND_SEQUENCE: {
691 // argument contains ';'-terminated commands
692 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
693 FuncRequest func(lyxaction.lookupFunc(firstcmd));
694 func.origin = cmd.origin;
695 flag = getStatus(func);
698 case LFUN_BUFFER_NEW:
699 case LFUN_BUFFER_NEW_TEMPLATE:
700 case LFUN_WORD_FIND_FORWARD:
701 case LFUN_WORD_FIND_BACKWARD:
702 case LFUN_COMMAND_PREFIX:
703 case LFUN_COMMAND_EXECUTE:
705 case LFUN_META_PREFIX:
706 case LFUN_BUFFER_CLOSE:
707 case LFUN_BUFFER_WRITE_AS:
708 case LFUN_BUFFER_UPDATE:
709 case LFUN_BUFFER_VIEW:
710 case LFUN_MASTER_BUFFER_UPDATE:
711 case LFUN_MASTER_BUFFER_VIEW:
712 case LFUN_BUFFER_IMPORT:
713 case LFUN_BUFFER_AUTO_SAVE:
714 case LFUN_RECONFIGURE:
718 case LFUN_DROP_LAYOUTS_CHOICE:
720 case LFUN_SERVER_GET_NAME:
721 case LFUN_SERVER_NOTIFY:
722 case LFUN_SERVER_GOTO_FILE_ROW:
723 case LFUN_DIALOG_HIDE:
724 case LFUN_DIALOG_DISCONNECT_INSET:
725 case LFUN_BUFFER_CHILD_OPEN:
726 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
727 case LFUN_KEYMAP_OFF:
728 case LFUN_KEYMAP_PRIMARY:
729 case LFUN_KEYMAP_SECONDARY:
730 case LFUN_KEYMAP_TOGGLE:
732 case LFUN_BUFFER_EXPORT_CUSTOM:
733 case LFUN_BUFFER_PRINT:
734 case LFUN_PREFERENCES_SAVE:
735 case LFUN_SCREEN_FONT_UPDATE:
738 case LFUN_EXTERNAL_EDIT:
739 case LFUN_GRAPHICS_EDIT:
740 case LFUN_ALL_INSETS_TOGGLE:
741 case LFUN_BUFFER_LANGUAGE:
742 case LFUN_TEXTCLASS_APPLY:
743 case LFUN_TEXTCLASS_LOAD:
744 case LFUN_BUFFER_SAVE_AS_DEFAULT:
745 case LFUN_BUFFER_PARAMS_APPLY:
746 case LFUN_LAYOUT_MODULES_CLEAR:
747 case LFUN_LAYOUT_MODULE_ADD:
748 case LFUN_LAYOUT_RELOAD:
749 case LFUN_LYXRC_APPLY:
750 case LFUN_BUFFER_NEXT:
751 case LFUN_BUFFER_PREVIOUS:
752 case LFUN_WINDOW_NEW:
754 // these are handled in our dispatch()
758 if (!getLocalStatus(cur, cmd, flag))
759 flag = view()->getStatus(cmd);
765 // Can we use a readonly buffer?
766 if (buf && buf->isReadonly()
767 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
768 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
769 flag.message(from_utf8(N_("Document is read-only")));
773 // Are we in a DELETED change-tracking region?
774 if (buf && lookupChangeType(cur, true) == Change::DELETED
775 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
776 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
777 flag.message(from_utf8(N_("This portion of the document is deleted.")));
781 // the default error message if we disable the command
782 if (!flag.enabled() && flag.message().empty())
783 flag.message(from_utf8(N_("Command disabled")));
789 bool LyXFunc::ensureBufferClean(BufferView * bv)
791 Buffer & buf = bv->buffer();
795 docstring const file = makeDisplayPath(buf.fileName(), 30);
796 docstring text = bformat(_("The document %1$s has unsaved "
797 "changes.\n\nDo you want to save "
798 "the document?"), file);
799 int const ret = Alert::prompt(_("Save changed document?"),
800 text, 0, 1, _("&Save"),
804 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
806 return buf.isClean();
812 void showPrintError(string const & name)
814 docstring str = bformat(_("Could not print the document %1$s.\n"
815 "Check that your printer is set up correctly."),
816 makeDisplayPath(name, 50));
817 Alert::error(_("Print document failed"), str);
821 void loadTextClass(string const & name)
823 std::pair<bool, textclass_type> const tc_pair =
824 textclasslist.numberOfClass(name);
826 if (!tc_pair.first) {
827 lyxerr << "Document class \"" << name
828 << "\" does not exist."
833 textclass_type const tc = tc_pair.second;
835 if (!textclasslist[tc].load()) {
836 docstring s = bformat(_("The document class %1$s."
837 "could not be loaded."),
838 from_utf8(textclasslist[tc].name()));
839 Alert::error(_("Could not load class"), s);
844 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
849 void LyXFunc::dispatch(FuncRequest const & cmd)
851 string const argument = to_utf8(cmd.argument());
852 kb_action const action = cmd.action;
854 LYXERR(Debug::ACTION) << endl << "LyXFunc::dispatch: cmd: " << cmd << endl;
855 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
857 // we have not done anything wrong yet.
859 dispatch_buffer.erase();
861 // redraw the screen at the end (first of the two drawing steps).
862 //This is done unless explicitely requested otherwise
863 Update::flags updateFlags = Update::FitCursor;
865 FuncStatus const flag = getStatus(cmd);
866 if (!flag.enabled()) {
867 // We cannot use this function here
868 LYXERR(Debug::ACTION) << "LyXFunc::dispatch: "
869 << lyxaction.getActionName(action)
870 << " [" << action << "] is disabled at this location"
872 setErrorMessage(flag.message());
876 case LFUN_WORD_FIND_FORWARD:
877 case LFUN_WORD_FIND_BACKWARD: {
878 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
879 static docstring last_search;
880 docstring searched_string;
882 if (!cmd.argument().empty()) {
883 last_search = cmd.argument();
884 searched_string = cmd.argument();
886 searched_string = last_search;
889 if (searched_string.empty())
892 bool const fw = action == LFUN_WORD_FIND_FORWARD;
893 docstring const data =
894 find2string(searched_string, true, false, fw);
895 find(view(), FuncRequest(LFUN_WORD_FIND, data));
899 case LFUN_COMMAND_PREFIX:
900 BOOST_ASSERT(lyx_view_);
901 lyx_view_->message(keyseq.printOptions(true));
904 case LFUN_COMMAND_EXECUTE:
905 BOOST_ASSERT(lyx_view_);
906 lyx_view_->showMiniBuffer(true);
910 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
912 meta_fake_bit = NoModifier;
913 if (lyx_view_->buffer())
914 // cancel any selection
915 dispatch(FuncRequest(LFUN_MARK_OFF));
916 setMessage(from_ascii(N_("Cancel")));
919 case LFUN_META_PREFIX:
920 meta_fake_bit = AltModifier;
921 setMessage(keyseq.print(true));
924 case LFUN_BUFFER_TOGGLE_READ_ONLY: {
925 BOOST_ASSERT(lyx_view_ && lyx_view_->view() && lyx_view_->buffer());
926 Buffer * buf = lyx_view_->buffer();
927 if (buf->lyxvc().inUse())
928 buf->lyxvc().toggleReadOnly();
930 buf->setReadonly(!lyx_view_->buffer()->isReadonly());
934 // --- Menus -----------------------------------------------
935 case LFUN_BUFFER_NEW:
936 menuNew(argument, false);
937 updateFlags = Update::None;
940 case LFUN_BUFFER_NEW_TEMPLATE:
941 menuNew(argument, true);
942 updateFlags = Update::None;
945 case LFUN_BUFFER_CLOSE:
947 updateFlags = Update::None;
950 case LFUN_BUFFER_WRITE:
951 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
952 if (!lyx_view_->buffer()->isUnnamed()) {
953 docstring const str = bformat(_("Saving document %1$s..."),
954 makeDisplayPath(lyx_view_->buffer()->fileName()));
955 lyx_view_->message(str);
956 lyx_view_->buffer()->menuWrite();
957 lyx_view_->message(str + _(" done."));
959 lyx_view_->buffer()->writeAs();
961 updateFlags = Update::None;
964 case LFUN_BUFFER_WRITE_AS:
965 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
966 lyx_view_->buffer()->writeAs(argument);
967 updateFlags = Update::None;
970 case LFUN_BUFFER_WRITE_ALL: {
971 Buffer * first = theBufferList().first();
974 lyx_view_->message(_("Saving all documents..."));
976 // We cannot use a for loop as the buffer list cycles.
979 if (!b->isUnnamed()) {
981 lyxerr[Debug::ACTION] << "Saved " << b->fileName() << endl;
985 b = theBufferList().next(b);
986 } while (b != first);
987 lyx_view_->message(_("All documents saved."));
990 updateFlags = Update::None;
994 case LFUN_BUFFER_RELOAD: {
995 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
996 docstring const file = makeDisplayPath(lyx_view_->buffer()->fileName(), 20);
997 docstring text = bformat(_("Any changes will be lost. Are you sure "
998 "you want to revert to the saved version of the document %1$s?"), file);
999 int const ret = Alert::prompt(_("Revert to saved document?"),
1000 text, 1, 1, _("&Revert"), _("&Cancel"));
1007 case LFUN_BUFFER_UPDATE:
1008 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1009 Exporter::Export(lyx_view_->buffer(), argument, true);
1012 case LFUN_BUFFER_VIEW:
1013 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1014 Exporter::preview(lyx_view_->buffer(), argument);
1017 case LFUN_MASTER_BUFFER_UPDATE:
1018 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->getMasterBuffer());
1019 Exporter::Export(lyx_view_->buffer()->getMasterBuffer(), argument, true);
1022 case LFUN_MASTER_BUFFER_VIEW:
1023 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->getMasterBuffer());
1024 Exporter::preview(lyx_view_->buffer()->getMasterBuffer(), argument);
1027 case LFUN_BUILD_PROGRAM:
1028 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1029 Exporter::Export(lyx_view_->buffer(), "program", true);
1032 case LFUN_BUFFER_CHKTEX:
1033 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1034 lyx_view_->buffer()->runChktex();
1037 case LFUN_BUFFER_EXPORT:
1038 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1039 if (argument == "custom")
1040 lyx_view_->getDialogs().show("sendto");
1042 Exporter::Export(lyx_view_->buffer(), argument, false);
1046 case LFUN_BUFFER_EXPORT_CUSTOM: {
1047 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1049 string command = split(argument, format_name, ' ');
1050 Format const * format = formats.getFormat(format_name);
1052 lyxerr << "Format \"" << format_name
1053 << "\" not recognized!"
1058 Buffer * buffer = lyx_view_->buffer();
1060 // The name of the file created by the conversion process
1063 // Output to filename
1064 if (format->name() == "lyx") {
1065 string const latexname =
1066 buffer->getLatexName(false);
1067 filename = changeExtension(latexname,
1068 format->extension());
1069 filename = addName(buffer->temppath(), filename);
1071 if (!buffer->writeFile(FileName(filename)))
1075 Exporter::Export(buffer, format_name, true, filename);
1078 // Substitute $$FName for filename
1079 if (!contains(command, "$$FName"))
1080 command = "( " + command + " ) < $$FName";
1081 command = subst(command, "$$FName", filename);
1083 // Execute the command in the background
1085 call.startscript(Systemcall::DontWait, command);
1089 case LFUN_BUFFER_PRINT: {
1090 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1091 // FIXME: cmd.getArg() might fail if one of the arguments
1092 // contains double quotes
1093 string target = cmd.getArg(0);
1094 string target_name = cmd.getArg(1);
1095 string command = cmd.getArg(2);
1098 || target_name.empty()
1099 || command.empty()) {
1100 lyxerr << "Unable to parse \""
1101 << argument << '"' << endl;
1104 if (target != "printer" && target != "file") {
1105 lyxerr << "Unrecognized target \""
1106 << target << '"' << endl;
1110 Buffer * buffer = lyx_view_->buffer();
1112 if (!Exporter::Export(buffer, "dvi", true)) {
1113 showPrintError(buffer->fileName());
1117 // Push directory path.
1118 string const path = buffer->temppath();
1119 // Prevent the compiler from optimizing away p
1121 support::Path p(pp);
1123 // there are three cases here:
1124 // 1. we print to a file
1125 // 2. we print directly to a printer
1126 // 3. we print using a spool command (print to file first)
1129 string const dviname =
1130 changeExtension(buffer->getLatexName(true),
1133 if (target == "printer") {
1134 if (!lyxrc.print_spool_command.empty()) {
1135 // case 3: print using a spool
1136 string const psname =
1137 changeExtension(dviname,".ps");
1138 command += ' ' + lyxrc.print_to_file
1141 + quoteName(dviname);
1144 lyxrc.print_spool_command + ' ';
1145 if (target_name != "default") {
1146 command2 += lyxrc.print_spool_printerprefix
1150 command2 += quoteName(psname);
1152 // If successful, then spool command
1153 res = one.startscript(
1158 res = one.startscript(
1159 Systemcall::DontWait,
1162 // case 2: print directly to a printer
1163 if (target_name != "default")
1164 command += ' ' + lyxrc.print_to_printer + target_name + ' ';
1165 res = one.startscript(
1166 Systemcall::DontWait,
1167 command + quoteName(dviname));
1171 // case 1: print to a file
1172 FileName const filename(makeAbsPath(target_name,
1173 lyx_view_->buffer()->filePath()));
1174 FileName const dvifile(makeAbsPath(dviname, path));
1175 if (fs::exists(filename.toFilesystemEncoding())) {
1176 docstring text = bformat(
1177 _("The file %1$s already exists.\n\n"
1178 "Do you want to overwrite that file?"),
1179 makeDisplayPath(filename.absFilename()));
1180 if (Alert::prompt(_("Overwrite file?"),
1181 text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
1184 command += ' ' + lyxrc.print_to_file
1185 + quoteName(filename.toFilesystemEncoding())
1187 + quoteName(dvifile.toFilesystemEncoding());
1188 res = one.startscript(Systemcall::DontWait,
1193 showPrintError(buffer->fileName());
1197 case LFUN_BUFFER_IMPORT:
1202 // quitting is triggered by the gui code
1203 // (leaving the event loop).
1204 lyx_view_->message(from_utf8(N_("Exiting.")));
1205 if (theBufferList().quitWriteAll())
1206 theApp()->gui().closeAllViews();
1209 case LFUN_BUFFER_AUTO_SAVE:
1210 lyx_view_->buffer()->autoSave();
1213 case LFUN_RECONFIGURE:
1214 BOOST_ASSERT(lyx_view_);
1215 // argument is any additional parameter to the configure.py command
1216 reconfigure(*lyx_view_, argument);
1219 case LFUN_HELP_OPEN: {
1220 BOOST_ASSERT(lyx_view_);
1221 string const arg = argument;
1223 setErrorMessage(from_ascii(N_("Missing argument")));
1226 FileName const fname = i18nLibFileSearch("doc", arg, "lyx");
1227 if (fname.empty()) {
1228 lyxerr << "LyX: unable to find documentation file `"
1229 << arg << "'. Bad installation?" << endl;
1232 lyx_view_->message(bformat(_("Opening help file %1$s..."),
1233 makeDisplayPath(fname.absFilename())));
1234 Buffer * buf = lyx_view_->loadLyXFile(fname, false);
1237 lyx_view_->setBuffer(buf);
1238 lyx_view_->showErrorList("Parse");
1240 updateFlags = Update::None;
1244 // --- version control -------------------------------
1245 case LFUN_VC_REGISTER:
1246 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1247 if (!ensureBufferClean(view()))
1249 if (!lyx_view_->buffer()->lyxvc().inUse()) {
1250 lyx_view_->buffer()->lyxvc().registrer();
1253 updateFlags = Update::Force;
1256 case LFUN_VC_CHECK_IN:
1257 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1258 if (!ensureBufferClean(view()))
1260 if (lyx_view_->buffer()->lyxvc().inUse()
1261 && !lyx_view_->buffer()->isReadonly()) {
1262 lyx_view_->buffer()->lyxvc().checkIn();
1267 case LFUN_VC_CHECK_OUT:
1268 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1269 if (!ensureBufferClean(view()))
1271 if (lyx_view_->buffer()->lyxvc().inUse()
1272 && lyx_view_->buffer()->isReadonly()) {
1273 lyx_view_->buffer()->lyxvc().checkOut();
1278 case LFUN_VC_REVERT:
1279 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1280 lyx_view_->buffer()->lyxvc().revert();
1284 case LFUN_VC_UNDO_LAST:
1285 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1286 lyx_view_->buffer()->lyxvc().undoLast();
1290 // --- buffers ----------------------------------------
1291 case LFUN_BUFFER_SWITCH:
1292 BOOST_ASSERT(lyx_view_);
1293 lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1294 updateFlags = Update::None;
1297 case LFUN_BUFFER_NEXT:
1298 BOOST_ASSERT(lyx_view_);
1299 lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer()));
1300 updateFlags = Update::None;
1303 case LFUN_BUFFER_PREVIOUS:
1304 BOOST_ASSERT(lyx_view_);
1305 lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer()));
1306 updateFlags = Update::None;
1309 case LFUN_FILE_NEW: {
1310 BOOST_ASSERT(lyx_view_);
1312 string tmpname = split(argument, name, ':'); // Split filename
1313 Buffer * const b = newFile(name, tmpname);
1315 lyx_view_->setBuffer(b);
1316 updateFlags = Update::None;
1320 case LFUN_FILE_OPEN:
1321 BOOST_ASSERT(lyx_view_);
1323 updateFlags = Update::None;
1326 case LFUN_DROP_LAYOUTS_CHOICE:
1327 BOOST_ASSERT(lyx_view_);
1328 lyx_view_->openLayoutList();
1331 case LFUN_MENU_OPEN:
1332 BOOST_ASSERT(lyx_view_);
1333 lyx_view_->openMenu(from_utf8(argument));
1336 // --- lyxserver commands ----------------------------
1337 case LFUN_SERVER_GET_NAME:
1338 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1339 setMessage(from_utf8(lyx_view_->buffer()->fileName()));
1340 LYXERR(Debug::INFO) << "FNAME["
1341 << lyx_view_->buffer()->fileName()
1345 case LFUN_SERVER_NOTIFY:
1346 dispatch_buffer = keyseq.print(false);
1347 theServer().notifyClient(to_utf8(dispatch_buffer));
1350 case LFUN_SERVER_GOTO_FILE_ROW: {
1351 BOOST_ASSERT(lyx_view_);
1354 istringstream is(argument);
1355 is >> file_name >> row;
1357 bool loaded = false;
1358 if (prefixIs(file_name, package().temp_dir().absFilename()))
1359 // Needed by inverse dvi search. If it is a file
1360 // in tmpdir, call the apropriated function
1361 buf = theBufferList().getBufferFromTmp(file_name);
1363 // Must replace extension of the file to be .lyx
1364 // and get full path
1365 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1366 // Either change buffer or load the file
1367 if (theBufferList().exists(s.absFilename()))
1368 buf = theBufferList().getBuffer(s.absFilename());
1370 buf = lyx_view_->loadLyXFile(s);
1376 updateFlags = Update::None;
1381 lyx_view_->setBuffer(buf);
1382 view()->setCursorFromRow(row);
1384 lyx_view_->showErrorList("Parse");
1385 updateFlags = Update::FitCursor;
1389 case LFUN_DIALOG_SHOW: {
1390 BOOST_ASSERT(lyx_view_);
1391 string const name = cmd.getArg(0);
1392 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1394 if (name == "character") {
1395 data = freefont2string();
1397 lyx_view_->getDialogs().show("character", data);
1398 } else if (name == "latexlog") {
1399 pair<Buffer::LogType, string> const logfile =
1400 lyx_view_->buffer()->getLogName();
1401 switch (logfile.first) {
1402 case Buffer::latexlog:
1405 case Buffer::buildlog:
1409 data += Lexer::quoteString(logfile.second);
1410 lyx_view_->getDialogs().show("log", data);
1411 } else if (name == "vclog") {
1412 string const data = "vc " +
1413 Lexer::quoteString(lyx_view_->buffer()->lyxvc().getLogFile());
1414 lyx_view_->getDialogs().show("log", data);
1416 lyx_view_->getDialogs().show(name, data);
1420 case LFUN_DIALOG_SHOW_NEW_INSET: {
1421 BOOST_ASSERT(lyx_view_);
1422 string const name = cmd.getArg(0);
1423 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1424 if (name == "bibitem" ||
1428 name == "nomenclature" ||
1432 InsetCommandParams p(name);
1433 data = InsetCommandMailer::params2string(name, p);
1434 } else if (name == "include") {
1435 // data is the include type: one of "include",
1436 // "input", "verbatiminput" or "verbatiminput*"
1438 // default type is requested
1440 InsetCommandParams p(data);
1441 data = InsetIncludeMailer::params2string(p);
1442 } else if (name == "box") {
1443 // \c data == "Boxed" || "Frameless" etc
1444 InsetBoxParams p(data);
1445 data = InsetBoxMailer::params2string(p);
1446 } else if (name == "branch") {
1447 InsetBranchParams p;
1448 data = InsetBranchMailer::params2string(p);
1449 } else if (name == "citation") {
1450 InsetCommandParams p("citation");
1451 data = InsetCommandMailer::params2string(name, p);
1452 } else if (name == "ert") {
1453 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1454 } else if (name == "external") {
1455 InsetExternalParams p;
1456 Buffer const & buffer = *lyx_view_->buffer();
1457 data = InsetExternalMailer::params2string(p, buffer);
1458 } else if (name == "float") {
1460 data = InsetFloatMailer::params2string(p);
1461 } else if (name == "listings") {
1462 InsetListingsParams p;
1463 data = InsetListingsMailer::params2string(p);
1464 } else if (name == "graphics") {
1465 InsetGraphicsParams p;
1466 Buffer const & buffer = *lyx_view_->buffer();
1467 data = InsetGraphicsMailer::params2string(p, buffer);
1468 } else if (name == "note") {
1470 data = InsetNoteMailer::params2string(p);
1471 } else if (name == "vspace") {
1473 data = InsetVSpaceMailer::params2string(space);
1474 } else if (name == "wrap") {
1476 data = InsetWrapMailer::params2string(p);
1478 lyx_view_->getDialogs().show(name, data, 0);
1482 case LFUN_DIALOG_UPDATE: {
1483 BOOST_ASSERT(lyx_view_);
1484 string const & name = argument;
1485 // Can only update a dialog connected to an existing inset
1486 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1488 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1489 inset->dispatch(view()->cursor(), fr);
1490 } else if (name == "paragraph") {
1491 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1492 } else if (name == "prefs") {
1493 lyx_view_->getDialogs().update(name, string());
1498 case LFUN_DIALOG_HIDE:
1499 LyX::cref().hideDialogs(argument, 0);
1502 case LFUN_DIALOG_TOGGLE: {
1503 BOOST_ASSERT(lyx_view_);
1504 if (lyx_view_->getDialogs().visible(cmd.getArg(0)))
1505 dispatch(FuncRequest(LFUN_DIALOG_HIDE, argument));
1507 dispatch(FuncRequest(LFUN_DIALOG_SHOW, argument));
1511 case LFUN_DIALOG_DISCONNECT_INSET:
1512 BOOST_ASSERT(lyx_view_);
1513 lyx_view_->getDialogs().disconnect(argument);
1517 case LFUN_CITATION_INSERT: {
1518 BOOST_ASSERT(lyx_view_);
1519 if (!argument.empty()) {
1520 // we can have one optional argument, delimited by '|'
1521 // citation-insert <key>|<text_before>
1522 // this should be enhanced to also support text_after
1523 // and citation style
1524 string arg = argument;
1526 if (contains(argument, "|")) {
1527 arg = token(argument, '|', 0);
1528 opt1 = token(argument, '|', 1);
1530 InsetCommandParams icp("citation");
1531 icp["key"] = from_utf8(arg);
1533 icp["before"] = from_utf8(opt1);
1534 string icstr = InsetCommandMailer::params2string("citation", icp);
1535 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1538 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1542 case LFUN_BUFFER_CHILD_OPEN: {
1543 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1544 Buffer * parent = lyx_view_->buffer();
1545 FileName filename = makeAbsPath(argument, parent->filePath());
1546 view()->saveBookmark(false);
1548 bool parsed = false;
1549 if (theBufferList().exists(filename.absFilename())) {
1550 child = theBufferList().getBuffer(filename.absFilename());
1552 setMessage(bformat(_("Opening child document %1$s..."),
1553 makeDisplayPath(filename.absFilename())));
1554 child = lyx_view_->loadLyXFile(filename, true);
1558 // Set the parent name of the child document.
1559 // This makes insertion of citations and references in the child work,
1560 // when the target is in the parent or another child document.
1561 child->setParentName(parent->fileName());
1562 updateLabels(*child->getMasterBuffer());
1563 lyx_view_->setBuffer(child);
1565 lyx_view_->showErrorList("Parse");
1568 // If a screen update is required (in case where auto_open is false),
1569 // setBuffer() would have taken care of it already. Otherwise we shall
1570 // reset the update flag because it can cause a circular problem.
1572 updateFlags = Update::None;
1576 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1577 BOOST_ASSERT(lyx_view_);
1578 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1581 case LFUN_KEYMAP_OFF:
1582 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1583 lyx_view_->view()->getIntl().keyMapOn(false);
1586 case LFUN_KEYMAP_PRIMARY:
1587 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1588 lyx_view_->view()->getIntl().keyMapPrim();
1591 case LFUN_KEYMAP_SECONDARY:
1592 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1593 lyx_view_->view()->getIntl().keyMapSec();
1596 case LFUN_KEYMAP_TOGGLE:
1597 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1598 lyx_view_->view()->getIntl().toggleKeyMap();
1604 string rest = split(argument, countstr, ' ');
1605 istringstream is(countstr);
1608 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1609 for (int i = 0; i < count; ++i)
1610 dispatch(lyxaction.lookupFunc(rest));
1614 case LFUN_COMMAND_SEQUENCE: {
1615 // argument contains ';'-terminated commands
1616 string arg = argument;
1617 while (!arg.empty()) {
1619 arg = split(arg, first, ';');
1620 FuncRequest func(lyxaction.lookupFunc(first));
1621 func.origin = cmd.origin;
1627 case LFUN_PREFERENCES_SAVE: {
1628 lyxrc.write(makeAbsPath("preferences",
1629 package().user_support().absFilename()),
1634 case LFUN_SCREEN_FONT_UPDATE:
1635 BOOST_ASSERT(lyx_view_);
1636 // handle the screen font changes.
1637 theFontLoader().update();
1638 /// FIXME: only the current view will be updated. the Gui
1639 /// class is able to furnish the list of views.
1640 updateFlags = Update::Force;
1643 case LFUN_SET_COLOR: {
1645 string const x11_name = split(argument, lyx_name, ' ');
1646 if (lyx_name.empty() || x11_name.empty()) {
1647 setErrorMessage(from_ascii(N_(
1648 "Syntax: set-color <lyx_name>"
1653 bool const graphicsbg_changed =
1654 (lyx_name == lcolor.getLyXName(Color::graphicsbg) &&
1655 x11_name != lcolor.getX11Name(Color::graphicsbg));
1657 if (!lcolor.setColor(lyx_name, x11_name)) {
1659 bformat(_("Set-color \"%1$s\" failed "
1660 "- color is undefined or "
1661 "may not be redefined"),
1662 from_utf8(lyx_name)));
1666 theApp()->updateColor(lcolor.getFromLyXName(lyx_name));
1668 if (graphicsbg_changed) {
1669 // FIXME: The graphics cache no longer has a changeDisplay method.
1671 graphics::GCache::get().changeDisplay(true);
1678 BOOST_ASSERT(lyx_view_);
1679 lyx_view_->message(from_utf8(argument));
1682 case LFUN_EXTERNAL_EDIT: {
1683 BOOST_ASSERT(lyx_view_);
1684 FuncRequest fr(action, argument);
1685 InsetExternal().dispatch(view()->cursor(), fr);
1689 case LFUN_GRAPHICS_EDIT: {
1690 FuncRequest fr(action, argument);
1691 InsetGraphics().dispatch(view()->cursor(), fr);
1695 case LFUN_INSET_APPLY: {
1696 BOOST_ASSERT(lyx_view_);
1697 string const name = cmd.getArg(0);
1698 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1700 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1701 inset->dispatch(view()->cursor(), fr);
1703 FuncRequest fr(LFUN_INSET_INSERT, argument);
1706 // ideally, the update flag should be set by the insets,
1707 // but this is not possible currently
1708 updateFlags = Update::Force | Update::FitCursor;
1712 case LFUN_ALL_INSETS_TOGGLE: {
1713 BOOST_ASSERT(lyx_view_);
1715 string const name = split(argument, action, ' ');
1716 Inset::Code const inset_code =
1717 Inset::translate(name);
1719 Cursor & cur = view()->cursor();
1720 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1722 Inset & inset = lyx_view_->buffer()->inset();
1723 InsetIterator it = inset_iterator_begin(inset);
1724 InsetIterator const end = inset_iterator_end(inset);
1725 for (; it != end; ++it) {
1726 if (!it->asInsetMath()
1727 && (inset_code == Inset::NO_CODE
1728 || inset_code == it->lyxCode())) {
1729 Cursor tmpcur = cur;
1730 tmpcur.pushLeft(*it);
1731 it->dispatch(tmpcur, fr);
1734 updateFlags = Update::Force | Update::FitCursor;
1738 case LFUN_BUFFER_LANGUAGE: {
1739 BOOST_ASSERT(lyx_view_);
1740 Buffer & buffer = *lyx_view_->buffer();
1741 Language const * oldL = buffer.params().language;
1742 Language const * newL = languages.getLanguage(argument);
1743 if (!newL || oldL == newL)
1746 if (oldL->rightToLeft() == newL->rightToLeft()
1747 && !buffer.isMultiLingual())
1748 buffer.changeLanguage(oldL, newL);
1752 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1753 string const fname =
1754 addName(addPath(package().user_support().absFilename(), "templates/"),
1756 Buffer defaults(fname);
1758 istringstream ss(argument);
1761 int const unknown_tokens = defaults.readHeader(lex);
1763 if (unknown_tokens != 0) {
1764 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1765 << unknown_tokens << " unknown token"
1766 << (unknown_tokens == 1 ? "" : "s")
1770 if (defaults.writeFile(FileName(defaults.fileName())))
1771 setMessage(bformat(_("Document defaults saved in %1$s"),
1772 makeDisplayPath(fname)));
1774 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1778 case LFUN_BUFFER_PARAMS_APPLY: {
1779 BOOST_ASSERT(lyx_view_);
1780 biblio::CiteEngine const oldEngine =
1781 lyx_view_->buffer()->params().getEngine();
1783 Buffer * buffer = lyx_view_->buffer();
1785 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1786 recordUndoFullDocument(view());
1788 istringstream ss(argument);
1791 int const unknown_tokens = buffer->readHeader(lex);
1793 if (unknown_tokens != 0) {
1794 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1795 << unknown_tokens << " unknown token"
1796 << (unknown_tokens == 1 ? "" : "s")
1800 updateLayout(oldClass, buffer);
1802 biblio::CiteEngine const newEngine =
1803 lyx_view_->buffer()->params().getEngine();
1805 if (oldEngine != newEngine) {
1806 Cursor & cur = view()->cursor();
1807 FuncRequest fr(LFUN_INSET_REFRESH);
1809 Inset & inset = lyx_view_->buffer()->inset();
1810 InsetIterator it = inset_iterator_begin(inset);
1811 InsetIterator const end = inset_iterator_end(inset);
1812 for (; it != end; ++it)
1813 if (it->lyxCode() == Inset::CITE_CODE)
1814 it->dispatch(cur, fr);
1817 updateFlags = Update::Force | Update::FitCursor;
1821 case LFUN_LAYOUT_MODULES_CLEAR: {
1822 BOOST_ASSERT(lyx_view_);
1823 Buffer * buffer = lyx_view_->buffer();
1824 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1825 recordUndoFullDocument(view());
1826 buffer->params().clearLayoutModules();
1827 updateLayout(oldClass, buffer);
1828 updateFlags = Update::Force | Update::FitCursor;
1832 case LFUN_LAYOUT_MODULE_ADD: {
1833 BOOST_ASSERT(lyx_view_);
1834 Buffer * buffer = lyx_view_->buffer();
1835 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1836 recordUndoFullDocument(view());
1837 buffer->params().addLayoutModule(argument);
1838 updateLayout(oldClass, buffer);
1839 updateFlags = Update::Force | Update::FitCursor;
1843 case LFUN_TEXTCLASS_APPLY: {
1844 BOOST_ASSERT(lyx_view_);
1845 Buffer * buffer = lyx_view_->buffer();
1847 loadTextClass(argument);
1849 std::pair<bool, textclass_type> const tc_pair =
1850 textclasslist.numberOfClass(argument);
1855 textclass_type const old_class = buffer->params().getBaseClass();
1856 textclass_type const new_class = tc_pair.second;
1858 if (old_class == new_class)
1862 //Save the old, possibly modular, layout for use in conversion.
1863 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1864 recordUndoFullDocument(view());
1865 buffer->params().setBaseClass(new_class);
1866 updateLayout(oldClass, buffer);
1867 updateFlags = Update::Force | Update::FitCursor;
1871 case LFUN_LAYOUT_RELOAD: {
1872 BOOST_ASSERT(lyx_view_);
1873 Buffer * buffer = lyx_view_->buffer();
1874 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1875 textclass_type const tc = buffer->params().getBaseClass();
1876 textclasslist.reset(tc);
1877 buffer->params().setBaseClass(tc);
1878 updateLayout(oldClass, buffer);
1879 updateFlags = Update::Force | Update::FitCursor;
1883 case LFUN_TEXTCLASS_LOAD:
1884 loadTextClass(argument);
1887 case LFUN_LYXRC_APPLY: {
1888 LyXRC const lyxrc_orig = lyxrc;
1890 istringstream ss(argument);
1891 bool const success = lyxrc.read(ss) == 0;
1894 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1895 << "Unable to read lyxrc data"
1900 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1902 /// We force the redraw in any case because there might be
1903 /// some screen font changes.
1904 /// FIXME: only the current view will be updated. the Gui
1905 /// class is able to furnish the list of views.
1906 updateFlags = Update::Force;
1910 case LFUN_WINDOW_NEW:
1911 LyX::ref().newLyXView();
1914 case LFUN_WINDOW_CLOSE:
1915 BOOST_ASSERT(lyx_view_);
1916 BOOST_ASSERT(theApp());
1917 // update bookmark pit of the current buffer before window close
1918 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1919 gotoBookmark(i+1, false, false);
1920 // ask the user for saving changes or cancel quit
1921 if (!theBufferList().quitWriteAll())
1926 case LFUN_BOOKMARK_GOTO:
1927 // go to bookmark, open unopened file and switch to buffer if necessary
1928 gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
1931 case LFUN_BOOKMARK_CLEAR:
1932 LyX::ref().session().bookmarks().clear();
1935 case LFUN_TOOLBAR_TOGGLE: {
1936 BOOST_ASSERT(lyx_view_);
1937 string const name = cmd.getArg(0);
1938 bool const allowauto = cmd.getArg(1) == "allowauto";
1939 lyx_view_->toggleToolbarState(name, allowauto);
1940 ToolbarInfo * tbi = lyx_view_->getToolbarInfo(name);
1942 setMessage(bformat(_("Unknown toolbar \"%1$s\""),
1947 if (tbi->flags & ToolbarInfo::ON)
1949 else if (tbi->flags & ToolbarInfo::OFF)
1951 else if (tbi->flags & ToolbarInfo::AUTO)
1954 setMessage(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1955 _(tbi->gui_name), state));
1960 BOOST_ASSERT(lyx_view_);
1961 view()->cursor().dispatch(cmd);
1962 updateFlags = view()->cursor().result().update();
1963 if (!view()->cursor().result().dispatched())
1964 updateFlags = view()->dispatch(cmd);
1969 if (lyx_view_ && lyx_view_->buffer()) {
1970 // BufferView::update() updates the ViewMetricsInfo and
1971 // also initializes the position cache for all insets in
1972 // (at least partially) visible top-level paragraphs.
1973 // We will redraw the screen only if needed.
1974 view()->processUpdateFlags(updateFlags);
1975 lyx_view_->updateStatusBar();
1977 // if we executed a mutating lfun, mark the buffer as dirty
1979 && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
1980 && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
1981 lyx_view_->buffer()->markDirty();
1983 //Do we have a selection?
1984 theSelection().haveSelection(view()->cursor().selection());
1986 if (view()->cursor().inTexted()) {
1987 lyx_view_->updateLayoutChoice();
1991 if (!quitting && lyx_view_) {
1992 lyx_view_->updateToolbars();
1993 // Some messages may already be translated, so we cannot use _()
1994 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
1999 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
2001 const bool verbose = (cmd.origin == FuncRequest::MENU
2002 || cmd.origin == FuncRequest::TOOLBAR
2003 || cmd.origin == FuncRequest::COMMANDBUFFER);
2005 if (cmd.action == LFUN_SELF_INSERT || !verbose) {
2006 LYXERR(Debug::ACTION) << "dispatch msg is " << to_utf8(msg) << endl;
2008 lyx_view_->message(msg);
2012 docstring dispatch_msg = msg;
2013 if (!dispatch_msg.empty())
2014 dispatch_msg += ' ';
2016 docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
2018 bool argsadded = false;
2020 if (!cmd.argument().empty()) {
2021 if (cmd.action != LFUN_UNKNOWN_ACTION) {
2022 comname += ' ' + cmd.argument();
2027 docstring const shortcuts = theTopLevelKeymap().printbindings(cmd);
2029 if (!shortcuts.empty())
2030 comname += ": " + shortcuts;
2031 else if (!argsadded && !cmd.argument().empty())
2032 comname += ' ' + cmd.argument();
2034 if (!comname.empty()) {
2035 comname = rtrim(comname);
2036 dispatch_msg += '(' + rtrim(comname) + ')';
2039 LYXERR(Debug::ACTION) << "verbose dispatch msg "
2040 << to_utf8(dispatch_msg) << endl;
2041 if (!dispatch_msg.empty())
2042 lyx_view_->message(dispatch_msg);
2046 void LyXFunc::menuNew(string const & name, bool fromTemplate)
2048 // FIXME: initpath is not used. What to do?
2049 string initpath = lyxrc.document_path;
2050 string filename(name);
2052 if (lyx_view_->buffer()) {
2053 string const trypath = lyx_view_->buffer()->filePath();
2054 // If directory is writeable, use this as default.
2055 if (isDirWriteable(FileName(trypath)))
2059 static int newfile_number;
2061 if (filename.empty()) {
2062 filename = addName(lyxrc.document_path,
2063 "newfile" + convert<string>(++newfile_number) + ".lyx");
2064 while (theBufferList().exists(filename) ||
2065 fs::is_readable(FileName(filename).toFilesystemEncoding())) {
2067 filename = addName(lyxrc.document_path,
2068 "newfile" + convert<string>(newfile_number) +
2073 // The template stuff
2076 FileDialog fileDlg(_("Select template file"),
2077 LFUN_SELECT_FILE_SYNC,
2078 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2079 make_pair(_("Templates|#T#t"), from_utf8(lyxrc.template_path)));
2081 FileDialog::Result result =
2082 fileDlg.open(from_utf8(lyxrc.template_path),
2083 FileFilterList(_("LyX Documents (*.lyx)")),
2086 if (result.first == FileDialog::Later)
2088 if (result.second.empty())
2090 templname = to_utf8(result.second);
2093 Buffer * const b = newFile(filename, templname, !name.empty());
2095 lyx_view_->setBuffer(b);
2099 void LyXFunc::open(string const & fname)
2101 string initpath = lyxrc.document_path;
2103 if (lyx_view_->buffer()) {
2104 string const trypath = lyx_view_->buffer()->filePath();
2105 // If directory is writeable, use this as default.
2106 if (isDirWriteable(FileName(trypath)))
2112 if (fname.empty()) {
2113 FileDialog fileDlg(_("Select document to open"),
2115 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2116 make_pair(_("Examples|#E#e"), from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2118 FileDialog::Result result =
2119 fileDlg.open(from_utf8(initpath),
2120 FileFilterList(_("LyX Documents (*.lyx)")),
2123 if (result.first == FileDialog::Later)
2126 filename = to_utf8(result.second);
2128 // check selected filename
2129 if (filename.empty()) {
2130 lyx_view_->message(_("Canceled."));
2136 // get absolute path of file and add ".lyx" to the filename if
2138 FileName const fullname = fileSearch(string(), filename, "lyx");
2139 if (!fullname.empty())
2140 filename = fullname.absFilename();
2142 // if the file doesn't exist, let the user create one
2143 if (!fs::exists(fullname.toFilesystemEncoding())) {
2144 // the user specifically chose this name. Believe him.
2145 Buffer * const b = newFile(filename, string(), true);
2147 lyx_view_->setBuffer(b);
2151 docstring const disp_fn = makeDisplayPath(filename);
2152 lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
2155 Buffer * buf = lyx_view_->loadLyXFile(fullname);
2158 lyx_view_->setBuffer(buf);
2159 lyx_view_->showErrorList("Parse");
2160 str2 = bformat(_("Document %1$s opened."), disp_fn);
2162 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2164 lyx_view_->message(str2);
2168 void LyXFunc::doImport(string const & argument)
2171 string filename = split(argument, format, ' ');
2173 LYXERR(Debug::INFO) << "LyXFunc::doImport: " << format
2174 << " file: " << filename << endl;
2176 // need user interaction
2177 if (filename.empty()) {
2178 string initpath = lyxrc.document_path;
2180 if (lyx_view_->buffer()) {
2181 string const trypath = lyx_view_->buffer()->filePath();
2182 // If directory is writeable, use this as default.
2183 if (isDirWriteable(FileName(trypath)))
2187 docstring const text = bformat(_("Select %1$s file to import"),
2188 formats.prettyName(format));
2190 FileDialog fileDlg(text,
2192 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2193 make_pair(_("Examples|#E#e"),
2194 from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2196 docstring filter = formats.prettyName(format);
2199 filter += from_utf8(formats.extension(format));
2202 FileDialog::Result result =
2203 fileDlg.open(from_utf8(initpath),
2204 FileFilterList(filter),
2207 if (result.first == FileDialog::Later)
2210 filename = to_utf8(result.second);
2212 // check selected filename
2213 if (filename.empty())
2214 lyx_view_->message(_("Canceled."));
2217 if (filename.empty())
2220 // get absolute path of file
2221 FileName const fullname(makeAbsPath(filename));
2223 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
2225 // Check if the document already is open
2226 if (use_gui && theBufferList().exists(lyxfile.absFilename())) {
2227 if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) {
2228 lyx_view_->message(_("Canceled."));
2233 // if the file exists already, and we didn't do
2234 // -i lyx thefile.lyx, warn
2235 if (fs::exists(lyxfile.toFilesystemEncoding()) && fullname != lyxfile) {
2236 docstring const file = makeDisplayPath(lyxfile.absFilename(), 30);
2238 docstring text = bformat(_("The document %1$s already exists.\n\n"
2239 "Do you want to overwrite that document?"), file);
2240 int const ret = Alert::prompt(_("Overwrite document?"),
2241 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2244 lyx_view_->message(_("Canceled."));
2249 ErrorList errorList;
2250 Importer::Import(lyx_view_, fullname, format, errorList);
2251 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2255 void LyXFunc::closeBuffer()
2257 // goto bookmark to update bookmark pit.
2258 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2259 gotoBookmark(i+1, false, false);
2261 theBufferList().close(lyx_view_->buffer(), true);
2265 void LyXFunc::reloadBuffer()
2267 FileName filename(lyx_view_->buffer()->fileName());
2268 docstring const disp_fn = makeDisplayPath(filename.absFilename());
2271 Buffer * buf = lyx_view_->loadLyXFile(filename);
2274 lyx_view_->setBuffer(buf);
2275 lyx_view_->showErrorList("Parse");
2276 str = bformat(_("Document %1$s reloaded."), disp_fn);
2278 str = bformat(_("Could not reload document %1$s"), disp_fn);
2280 lyx_view_->message(str);
2283 // Each "lyx_view_" should have it's own message method. lyxview and
2284 // the minibuffer would use the minibuffer, but lyxserver would
2285 // send an ERROR signal to its client. Alejandro 970603
2286 // This function is bit problematic when it comes to NLS, to make the
2287 // lyx servers client be language indepenent we must not translate
2288 // strings sent to this func.
2289 void LyXFunc::setErrorMessage(docstring const & m) const
2291 dispatch_buffer = m;
2296 void LyXFunc::setMessage(docstring const & m) const
2298 dispatch_buffer = m;
2302 docstring const LyXFunc::viewStatusMessage()
2304 // When meta-fake key is pressed, show the key sequence so far + "M-".
2306 return keyseq.print(true) + "M-";
2308 // Else, when a non-complete key sequence is pressed,
2309 // show the available options.
2310 if (keyseq.length() > 0 && !keyseq.deleted())
2311 return keyseq.printOptions(true);
2313 BOOST_ASSERT(lyx_view_);
2314 if (!lyx_view_->buffer())
2315 return _("Welcome to LyX!");
2317 return view()->cursor().currentState();
2321 BufferView * LyXFunc::view() const
2323 BOOST_ASSERT(lyx_view_);
2324 return lyx_view_->view();
2328 bool LyXFunc::wasMetaKey() const
2330 return (meta_fake_bit != NoModifier);
2334 void LyXFunc::updateLayout(TextClassPtr const & oldlayout,
2337 lyx_view_->message(_("Converting document to new document class..."));
2339 StableDocIterator backcur(view()->cursor());
2340 ErrorList & el = buffer->errorList("Class Switch");
2341 cap::switchBetweenClasses(
2342 oldlayout, buffer->params().getTextClassPtr(),
2343 static_cast<InsetText &>(buffer->inset()), el);
2345 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
2347 buffer->errors("Class Switch");
2348 updateLabels(*buffer);
2354 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2356 // Why the switch you might ask. It is a trick to ensure that all
2357 // the elements in the LyXRCTags enum is handled. As you can see
2358 // there are no breaks at all. So it is just a huge fall-through.
2359 // The nice thing is that we will get a warning from the compiler
2360 // if we forget an element.
2361 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2363 case LyXRC::RC_ACCEPT_COMPOUND:
2364 case LyXRC::RC_ALT_LANG:
2365 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
2366 case LyXRC::RC_PLAINTEXT_LINELEN:
2367 case LyXRC::RC_AUTOREGIONDELETE:
2368 case LyXRC::RC_AUTORESET_OPTIONS:
2369 case LyXRC::RC_AUTOSAVE:
2370 case LyXRC::RC_AUTO_NUMBER:
2371 case LyXRC::RC_BACKUPDIR_PATH:
2372 case LyXRC::RC_BIBTEX_COMMAND:
2373 case LyXRC::RC_BINDFILE:
2374 case LyXRC::RC_CHECKLASTFILES:
2375 case LyXRC::RC_USELASTFILEPOS:
2376 case LyXRC::RC_LOADSESSION:
2377 case LyXRC::RC_CHKTEX_COMMAND:
2378 case LyXRC::RC_CONVERTER:
2379 case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
2380 case LyXRC::RC_COPIER:
2381 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2382 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2383 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2384 case LyXRC::RC_DATE_INSERT_FORMAT:
2385 case LyXRC::RC_DEFAULT_LANGUAGE:
2386 case LyXRC::RC_DEFAULT_PAPERSIZE:
2387 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2388 case LyXRC::RC_DISPLAY_GRAPHICS:
2389 case LyXRC::RC_DOCUMENTPATH:
2390 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2391 string const encoded = FileName(
2392 lyxrc_new.document_path).toFilesystemEncoding();
2393 if (fs::exists(encoded) && fs::is_directory(encoded))
2394 support::package().document_dir() = FileName(lyxrc.document_path);
2396 case LyXRC::RC_ESC_CHARS:
2397 case LyXRC::RC_FONT_ENCODING:
2398 case LyXRC::RC_FORMAT:
2399 case LyXRC::RC_INDEX_COMMAND:
2400 case LyXRC::RC_INPUT:
2401 case LyXRC::RC_KBMAP:
2402 case LyXRC::RC_KBMAP_PRIMARY:
2403 case LyXRC::RC_KBMAP_SECONDARY:
2404 case LyXRC::RC_LABEL_INIT_LENGTH:
2405 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2406 case LyXRC::RC_LANGUAGE_AUTO_END:
2407 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2408 case LyXRC::RC_LANGUAGE_COMMAND_END:
2409 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2410 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2411 case LyXRC::RC_LANGUAGE_PACKAGE:
2412 case LyXRC::RC_LANGUAGE_USE_BABEL:
2413 case LyXRC::RC_MAKE_BACKUP:
2414 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2415 case LyXRC::RC_NUMLASTFILES:
2416 case LyXRC::RC_PATH_PREFIX:
2417 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2418 support::prependEnvPath("PATH", lyxrc.path_prefix);
2420 case LyXRC::RC_PERS_DICT:
2421 case LyXRC::RC_PREVIEW:
2422 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2423 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2424 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2425 case LyXRC::RC_PRINTCOPIESFLAG:
2426 case LyXRC::RC_PRINTER:
2427 case LyXRC::RC_PRINTEVENPAGEFLAG:
2428 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2429 case LyXRC::RC_PRINTFILEEXTENSION:
2430 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2431 case LyXRC::RC_PRINTODDPAGEFLAG:
2432 case LyXRC::RC_PRINTPAGERANGEFLAG:
2433 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2434 case LyXRC::RC_PRINTPAPERFLAG:
2435 case LyXRC::RC_PRINTREVERSEFLAG:
2436 case LyXRC::RC_PRINTSPOOL_COMMAND:
2437 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2438 case LyXRC::RC_PRINTTOFILE:
2439 case LyXRC::RC_PRINTTOPRINTER:
2440 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2441 case LyXRC::RC_PRINT_COMMAND:
2442 case LyXRC::RC_RTL_SUPPORT:
2443 case LyXRC::RC_SCREEN_DPI:
2444 case LyXRC::RC_SCREEN_FONT_ROMAN:
2445 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2446 case LyXRC::RC_SCREEN_FONT_SANS:
2447 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2448 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2449 case LyXRC::RC_SCREEN_FONT_SIZES:
2450 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2451 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2452 case LyXRC::RC_SCREEN_GEOMETRY_HEIGHT:
2453 case LyXRC::RC_SCREEN_GEOMETRY_WIDTH:
2454 case LyXRC::RC_SCREEN_GEOMETRY_XYSAVED:
2455 case LyXRC::RC_SCREEN_ZOOM:
2456 case LyXRC::RC_SERVERPIPE:
2457 case LyXRC::RC_SET_COLOR:
2458 case LyXRC::RC_SHOW_BANNER:
2459 case LyXRC::RC_SPELL_COMMAND:
2460 case LyXRC::RC_TEMPDIRPATH:
2461 case LyXRC::RC_TEMPLATEPATH:
2462 case LyXRC::RC_TEX_ALLOWS_SPACES:
2463 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2464 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2465 support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2467 case LyXRC::RC_UIFILE:
2468 case LyXRC::RC_USER_EMAIL:
2469 case LyXRC::RC_USER_NAME:
2470 case LyXRC::RC_USETEMPDIR:
2471 case LyXRC::RC_USE_ALT_LANG:
2472 case LyXRC::RC_USE_CONVERTER_CACHE:
2473 case LyXRC::RC_USE_ESC_CHARS:
2474 case LyXRC::RC_USE_INP_ENC:
2475 case LyXRC::RC_USE_PERS_DICT:
2476 case LyXRC::RC_USE_SPELL_LIB:
2477 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2478 case LyXRC::RC_VIEWER:
2479 case LyXRC::RC_LAST: