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);
318 void restartCursor(LyXView * lv)
320 /* When we move around, or type, it's nice to be able to see
321 * the cursor immediately after the keypress.
323 if (lv && lv->currentWorkArea())
324 lv->currentWorkArea()->startBlinkingCursor();
328 void LyXFunc::processKeySym(KeySymbol const & keysym, KeyModifier state)
330 LYXERR(Debug::KEY) << "KeySym is " << keysym.getSymbolName() << endl;
332 // Do nothing if we have nothing (JMarc)
333 if (!keysym.isOK()) {
334 LYXERR(Debug::KEY) << "Empty kbd action (probably composing)"
336 restartCursor(lyx_view_);
340 if (keysym.isModifier()) {
341 LYXERR(Debug::KEY) << "isModifier true" << endl;
342 restartCursor(lyx_view_);
346 //Encoding const * encoding = view()->cursor().getEncoding();
347 //encoded_last_key = keysym.getISOEncoded(encoding ? encoding->name() : "");
348 // FIXME: encoded_last_key shadows the member variable of the same
349 // name. Is that intended?
350 char_type encoded_last_key = keysym.getUCSEncoded();
352 // Do a one-deep top-level lookup for
353 // cancel and meta-fake keys. RVDK_PATCH_5
354 cancel_meta_seq.reset();
356 FuncRequest func = cancel_meta_seq.addkey(keysym, state);
357 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
358 << " action first set to [" << func.action << ']'
361 // When not cancel or meta-fake, do the normal lookup.
362 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
363 // Mostly, meta_fake_bit = NoModifier. RVDK_PATCH_5.
364 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_PREFIX)) {
365 // remove Caps Lock and Mod2 as a modifiers
366 func = keyseq.addkey(keysym, (state | meta_fake_bit));
367 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
368 << "action now set to ["
369 << func.action << ']' << endl;
372 // Dont remove this unless you know what you are doing.
373 meta_fake_bit = NoModifier;
375 // Can this happen now ?
376 if (func.action == LFUN_NOACTION)
377 func = FuncRequest(LFUN_COMMAND_PREFIX);
379 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
381 << func.action << "]["
382 << to_utf8(keyseq.print(false)) << ']'
385 // already here we know if it any point in going further
386 // why not return already here if action == -1 and
387 // num_bytes == 0? (Lgb)
389 if (keyseq.length() > 1)
390 lyx_view_->message(keyseq.print(true));
393 // Maybe user can only reach the key via holding down shift.
394 // Let's see. But only if shift is the only modifier
395 if (func.action == LFUN_UNKNOWN_ACTION && state == ShiftModifier) {
396 LYXERR(Debug::KEY) << "Trying without shift" << endl;
397 func = keyseq.addkey(keysym, NoModifier);
398 LYXERR(Debug::KEY) << "Action now " << func.action << endl;
401 if (func.action == LFUN_UNKNOWN_ACTION) {
402 // Hmm, we didn't match any of the keysequences. See
403 // if it's normal insertable text not already covered
405 if (keysym.isText() && keyseq.length() == 1) {
406 LYXERR(Debug::KEY) << "isText() is true, inserting." << endl;
407 func = FuncRequest(LFUN_SELF_INSERT,
408 FuncRequest::KEYBOARD);
410 LYXERR(Debug::KEY) << "Unknown, !isText() - giving up" << endl;
411 lyx_view_->message(_("Unknown function."));
412 restartCursor(lyx_view_);
417 if (func.action == LFUN_SELF_INSERT) {
418 if (encoded_last_key != 0) {
419 docstring const arg(1, encoded_last_key);
420 dispatch(FuncRequest(LFUN_SELF_INSERT, arg,
421 FuncRequest::KEYBOARD));
423 << "SelfInsert arg[`" << to_utf8(arg) << "']" << endl;
429 restartCursor(lyx_view_);
433 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
435 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
438 /* In LyX/Mac, when a dialog is open, the menus of the
439 application can still be accessed without giving focus to
440 the main window. In this case, we want to disable the menu
441 entries that are buffer-related.
443 Note that this code is not perfect, as bug 1941 attests:
444 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
446 Buffer * buf = lyx_view_? lyx_view_->buffer() : 0;
447 if (lyx_view_ && cmd.origin == FuncRequest::MENU && !lyx_view_->hasFocus())
450 if (cmd.action == LFUN_NOACTION) {
451 flag.message(from_utf8(N_("Nothing to do")));
456 switch (cmd.action) {
457 case LFUN_UNKNOWN_ACTION:
458 #ifndef HAVE_LIBAIKSAURUS
459 case LFUN_THESAURUS_ENTRY:
469 if (flag.unknown()) {
470 flag.message(from_utf8(N_("Unknown action")));
474 if (!flag.enabled()) {
475 if (flag.message().empty())
476 flag.message(from_utf8(N_("Command disabled")));
480 // Check whether we need a buffer
481 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
483 flag.message(from_utf8(N_("Command not allowed with"
484 "out any document open")));
489 Cursor * cur = view()? &view()->cursor(): 0;
491 // I would really like to avoid having this switch and rather try to
492 // encode this in the function itself.
493 // -- And I'd rather let an inset decide which LFUNs it is willing
494 // to handle (Andre')
496 switch (cmd.action) {
497 case LFUN_BUFFER_TOGGLE_READ_ONLY:
498 flag.setOnOff(buf->isReadonly());
501 case LFUN_BUFFER_SWITCH:
502 // toggle on the current buffer, but do not toggle off
503 // the other ones (is that a good idea?)
504 if (buf && to_utf8(cmd.argument()) == buf->fileName())
508 case LFUN_BUFFER_EXPORT:
509 enable = cmd.argument() == "custom"
510 || Exporter::isExportable(*buf, to_utf8(cmd.argument()));
513 case LFUN_BUFFER_CHKTEX:
514 enable = buf->isLatex() && !lyxrc.chktex_command.empty();
517 case LFUN_BUILD_PROGRAM:
518 enable = Exporter::isExportable(*buf, "program");
521 case LFUN_LAYOUT_TABULAR:
522 enable = cur? cur->innerInsetOfType(Inset::TABULAR_CODE) : false;
526 case LFUN_LAYOUT_PARAGRAPH:
527 enable = cur? !cur->inset().forceDefaultParagraphs(cur->idx()) : false;
530 case LFUN_VC_REGISTER:
531 enable = !buf->lyxvc().inUse();
533 case LFUN_VC_CHECK_IN:
534 enable = buf->lyxvc().inUse() && !buf->isReadonly();
536 case LFUN_VC_CHECK_OUT:
537 enable = buf->lyxvc().inUse() && buf->isReadonly();
540 case LFUN_VC_UNDO_LAST:
541 enable = buf->lyxvc().inUse();
543 case LFUN_BUFFER_RELOAD:
544 enable = !buf->isUnnamed() && fs::exists(buf->fileName())
545 && (!buf->isClean() || buf->isExternallyModified(Buffer::timestamp_method));
548 case LFUN_INSET_SETTINGS: {
553 Inset::Code code = cur->inset().lyxCode();
555 case Inset::TABULAR_CODE:
556 enable = cmd.argument() == "tabular";
558 case Inset::ERT_CODE:
559 enable = cmd.argument() == "ert";
561 case Inset::FLOAT_CODE:
562 enable = cmd.argument() == "float";
564 case Inset::WRAP_CODE:
565 enable = cmd.argument() == "wrap";
567 case Inset::NOTE_CODE:
568 enable = cmd.argument() == "note";
570 case Inset::BRANCH_CODE:
571 enable = cmd.argument() == "branch";
573 case Inset::BOX_CODE:
574 enable = cmd.argument() == "box";
576 case Inset::LISTINGS_CODE:
577 enable = cmd.argument() == "listings";
585 case LFUN_INSET_APPLY: {
590 string const name = cmd.getArg(0);
591 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
593 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
595 if (!inset->getStatus(*cur, fr, fs)) {
596 // Every inset is supposed to handle this
601 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
602 flag |= getStatus(fr);
604 enable = flag.enabled();
608 case LFUN_DIALOG_TOGGLE:
609 flag.setOnOff(lyx_view_->getDialogs().visible(cmd.getArg(0)));
610 // fall through to set "enable"
611 case LFUN_DIALOG_SHOW: {
616 string const name = cmd.getArg(0);
618 enable = name == "aboutlyx"
619 || name == "file" //FIXME: should be removed.
621 || name == "texinfo";
622 else if (name == "print")
623 enable = Exporter::isExportable(*buf, "dvi")
624 && lyxrc.print_command != "none";
625 else if (name == "character")
626 enable = cur->inset().lyxCode() != Inset::ERT_CODE &&
627 cur->inset().lyxCode() != Inset::LISTINGS_CODE;
628 else if (name == "latexlog")
629 enable = isFileReadable(FileName(buf->getLogName().second));
630 else if (name == "spellchecker")
631 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
632 enable = !buf->isReadonly();
636 else if (name == "vclog")
637 enable = buf->lyxvc().inUse();
641 case LFUN_DIALOG_SHOW_NEW_INSET:
646 enable = cur->inset().lyxCode() != Inset::ERT_CODE &&
647 cur->inset().lyxCode() != Inset::LISTINGS_CODE;
648 if (cur->inset().lyxCode() == Inset::CAPTION_CODE) {
650 if (cur->inset().getStatus(*cur, cmd, flag))
655 case LFUN_DIALOG_UPDATE: {
656 string const name = cmd.getArg(0);
658 enable = name == "prefs";
662 case LFUN_CITATION_INSERT: {
663 FuncRequest fr(LFUN_INSET_INSERT, "citation");
664 enable = getStatus(fr).enabled();
668 case LFUN_BUFFER_WRITE: {
669 enable = lyx_view_->buffer()->isUnnamed()
670 || !lyx_view_->buffer()->isClean();
675 case LFUN_BUFFER_WRITE_ALL: {
676 // We enable the command only if there are some modified buffers
677 Buffer * first = theBufferList().first();
678 bool modified = false;
682 // We cannot use a for loop as the buffer list is a cycle.
688 b = theBufferList().next(b);
689 } while (b != first);
697 case LFUN_BOOKMARK_GOTO: {
698 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
699 enable = LyX::ref().session().bookmarks().isValid(num);
703 case LFUN_BOOKMARK_CLEAR:
704 enable = LyX::ref().session().bookmarks().size() > 0;
707 case LFUN_TOOLBAR_TOGGLE: {
708 bool const current = lyx_view_->isToolbarVisible(cmd.getArg(0));
709 flag.setOnOff(current);
712 case LFUN_WINDOW_CLOSE: {
713 enable = (theApp()->gui().viewIds().size() > 1);
717 // this one is difficult to get right. As a half-baked
718 // solution, we consider only the first action of the sequence
719 case LFUN_COMMAND_SEQUENCE: {
720 // argument contains ';'-terminated commands
721 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
722 FuncRequest func(lyxaction.lookupFunc(firstcmd));
723 func.origin = cmd.origin;
724 flag = getStatus(func);
727 case LFUN_BUFFER_NEW:
728 case LFUN_BUFFER_NEW_TEMPLATE:
729 case LFUN_WORD_FIND_FORWARD:
730 case LFUN_WORD_FIND_BACKWARD:
731 case LFUN_COMMAND_PREFIX:
732 case LFUN_COMMAND_EXECUTE:
734 case LFUN_META_PREFIX:
735 case LFUN_BUFFER_CLOSE:
736 case LFUN_BUFFER_WRITE_AS:
737 case LFUN_BUFFER_UPDATE:
738 case LFUN_BUFFER_VIEW:
739 case LFUN_MASTER_BUFFER_UPDATE:
740 case LFUN_MASTER_BUFFER_VIEW:
741 case LFUN_BUFFER_IMPORT:
742 case LFUN_BUFFER_AUTO_SAVE:
743 case LFUN_RECONFIGURE:
747 case LFUN_DROP_LAYOUTS_CHOICE:
749 case LFUN_SERVER_GET_NAME:
750 case LFUN_SERVER_NOTIFY:
751 case LFUN_SERVER_GOTO_FILE_ROW:
752 case LFUN_DIALOG_HIDE:
753 case LFUN_DIALOG_DISCONNECT_INSET:
754 case LFUN_BUFFER_CHILD_OPEN:
755 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
756 case LFUN_KEYMAP_OFF:
757 case LFUN_KEYMAP_PRIMARY:
758 case LFUN_KEYMAP_SECONDARY:
759 case LFUN_KEYMAP_TOGGLE:
761 case LFUN_BUFFER_EXPORT_CUSTOM:
762 case LFUN_BUFFER_PRINT:
763 case LFUN_PREFERENCES_SAVE:
764 case LFUN_SCREEN_FONT_UPDATE:
767 case LFUN_EXTERNAL_EDIT:
768 case LFUN_GRAPHICS_EDIT:
769 case LFUN_ALL_INSETS_TOGGLE:
770 case LFUN_BUFFER_LANGUAGE:
771 case LFUN_TEXTCLASS_APPLY:
772 case LFUN_TEXTCLASS_LOAD:
773 case LFUN_BUFFER_SAVE_AS_DEFAULT:
774 case LFUN_BUFFER_PARAMS_APPLY:
775 case LFUN_LAYOUT_MODULES_CLEAR:
776 case LFUN_LAYOUT_MODULE_ADD:
777 case LFUN_LAYOUT_RELOAD:
778 case LFUN_LYXRC_APPLY:
779 case LFUN_BUFFER_NEXT:
780 case LFUN_BUFFER_PREVIOUS:
781 case LFUN_WINDOW_NEW:
783 // these are handled in our dispatch()
791 if (!getLocalStatus(*cur, cmd, flag))
792 flag = view()->getStatus(cmd);
798 // Can we use a readonly buffer?
799 if (buf && buf->isReadonly()
800 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
801 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
802 flag.message(from_utf8(N_("Document is read-only")));
806 // Are we in a DELETED change-tracking region?
808 && lookupChangeType(*cur, true) == Change::DELETED
809 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
810 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
811 flag.message(from_utf8(N_("This portion of the document is deleted.")));
815 // the default error message if we disable the command
816 if (!flag.enabled() && flag.message().empty())
817 flag.message(from_utf8(N_("Command disabled")));
823 bool LyXFunc::ensureBufferClean(BufferView * bv)
825 Buffer & buf = bv->buffer();
829 docstring const file = makeDisplayPath(buf.fileName(), 30);
830 docstring text = bformat(_("The document %1$s has unsaved "
831 "changes.\n\nDo you want to save "
832 "the document?"), file);
833 int const ret = Alert::prompt(_("Save changed document?"),
834 text, 0, 1, _("&Save"),
838 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
840 return buf.isClean();
846 void showPrintError(string const & name)
848 docstring str = bformat(_("Could not print the document %1$s.\n"
849 "Check that your printer is set up correctly."),
850 makeDisplayPath(name, 50));
851 Alert::error(_("Print document failed"), str);
855 void loadTextClass(string const & name)
857 std::pair<bool, textclass_type> const tc_pair =
858 textclasslist.numberOfClass(name);
860 if (!tc_pair.first) {
861 lyxerr << "Document class \"" << name
862 << "\" does not exist."
867 textclass_type const tc = tc_pair.second;
869 if (!textclasslist[tc].load()) {
870 docstring s = bformat(_("The document class %1$s."
871 "could not be loaded."),
872 from_utf8(textclasslist[tc].name()));
873 Alert::error(_("Could not load class"), s);
878 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
883 void LyXFunc::dispatch(FuncRequest const & cmd)
885 string const argument = to_utf8(cmd.argument());
886 kb_action const action = cmd.action;
888 LYXERR(Debug::ACTION) << endl << "LyXFunc::dispatch: cmd: " << cmd << endl;
889 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
891 // we have not done anything wrong yet.
893 dispatch_buffer.erase();
895 // redraw the screen at the end (first of the two drawing steps).
896 //This is done unless explicitely requested otherwise
897 Update::flags updateFlags = Update::FitCursor;
899 FuncStatus const flag = getStatus(cmd);
900 if (!flag.enabled()) {
901 // We cannot use this function here
902 LYXERR(Debug::ACTION) << "LyXFunc::dispatch: "
903 << lyxaction.getActionName(action)
904 << " [" << action << "] is disabled at this location"
906 setErrorMessage(flag.message());
910 case LFUN_WORD_FIND_FORWARD:
911 case LFUN_WORD_FIND_BACKWARD: {
912 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
913 static docstring last_search;
914 docstring searched_string;
916 if (!cmd.argument().empty()) {
917 last_search = cmd.argument();
918 searched_string = cmd.argument();
920 searched_string = last_search;
923 if (searched_string.empty())
926 bool const fw = action == LFUN_WORD_FIND_FORWARD;
927 docstring const data =
928 find2string(searched_string, true, false, fw);
929 find(view(), FuncRequest(LFUN_WORD_FIND, data));
933 case LFUN_COMMAND_PREFIX:
934 BOOST_ASSERT(lyx_view_);
935 lyx_view_->message(keyseq.printOptions(true));
938 case LFUN_COMMAND_EXECUTE:
939 BOOST_ASSERT(lyx_view_);
940 lyx_view_->showMiniBuffer(true);
944 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
946 meta_fake_bit = NoModifier;
947 if (lyx_view_->buffer())
948 // cancel any selection
949 dispatch(FuncRequest(LFUN_MARK_OFF));
950 setMessage(from_ascii(N_("Cancel")));
953 case LFUN_META_PREFIX:
954 meta_fake_bit = AltModifier;
955 setMessage(keyseq.print(true));
958 case LFUN_BUFFER_TOGGLE_READ_ONLY: {
959 BOOST_ASSERT(lyx_view_ && lyx_view_->view() && lyx_view_->buffer());
960 Buffer * buf = lyx_view_->buffer();
961 if (buf->lyxvc().inUse())
962 buf->lyxvc().toggleReadOnly();
964 buf->setReadonly(!lyx_view_->buffer()->isReadonly());
968 // --- Menus -----------------------------------------------
969 case LFUN_BUFFER_NEW:
970 menuNew(argument, false);
971 updateFlags = Update::None;
974 case LFUN_BUFFER_NEW_TEMPLATE:
975 menuNew(argument, true);
976 updateFlags = Update::None;
979 case LFUN_BUFFER_CLOSE:
981 updateFlags = Update::None;
984 case LFUN_BUFFER_WRITE:
985 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
986 if (!lyx_view_->buffer()->isUnnamed()) {
987 docstring const str = bformat(_("Saving document %1$s..."),
988 makeDisplayPath(lyx_view_->buffer()->fileName()));
989 lyx_view_->message(str);
990 lyx_view_->buffer()->menuWrite();
991 lyx_view_->message(str + _(" done."));
993 lyx_view_->buffer()->writeAs();
995 updateFlags = Update::None;
998 case LFUN_BUFFER_WRITE_AS:
999 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1000 lyx_view_->buffer()->writeAs(argument);
1001 updateFlags = Update::None;
1004 case LFUN_BUFFER_WRITE_ALL: {
1005 Buffer * first = theBufferList().first();
1008 lyx_view_->message(_("Saving all documents..."));
1010 // We cannot use a for loop as the buffer list cycles.
1012 if (!b->isClean()) {
1013 if (!b->isUnnamed()) {
1015 lyxerr[Debug::ACTION] << "Saved " << b->fileName() << endl;
1019 b = theBufferList().next(b);
1020 } while (b != first);
1021 lyx_view_->message(_("All documents saved."));
1024 updateFlags = Update::None;
1028 case LFUN_BUFFER_RELOAD: {
1029 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1030 docstring const file = makeDisplayPath(lyx_view_->buffer()->fileName(), 20);
1031 docstring text = bformat(_("Any changes will be lost. Are you sure "
1032 "you want to revert to the saved version of the document %1$s?"), file);
1033 int const ret = Alert::prompt(_("Revert to saved document?"),
1034 text, 1, 1, _("&Revert"), _("&Cancel"));
1041 case LFUN_BUFFER_UPDATE:
1042 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1043 Exporter::Export(lyx_view_->buffer(), argument, true);
1046 case LFUN_BUFFER_VIEW:
1047 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1048 Exporter::preview(lyx_view_->buffer(), argument);
1051 case LFUN_MASTER_BUFFER_UPDATE:
1052 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->getMasterBuffer());
1053 Exporter::Export(lyx_view_->buffer()->getMasterBuffer(), argument, true);
1056 case LFUN_MASTER_BUFFER_VIEW:
1057 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->getMasterBuffer());
1058 Exporter::preview(lyx_view_->buffer()->getMasterBuffer(), argument);
1061 case LFUN_BUILD_PROGRAM:
1062 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1063 Exporter::Export(lyx_view_->buffer(), "program", true);
1066 case LFUN_BUFFER_CHKTEX:
1067 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1068 lyx_view_->buffer()->runChktex();
1071 case LFUN_BUFFER_EXPORT:
1072 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1073 if (argument == "custom")
1074 lyx_view_->getDialogs().show("sendto");
1076 Exporter::Export(lyx_view_->buffer(), argument, false);
1080 case LFUN_BUFFER_EXPORT_CUSTOM: {
1081 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1083 string command = split(argument, format_name, ' ');
1084 Format const * format = formats.getFormat(format_name);
1086 lyxerr << "Format \"" << format_name
1087 << "\" not recognized!"
1092 Buffer * buffer = lyx_view_->buffer();
1094 // The name of the file created by the conversion process
1097 // Output to filename
1098 if (format->name() == "lyx") {
1099 string const latexname =
1100 buffer->getLatexName(false);
1101 filename = changeExtension(latexname,
1102 format->extension());
1103 filename = addName(buffer->temppath(), filename);
1105 if (!buffer->writeFile(FileName(filename)))
1109 Exporter::Export(buffer, format_name, true, filename);
1112 // Substitute $$FName for filename
1113 if (!contains(command, "$$FName"))
1114 command = "( " + command + " ) < $$FName";
1115 command = subst(command, "$$FName", filename);
1117 // Execute the command in the background
1119 call.startscript(Systemcall::DontWait, command);
1123 case LFUN_BUFFER_PRINT: {
1124 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1125 // FIXME: cmd.getArg() might fail if one of the arguments
1126 // contains double quotes
1127 string target = cmd.getArg(0);
1128 string target_name = cmd.getArg(1);
1129 string command = cmd.getArg(2);
1132 || target_name.empty()
1133 || command.empty()) {
1134 lyxerr << "Unable to parse \""
1135 << argument << '"' << endl;
1138 if (target != "printer" && target != "file") {
1139 lyxerr << "Unrecognized target \""
1140 << target << '"' << endl;
1144 Buffer * buffer = lyx_view_->buffer();
1146 if (!Exporter::Export(buffer, "dvi", true)) {
1147 showPrintError(buffer->fileName());
1151 // Push directory path.
1152 string const path = buffer->temppath();
1153 // Prevent the compiler from optimizing away p
1155 support::Path p(pp);
1157 // there are three cases here:
1158 // 1. we print to a file
1159 // 2. we print directly to a printer
1160 // 3. we print using a spool command (print to file first)
1163 string const dviname =
1164 changeExtension(buffer->getLatexName(true),
1167 if (target == "printer") {
1168 if (!lyxrc.print_spool_command.empty()) {
1169 // case 3: print using a spool
1170 string const psname =
1171 changeExtension(dviname,".ps");
1172 command += ' ' + lyxrc.print_to_file
1175 + quoteName(dviname);
1178 lyxrc.print_spool_command + ' ';
1179 if (target_name != "default") {
1180 command2 += lyxrc.print_spool_printerprefix
1184 command2 += quoteName(psname);
1186 // If successful, then spool command
1187 res = one.startscript(
1192 res = one.startscript(
1193 Systemcall::DontWait,
1196 // case 2: print directly to a printer
1197 if (target_name != "default")
1198 command += ' ' + lyxrc.print_to_printer + target_name + ' ';
1199 res = one.startscript(
1200 Systemcall::DontWait,
1201 command + quoteName(dviname));
1205 // case 1: print to a file
1206 FileName const filename(makeAbsPath(target_name,
1207 lyx_view_->buffer()->filePath()));
1208 FileName const dvifile(makeAbsPath(dviname, path));
1209 if (fs::exists(filename.toFilesystemEncoding())) {
1210 docstring text = bformat(
1211 _("The file %1$s already exists.\n\n"
1212 "Do you want to overwrite that file?"),
1213 makeDisplayPath(filename.absFilename()));
1214 if (Alert::prompt(_("Overwrite file?"),
1215 text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
1218 command += ' ' + lyxrc.print_to_file
1219 + quoteName(filename.toFilesystemEncoding())
1221 + quoteName(dvifile.toFilesystemEncoding());
1222 res = one.startscript(Systemcall::DontWait,
1227 showPrintError(buffer->fileName());
1231 case LFUN_BUFFER_IMPORT:
1236 // quitting is triggered by the gui code
1237 // (leaving the event loop).
1238 lyx_view_->message(from_utf8(N_("Exiting.")));
1239 if (theBufferList().quitWriteAll())
1240 theApp()->gui().closeAllViews();
1243 case LFUN_BUFFER_AUTO_SAVE:
1244 lyx_view_->buffer()->autoSave();
1247 case LFUN_RECONFIGURE:
1248 BOOST_ASSERT(lyx_view_);
1249 // argument is any additional parameter to the configure.py command
1250 reconfigure(*lyx_view_, argument);
1253 case LFUN_HELP_OPEN: {
1254 BOOST_ASSERT(lyx_view_);
1255 string const arg = argument;
1257 setErrorMessage(from_ascii(N_("Missing argument")));
1260 FileName const fname = i18nLibFileSearch("doc", arg, "lyx");
1261 if (fname.empty()) {
1262 lyxerr << "LyX: unable to find documentation file `"
1263 << arg << "'. Bad installation?" << endl;
1266 lyx_view_->message(bformat(_("Opening help file %1$s..."),
1267 makeDisplayPath(fname.absFilename())));
1268 Buffer * buf = lyx_view_->loadLyXFile(fname, false);
1271 lyx_view_->setBuffer(buf);
1272 lyx_view_->showErrorList("Parse");
1274 updateFlags = Update::None;
1278 // --- version control -------------------------------
1279 case LFUN_VC_REGISTER:
1280 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1281 if (!ensureBufferClean(view()))
1283 if (!lyx_view_->buffer()->lyxvc().inUse()) {
1284 lyx_view_->buffer()->lyxvc().registrer();
1287 updateFlags = Update::Force;
1290 case LFUN_VC_CHECK_IN:
1291 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1292 if (!ensureBufferClean(view()))
1294 if (lyx_view_->buffer()->lyxvc().inUse()
1295 && !lyx_view_->buffer()->isReadonly()) {
1296 lyx_view_->buffer()->lyxvc().checkIn();
1301 case LFUN_VC_CHECK_OUT:
1302 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1303 if (!ensureBufferClean(view()))
1305 if (lyx_view_->buffer()->lyxvc().inUse()
1306 && lyx_view_->buffer()->isReadonly()) {
1307 lyx_view_->buffer()->lyxvc().checkOut();
1312 case LFUN_VC_REVERT:
1313 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1314 lyx_view_->buffer()->lyxvc().revert();
1318 case LFUN_VC_UNDO_LAST:
1319 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1320 lyx_view_->buffer()->lyxvc().undoLast();
1324 // --- buffers ----------------------------------------
1325 case LFUN_BUFFER_SWITCH:
1326 BOOST_ASSERT(lyx_view_);
1327 lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1328 updateFlags = Update::None;
1331 case LFUN_BUFFER_NEXT:
1332 BOOST_ASSERT(lyx_view_);
1333 lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer()));
1334 updateFlags = Update::None;
1337 case LFUN_BUFFER_PREVIOUS:
1338 BOOST_ASSERT(lyx_view_);
1339 lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer()));
1340 updateFlags = Update::None;
1343 case LFUN_FILE_NEW: {
1344 BOOST_ASSERT(lyx_view_);
1346 string tmpname = split(argument, name, ':'); // Split filename
1347 Buffer * const b = newFile(name, tmpname);
1349 lyx_view_->setBuffer(b);
1350 updateFlags = Update::None;
1354 case LFUN_FILE_OPEN:
1355 BOOST_ASSERT(lyx_view_);
1357 updateFlags = Update::None;
1360 case LFUN_DROP_LAYOUTS_CHOICE:
1361 BOOST_ASSERT(lyx_view_);
1362 lyx_view_->openLayoutList();
1365 case LFUN_MENU_OPEN:
1366 BOOST_ASSERT(lyx_view_);
1367 lyx_view_->openMenu(from_utf8(argument));
1370 // --- lyxserver commands ----------------------------
1371 case LFUN_SERVER_GET_NAME:
1372 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1373 setMessage(from_utf8(lyx_view_->buffer()->fileName()));
1374 LYXERR(Debug::INFO) << "FNAME["
1375 << lyx_view_->buffer()->fileName()
1379 case LFUN_SERVER_NOTIFY:
1380 dispatch_buffer = keyseq.print(false);
1381 theServer().notifyClient(to_utf8(dispatch_buffer));
1384 case LFUN_SERVER_GOTO_FILE_ROW: {
1385 BOOST_ASSERT(lyx_view_);
1388 istringstream is(argument);
1389 is >> file_name >> row;
1391 bool loaded = false;
1392 if (prefixIs(file_name, package().temp_dir().absFilename()))
1393 // Needed by inverse dvi search. If it is a file
1394 // in tmpdir, call the apropriated function
1395 buf = theBufferList().getBufferFromTmp(file_name);
1397 // Must replace extension of the file to be .lyx
1398 // and get full path
1399 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1400 // Either change buffer or load the file
1401 if (theBufferList().exists(s.absFilename()))
1402 buf = theBufferList().getBuffer(s.absFilename());
1404 buf = lyx_view_->loadLyXFile(s);
1410 updateFlags = Update::None;
1415 lyx_view_->setBuffer(buf);
1416 view()->setCursorFromRow(row);
1418 lyx_view_->showErrorList("Parse");
1419 updateFlags = Update::FitCursor;
1423 case LFUN_DIALOG_SHOW: {
1424 BOOST_ASSERT(lyx_view_);
1425 string const name = cmd.getArg(0);
1426 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1428 if (name == "character") {
1429 data = freefont2string();
1431 lyx_view_->getDialogs().show("character", data);
1432 } else if (name == "latexlog") {
1433 pair<Buffer::LogType, string> const logfile =
1434 lyx_view_->buffer()->getLogName();
1435 switch (logfile.first) {
1436 case Buffer::latexlog:
1439 case Buffer::buildlog:
1443 data += Lexer::quoteString(logfile.second);
1444 lyx_view_->getDialogs().show("log", data);
1445 } else if (name == "vclog") {
1446 string const data = "vc " +
1447 Lexer::quoteString(lyx_view_->buffer()->lyxvc().getLogFile());
1448 lyx_view_->getDialogs().show("log", data);
1450 lyx_view_->getDialogs().show(name, data);
1454 case LFUN_DIALOG_SHOW_NEW_INSET: {
1455 BOOST_ASSERT(lyx_view_);
1456 string const name = cmd.getArg(0);
1457 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1458 if (name == "bibitem" ||
1462 name == "nomenclature" ||
1466 InsetCommandParams p(name);
1467 data = InsetCommandMailer::params2string(name, p);
1468 } else if (name == "include") {
1469 // data is the include type: one of "include",
1470 // "input", "verbatiminput" or "verbatiminput*"
1472 // default type is requested
1474 InsetCommandParams p(data);
1475 data = InsetIncludeMailer::params2string(p);
1476 } else if (name == "box") {
1477 // \c data == "Boxed" || "Frameless" etc
1478 InsetBoxParams p(data);
1479 data = InsetBoxMailer::params2string(p);
1480 } else if (name == "branch") {
1481 InsetBranchParams p;
1482 data = InsetBranchMailer::params2string(p);
1483 } else if (name == "citation") {
1484 InsetCommandParams p("citation");
1485 data = InsetCommandMailer::params2string(name, p);
1486 } else if (name == "ert") {
1487 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1488 } else if (name == "external") {
1489 InsetExternalParams p;
1490 Buffer const & buffer = *lyx_view_->buffer();
1491 data = InsetExternalMailer::params2string(p, buffer);
1492 } else if (name == "float") {
1494 data = InsetFloatMailer::params2string(p);
1495 } else if (name == "listings") {
1496 InsetListingsParams p;
1497 data = InsetListingsMailer::params2string(p);
1498 } else if (name == "graphics") {
1499 InsetGraphicsParams p;
1500 Buffer const & buffer = *lyx_view_->buffer();
1501 data = InsetGraphicsMailer::params2string(p, buffer);
1502 } else if (name == "note") {
1504 data = InsetNoteMailer::params2string(p);
1505 } else if (name == "vspace") {
1507 data = InsetVSpaceMailer::params2string(space);
1508 } else if (name == "wrap") {
1510 data = InsetWrapMailer::params2string(p);
1512 lyx_view_->getDialogs().show(name, data, 0);
1516 case LFUN_DIALOG_UPDATE: {
1517 BOOST_ASSERT(lyx_view_);
1518 string const & name = argument;
1519 // Can only update a dialog connected to an existing inset
1520 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1522 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1523 inset->dispatch(view()->cursor(), fr);
1524 } else if (name == "paragraph") {
1525 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1526 } else if (name == "prefs") {
1527 lyx_view_->getDialogs().update(name, string());
1532 case LFUN_DIALOG_HIDE:
1533 LyX::cref().hideDialogs(argument, 0);
1536 case LFUN_DIALOG_TOGGLE: {
1537 BOOST_ASSERT(lyx_view_);
1538 if (lyx_view_->getDialogs().visible(cmd.getArg(0)))
1539 dispatch(FuncRequest(LFUN_DIALOG_HIDE, argument));
1541 dispatch(FuncRequest(LFUN_DIALOG_SHOW, argument));
1545 case LFUN_DIALOG_DISCONNECT_INSET:
1546 BOOST_ASSERT(lyx_view_);
1547 lyx_view_->getDialogs().disconnect(argument);
1551 case LFUN_CITATION_INSERT: {
1552 BOOST_ASSERT(lyx_view_);
1553 if (!argument.empty()) {
1554 // we can have one optional argument, delimited by '|'
1555 // citation-insert <key>|<text_before>
1556 // this should be enhanced to also support text_after
1557 // and citation style
1558 string arg = argument;
1560 if (contains(argument, "|")) {
1561 arg = token(argument, '|', 0);
1562 opt1 = token(argument, '|', 1);
1564 InsetCommandParams icp("citation");
1565 icp["key"] = from_utf8(arg);
1567 icp["before"] = from_utf8(opt1);
1568 string icstr = InsetCommandMailer::params2string("citation", icp);
1569 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1572 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1576 case LFUN_BUFFER_CHILD_OPEN: {
1577 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1578 Buffer * parent = lyx_view_->buffer();
1579 FileName filename = makeAbsPath(argument, parent->filePath());
1580 view()->saveBookmark(false);
1582 bool parsed = false;
1583 if (theBufferList().exists(filename.absFilename())) {
1584 child = theBufferList().getBuffer(filename.absFilename());
1586 setMessage(bformat(_("Opening child document %1$s..."),
1587 makeDisplayPath(filename.absFilename())));
1588 child = lyx_view_->loadLyXFile(filename, true);
1592 // Set the parent name of the child document.
1593 // This makes insertion of citations and references in the child work,
1594 // when the target is in the parent or another child document.
1595 child->setParentName(parent->fileName());
1596 updateLabels(*child->getMasterBuffer());
1597 lyx_view_->setBuffer(child);
1599 lyx_view_->showErrorList("Parse");
1602 // If a screen update is required (in case where auto_open is false),
1603 // setBuffer() would have taken care of it already. Otherwise we shall
1604 // reset the update flag because it can cause a circular problem.
1606 updateFlags = Update::None;
1610 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1611 BOOST_ASSERT(lyx_view_);
1612 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1615 case LFUN_KEYMAP_OFF:
1616 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1617 lyx_view_->view()->getIntl().keyMapOn(false);
1620 case LFUN_KEYMAP_PRIMARY:
1621 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1622 lyx_view_->view()->getIntl().keyMapPrim();
1625 case LFUN_KEYMAP_SECONDARY:
1626 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1627 lyx_view_->view()->getIntl().keyMapSec();
1630 case LFUN_KEYMAP_TOGGLE:
1631 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1632 lyx_view_->view()->getIntl().toggleKeyMap();
1638 string rest = split(argument, countstr, ' ');
1639 istringstream is(countstr);
1642 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1643 for (int i = 0; i < count; ++i)
1644 dispatch(lyxaction.lookupFunc(rest));
1648 case LFUN_COMMAND_SEQUENCE: {
1649 // argument contains ';'-terminated commands
1650 string arg = argument;
1651 while (!arg.empty()) {
1653 arg = split(arg, first, ';');
1654 FuncRequest func(lyxaction.lookupFunc(first));
1655 func.origin = cmd.origin;
1661 case LFUN_PREFERENCES_SAVE: {
1662 lyxrc.write(makeAbsPath("preferences",
1663 package().user_support().absFilename()),
1668 case LFUN_SCREEN_FONT_UPDATE:
1669 BOOST_ASSERT(lyx_view_);
1670 // handle the screen font changes.
1671 theFontLoader().update();
1672 /// FIXME: only the current view will be updated. the Gui
1673 /// class is able to furnish the list of views.
1674 updateFlags = Update::Force;
1677 case LFUN_SET_COLOR: {
1679 string const x11_name = split(argument, lyx_name, ' ');
1680 if (lyx_name.empty() || x11_name.empty()) {
1681 setErrorMessage(from_ascii(N_(
1682 "Syntax: set-color <lyx_name>"
1687 bool const graphicsbg_changed =
1688 (lyx_name == lcolor.getLyXName(Color::graphicsbg) &&
1689 x11_name != lcolor.getX11Name(Color::graphicsbg));
1691 if (!lcolor.setColor(lyx_name, x11_name)) {
1693 bformat(_("Set-color \"%1$s\" failed "
1694 "- color is undefined or "
1695 "may not be redefined"),
1696 from_utf8(lyx_name)));
1700 theApp()->updateColor(lcolor.getFromLyXName(lyx_name));
1702 if (graphicsbg_changed) {
1703 // FIXME: The graphics cache no longer has a changeDisplay method.
1705 graphics::GCache::get().changeDisplay(true);
1712 BOOST_ASSERT(lyx_view_);
1713 lyx_view_->message(from_utf8(argument));
1716 case LFUN_EXTERNAL_EDIT: {
1717 BOOST_ASSERT(lyx_view_);
1718 FuncRequest fr(action, argument);
1719 InsetExternal().dispatch(view()->cursor(), fr);
1723 case LFUN_GRAPHICS_EDIT: {
1724 FuncRequest fr(action, argument);
1725 InsetGraphics().dispatch(view()->cursor(), fr);
1729 case LFUN_INSET_APPLY: {
1730 BOOST_ASSERT(lyx_view_);
1731 string const name = cmd.getArg(0);
1732 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1734 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1735 inset->dispatch(view()->cursor(), fr);
1737 FuncRequest fr(LFUN_INSET_INSERT, argument);
1740 // ideally, the update flag should be set by the insets,
1741 // but this is not possible currently
1742 updateFlags = Update::Force | Update::FitCursor;
1746 case LFUN_ALL_INSETS_TOGGLE: {
1747 BOOST_ASSERT(lyx_view_);
1749 string const name = split(argument, action, ' ');
1750 Inset::Code const inset_code =
1751 Inset::translate(name);
1753 Cursor & cur = view()->cursor();
1754 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1756 Inset & inset = lyx_view_->buffer()->inset();
1757 InsetIterator it = inset_iterator_begin(inset);
1758 InsetIterator const end = inset_iterator_end(inset);
1759 for (; it != end; ++it) {
1760 if (!it->asInsetMath()
1761 && (inset_code == Inset::NO_CODE
1762 || inset_code == it->lyxCode())) {
1763 Cursor tmpcur = cur;
1764 tmpcur.pushLeft(*it);
1765 it->dispatch(tmpcur, fr);
1768 updateFlags = Update::Force | Update::FitCursor;
1772 case LFUN_BUFFER_LANGUAGE: {
1773 BOOST_ASSERT(lyx_view_);
1774 Buffer & buffer = *lyx_view_->buffer();
1775 Language const * oldL = buffer.params().language;
1776 Language const * newL = languages.getLanguage(argument);
1777 if (!newL || oldL == newL)
1780 if (oldL->rightToLeft() == newL->rightToLeft()
1781 && !buffer.isMultiLingual())
1782 buffer.changeLanguage(oldL, newL);
1786 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1787 string const fname =
1788 addName(addPath(package().user_support().absFilename(), "templates/"),
1790 Buffer defaults(fname);
1792 istringstream ss(argument);
1795 int const unknown_tokens = defaults.readHeader(lex);
1797 if (unknown_tokens != 0) {
1798 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1799 << unknown_tokens << " unknown token"
1800 << (unknown_tokens == 1 ? "" : "s")
1804 if (defaults.writeFile(FileName(defaults.fileName())))
1805 setMessage(bformat(_("Document defaults saved in %1$s"),
1806 makeDisplayPath(fname)));
1808 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1812 case LFUN_BUFFER_PARAMS_APPLY: {
1813 BOOST_ASSERT(lyx_view_);
1814 biblio::CiteEngine const oldEngine =
1815 lyx_view_->buffer()->params().getEngine();
1817 Buffer * buffer = lyx_view_->buffer();
1819 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1820 recordUndoFullDocument(view());
1822 istringstream ss(argument);
1825 int const unknown_tokens = buffer->readHeader(lex);
1827 if (unknown_tokens != 0) {
1828 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1829 << unknown_tokens << " unknown token"
1830 << (unknown_tokens == 1 ? "" : "s")
1834 updateLayout(oldClass, buffer);
1836 biblio::CiteEngine const newEngine =
1837 lyx_view_->buffer()->params().getEngine();
1839 if (oldEngine != newEngine) {
1840 Cursor & cur = view()->cursor();
1841 FuncRequest fr(LFUN_INSET_REFRESH);
1843 Inset & inset = lyx_view_->buffer()->inset();
1844 InsetIterator it = inset_iterator_begin(inset);
1845 InsetIterator const end = inset_iterator_end(inset);
1846 for (; it != end; ++it)
1847 if (it->lyxCode() == Inset::CITE_CODE)
1848 it->dispatch(cur, fr);
1851 updateFlags = Update::Force | Update::FitCursor;
1855 case LFUN_LAYOUT_MODULES_CLEAR: {
1856 BOOST_ASSERT(lyx_view_);
1857 Buffer * buffer = lyx_view_->buffer();
1858 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1859 recordUndoFullDocument(view());
1860 buffer->params().clearLayoutModules();
1861 updateLayout(oldClass, buffer);
1862 updateFlags = Update::Force | Update::FitCursor;
1866 case LFUN_LAYOUT_MODULE_ADD: {
1867 BOOST_ASSERT(lyx_view_);
1868 Buffer * buffer = lyx_view_->buffer();
1869 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1870 recordUndoFullDocument(view());
1871 buffer->params().addLayoutModule(argument);
1872 updateLayout(oldClass, buffer);
1873 updateFlags = Update::Force | Update::FitCursor;
1877 case LFUN_TEXTCLASS_APPLY: {
1878 BOOST_ASSERT(lyx_view_);
1879 Buffer * buffer = lyx_view_->buffer();
1881 loadTextClass(argument);
1883 std::pair<bool, textclass_type> const tc_pair =
1884 textclasslist.numberOfClass(argument);
1889 textclass_type const old_class = buffer->params().getBaseClass();
1890 textclass_type const new_class = tc_pair.second;
1892 if (old_class == new_class)
1896 //Save the old, possibly modular, layout for use in conversion.
1897 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1898 recordUndoFullDocument(view());
1899 buffer->params().setBaseClass(new_class);
1900 updateLayout(oldClass, buffer);
1901 updateFlags = Update::Force | Update::FitCursor;
1905 case LFUN_LAYOUT_RELOAD: {
1906 BOOST_ASSERT(lyx_view_);
1907 Buffer * buffer = lyx_view_->buffer();
1908 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1909 textclass_type const tc = buffer->params().getBaseClass();
1910 textclasslist.reset(tc);
1911 buffer->params().setBaseClass(tc);
1912 updateLayout(oldClass, buffer);
1913 updateFlags = Update::Force | Update::FitCursor;
1917 case LFUN_TEXTCLASS_LOAD:
1918 loadTextClass(argument);
1921 case LFUN_LYXRC_APPLY: {
1922 LyXRC const lyxrc_orig = lyxrc;
1924 istringstream ss(argument);
1925 bool const success = lyxrc.read(ss) == 0;
1928 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1929 << "Unable to read lyxrc data"
1934 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1936 /// We force the redraw in any case because there might be
1937 /// some screen font changes.
1938 /// FIXME: only the current view will be updated. the Gui
1939 /// class is able to furnish the list of views.
1940 updateFlags = Update::Force;
1944 case LFUN_WINDOW_NEW:
1945 LyX::ref().newLyXView();
1948 case LFUN_WINDOW_CLOSE:
1949 BOOST_ASSERT(lyx_view_);
1950 BOOST_ASSERT(theApp());
1951 // update bookmark pit of the current buffer before window close
1952 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1953 gotoBookmark(i+1, false, false);
1954 // ask the user for saving changes or cancel quit
1955 if (!theBufferList().quitWriteAll())
1960 case LFUN_BOOKMARK_GOTO:
1961 // go to bookmark, open unopened file and switch to buffer if necessary
1962 gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
1965 case LFUN_BOOKMARK_CLEAR:
1966 LyX::ref().session().bookmarks().clear();
1969 case LFUN_TOOLBAR_TOGGLE: {
1970 BOOST_ASSERT(lyx_view_);
1971 string const name = cmd.getArg(0);
1972 bool const allowauto = cmd.getArg(1) == "allowauto";
1973 lyx_view_->toggleToolbarState(name, allowauto);
1974 ToolbarInfo * tbi = lyx_view_->getToolbarInfo(name);
1976 setMessage(bformat(_("Unknown toolbar \"%1$s\""),
1981 if (tbi->flags & ToolbarInfo::ON)
1983 else if (tbi->flags & ToolbarInfo::OFF)
1985 else if (tbi->flags & ToolbarInfo::AUTO)
1988 setMessage(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
1989 _(tbi->gui_name), state));
1994 BOOST_ASSERT(lyx_view_);
1995 view()->cursor().dispatch(cmd);
1996 updateFlags = view()->cursor().result().update();
1997 if (!view()->cursor().result().dispatched())
1998 updateFlags = view()->dispatch(cmd);
2003 if (lyx_view_ && lyx_view_->buffer()) {
2004 // BufferView::update() updates the ViewMetricsInfo and
2005 // also initializes the position cache for all insets in
2006 // (at least partially) visible top-level paragraphs.
2007 // We will redraw the screen only if needed.
2008 view()->processUpdateFlags(updateFlags);
2009 lyx_view_->updateStatusBar();
2011 // if we executed a mutating lfun, mark the buffer as dirty
2013 && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
2014 && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
2015 lyx_view_->buffer()->markDirty();
2017 //Do we have a selection?
2018 theSelection().haveSelection(view()->cursor().selection());
2020 if (view()->cursor().inTexted()) {
2021 lyx_view_->updateLayoutChoice();
2025 if (!quitting && lyx_view_) {
2026 lyx_view_->updateToolbars();
2027 // Some messages may already be translated, so we cannot use _()
2028 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
2033 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
2035 const bool verbose = (cmd.origin == FuncRequest::MENU
2036 || cmd.origin == FuncRequest::TOOLBAR
2037 || cmd.origin == FuncRequest::COMMANDBUFFER);
2039 if (cmd.action == LFUN_SELF_INSERT || !verbose) {
2040 LYXERR(Debug::ACTION) << "dispatch msg is " << to_utf8(msg) << endl;
2042 lyx_view_->message(msg);
2046 docstring dispatch_msg = msg;
2047 if (!dispatch_msg.empty())
2048 dispatch_msg += ' ';
2050 docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
2052 bool argsadded = false;
2054 if (!cmd.argument().empty()) {
2055 if (cmd.action != LFUN_UNKNOWN_ACTION) {
2056 comname += ' ' + cmd.argument();
2061 docstring const shortcuts = theTopLevelKeymap().printbindings(cmd);
2063 if (!shortcuts.empty())
2064 comname += ": " + shortcuts;
2065 else if (!argsadded && !cmd.argument().empty())
2066 comname += ' ' + cmd.argument();
2068 if (!comname.empty()) {
2069 comname = rtrim(comname);
2070 dispatch_msg += '(' + rtrim(comname) + ')';
2073 LYXERR(Debug::ACTION) << "verbose dispatch msg "
2074 << to_utf8(dispatch_msg) << endl;
2075 if (!dispatch_msg.empty())
2076 lyx_view_->message(dispatch_msg);
2080 void LyXFunc::menuNew(string const & name, bool fromTemplate)
2082 // FIXME: initpath is not used. What to do?
2083 string initpath = lyxrc.document_path;
2084 string filename(name);
2086 if (lyx_view_->buffer()) {
2087 string const trypath = lyx_view_->buffer()->filePath();
2088 // If directory is writeable, use this as default.
2089 if (isDirWriteable(FileName(trypath)))
2093 static int newfile_number;
2095 if (filename.empty()) {
2096 filename = addName(lyxrc.document_path,
2097 "newfile" + convert<string>(++newfile_number) + ".lyx");
2098 while (theBufferList().exists(filename) ||
2099 fs::is_readable(FileName(filename).toFilesystemEncoding())) {
2101 filename = addName(lyxrc.document_path,
2102 "newfile" + convert<string>(newfile_number) +
2107 // The template stuff
2110 FileDialog fileDlg(_("Select template file"),
2111 LFUN_SELECT_FILE_SYNC,
2112 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2113 make_pair(_("Templates|#T#t"), from_utf8(lyxrc.template_path)));
2115 FileDialog::Result result =
2116 fileDlg.open(from_utf8(lyxrc.template_path),
2117 FileFilterList(_("LyX Documents (*.lyx)")),
2120 if (result.first == FileDialog::Later)
2122 if (result.second.empty())
2124 templname = to_utf8(result.second);
2127 Buffer * const b = newFile(filename, templname, !name.empty());
2129 lyx_view_->setBuffer(b);
2133 void LyXFunc::open(string const & fname)
2135 string initpath = lyxrc.document_path;
2137 if (lyx_view_->buffer()) {
2138 string const trypath = lyx_view_->buffer()->filePath();
2139 // If directory is writeable, use this as default.
2140 if (isDirWriteable(FileName(trypath)))
2146 if (fname.empty()) {
2147 FileDialog fileDlg(_("Select document to open"),
2149 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2150 make_pair(_("Examples|#E#e"), from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2152 FileDialog::Result result =
2153 fileDlg.open(from_utf8(initpath),
2154 FileFilterList(_("LyX Documents (*.lyx)")),
2157 if (result.first == FileDialog::Later)
2160 filename = to_utf8(result.second);
2162 // check selected filename
2163 if (filename.empty()) {
2164 lyx_view_->message(_("Canceled."));
2170 // get absolute path of file and add ".lyx" to the filename if
2172 FileName const fullname = fileSearch(string(), filename, "lyx");
2173 if (!fullname.empty())
2174 filename = fullname.absFilename();
2176 // if the file doesn't exist, let the user create one
2177 if (!fs::exists(fullname.toFilesystemEncoding())) {
2178 // the user specifically chose this name. Believe him.
2179 Buffer * const b = newFile(filename, string(), true);
2181 lyx_view_->setBuffer(b);
2185 docstring const disp_fn = makeDisplayPath(filename);
2186 lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
2189 Buffer * buf = lyx_view_->loadLyXFile(fullname);
2192 lyx_view_->setBuffer(buf);
2193 lyx_view_->showErrorList("Parse");
2194 str2 = bformat(_("Document %1$s opened."), disp_fn);
2196 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2198 lyx_view_->message(str2);
2202 void LyXFunc::doImport(string const & argument)
2205 string filename = split(argument, format, ' ');
2207 LYXERR(Debug::INFO) << "LyXFunc::doImport: " << format
2208 << " file: " << filename << endl;
2210 // need user interaction
2211 if (filename.empty()) {
2212 string initpath = lyxrc.document_path;
2214 if (lyx_view_->buffer()) {
2215 string const trypath = lyx_view_->buffer()->filePath();
2216 // If directory is writeable, use this as default.
2217 if (isDirWriteable(FileName(trypath)))
2221 docstring const text = bformat(_("Select %1$s file to import"),
2222 formats.prettyName(format));
2224 FileDialog fileDlg(text,
2226 make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2227 make_pair(_("Examples|#E#e"),
2228 from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2230 docstring filter = formats.prettyName(format);
2233 filter += from_utf8(formats.extension(format));
2236 FileDialog::Result result =
2237 fileDlg.open(from_utf8(initpath),
2238 FileFilterList(filter),
2241 if (result.first == FileDialog::Later)
2244 filename = to_utf8(result.second);
2246 // check selected filename
2247 if (filename.empty())
2248 lyx_view_->message(_("Canceled."));
2251 if (filename.empty())
2254 // get absolute path of file
2255 FileName const fullname(makeAbsPath(filename));
2257 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
2259 // Check if the document already is open
2260 if (use_gui && theBufferList().exists(lyxfile.absFilename())) {
2261 if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) {
2262 lyx_view_->message(_("Canceled."));
2267 // if the file exists already, and we didn't do
2268 // -i lyx thefile.lyx, warn
2269 if (fs::exists(lyxfile.toFilesystemEncoding()) && fullname != lyxfile) {
2270 docstring const file = makeDisplayPath(lyxfile.absFilename(), 30);
2272 docstring text = bformat(_("The document %1$s already exists.\n\n"
2273 "Do you want to overwrite that document?"), file);
2274 int const ret = Alert::prompt(_("Overwrite document?"),
2275 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2278 lyx_view_->message(_("Canceled."));
2283 ErrorList errorList;
2284 Importer::Import(lyx_view_, fullname, format, errorList);
2285 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2289 void LyXFunc::closeBuffer()
2291 // goto bookmark to update bookmark pit.
2292 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2293 gotoBookmark(i+1, false, false);
2295 theBufferList().close(lyx_view_->buffer(), true);
2299 void LyXFunc::reloadBuffer()
2301 FileName filename(lyx_view_->buffer()->fileName());
2302 docstring const disp_fn = makeDisplayPath(filename.absFilename());
2305 Buffer * buf = lyx_view_->loadLyXFile(filename);
2308 lyx_view_->setBuffer(buf);
2309 lyx_view_->showErrorList("Parse");
2310 str = bformat(_("Document %1$s reloaded."), disp_fn);
2312 str = bformat(_("Could not reload document %1$s"), disp_fn);
2314 lyx_view_->message(str);
2317 // Each "lyx_view_" should have it's own message method. lyxview and
2318 // the minibuffer would use the minibuffer, but lyxserver would
2319 // send an ERROR signal to its client. Alejandro 970603
2320 // This function is bit problematic when it comes to NLS, to make the
2321 // lyx servers client be language indepenent we must not translate
2322 // strings sent to this func.
2323 void LyXFunc::setErrorMessage(docstring const & m) const
2325 dispatch_buffer = m;
2330 void LyXFunc::setMessage(docstring const & m) const
2332 dispatch_buffer = m;
2336 docstring const LyXFunc::viewStatusMessage()
2338 // When meta-fake key is pressed, show the key sequence so far + "M-".
2340 return keyseq.print(true) + "M-";
2342 // Else, when a non-complete key sequence is pressed,
2343 // show the available options.
2344 if (keyseq.length() > 0 && !keyseq.deleted())
2345 return keyseq.printOptions(true);
2347 BOOST_ASSERT(lyx_view_);
2348 if (!lyx_view_->buffer())
2349 return _("Welcome to LyX!");
2351 return view()->cursor().currentState();
2355 BufferView * LyXFunc::view() const
2357 BOOST_ASSERT(lyx_view_);
2358 return lyx_view_->view();
2362 bool LyXFunc::wasMetaKey() const
2364 return (meta_fake_bit != NoModifier);
2368 void LyXFunc::updateLayout(TextClassPtr const & oldlayout,
2371 lyx_view_->message(_("Converting document to new document class..."));
2373 StableDocIterator backcur(view()->cursor());
2374 ErrorList & el = buffer->errorList("Class Switch");
2375 cap::switchBetweenClasses(
2376 oldlayout, buffer->params().getTextClassPtr(),
2377 static_cast<InsetText &>(buffer->inset()), el);
2379 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
2381 buffer->errors("Class Switch");
2382 updateLabels(*buffer);
2388 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2390 // Why the switch you might ask. It is a trick to ensure that all
2391 // the elements in the LyXRCTags enum is handled. As you can see
2392 // there are no breaks at all. So it is just a huge fall-through.
2393 // The nice thing is that we will get a warning from the compiler
2394 // if we forget an element.
2395 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2397 case LyXRC::RC_ACCEPT_COMPOUND:
2398 case LyXRC::RC_ALT_LANG:
2399 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
2400 case LyXRC::RC_PLAINTEXT_LINELEN:
2401 case LyXRC::RC_AUTOREGIONDELETE:
2402 case LyXRC::RC_AUTORESET_OPTIONS:
2403 case LyXRC::RC_AUTOSAVE:
2404 case LyXRC::RC_AUTO_NUMBER:
2405 case LyXRC::RC_BACKUPDIR_PATH:
2406 case LyXRC::RC_BIBTEX_COMMAND:
2407 case LyXRC::RC_BINDFILE:
2408 case LyXRC::RC_CHECKLASTFILES:
2409 case LyXRC::RC_USELASTFILEPOS:
2410 case LyXRC::RC_LOADSESSION:
2411 case LyXRC::RC_CHKTEX_COMMAND:
2412 case LyXRC::RC_CONVERTER:
2413 case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
2414 case LyXRC::RC_COPIER:
2415 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2416 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2417 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2418 case LyXRC::RC_DATE_INSERT_FORMAT:
2419 case LyXRC::RC_DEFAULT_LANGUAGE:
2420 case LyXRC::RC_DEFAULT_PAPERSIZE:
2421 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2422 case LyXRC::RC_DISPLAY_GRAPHICS:
2423 case LyXRC::RC_DOCUMENTPATH:
2424 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2425 string const encoded = FileName(
2426 lyxrc_new.document_path).toFilesystemEncoding();
2427 if (fs::exists(encoded) && fs::is_directory(encoded))
2428 support::package().document_dir() = FileName(lyxrc.document_path);
2430 case LyXRC::RC_ESC_CHARS:
2431 case LyXRC::RC_FONT_ENCODING:
2432 case LyXRC::RC_FORMAT:
2433 case LyXRC::RC_INDEX_COMMAND:
2434 case LyXRC::RC_INPUT:
2435 case LyXRC::RC_KBMAP:
2436 case LyXRC::RC_KBMAP_PRIMARY:
2437 case LyXRC::RC_KBMAP_SECONDARY:
2438 case LyXRC::RC_LABEL_INIT_LENGTH:
2439 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2440 case LyXRC::RC_LANGUAGE_AUTO_END:
2441 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2442 case LyXRC::RC_LANGUAGE_COMMAND_END:
2443 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2444 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2445 case LyXRC::RC_LANGUAGE_PACKAGE:
2446 case LyXRC::RC_LANGUAGE_USE_BABEL:
2447 case LyXRC::RC_MAKE_BACKUP:
2448 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2449 case LyXRC::RC_NUMLASTFILES:
2450 case LyXRC::RC_PATH_PREFIX:
2451 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2452 support::prependEnvPath("PATH", lyxrc.path_prefix);
2454 case LyXRC::RC_PERS_DICT:
2455 case LyXRC::RC_PREVIEW:
2456 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2457 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2458 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2459 case LyXRC::RC_PRINTCOPIESFLAG:
2460 case LyXRC::RC_PRINTER:
2461 case LyXRC::RC_PRINTEVENPAGEFLAG:
2462 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2463 case LyXRC::RC_PRINTFILEEXTENSION:
2464 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2465 case LyXRC::RC_PRINTODDPAGEFLAG:
2466 case LyXRC::RC_PRINTPAGERANGEFLAG:
2467 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2468 case LyXRC::RC_PRINTPAPERFLAG:
2469 case LyXRC::RC_PRINTREVERSEFLAG:
2470 case LyXRC::RC_PRINTSPOOL_COMMAND:
2471 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2472 case LyXRC::RC_PRINTTOFILE:
2473 case LyXRC::RC_PRINTTOPRINTER:
2474 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2475 case LyXRC::RC_PRINT_COMMAND:
2476 case LyXRC::RC_RTL_SUPPORT:
2477 case LyXRC::RC_SCREEN_DPI:
2478 case LyXRC::RC_SCREEN_FONT_ROMAN:
2479 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2480 case LyXRC::RC_SCREEN_FONT_SANS:
2481 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2482 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2483 case LyXRC::RC_SCREEN_FONT_SIZES:
2484 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2485 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2486 case LyXRC::RC_SCREEN_GEOMETRY_HEIGHT:
2487 case LyXRC::RC_SCREEN_GEOMETRY_WIDTH:
2488 case LyXRC::RC_SCREEN_GEOMETRY_XYSAVED:
2489 case LyXRC::RC_SCREEN_ZOOM:
2490 case LyXRC::RC_SERVERPIPE:
2491 case LyXRC::RC_SET_COLOR:
2492 case LyXRC::RC_SHOW_BANNER:
2493 case LyXRC::RC_SPELL_COMMAND:
2494 case LyXRC::RC_TEMPDIRPATH:
2495 case LyXRC::RC_TEMPLATEPATH:
2496 case LyXRC::RC_TEX_ALLOWS_SPACES:
2497 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2498 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2499 support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2501 case LyXRC::RC_UIFILE:
2502 case LyXRC::RC_USER_EMAIL:
2503 case LyXRC::RC_USER_NAME:
2504 case LyXRC::RC_USETEMPDIR:
2505 case LyXRC::RC_USE_ALT_LANG:
2506 case LyXRC::RC_USE_CONVERTER_CACHE:
2507 case LyXRC::RC_USE_ESC_CHARS:
2508 case LyXRC::RC_USE_INP_ENC:
2509 case LyXRC::RC_USE_PERS_DICT:
2510 case LyXRC::RC_USE_SPELL_LIB:
2511 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2512 case LyXRC::RC_VIEWER:
2513 case LyXRC::RC_LAST: