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 "Converter.h"
35 #include "CutAndPaste.h"
37 #include "DispatchResult.h"
39 #include "ErrorList.h"
41 #include "FuncRequest.h"
42 #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"
63 #include "insets/InsetBox.h"
64 #include "insets/InsetBranch.h"
65 #include "insets/InsetCommand.h"
66 #include "insets/InsetERT.h"
67 #include "insets/InsetExternal.h"
68 #include "insets/InsetFloat.h"
69 #include "insets/InsetListings.h"
70 #include "insets/InsetGraphics.h"
71 #include "insets/InsetInclude.h"
72 #include "insets/InsetNote.h"
73 #include "insets/InsetTabular.h"
74 #include "insets/InsetVSpace.h"
75 #include "insets/InsetWrap.h"
77 #include "frontends/Application.h"
78 #include "frontends/alert.h"
79 #include "frontends/Dialogs.h"
80 #include "frontends/FileDialog.h"
81 #include "frontends/FontLoader.h"
82 #include "frontends/Gui.h"
83 #include "frontends/KeySymbol.h"
84 #include "frontends/LyXView.h"
85 #include "frontends/Selection.h"
87 #include "support/environment.h"
88 #include "support/FileFilterList.h"
89 #include "support/filetools.h"
90 #include "support/lstrings.h"
91 #include "support/Path.h"
92 #include "support/Package.h"
93 #include "support/Systemcall.h"
94 #include "support/convert.h"
95 #include "support/os.h"
97 #include <boost/current_function.hpp>
102 using std::make_pair;
105 using std::istringstream;
106 using std::ostringstream;
112 using frontend::LyXView;
114 using support::absolutePath;
115 using support::addName;
116 using support::addPath;
117 using support::bformat;
118 using support::changeExtension;
119 using support::contains;
120 using support::FileFilterList;
121 using support::FileName;
122 using support::fileSearch;
123 using support::i18nLibFileSearch;
124 using support::makeDisplayPath;
125 using support::makeAbsPath;
126 using support::package;
127 using support::quoteName;
128 using support::rtrim;
129 using support::split;
130 using support::subst;
131 using support::Systemcall;
132 using support::token;
134 using support::prefixIs;
137 namespace Alert = frontend::Alert;
139 extern bool quitting;
144 bool import(LyXView * lv, FileName const & filename,
145 string const & format, ErrorList & errorList)
147 docstring const displaypath = makeDisplayPath(filename.absFilename());
148 lv->message(bformat(_("Importing %1$s..."), displaypath));
150 FileName const lyxfile(changeExtension(filename.absFilename(), ".lyx"));
152 string loader_format;
153 vector<string> loaders = theConverters().loaders();
154 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
155 for (vector<string>::const_iterator it = loaders.begin();
156 it != loaders.end(); ++it) {
157 if (theConverters().isReachable(format, *it)) {
158 string const tofile =
159 changeExtension(filename.absFilename(),
160 formats.extension(*it));
161 if (!theConverters().convert(0, filename, FileName(tofile),
162 filename, format, *it, errorList))
168 if (loader_format.empty()) {
169 frontend::Alert::error(_("Couldn't import file"),
170 bformat(_("No information for importing the format %1$s."),
171 formats.prettyName(format)));
175 loader_format = format;
179 if (loader_format == "lyx") {
180 Buffer * buf = lv->loadLyXFile(lyxfile);
183 lv->message(_("file not imported!"));
190 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
195 bool as_paragraphs = loader_format == "textparagraph";
196 string filename2 = (loader_format == format) ? filename.absFilename()
197 : changeExtension(filename.absFilename(),
198 formats.extension(loader_format));
199 lv->view()->insertPlaintextFile(filename2, as_paragraphs);
200 lv->dispatch(FuncRequest(LFUN_MARK_OFF));
204 lv->message(_("imported."));
210 // This function runs "configure" and then rereads lyx.defaults to
211 // reconfigure the automatic settings.
212 void reconfigure(LyXView & lv, string const & option)
214 // emit message signal.
215 lv.message(_("Running configure..."));
217 // Run configure in user lyx directory
218 support::PathChanger p(package().user_support());
219 string configure_command = package().configure_command();
220 configure_command += option;
222 int ret = one.startscript(Systemcall::Wait, configure_command);
224 // emit message signal.
225 lv.message(_("Reloading configuration..."));
226 lyxrc.read(support::libFileSearch(string(), "lyxrc.defaults"));
227 // Re-read packages.lst
228 LaTeXFeatures::getAvailable();
231 Alert::information(_("System reconfiguration failed"),
232 _("The system reconfiguration has failed.\n"
233 "Default textclass is used but LyX may "
234 "not be able to work properly.\n"
235 "Please reconfigure again if needed."));
238 Alert::information(_("System reconfigured"),
239 _("The system has been reconfigured.\n"
240 "You need to restart LyX to make use of any\n"
241 "updated document class specifications."));
245 bool getLocalStatus(Cursor cursor, FuncRequest const & cmd, FuncStatus & status)
247 // Try to fix cursor in case it is broken.
248 cursor.fixIfBroken();
250 // This is, of course, a mess. Better create a new doc iterator and use
251 // this in Inset::getStatus. This might require an additional
252 // BufferView * arg, though (which should be avoided)
253 //Cursor safe = *this;
255 for ( ; cursor.depth(); cursor.pop()) {
256 //lyxerr << "\nCursor::getStatus: cmd: " << cmd << endl << *this << endl;
257 BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
258 BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
259 BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
261 // The inset's getStatus() will return 'true' if it made
262 // a definitive decision on whether it want to handle the
263 // request or not. The result of this decision is put into
264 // the 'status' parameter.
265 if (cursor.inset().getStatus(cursor, cmd, status)) {
274 /** Return the change status at cursor position, taking in account the
275 * status at each level of the document iterator (a table in a deleted
276 * footnote is deleted).
277 * When \param outer is true, the top slice is not looked at.
279 Change::Type lookupChangeType(DocIterator const & dit, bool outer = false)
281 size_t const depth = dit.depth() - (outer ? 1 : 0);
283 for (size_t i = 0 ; i < depth ; ++i) {
284 CursorSlice const & slice = dit[i];
285 if (!slice.inset().inMathed()
286 && slice.pos() < slice.paragraph().size()) {
287 Change::Type const ch = slice.paragraph().lookupChange(slice.pos()).type;
288 if (ch != Change::UNCHANGED)
292 return Change::UNCHANGED;
299 : lyx_view_(0), encoded_last_key(0), meta_fake_bit(NoModifier)
304 void LyXFunc::initKeySequences(KeyMap * kb)
306 keyseq = KeySequence(kb, kb);
307 cancel_meta_seq = KeySequence(kb, kb);
311 void LyXFunc::setLyXView(LyXView * lv)
313 if (!quitting && lyx_view_ && lyx_view_->view() && lyx_view_ != lv)
314 // save current selection to the selection buffer to allow
315 // middle-button paste in another window
316 cap::saveSelection(lyx_view_->view()->cursor());
321 void LyXFunc::handleKeyFunc(kb_action action)
323 char_type c = encoded_last_key;
328 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
329 lyx_view_->view()->getIntl().getTransManager().deadkey(
330 c, get_accent(action).accent, view()->cursor().innerText(), view()->cursor());
331 // Need to clear, in case the minibuffer calls these
334 // copied verbatim from do_accent_char
335 view()->cursor().resetAnchor();
336 view()->processUpdateFlags(Update::FitCursor);
340 void LyXFunc::gotoBookmark(unsigned int idx, bool openFile, bool switchToBuffer)
342 BOOST_ASSERT(lyx_view_);
343 if (!LyX::ref().session().bookmarks().isValid(idx))
345 BookmarksSection::Bookmark const & bm = LyX::ref().session().bookmarks().bookmark(idx);
346 BOOST_ASSERT(!bm.filename.empty());
347 string const file = bm.filename.absFilename();
348 // if the file is not opened, open it.
349 if (!theBufferList().exists(file)) {
351 dispatch(FuncRequest(LFUN_FILE_OPEN, file));
355 // open may fail, so we need to test it again
356 if (!theBufferList().exists(file))
359 // if the current buffer is not that one, switch to it.
360 if (lyx_view_->buffer()->absFileName() != file) {
363 dispatch(FuncRequest(LFUN_BUFFER_SWITCH, file));
365 // moveToPosition try paragraph id first and then paragraph (pit, pos).
366 if (!view()->moveToPosition(bm.bottom_pit, bm.bottom_pos,
367 bm.top_id, bm.top_pos))
370 // Cursor jump succeeded!
371 Cursor const & cur = view()->cursor();
372 pit_type new_pit = cur.pit();
373 pos_type new_pos = cur.pos();
374 int new_id = cur.paragraph().id();
376 // if bottom_pit, bottom_pos or top_id has been changed, update bookmark
377 // see http://bugzilla.lyx.org/show_bug.cgi?id=3092
378 if (bm.bottom_pit != new_pit || bm.bottom_pos != new_pos
379 || bm.top_id != new_id) {
380 const_cast<BookmarksSection::Bookmark &>(bm).updatePos(
381 new_pit, new_pos, new_id);
386 void LyXFunc::processKeySym(KeySymbol const & keysym, KeyModifier state)
388 LYXERR(Debug::KEY, "KeySym is " << keysym.getSymbolName());
390 // Do nothing if we have nothing (JMarc)
391 if (!keysym.isOK()) {
392 LYXERR(Debug::KEY, "Empty kbd action (probably composing)");
393 lyx_view_->restartCursor();
397 if (keysym.isModifier()) {
398 LYXERR(Debug::KEY, "isModifier true");
399 lyx_view_->restartCursor();
403 //Encoding const * encoding = view()->cursor().getEncoding();
404 //encoded_last_key = keysym.getISOEncoded(encoding ? encoding->name() : "");
405 // FIXME: encoded_last_key shadows the member variable of the same
406 // name. Is that intended?
407 char_type encoded_last_key = keysym.getUCSEncoded();
409 // Do a one-deep top-level lookup for
410 // cancel and meta-fake keys. RVDK_PATCH_5
411 cancel_meta_seq.reset();
413 FuncRequest func = cancel_meta_seq.addkey(keysym, state);
414 LYXERR(Debug::KEY, BOOST_CURRENT_FUNCTION
415 << " action first set to [" << func.action << ']');
417 // When not cancel or meta-fake, do the normal lookup.
418 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
419 // Mostly, meta_fake_bit = NoModifier. RVDK_PATCH_5.
420 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_PREFIX)) {
421 // remove Caps Lock and Mod2 as a modifiers
422 func = keyseq.addkey(keysym, (state | meta_fake_bit));
423 LYXERR(Debug::KEY, BOOST_CURRENT_FUNCTION
424 << "action now set to [" << func.action << ']');
427 // Dont remove this unless you know what you are doing.
428 meta_fake_bit = NoModifier;
430 // Can this happen now ?
431 if (func.action == LFUN_NOACTION)
432 func = FuncRequest(LFUN_COMMAND_PREFIX);
434 LYXERR(Debug::KEY, BOOST_CURRENT_FUNCTION
435 << " Key [action=" << func.action << "]["
436 << to_utf8(keyseq.print(KeySequence::Portable)) << ']');
438 // already here we know if it any point in going further
439 // why not return already here if action == -1 and
440 // num_bytes == 0? (Lgb)
442 if (keyseq.length() > 1)
443 lyx_view_->message(keyseq.print(KeySequence::ForGui));
446 // Maybe user can only reach the key via holding down shift.
447 // Let's see. But only if shift is the only modifier
448 if (func.action == LFUN_UNKNOWN_ACTION && state == ShiftModifier) {
449 LYXERR(Debug::KEY, "Trying without shift");
450 func = keyseq.addkey(keysym, NoModifier);
451 LYXERR(Debug::KEY, "Action now " << func.action);
454 if (func.action == LFUN_UNKNOWN_ACTION) {
455 // Hmm, we didn't match any of the keysequences. See
456 // if it's normal insertable text not already covered
458 if (keysym.isText() && keyseq.length() == 1) {
459 LYXERR(Debug::KEY, "isText() is true, inserting.");
460 func = FuncRequest(LFUN_SELF_INSERT,
461 FuncRequest::KEYBOARD);
463 LYXERR(Debug::KEY, "Unknown, !isText() - giving up");
464 lyx_view_->message(_("Unknown function."));
465 lyx_view_->restartCursor();
470 if (func.action == LFUN_SELF_INSERT) {
471 if (encoded_last_key != 0) {
472 docstring const arg(1, encoded_last_key);
473 dispatch(FuncRequest(LFUN_SELF_INSERT, arg,
474 FuncRequest::KEYBOARD));
475 LYXERR(Debug::KEY, "SelfInsert arg[`" << to_utf8(arg) << "']");
481 lyx_view_->restartCursor();
485 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
487 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
490 /* In LyX/Mac, when a dialog is open, the menus of the
491 application can still be accessed without giving focus to
492 the main window. In this case, we want to disable the menu
493 entries that are buffer-related.
495 Note that this code is not perfect, as bug 1941 attests:
496 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
498 Buffer * buf = lyx_view_? lyx_view_->buffer() : 0;
499 if (lyx_view_ && cmd.origin == FuncRequest::MENU && !lyx_view_->hasFocus())
502 if (cmd.action == LFUN_NOACTION) {
503 flag.message(from_utf8(N_("Nothing to do")));
508 switch (cmd.action) {
509 case LFUN_UNKNOWN_ACTION:
510 #ifndef HAVE_LIBAIKSAURUS
511 case LFUN_THESAURUS_ENTRY:
521 if (flag.unknown()) {
522 flag.message(from_utf8(N_("Unknown action")));
526 if (!flag.enabled()) {
527 if (flag.message().empty())
528 flag.message(from_utf8(N_("Command disabled")));
532 // Check whether we need a buffer
533 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
535 flag.message(from_utf8(N_("Command not allowed with"
536 "out any document open")));
541 // I would really like to avoid having this switch and rather try to
542 // encode this in the function itself.
543 // -- And I'd rather let an inset decide which LFUNs it is willing
544 // to handle (Andre')
546 switch (cmd.action) {
547 case LFUN_BUFFER_TOGGLE_READ_ONLY:
548 flag.setOnOff(buf->isReadonly());
551 case LFUN_BUFFER_SWITCH:
552 // toggle on the current buffer, but do not toggle off
553 // the other ones (is that a good idea?)
554 if (buf && to_utf8(cmd.argument()) == buf->absFileName())
558 case LFUN_BUFFER_EXPORT:
559 enable = cmd.argument() == "custom"
560 || buf->isExportable(to_utf8(cmd.argument()));
563 case LFUN_BUFFER_CHKTEX:
564 enable = buf->isLatex() && !lyxrc.chktex_command.empty();
567 case LFUN_BUILD_PROGRAM:
568 enable = buf->isExportable("program");
571 case LFUN_VC_REGISTER:
572 enable = !buf->lyxvc().inUse();
574 case LFUN_VC_CHECK_IN:
575 enable = buf->lyxvc().inUse() && !buf->isReadonly();
577 case LFUN_VC_CHECK_OUT:
578 enable = buf->lyxvc().inUse() && buf->isReadonly();
581 case LFUN_VC_UNDO_LAST:
582 enable = buf->lyxvc().inUse();
584 case LFUN_BUFFER_RELOAD:
585 enable = !buf->isUnnamed() && buf->fileName().exists()
586 && (!buf->isClean() || buf->isExternallyModified(Buffer::timestamp_method));
589 case LFUN_INSET_APPLY: {
594 string const name = cmd.getArg(0);
595 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
597 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
599 if (!inset->getStatus(view()->cursor(), fr, fs)) {
600 // Every inset is supposed to handle this
605 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
606 flag |= getStatus(fr);
608 enable = flag.enabled();
612 case LFUN_DIALOG_TOGGLE:
613 flag.setOnOff(lyx_view_->getDialogs().visible(cmd.getArg(0)));
614 // fall through to set "enable"
615 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 = buf->isExportable("dvi")
624 && lyxrc.print_command != "none";
625 else if (name == "character") {
629 InsetCode ic = view()->cursor().inset().lyxCode();
630 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
633 else if (name == "latexlog")
634 enable = FileName(buf->logName()).isFileReadable();
635 else if (name == "spellchecker")
636 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
637 enable = !buf->isReadonly();
641 else if (name == "vclog")
642 enable = buf->lyxvc().inUse();
646 case LFUN_DIALOG_UPDATE: {
647 string const name = cmd.getArg(0);
649 enable = name == "prefs";
653 case LFUN_CITATION_INSERT: {
654 FuncRequest fr(LFUN_INSET_INSERT, "citation");
655 enable = getStatus(fr).enabled();
659 case LFUN_BUFFER_WRITE: {
660 enable = lyx_view_->buffer()->isUnnamed()
661 || !lyx_view_->buffer()->isClean();
666 case LFUN_BUFFER_WRITE_ALL: {
667 // We enable the command only if there are some modified buffers
668 Buffer * first = theBufferList().first();
669 bool modified = false;
673 // We cannot use a for loop as the buffer list is a cycle.
679 b = theBufferList().next(b);
680 } while (b != first);
688 case LFUN_BOOKMARK_GOTO: {
689 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
690 enable = LyX::ref().session().bookmarks().isValid(num);
694 case LFUN_BOOKMARK_CLEAR:
695 enable = LyX::ref().session().bookmarks().size() > 0;
698 case LFUN_TOOLBAR_TOGGLE: {
699 bool const current = lyx_view_->isToolbarVisible(cmd.getArg(0));
700 flag.setOnOff(current);
703 case LFUN_WINDOW_CLOSE: {
704 enable = (theApp()->gui().viewIds().size() > 1);
708 // this one is difficult to get right. As a half-baked
709 // solution, we consider only the first action of the sequence
710 case LFUN_COMMAND_SEQUENCE: {
711 // argument contains ';'-terminated commands
712 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
713 FuncRequest func(lyxaction.lookupFunc(firstcmd));
714 func.origin = cmd.origin;
715 flag = getStatus(func);
721 std::string name(to_utf8(cmd.argument()));
722 if (LyX::ref().topLevelCmdDef().lock(name, func)) {
723 func.origin = cmd.origin;
724 flag = getStatus(func);
725 LyX::ref().topLevelCmdDef().release(name);
727 // catch recursion or unknown command definiton
728 // all operations until the recursion or unknown command
729 // definiton occures are performed, so set the state to enabled
735 case LFUN_BUFFER_NEW:
736 case LFUN_BUFFER_NEW_TEMPLATE:
737 case LFUN_WORD_FIND_FORWARD:
738 case LFUN_WORD_FIND_BACKWARD:
739 case LFUN_COMMAND_PREFIX:
740 case LFUN_COMMAND_EXECUTE:
742 case LFUN_META_PREFIX:
743 case LFUN_BUFFER_CLOSE:
744 case LFUN_BUFFER_WRITE_AS:
745 case LFUN_BUFFER_UPDATE:
746 case LFUN_BUFFER_VIEW:
747 case LFUN_MASTER_BUFFER_UPDATE:
748 case LFUN_MASTER_BUFFER_VIEW:
749 case LFUN_BUFFER_IMPORT:
750 case LFUN_BUFFER_AUTO_SAVE:
751 case LFUN_RECONFIGURE:
755 case LFUN_DROP_LAYOUTS_CHOICE:
757 case LFUN_SERVER_GET_NAME:
758 case LFUN_SERVER_NOTIFY:
759 case LFUN_SERVER_GOTO_FILE_ROW:
760 case LFUN_DIALOG_HIDE:
761 case LFUN_DIALOG_DISCONNECT_INSET:
762 case LFUN_BUFFER_CHILD_OPEN:
763 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
764 case LFUN_KEYMAP_OFF:
765 case LFUN_KEYMAP_PRIMARY:
766 case LFUN_KEYMAP_SECONDARY:
767 case LFUN_KEYMAP_TOGGLE:
769 case LFUN_BUFFER_EXPORT_CUSTOM:
770 case LFUN_BUFFER_PRINT:
771 case LFUN_PREFERENCES_SAVE:
772 case LFUN_SCREEN_FONT_UPDATE:
775 case LFUN_EXTERNAL_EDIT:
776 case LFUN_GRAPHICS_EDIT:
777 case LFUN_ALL_INSETS_TOGGLE:
778 case LFUN_BUFFER_LANGUAGE:
779 case LFUN_TEXTCLASS_APPLY:
780 case LFUN_TEXTCLASS_LOAD:
781 case LFUN_BUFFER_SAVE_AS_DEFAULT:
782 case LFUN_BUFFER_PARAMS_APPLY:
783 case LFUN_LAYOUT_MODULES_CLEAR:
784 case LFUN_LAYOUT_MODULE_ADD:
785 case LFUN_LAYOUT_RELOAD:
786 case LFUN_LYXRC_APPLY:
787 case LFUN_BUFFER_NEXT:
788 case LFUN_BUFFER_PREVIOUS:
789 case LFUN_WINDOW_NEW:
791 // these are handled in our dispatch()
799 if (!getLocalStatus(view()->cursor(), cmd, flag))
800 flag = view()->getStatus(cmd);
806 // Can we use a readonly buffer?
807 if (buf && buf->isReadonly()
808 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
809 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
810 flag.message(from_utf8(N_("Document is read-only")));
814 // Are we in a DELETED change-tracking region?
816 && lookupChangeType(view()->cursor(), true) == Change::DELETED
817 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
818 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
819 flag.message(from_utf8(N_("This portion of the document is deleted.")));
823 // the default error message if we disable the command
824 if (!flag.enabled() && flag.message().empty())
825 flag.message(from_utf8(N_("Command disabled")));
831 bool LyXFunc::ensureBufferClean(BufferView * bv)
833 Buffer & buf = bv->buffer();
837 docstring const file = buf.fileName().displayName(30);
838 docstring text = bformat(_("The document %1$s has unsaved "
839 "changes.\n\nDo you want to save "
840 "the document?"), file);
841 int const ret = Alert::prompt(_("Save changed document?"),
842 text, 0, 1, _("&Save"),
846 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
848 return buf.isClean();
854 void showPrintError(string const & name)
856 docstring str = bformat(_("Could not print the document %1$s.\n"
857 "Check that your printer is set up correctly."),
858 makeDisplayPath(name, 50));
859 Alert::error(_("Print document failed"), str);
863 void loadTextClass(string const & name)
865 std::pair<bool, textclass_type> const tc_pair =
866 textclasslist.numberOfClass(name);
868 if (!tc_pair.first) {
869 lyxerr << "Document class \"" << name
870 << "\" does not exist."
875 textclass_type const tc = tc_pair.second;
877 if (!textclasslist[tc].load()) {
878 docstring s = bformat(_("The document class %1$s."
879 "could not be loaded."),
880 from_utf8(textclasslist[tc].name()));
881 Alert::error(_("Could not load class"), s);
886 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
891 void LyXFunc::dispatch(FuncRequest const & cmd)
893 string const argument = to_utf8(cmd.argument());
894 kb_action const action = cmd.action;
896 LYXERR(Debug::ACTION, "\nLyXFunc::dispatch: cmd: " << cmd);
897 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
899 // we have not done anything wrong yet.
901 dispatch_buffer.erase();
903 // redraw the screen at the end (first of the two drawing steps).
904 //This is done unless explicitely requested otherwise
905 Update::flags updateFlags = Update::FitCursor;
907 FuncStatus const flag = getStatus(cmd);
908 if (!flag.enabled()) {
909 // We cannot use this function here
910 LYXERR(Debug::ACTION, "LyXFunc::dispatch: "
911 << lyxaction.getActionName(action)
912 << " [" << action << "] is disabled at this location");
913 setErrorMessage(flag.message());
916 // Let lyx_view_ dispatch its own actions.
917 case LFUN_COMMAND_EXECUTE:
918 case LFUN_DROP_LAYOUTS_CHOICE:
920 case LFUN_TOOLBAR_TOGGLE:
921 BOOST_ASSERT(lyx_view_);
922 lyx_view_->dispatch(cmd);
925 case LFUN_WORD_FIND_FORWARD:
926 case LFUN_WORD_FIND_BACKWARD: {
927 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
928 static docstring last_search;
929 docstring searched_string;
931 if (!cmd.argument().empty()) {
932 last_search = cmd.argument();
933 searched_string = cmd.argument();
935 searched_string = last_search;
938 if (searched_string.empty())
941 bool const fw = action == LFUN_WORD_FIND_FORWARD;
942 docstring const data =
943 find2string(searched_string, true, false, fw);
944 find(view(), FuncRequest(LFUN_WORD_FIND, data));
948 case LFUN_COMMAND_PREFIX:
949 BOOST_ASSERT(lyx_view_);
950 lyx_view_->message(keyseq.printOptions(true));
954 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
956 meta_fake_bit = NoModifier;
957 if (lyx_view_->buffer())
958 // cancel any selection
959 dispatch(FuncRequest(LFUN_MARK_OFF));
960 setMessage(from_ascii(N_("Cancel")));
963 case LFUN_META_PREFIX:
964 meta_fake_bit = AltModifier;
965 setMessage(keyseq.print(KeySequence::ForGui));
968 case LFUN_BUFFER_TOGGLE_READ_ONLY: {
969 BOOST_ASSERT(lyx_view_ && lyx_view_->view() && lyx_view_->buffer());
970 Buffer * buf = lyx_view_->buffer();
971 if (buf->lyxvc().inUse())
972 buf->lyxvc().toggleReadOnly();
974 buf->setReadonly(!lyx_view_->buffer()->isReadonly());
978 // --- Menus -----------------------------------------------
979 case LFUN_BUFFER_NEW:
980 menuNew(argument, false);
981 updateFlags = Update::None;
984 case LFUN_BUFFER_NEW_TEMPLATE:
985 menuNew(argument, true);
986 updateFlags = Update::None;
989 case LFUN_BUFFER_CLOSE:
991 updateFlags = Update::None;
994 case LFUN_BUFFER_WRITE:
995 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
996 if (!lyx_view_->buffer()->isUnnamed()) {
997 docstring const str = bformat(_("Saving document %1$s..."),
998 makeDisplayPath(lyx_view_->buffer()->absFileName()));
999 lyx_view_->message(str);
1000 lyx_view_->buffer()->menuWrite();
1001 lyx_view_->message(str + _(" done."));
1003 lyx_view_->buffer()->writeAs();
1005 updateFlags = Update::None;
1008 case LFUN_BUFFER_WRITE_AS:
1009 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1010 lyx_view_->buffer()->writeAs(argument);
1011 updateFlags = Update::None;
1014 case LFUN_BUFFER_WRITE_ALL: {
1015 Buffer * first = theBufferList().first();
1018 lyx_view_->message(_("Saving all documents..."));
1020 // We cannot use a for loop as the buffer list cycles.
1022 if (!b->isClean()) {
1023 if (!b->isUnnamed()) {
1025 lyxerr[Debug::ACTION] << "Saved " << b->absFileName() << endl;
1029 b = theBufferList().next(b);
1030 } while (b != first);
1031 lyx_view_->message(_("All documents saved."));
1034 updateFlags = Update::None;
1038 case LFUN_BUFFER_RELOAD: {
1039 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1040 docstring const file = makeDisplayPath(lyx_view_->buffer()->absFileName(), 20);
1041 docstring text = bformat(_("Any changes will be lost. Are you sure "
1042 "you want to revert to the saved version of the document %1$s?"), file);
1043 int const ret = Alert::prompt(_("Revert to saved document?"),
1044 text, 1, 1, _("&Revert"), _("&Cancel"));
1051 case LFUN_BUFFER_UPDATE:
1052 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1053 lyx_view_->buffer()->doExport(argument, true);
1056 case LFUN_BUFFER_VIEW:
1057 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1058 lyx_view_->buffer()->preview(argument);
1061 case LFUN_MASTER_BUFFER_UPDATE:
1062 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->masterBuffer());
1063 lyx_view_->buffer()->masterBuffer()->doExport(argument, true);
1066 case LFUN_MASTER_BUFFER_VIEW:
1067 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->masterBuffer());
1068 lyx_view_->buffer()->masterBuffer()->preview(argument);
1071 case LFUN_BUILD_PROGRAM:
1072 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1073 lyx_view_->buffer()->doExport("program", true);
1076 case LFUN_BUFFER_CHKTEX:
1077 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1078 lyx_view_->buffer()->runChktex();
1081 case LFUN_BUFFER_EXPORT:
1082 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1083 if (argument == "custom")
1084 lyx_view_->showDialog("sendto");
1086 lyx_view_->buffer()->doExport(argument, false);
1089 case LFUN_BUFFER_EXPORT_CUSTOM: {
1090 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1092 string command = split(argument, format_name, ' ');
1093 Format const * format = formats.getFormat(format_name);
1095 lyxerr << "Format \"" << format_name
1096 << "\" not recognized!"
1101 Buffer * buffer = lyx_view_->buffer();
1103 // The name of the file created by the conversion process
1106 // Output to filename
1107 if (format->name() == "lyx") {
1108 string const latexname = buffer->latexName(false);
1109 filename = changeExtension(latexname,
1110 format->extension());
1111 filename = addName(buffer->temppath(), filename);
1113 if (!buffer->writeFile(FileName(filename)))
1117 buffer->doExport(format_name, true, filename);
1120 // Substitute $$FName for filename
1121 if (!contains(command, "$$FName"))
1122 command = "( " + command + " ) < $$FName";
1123 command = subst(command, "$$FName", filename);
1125 // Execute the command in the background
1127 call.startscript(Systemcall::DontWait, command);
1131 case LFUN_BUFFER_PRINT: {
1132 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1133 // FIXME: cmd.getArg() might fail if one of the arguments
1134 // contains double quotes
1135 string target = cmd.getArg(0);
1136 string target_name = cmd.getArg(1);
1137 string command = cmd.getArg(2);
1140 || target_name.empty()
1141 || command.empty()) {
1142 lyxerr << "Unable to parse \""
1143 << argument << '"' << endl;
1146 if (target != "printer" && target != "file") {
1147 lyxerr << "Unrecognized target \""
1148 << target << '"' << endl;
1152 Buffer * buffer = lyx_view_->buffer();
1154 if (!buffer->doExport("dvi", true)) {
1155 showPrintError(buffer->absFileName());
1159 // Push directory path.
1160 string const path = buffer->temppath();
1161 // Prevent the compiler from optimizing away p
1163 support::PathChanger p(pp);
1165 // there are three cases here:
1166 // 1. we print to a file
1167 // 2. we print directly to a printer
1168 // 3. we print using a spool command (print to file first)
1171 string const dviname =
1172 changeExtension(buffer->latexName(true), "dvi");
1174 if (target == "printer") {
1175 if (!lyxrc.print_spool_command.empty()) {
1176 // case 3: print using a spool
1177 string const psname =
1178 changeExtension(dviname,".ps");
1179 command += ' ' + lyxrc.print_to_file
1182 + quoteName(dviname);
1185 lyxrc.print_spool_command + ' ';
1186 if (target_name != "default") {
1187 command2 += lyxrc.print_spool_printerprefix
1191 command2 += quoteName(psname);
1193 // If successful, then spool command
1194 res = one.startscript(
1199 res = one.startscript(
1200 Systemcall::DontWait,
1203 // case 2: print directly to a printer
1204 if (target_name != "default")
1205 command += ' ' + lyxrc.print_to_printer + target_name + ' ';
1206 res = one.startscript(
1207 Systemcall::DontWait,
1208 command + quoteName(dviname));
1212 // case 1: print to a file
1213 FileName const filename(makeAbsPath(target_name,
1214 lyx_view_->buffer()->filePath()));
1215 FileName const dvifile(makeAbsPath(dviname, path));
1216 if (filename.exists()) {
1217 docstring text = bformat(
1218 _("The file %1$s already exists.\n\n"
1219 "Do you want to overwrite that file?"),
1220 makeDisplayPath(filename.absFilename()));
1221 if (Alert::prompt(_("Overwrite file?"),
1222 text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
1225 command += ' ' + lyxrc.print_to_file
1226 + quoteName(filename.toFilesystemEncoding())
1228 + quoteName(dvifile.toFilesystemEncoding());
1229 res = one.startscript(Systemcall::DontWait,
1234 showPrintError(buffer->absFileName());
1238 case LFUN_BUFFER_IMPORT:
1243 // quitting is triggered by the gui code
1244 // (leaving the event loop).
1245 lyx_view_->message(from_utf8(N_("Exiting.")));
1246 if (theBufferList().quitWriteAll())
1247 theApp()->gui().closeAllViews();
1250 case LFUN_BUFFER_AUTO_SAVE:
1251 lyx_view_->buffer()->autoSave();
1254 case LFUN_RECONFIGURE:
1255 BOOST_ASSERT(lyx_view_);
1256 // argument is any additional parameter to the configure.py command
1257 reconfigure(*lyx_view_, argument);
1260 case LFUN_HELP_OPEN: {
1261 BOOST_ASSERT(lyx_view_);
1262 string const arg = argument;
1264 setErrorMessage(from_ascii(N_("Missing argument")));
1267 FileName const fname = i18nLibFileSearch("doc", arg, "lyx");
1268 if (fname.empty()) {
1269 lyxerr << "LyX: unable to find documentation file `"
1270 << arg << "'. Bad installation?" << endl;
1273 lyx_view_->message(bformat(_("Opening help file %1$s..."),
1274 makeDisplayPath(fname.absFilename())));
1275 Buffer * buf = lyx_view_->loadLyXFile(fname, false);
1278 lyx_view_->setBuffer(buf);
1279 lyx_view_->errors("Parse");
1281 updateFlags = Update::None;
1285 // --- version control -------------------------------
1286 case LFUN_VC_REGISTER:
1287 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1288 if (!ensureBufferClean(view()))
1290 if (!lyx_view_->buffer()->lyxvc().inUse()) {
1291 lyx_view_->buffer()->lyxvc().registrer();
1294 updateFlags = Update::Force;
1297 case LFUN_VC_CHECK_IN:
1298 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1299 if (!ensureBufferClean(view()))
1301 if (lyx_view_->buffer()->lyxvc().inUse()
1302 && !lyx_view_->buffer()->isReadonly()) {
1303 lyx_view_->buffer()->lyxvc().checkIn();
1308 case LFUN_VC_CHECK_OUT:
1309 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1310 if (!ensureBufferClean(view()))
1312 if (lyx_view_->buffer()->lyxvc().inUse()
1313 && lyx_view_->buffer()->isReadonly()) {
1314 lyx_view_->buffer()->lyxvc().checkOut();
1319 case LFUN_VC_REVERT:
1320 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1321 lyx_view_->buffer()->lyxvc().revert();
1325 case LFUN_VC_UNDO_LAST:
1326 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1327 lyx_view_->buffer()->lyxvc().undoLast();
1331 // --- buffers ----------------------------------------
1332 case LFUN_BUFFER_SWITCH:
1333 BOOST_ASSERT(lyx_view_);
1334 lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1335 updateFlags = Update::None;
1338 case LFUN_BUFFER_NEXT:
1339 BOOST_ASSERT(lyx_view_);
1340 lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer()));
1341 updateFlags = Update::None;
1344 case LFUN_BUFFER_PREVIOUS:
1345 BOOST_ASSERT(lyx_view_);
1346 lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer()));
1347 updateFlags = Update::None;
1350 case LFUN_FILE_NEW: {
1351 BOOST_ASSERT(lyx_view_);
1353 string tmpname = split(argument, name, ':'); // Split filename
1354 Buffer * const b = newFile(name, tmpname);
1356 lyx_view_->setBuffer(b);
1357 updateFlags = Update::None;
1361 case LFUN_FILE_OPEN:
1362 BOOST_ASSERT(lyx_view_);
1364 updateFlags = Update::None;
1367 // --- lyxserver commands ----------------------------
1368 case LFUN_SERVER_GET_NAME:
1369 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1370 setMessage(from_utf8(lyx_view_->buffer()->absFileName()));
1371 LYXERR(Debug::INFO, "FNAME["
1372 << lyx_view_->buffer()->absFileName() << ']');
1375 case LFUN_SERVER_NOTIFY:
1376 dispatch_buffer = keyseq.print(KeySequence::Portable);
1377 theServer().notifyClient(to_utf8(dispatch_buffer));
1380 case LFUN_SERVER_GOTO_FILE_ROW: {
1381 BOOST_ASSERT(lyx_view_);
1384 istringstream is(argument);
1385 is >> file_name >> row;
1387 bool loaded = false;
1388 if (prefixIs(file_name, package().temp_dir().absFilename()))
1389 // Needed by inverse dvi search. If it is a file
1390 // in tmpdir, call the apropriated function
1391 buf = theBufferList().getBufferFromTmp(file_name);
1393 // Must replace extension of the file to be .lyx
1394 // and get full path
1395 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1396 // Either change buffer or load the file
1397 if (theBufferList().exists(s.absFilename()))
1398 buf = theBufferList().getBuffer(s.absFilename());
1400 buf = lyx_view_->loadLyXFile(s);
1406 updateFlags = Update::None;
1411 lyx_view_->setBuffer(buf);
1412 view()->setCursorFromRow(row);
1414 lyx_view_->errors("Parse");
1415 updateFlags = Update::FitCursor;
1419 case LFUN_DIALOG_SHOW: {
1420 BOOST_ASSERT(lyx_view_);
1421 string const name = cmd.getArg(0);
1422 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1424 if (name == "character") {
1425 data = freefont2string();
1427 lyx_view_->showDialogWithData("character", data);
1428 } else if (name == "latexlog") {
1429 Buffer::LogType type;
1430 string const logfile = lyx_view_->buffer()->logName(&type);
1432 case Buffer::latexlog:
1435 case Buffer::buildlog:
1439 data += Lexer::quoteString(logfile);
1440 lyx_view_->showDialogWithData("log", data);
1441 } else if (name == "vclog") {
1442 string const data = "vc " +
1443 Lexer::quoteString(lyx_view_->buffer()->lyxvc().getLogFile());
1444 lyx_view_->showDialogWithData("log", data);
1446 lyx_view_->showDialogWithData(name, data);
1450 case LFUN_DIALOG_SHOW_NEW_INSET: {
1451 BOOST_ASSERT(lyx_view_);
1452 string const name = cmd.getArg(0);
1453 InsetCode code = insetCode(name);
1454 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1455 bool insetCodeOK = true;
1464 case HYPERLINK_CODE: {
1465 InsetCommandParams p(code);
1466 data = InsetCommandMailer::params2string(name, p);
1469 case INCLUDE_CODE: {
1470 // data is the include type: one of "include",
1471 // "input", "verbatiminput" or "verbatiminput*"
1473 // default type is requested
1475 InsetCommandParams p(INCLUDE_CODE, data);
1476 data = InsetCommandMailer::params2string("include", p);
1480 // \c data == "Boxed" || "Frameless" etc
1481 InsetBoxParams p(data);
1482 data = InsetBoxMailer::params2string(p);
1486 InsetBranchParams p;
1487 data = InsetBranchMailer::params2string(p);
1491 InsetCommandParams p(CITE_CODE);
1492 data = InsetCommandMailer::params2string(name, p);
1496 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1499 case EXTERNAL_CODE: {
1500 InsetExternalParams p;
1501 Buffer const & buffer = *lyx_view_->buffer();
1502 data = InsetExternalMailer::params2string(p, buffer);
1507 data = InsetFloatMailer::params2string(p);
1510 case LISTINGS_CODE: {
1511 InsetListingsParams p;
1512 data = InsetListingsMailer::params2string(p);
1515 case GRAPHICS_CODE: {
1516 InsetGraphicsParams p;
1517 Buffer const & buffer = *lyx_view_->buffer();
1518 data = InsetGraphicsMailer::params2string(p, buffer);
1523 data = InsetNoteMailer::params2string(p);
1528 data = InsetVSpaceMailer::params2string(space);
1533 data = InsetWrapMailer::params2string(p);
1537 lyxerr << "Inset type '" << name <<
1538 "' not recognized in LFUN_DIALOG_SHOW_NEW_INSET" << std:: endl;
1539 insetCodeOK = false;
1541 } // end switch(code)
1543 lyx_view_->getDialogs().show(name, data, 0);
1547 case LFUN_DIALOG_UPDATE: {
1548 BOOST_ASSERT(lyx_view_);
1549 string const & name = argument;
1550 // Can only update a dialog connected to an existing inset
1551 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1553 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1554 inset->dispatch(view()->cursor(), fr);
1555 } else if (name == "paragraph") {
1556 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1557 } else if (name == "prefs") {
1558 lyx_view_->updateDialog(name, string());
1563 case LFUN_DIALOG_HIDE:
1564 LyX::cref().hideDialogs(argument, 0);
1567 case LFUN_DIALOG_TOGGLE: {
1568 BOOST_ASSERT(lyx_view_);
1569 if (lyx_view_->getDialogs().visible(cmd.getArg(0)))
1570 dispatch(FuncRequest(LFUN_DIALOG_HIDE, argument));
1572 dispatch(FuncRequest(LFUN_DIALOG_SHOW, argument));
1576 case LFUN_DIALOG_DISCONNECT_INSET:
1577 BOOST_ASSERT(lyx_view_);
1578 lyx_view_->getDialogs().disconnect(argument);
1582 case LFUN_CITATION_INSERT: {
1583 BOOST_ASSERT(lyx_view_);
1584 if (!argument.empty()) {
1585 // we can have one optional argument, delimited by '|'
1586 // citation-insert <key>|<text_before>
1587 // this should be enhanced to also support text_after
1588 // and citation style
1589 string arg = argument;
1591 if (contains(argument, "|")) {
1592 arg = token(argument, '|', 0);
1593 opt1 = token(argument, '|', 1);
1595 InsetCommandParams icp(CITE_CODE);
1596 icp["key"] = from_utf8(arg);
1598 icp["before"] = from_utf8(opt1);
1599 string icstr = InsetCommandMailer::params2string("citation", icp);
1600 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1603 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1607 case LFUN_BUFFER_CHILD_OPEN: {
1608 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1609 Buffer * parent = lyx_view_->buffer();
1610 FileName filename = makeAbsPath(argument, parent->filePath());
1611 view()->saveBookmark(false);
1613 bool parsed = false;
1614 if (theBufferList().exists(filename.absFilename())) {
1615 child = theBufferList().getBuffer(filename.absFilename());
1617 setMessage(bformat(_("Opening child document %1$s..."),
1618 makeDisplayPath(filename.absFilename())));
1619 child = lyx_view_->loadLyXFile(filename, true);
1623 // Set the parent name of the child document.
1624 // This makes insertion of citations and references in the child work,
1625 // when the target is in the parent or another child document.
1626 child->setParentName(parent->absFileName());
1627 updateLabels(*child->masterBuffer());
1628 lyx_view_->setBuffer(child);
1630 lyx_view_->errors("Parse");
1633 // If a screen update is required (in case where auto_open is false),
1634 // setBuffer() would have taken care of it already. Otherwise we shall
1635 // reset the update flag because it can cause a circular problem.
1637 updateFlags = Update::None;
1641 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1642 BOOST_ASSERT(lyx_view_);
1643 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1646 case LFUN_KEYMAP_OFF:
1647 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1648 lyx_view_->view()->getIntl().keyMapOn(false);
1651 case LFUN_KEYMAP_PRIMARY:
1652 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1653 lyx_view_->view()->getIntl().keyMapPrim();
1656 case LFUN_KEYMAP_SECONDARY:
1657 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1658 lyx_view_->view()->getIntl().keyMapSec();
1661 case LFUN_KEYMAP_TOGGLE:
1662 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1663 lyx_view_->view()->getIntl().toggleKeyMap();
1669 string rest = split(argument, countstr, ' ');
1670 istringstream is(countstr);
1673 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1674 for (int i = 0; i < count; ++i)
1675 dispatch(lyxaction.lookupFunc(rest));
1679 case LFUN_COMMAND_SEQUENCE: {
1680 // argument contains ';'-terminated commands
1681 string arg = argument;
1682 while (!arg.empty()) {
1684 arg = split(arg, first, ';');
1685 FuncRequest func(lyxaction.lookupFunc(first));
1686 func.origin = cmd.origin;
1694 if (LyX::ref().topLevelCmdDef().lock(argument, func)) {
1695 func.origin = cmd.origin;
1697 LyX::ref().topLevelCmdDef().release(argument);
1699 if (func.action == LFUN_UNKNOWN_ACTION) {
1700 // unknown command definition
1701 lyxerr << "Warning: unknown command definition `"
1705 // recursion detected
1706 lyxerr << "Warning: Recursion in the command definition `"
1707 << argument << "' detected"
1714 case LFUN_PREFERENCES_SAVE: {
1715 lyxrc.write(makeAbsPath("preferences",
1716 package().user_support().absFilename()),
1721 case LFUN_SCREEN_FONT_UPDATE:
1722 BOOST_ASSERT(lyx_view_);
1723 // handle the screen font changes.
1724 theFontLoader().update();
1725 /// FIXME: only the current view will be updated. the Gui
1726 /// class is able to furnish the list of views.
1727 updateFlags = Update::Force;
1730 case LFUN_SET_COLOR: {
1732 string const x11_name = split(argument, lyx_name, ' ');
1733 if (lyx_name.empty() || x11_name.empty()) {
1734 setErrorMessage(from_ascii(N_(
1735 "Syntax: set-color <lyx_name>"
1740 bool const graphicsbg_changed =
1741 (lyx_name == lcolor.getLyXName(Color_graphicsbg) &&
1742 x11_name != lcolor.getX11Name(Color_graphicsbg));
1744 if (!lcolor.setColor(lyx_name, x11_name)) {
1746 bformat(_("Set-color \"%1$s\" failed "
1747 "- color is undefined or "
1748 "may not be redefined"),
1749 from_utf8(lyx_name)));
1753 theApp()->updateColor(lcolor.getFromLyXName(lyx_name));
1755 if (graphicsbg_changed) {
1756 // FIXME: The graphics cache no longer has a changeDisplay method.
1758 graphics::GCache::get().changeDisplay(true);
1765 BOOST_ASSERT(lyx_view_);
1766 lyx_view_->message(from_utf8(argument));
1769 case LFUN_EXTERNAL_EDIT: {
1770 BOOST_ASSERT(lyx_view_);
1771 FuncRequest fr(action, argument);
1772 InsetExternal().dispatch(view()->cursor(), fr);
1776 case LFUN_GRAPHICS_EDIT: {
1777 FuncRequest fr(action, argument);
1778 InsetGraphics().dispatch(view()->cursor(), fr);
1782 case LFUN_INSET_APPLY: {
1783 BOOST_ASSERT(lyx_view_);
1784 string const name = cmd.getArg(0);
1785 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1787 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1788 inset->dispatch(view()->cursor(), fr);
1790 FuncRequest fr(LFUN_INSET_INSERT, argument);
1793 // ideally, the update flag should be set by the insets,
1794 // but this is not possible currently
1795 updateFlags = Update::Force | Update::FitCursor;
1799 case LFUN_ALL_INSETS_TOGGLE: {
1800 BOOST_ASSERT(lyx_view_);
1802 string const name = split(argument, action, ' ');
1803 InsetCode const inset_code = insetCode(name);
1805 Cursor & cur = view()->cursor();
1806 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1808 Inset & inset = lyx_view_->buffer()->inset();
1809 InsetIterator it = inset_iterator_begin(inset);
1810 InsetIterator const end = inset_iterator_end(inset);
1811 for (; it != end; ++it) {
1812 if (!it->asInsetMath()
1813 && (inset_code == NO_CODE
1814 || inset_code == it->lyxCode())) {
1815 Cursor tmpcur = cur;
1816 tmpcur.pushBackward(*it);
1817 it->dispatch(tmpcur, fr);
1820 updateFlags = Update::Force | Update::FitCursor;
1824 case LFUN_BUFFER_LANGUAGE: {
1825 BOOST_ASSERT(lyx_view_);
1826 Buffer & buffer = *lyx_view_->buffer();
1827 Language const * oldL = buffer.params().language;
1828 Language const * newL = languages.getLanguage(argument);
1829 if (!newL || oldL == newL)
1832 if (oldL->rightToLeft() == newL->rightToLeft()
1833 && !buffer.isMultiLingual())
1834 buffer.changeLanguage(oldL, newL);
1838 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1839 string const fname =
1840 addName(addPath(package().user_support().absFilename(), "templates/"),
1842 Buffer defaults(fname);
1844 istringstream ss(argument);
1847 int const unknown_tokens = defaults.readHeader(lex);
1849 if (unknown_tokens != 0) {
1850 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1851 << unknown_tokens << " unknown token"
1852 << (unknown_tokens == 1 ? "" : "s")
1856 if (defaults.writeFile(FileName(defaults.absFileName())))
1857 setMessage(bformat(_("Document defaults saved in %1$s"),
1858 makeDisplayPath(fname)));
1860 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1864 case LFUN_BUFFER_PARAMS_APPLY: {
1865 BOOST_ASSERT(lyx_view_);
1866 biblio::CiteEngine const oldEngine =
1867 lyx_view_->buffer()->params().getEngine();
1869 Buffer * buffer = lyx_view_->buffer();
1871 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1873 Cursor & cur = view()->cursor();
1874 cur.recordUndoFullDocument();
1876 istringstream ss(argument);
1879 int const unknown_tokens = buffer->readHeader(lex);
1881 if (unknown_tokens != 0) {
1882 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1883 << unknown_tokens << " unknown token"
1884 << (unknown_tokens == 1 ? "" : "s")
1888 updateLayout(oldClass, buffer);
1890 biblio::CiteEngine const newEngine =
1891 lyx_view_->buffer()->params().getEngine();
1893 if (oldEngine != newEngine) {
1894 FuncRequest fr(LFUN_INSET_REFRESH);
1896 Inset & inset = lyx_view_->buffer()->inset();
1897 InsetIterator it = inset_iterator_begin(inset);
1898 InsetIterator const end = inset_iterator_end(inset);
1899 for (; it != end; ++it)
1900 if (it->lyxCode() == CITE_CODE)
1901 it->dispatch(cur, fr);
1904 updateFlags = Update::Force | Update::FitCursor;
1908 case LFUN_LAYOUT_MODULES_CLEAR: {
1909 BOOST_ASSERT(lyx_view_);
1910 Buffer * buffer = lyx_view_->buffer();
1911 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1912 view()->cursor().recordUndoFullDocument();
1913 buffer->params().clearLayoutModules();
1914 updateLayout(oldClass, buffer);
1915 updateFlags = Update::Force | Update::FitCursor;
1919 case LFUN_LAYOUT_MODULE_ADD: {
1920 BOOST_ASSERT(lyx_view_);
1921 Buffer * buffer = lyx_view_->buffer();
1922 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1923 view()->cursor().recordUndoFullDocument();
1924 buffer->params().addLayoutModule(argument);
1925 updateLayout(oldClass, buffer);
1926 updateFlags = Update::Force | Update::FitCursor;
1930 case LFUN_TEXTCLASS_APPLY: {
1931 BOOST_ASSERT(lyx_view_);
1932 Buffer * buffer = lyx_view_->buffer();
1934 loadTextClass(argument);
1936 std::pair<bool, textclass_type> const tc_pair =
1937 textclasslist.numberOfClass(argument);
1942 textclass_type const old_class = buffer->params().getBaseClass();
1943 textclass_type const new_class = tc_pair.second;
1945 if (old_class == new_class)
1949 //Save the old, possibly modular, layout for use in conversion.
1950 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1951 view()->cursor().recordUndoFullDocument();
1952 buffer->params().setBaseClass(new_class);
1953 updateLayout(oldClass, buffer);
1954 updateFlags = Update::Force | Update::FitCursor;
1958 case LFUN_LAYOUT_RELOAD: {
1959 BOOST_ASSERT(lyx_view_);
1960 Buffer * buffer = lyx_view_->buffer();
1961 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1962 textclass_type const tc = buffer->params().getBaseClass();
1963 textclasslist.reset(tc);
1964 buffer->params().setBaseClass(tc);
1965 updateLayout(oldClass, buffer);
1966 updateFlags = Update::Force | Update::FitCursor;
1970 case LFUN_TEXTCLASS_LOAD:
1971 loadTextClass(argument);
1974 case LFUN_LYXRC_APPLY: {
1975 LyXRC const lyxrc_orig = lyxrc;
1977 istringstream ss(argument);
1978 bool const success = lyxrc.read(ss) == 0;
1981 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1982 << "Unable to read lyxrc data"
1987 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1989 if (lyx_view_ && lyx_view_->buffer())
1990 lyx_view_->updateLayoutChoice(true);
1992 /// We force the redraw in any case because there might be
1993 /// some screen font changes.
1994 /// FIXME: only the current view will be updated. the Gui
1995 /// class is able to furnish the list of views.
1996 updateFlags = Update::Force;
2000 case LFUN_WINDOW_NEW:
2001 LyX::ref().newLyXView();
2004 case LFUN_WINDOW_CLOSE:
2005 BOOST_ASSERT(lyx_view_);
2006 BOOST_ASSERT(theApp());
2007 // update bookmark pit of the current buffer before window close
2008 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2009 gotoBookmark(i+1, false, false);
2010 // ask the user for saving changes or cancel quit
2011 if (!theBufferList().quitWriteAll())
2016 case LFUN_BOOKMARK_GOTO:
2017 // go to bookmark, open unopened file and switch to buffer if necessary
2018 gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
2021 case LFUN_BOOKMARK_CLEAR:
2022 LyX::ref().session().bookmarks().clear();
2026 BOOST_ASSERT(lyx_view_);
2027 view()->cursor().dispatch(cmd);
2028 updateFlags = view()->cursor().result().update();
2029 if (!view()->cursor().result().dispatched())
2030 updateFlags = view()->dispatch(cmd);
2035 if (lyx_view_ && lyx_view_->buffer()) {
2036 // BufferView::update() updates the ViewMetricsInfo and
2037 // also initializes the position cache for all insets in
2038 // (at least partially) visible top-level paragraphs.
2039 // We will redraw the screen only if needed.
2040 view()->processUpdateFlags(updateFlags);
2041 lyx_view_->updateStatusBar();
2043 // if we executed a mutating lfun, mark the buffer as dirty
2045 && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
2046 && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
2047 lyx_view_->buffer()->markDirty();
2049 //Do we have a selection?
2050 theSelection().haveSelection(view()->cursor().selection());
2052 if (view()->cursor().inTexted()) {
2053 lyx_view_->updateLayoutChoice(false);
2057 if (!quitting && lyx_view_) {
2058 lyx_view_->updateToolbars();
2059 // Some messages may already be translated, so we cannot use _()
2060 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
2065 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
2067 const bool verbose = (cmd.origin == FuncRequest::MENU
2068 || cmd.origin == FuncRequest::TOOLBAR
2069 || cmd.origin == FuncRequest::COMMANDBUFFER);
2071 if (cmd.action == LFUN_SELF_INSERT || !verbose) {
2072 LYXERR(Debug::ACTION, "dispatch msg is " << to_utf8(msg));
2074 lyx_view_->message(msg);
2078 docstring dispatch_msg = msg;
2079 if (!dispatch_msg.empty())
2080 dispatch_msg += ' ';
2082 docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
2084 bool argsadded = false;
2086 if (!cmd.argument().empty()) {
2087 if (cmd.action != LFUN_UNKNOWN_ACTION) {
2088 comname += ' ' + cmd.argument();
2093 docstring const shortcuts = theTopLevelKeymap().printBindings(cmd);
2095 if (!shortcuts.empty())
2096 comname += ": " + shortcuts;
2097 else if (!argsadded && !cmd.argument().empty())
2098 comname += ' ' + cmd.argument();
2100 if (!comname.empty()) {
2101 comname = rtrim(comname);
2102 dispatch_msg += '(' + rtrim(comname) + ')';
2105 LYXERR(Debug::ACTION, "verbose dispatch msg " << to_utf8(dispatch_msg));
2106 if (!dispatch_msg.empty())
2107 lyx_view_->message(dispatch_msg);
2111 void LyXFunc::menuNew(string const & name, bool fromTemplate)
2113 // FIXME: initpath is not used. What to do?
2114 string initpath = lyxrc.document_path;
2115 string filename(name);
2117 if (lyx_view_->buffer()) {
2118 string const trypath = lyx_view_->buffer()->filePath();
2119 // If directory is writeable, use this as default.
2120 if (FileName(trypath).isDirWritable())
2124 static int newfile_number;
2126 if (filename.empty()) {
2127 filename = addName(lyxrc.document_path,
2128 "newfile" + convert<string>(++newfile_number) + ".lyx");
2129 while (theBufferList().exists(filename) ||
2130 FileName(filename).isReadable()) {
2132 filename = addName(lyxrc.document_path,
2133 "newfile" + convert<string>(newfile_number) +
2138 // The template stuff
2141 FileDialog dlg(_("Select template file"));
2142 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
2143 dlg.setButton1(_("Templates|#T#t"), from_utf8(lyxrc.template_path));
2145 FileDialog::Result result =
2146 dlg.open(from_utf8(lyxrc.template_path),
2147 FileFilterList(_("LyX Documents (*.lyx)")),
2150 if (result.first == FileDialog::Later)
2152 if (result.second.empty())
2154 templname = to_utf8(result.second);
2157 Buffer * const b = newFile(filename, templname, !name.empty());
2159 lyx_view_->setBuffer(b);
2163 void LyXFunc::open(string const & fname)
2165 string initpath = lyxrc.document_path;
2167 if (lyx_view_->buffer()) {
2168 string const trypath = lyx_view_->buffer()->filePath();
2169 // If directory is writeable, use this as default.
2170 if (FileName(trypath).isDirWritable())
2176 if (fname.empty()) {
2177 FileDialog dlg(_("Select document to open"), LFUN_FILE_OPEN);
2178 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
2179 dlg.setButton2(_("Examples|#E#e"),
2180 from_utf8(addPath(package().system_support().absFilename(), "examples")));
2182 FileDialog::Result result =
2183 dlg.open(from_utf8(initpath),
2184 FileFilterList(_("LyX Documents (*.lyx)")),
2187 if (result.first == FileDialog::Later)
2190 filename = to_utf8(result.second);
2192 // check selected filename
2193 if (filename.empty()) {
2194 lyx_view_->message(_("Canceled."));
2200 // get absolute path of file and add ".lyx" to the filename if
2202 FileName const fullname = fileSearch(string(), filename, "lyx");
2203 if (!fullname.empty())
2204 filename = fullname.absFilename();
2206 // if the file doesn't exist, let the user create one
2207 if (!fullname.exists()) {
2208 // the user specifically chose this name. Believe him.
2209 Buffer * const b = newFile(filename, string(), true);
2211 lyx_view_->setBuffer(b);
2215 docstring const disp_fn = makeDisplayPath(filename);
2216 lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
2219 Buffer * buf = lyx_view_->loadLyXFile(fullname);
2222 lyx_view_->setBuffer(buf);
2223 lyx_view_->errors("Parse");
2224 str2 = bformat(_("Document %1$s opened."), disp_fn);
2226 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2228 lyx_view_->message(str2);
2232 void LyXFunc::doImport(string const & argument)
2235 string filename = split(argument, format, ' ');
2237 LYXERR(Debug::INFO, "LyXFunc::doImport: " << format
2238 << " file: " << filename);
2240 // need user interaction
2241 if (filename.empty()) {
2242 string initpath = lyxrc.document_path;
2244 if (lyx_view_->buffer()) {
2245 string const trypath = lyx_view_->buffer()->filePath();
2246 // If directory is writeable, use this as default.
2247 if (FileName(trypath).isDirWritable())
2251 docstring const text = bformat(_("Select %1$s file to import"),
2252 formats.prettyName(format));
2254 FileDialog dlg(text, LFUN_BUFFER_IMPORT);
2255 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
2256 dlg.setButton2(_("Examples|#E#e"),
2257 from_utf8(addPath(package().system_support().absFilename(), "examples")));
2259 docstring filter = formats.prettyName(format);
2262 filter += from_utf8(formats.extension(format));
2265 FileDialog::Result result =
2266 dlg.open(from_utf8(initpath),
2267 FileFilterList(filter),
2270 if (result.first == FileDialog::Later)
2273 filename = to_utf8(result.second);
2275 // check selected filename
2276 if (filename.empty())
2277 lyx_view_->message(_("Canceled."));
2280 if (filename.empty())
2283 // get absolute path of file
2284 FileName const fullname(makeAbsPath(filename));
2286 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
2288 // Check if the document already is open
2289 if (use_gui && theBufferList().exists(lyxfile.absFilename())) {
2290 if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) {
2291 lyx_view_->message(_("Canceled."));
2296 // if the file exists already, and we didn't do
2297 // -i lyx thefile.lyx, warn
2298 if (lyxfile.exists() && fullname != lyxfile) {
2299 docstring const file = makeDisplayPath(lyxfile.absFilename(), 30);
2301 docstring text = bformat(_("The document %1$s already exists.\n\n"
2302 "Do you want to overwrite that document?"), file);
2303 int const ret = Alert::prompt(_("Overwrite document?"),
2304 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2307 lyx_view_->message(_("Canceled."));
2312 ErrorList errorList;
2313 import(lyx_view_, fullname, format, errorList);
2314 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2318 void LyXFunc::closeBuffer()
2320 // goto bookmark to update bookmark pit.
2321 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2322 gotoBookmark(i+1, false, false);
2324 theBufferList().close(lyx_view_->buffer(), true);
2328 void LyXFunc::reloadBuffer()
2330 FileName filename(lyx_view_->buffer()->absFileName());
2331 docstring const disp_fn = makeDisplayPath(filename.absFilename());
2334 Buffer * buf = lyx_view_->loadLyXFile(filename);
2337 lyx_view_->setBuffer(buf);
2338 lyx_view_->errors("Parse");
2339 str = bformat(_("Document %1$s reloaded."), disp_fn);
2341 str = bformat(_("Could not reload document %1$s"), disp_fn);
2343 lyx_view_->message(str);
2346 // Each "lyx_view_" should have it's own message method. lyxview and
2347 // the minibuffer would use the minibuffer, but lyxserver would
2348 // send an ERROR signal to its client. Alejandro 970603
2349 // This function is bit problematic when it comes to NLS, to make the
2350 // lyx servers client be language indepenent we must not translate
2351 // strings sent to this func.
2352 void LyXFunc::setErrorMessage(docstring const & m) const
2354 dispatch_buffer = m;
2359 void LyXFunc::setMessage(docstring const & m) const
2361 dispatch_buffer = m;
2365 docstring const LyXFunc::viewStatusMessage()
2367 // When meta-fake key is pressed, show the key sequence so far + "M-".
2369 return keyseq.print(KeySequence::ForGui) + "M-";
2371 // Else, when a non-complete key sequence is pressed,
2372 // show the available options.
2373 if (keyseq.length() > 0 && !keyseq.deleted())
2374 return keyseq.printOptions(true);
2376 BOOST_ASSERT(lyx_view_);
2377 if (!lyx_view_->buffer())
2378 return _("Welcome to LyX!");
2380 return view()->cursor().currentState();
2384 BufferView * LyXFunc::view() const
2386 BOOST_ASSERT(lyx_view_);
2387 return lyx_view_->view();
2391 bool LyXFunc::wasMetaKey() const
2393 return (meta_fake_bit != NoModifier);
2397 void LyXFunc::updateLayout(TextClassPtr const & oldlayout,
2400 lyx_view_->message(_("Converting document to new document class..."));
2402 StableDocIterator backcur(view()->cursor());
2403 ErrorList & el = buffer->errorList("Class Switch");
2404 cap::switchBetweenClasses(
2405 oldlayout, buffer->params().getTextClassPtr(),
2406 static_cast<InsetText &>(buffer->inset()), el);
2408 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
2410 buffer->errors("Class Switch");
2411 updateLabels(*buffer);
2417 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2419 // Why the switch you might ask. It is a trick to ensure that all
2420 // the elements in the LyXRCTags enum is handled. As you can see
2421 // there are no breaks at all. So it is just a huge fall-through.
2422 // The nice thing is that we will get a warning from the compiler
2423 // if we forget an element.
2424 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2426 case LyXRC::RC_ACCEPT_COMPOUND:
2427 case LyXRC::RC_ALT_LANG:
2428 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
2429 case LyXRC::RC_PLAINTEXT_LINELEN:
2430 case LyXRC::RC_AUTOREGIONDELETE:
2431 case LyXRC::RC_AUTORESET_OPTIONS:
2432 case LyXRC::RC_AUTOSAVE:
2433 case LyXRC::RC_AUTO_NUMBER:
2434 case LyXRC::RC_BACKUPDIR_PATH:
2435 case LyXRC::RC_BIBTEX_COMMAND:
2436 case LyXRC::RC_BINDFILE:
2437 case LyXRC::RC_CHECKLASTFILES:
2438 case LyXRC::RC_USELASTFILEPOS:
2439 case LyXRC::RC_LOADSESSION:
2440 case LyXRC::RC_CHKTEX_COMMAND:
2441 case LyXRC::RC_CONVERTER:
2442 case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
2443 case LyXRC::RC_COPIER:
2444 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2445 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2446 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2447 case LyXRC::RC_DATE_INSERT_FORMAT:
2448 case LyXRC::RC_DEFAULT_LANGUAGE:
2449 case LyXRC::RC_DEFAULT_PAPERSIZE:
2450 case LyXRC::RC_DEFFILE:
2451 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2452 case LyXRC::RC_DISPLAY_GRAPHICS:
2453 case LyXRC::RC_DOCUMENTPATH:
2454 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2455 FileName path(lyxrc_new.document_path);
2456 if (path.exists() && path.isDirectory())
2457 support::package().document_dir() = FileName(lyxrc.document_path);
2459 case LyXRC::RC_ESC_CHARS:
2460 case LyXRC::RC_FONT_ENCODING:
2461 case LyXRC::RC_FORMAT:
2462 case LyXRC::RC_INDEX_COMMAND:
2463 case LyXRC::RC_INPUT:
2464 case LyXRC::RC_KBMAP:
2465 case LyXRC::RC_KBMAP_PRIMARY:
2466 case LyXRC::RC_KBMAP_SECONDARY:
2467 case LyXRC::RC_LABEL_INIT_LENGTH:
2468 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2469 case LyXRC::RC_LANGUAGE_AUTO_END:
2470 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2471 case LyXRC::RC_LANGUAGE_COMMAND_END:
2472 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2473 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2474 case LyXRC::RC_LANGUAGE_PACKAGE:
2475 case LyXRC::RC_LANGUAGE_USE_BABEL:
2476 case LyXRC::RC_MAKE_BACKUP:
2477 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2478 case LyXRC::RC_NUMLASTFILES:
2479 case LyXRC::RC_PATH_PREFIX:
2480 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2481 support::prependEnvPath("PATH", lyxrc.path_prefix);
2483 case LyXRC::RC_PERS_DICT:
2484 case LyXRC::RC_PREVIEW:
2485 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2486 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2487 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2488 case LyXRC::RC_PRINTCOPIESFLAG:
2489 case LyXRC::RC_PRINTER:
2490 case LyXRC::RC_PRINTEVENPAGEFLAG:
2491 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2492 case LyXRC::RC_PRINTFILEEXTENSION:
2493 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2494 case LyXRC::RC_PRINTODDPAGEFLAG:
2495 case LyXRC::RC_PRINTPAGERANGEFLAG:
2496 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2497 case LyXRC::RC_PRINTPAPERFLAG:
2498 case LyXRC::RC_PRINTREVERSEFLAG:
2499 case LyXRC::RC_PRINTSPOOL_COMMAND:
2500 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2501 case LyXRC::RC_PRINTTOFILE:
2502 case LyXRC::RC_PRINTTOPRINTER:
2503 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2504 case LyXRC::RC_PRINT_COMMAND:
2505 case LyXRC::RC_RTL_SUPPORT:
2506 case LyXRC::RC_SCREEN_DPI:
2507 case LyXRC::RC_SCREEN_FONT_ROMAN:
2508 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2509 case LyXRC::RC_SCREEN_FONT_SANS:
2510 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2511 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2512 case LyXRC::RC_SCREEN_FONT_SIZES:
2513 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2514 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2515 case LyXRC::RC_GEOMETRY_SESSION:
2516 case LyXRC::RC_SCREEN_ZOOM:
2517 case LyXRC::RC_SERVERPIPE:
2518 case LyXRC::RC_SET_COLOR:
2519 case LyXRC::RC_SHOW_BANNER:
2520 case LyXRC::RC_SPELL_COMMAND:
2521 case LyXRC::RC_TEMPDIRPATH:
2522 case LyXRC::RC_TEMPLATEPATH:
2523 case LyXRC::RC_TEX_ALLOWS_SPACES:
2524 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2525 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2526 support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2528 case LyXRC::RC_UIFILE:
2529 case LyXRC::RC_USER_EMAIL:
2530 case LyXRC::RC_USER_NAME:
2531 case LyXRC::RC_USETEMPDIR:
2532 case LyXRC::RC_USE_ALT_LANG:
2533 case LyXRC::RC_USE_CONVERTER_CACHE:
2534 case LyXRC::RC_USE_ESC_CHARS:
2535 case LyXRC::RC_USE_INP_ENC:
2536 case LyXRC::RC_USE_PERS_DICT:
2537 case LyXRC::RC_USE_PIXMAP_CACHE:
2538 case LyXRC::RC_USE_SPELL_LIB:
2539 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2540 case LyXRC::RC_SORT_LAYOUTS:
2541 case LyXRC::RC_VIEWER:
2542 case LyXRC::RC_LAST: