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/KeySymbol.h"
83 #include "frontends/LyXView.h"
84 #include "frontends/Selection.h"
86 #include "support/environment.h"
87 #include "support/FileFilterList.h"
88 #include "support/filetools.h"
89 #include "support/lstrings.h"
90 #include "support/Path.h"
91 #include "support/Package.h"
92 #include "support/Systemcall.h"
93 #include "support/convert.h"
94 #include "support/os.h"
96 #include <boost/current_function.hpp>
101 using std::make_pair;
104 using std::istringstream;
105 using std::ostringstream;
111 using frontend::LyXView;
113 using support::absolutePath;
114 using support::addName;
115 using support::addPath;
116 using support::bformat;
117 using support::changeExtension;
118 using support::contains;
119 using support::FileFilterList;
120 using support::FileName;
121 using support::fileSearch;
122 using support::i18nLibFileSearch;
123 using support::makeDisplayPath;
124 using support::makeAbsPath;
125 using support::package;
126 using support::quoteName;
127 using support::rtrim;
128 using support::split;
129 using support::subst;
130 using support::Systemcall;
131 using support::token;
133 using support::prefixIs;
136 namespace Alert = frontend::Alert;
138 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()->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()->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 if (quitting || !use_gui)
1566 theApp()->hideDialogs(argument, 0);
1570 case LFUN_DIALOG_TOGGLE: {
1571 BOOST_ASSERT(lyx_view_);
1572 if (lyx_view_->getDialogs().visible(cmd.getArg(0)))
1573 dispatch(FuncRequest(LFUN_DIALOG_HIDE, argument));
1575 dispatch(FuncRequest(LFUN_DIALOG_SHOW, argument));
1579 case LFUN_DIALOG_DISCONNECT_INSET:
1580 BOOST_ASSERT(lyx_view_);
1581 lyx_view_->getDialogs().disconnect(argument);
1585 case LFUN_CITATION_INSERT: {
1586 BOOST_ASSERT(lyx_view_);
1587 if (!argument.empty()) {
1588 // we can have one optional argument, delimited by '|'
1589 // citation-insert <key>|<text_before>
1590 // this should be enhanced to also support text_after
1591 // and citation style
1592 string arg = argument;
1594 if (contains(argument, "|")) {
1595 arg = token(argument, '|', 0);
1596 opt1 = token(argument, '|', 1);
1598 InsetCommandParams icp(CITE_CODE);
1599 icp["key"] = from_utf8(arg);
1601 icp["before"] = from_utf8(opt1);
1602 string icstr = InsetCommandMailer::params2string("citation", icp);
1603 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1606 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1610 case LFUN_BUFFER_CHILD_OPEN: {
1611 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1612 Buffer * parent = lyx_view_->buffer();
1613 FileName filename = makeAbsPath(argument, parent->filePath());
1614 view()->saveBookmark(false);
1616 bool parsed = false;
1617 if (theBufferList().exists(filename.absFilename())) {
1618 child = theBufferList().getBuffer(filename.absFilename());
1620 setMessage(bformat(_("Opening child document %1$s..."),
1621 makeDisplayPath(filename.absFilename())));
1622 child = lyx_view_->loadLyXFile(filename, true);
1626 // Set the parent name of the child document.
1627 // This makes insertion of citations and references in the child work,
1628 // when the target is in the parent or another child document.
1629 child->setParentName(parent->absFileName());
1630 updateLabels(*child->masterBuffer());
1631 lyx_view_->setBuffer(child);
1633 lyx_view_->errors("Parse");
1636 // If a screen update is required (in case where auto_open is false),
1637 // setBuffer() would have taken care of it already. Otherwise we shall
1638 // reset the update flag because it can cause a circular problem.
1640 updateFlags = Update::None;
1644 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1645 BOOST_ASSERT(lyx_view_);
1646 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1649 case LFUN_KEYMAP_OFF:
1650 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1651 lyx_view_->view()->getIntl().keyMapOn(false);
1654 case LFUN_KEYMAP_PRIMARY:
1655 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1656 lyx_view_->view()->getIntl().keyMapPrim();
1659 case LFUN_KEYMAP_SECONDARY:
1660 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1661 lyx_view_->view()->getIntl().keyMapSec();
1664 case LFUN_KEYMAP_TOGGLE:
1665 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1666 lyx_view_->view()->getIntl().toggleKeyMap();
1672 string rest = split(argument, countstr, ' ');
1673 istringstream is(countstr);
1676 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1677 for (int i = 0; i < count; ++i)
1678 dispatch(lyxaction.lookupFunc(rest));
1682 case LFUN_COMMAND_SEQUENCE: {
1683 // argument contains ';'-terminated commands
1684 string arg = argument;
1685 while (!arg.empty()) {
1687 arg = split(arg, first, ';');
1688 FuncRequest func(lyxaction.lookupFunc(first));
1689 func.origin = cmd.origin;
1697 if (LyX::ref().topLevelCmdDef().lock(argument, func)) {
1698 func.origin = cmd.origin;
1700 LyX::ref().topLevelCmdDef().release(argument);
1702 if (func.action == LFUN_UNKNOWN_ACTION) {
1703 // unknown command definition
1704 lyxerr << "Warning: unknown command definition `"
1708 // recursion detected
1709 lyxerr << "Warning: Recursion in the command definition `"
1710 << argument << "' detected"
1717 case LFUN_PREFERENCES_SAVE: {
1718 lyxrc.write(makeAbsPath("preferences",
1719 package().user_support().absFilename()),
1724 case LFUN_SCREEN_FONT_UPDATE:
1725 BOOST_ASSERT(lyx_view_);
1726 // handle the screen font changes.
1727 theFontLoader().update();
1728 /// FIXME: only the current view will be updated. the Gui
1729 /// class is able to furnish the list of views.
1730 updateFlags = Update::Force;
1733 case LFUN_SET_COLOR: {
1735 string const x11_name = split(argument, lyx_name, ' ');
1736 if (lyx_name.empty() || x11_name.empty()) {
1737 setErrorMessage(from_ascii(N_(
1738 "Syntax: set-color <lyx_name>"
1743 bool const graphicsbg_changed =
1744 (lyx_name == lcolor.getLyXName(Color_graphicsbg) &&
1745 x11_name != lcolor.getX11Name(Color_graphicsbg));
1747 if (!lcolor.setColor(lyx_name, x11_name)) {
1749 bformat(_("Set-color \"%1$s\" failed "
1750 "- color is undefined or "
1751 "may not be redefined"),
1752 from_utf8(lyx_name)));
1756 theApp()->updateColor(lcolor.getFromLyXName(lyx_name));
1758 if (graphicsbg_changed) {
1759 // FIXME: The graphics cache no longer has a changeDisplay method.
1761 graphics::GCache::get().changeDisplay(true);
1768 BOOST_ASSERT(lyx_view_);
1769 lyx_view_->message(from_utf8(argument));
1772 case LFUN_EXTERNAL_EDIT: {
1773 BOOST_ASSERT(lyx_view_);
1774 FuncRequest fr(action, argument);
1775 InsetExternal().dispatch(view()->cursor(), fr);
1779 case LFUN_GRAPHICS_EDIT: {
1780 FuncRequest fr(action, argument);
1781 InsetGraphics().dispatch(view()->cursor(), fr);
1785 case LFUN_INSET_APPLY: {
1786 BOOST_ASSERT(lyx_view_);
1787 string const name = cmd.getArg(0);
1788 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1790 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1791 inset->dispatch(view()->cursor(), fr);
1793 FuncRequest fr(LFUN_INSET_INSERT, argument);
1796 // ideally, the update flag should be set by the insets,
1797 // but this is not possible currently
1798 updateFlags = Update::Force | Update::FitCursor;
1802 case LFUN_ALL_INSETS_TOGGLE: {
1803 BOOST_ASSERT(lyx_view_);
1805 string const name = split(argument, action, ' ');
1806 InsetCode const inset_code = insetCode(name);
1808 Cursor & cur = view()->cursor();
1809 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1811 Inset & inset = lyx_view_->buffer()->inset();
1812 InsetIterator it = inset_iterator_begin(inset);
1813 InsetIterator const end = inset_iterator_end(inset);
1814 for (; it != end; ++it) {
1815 if (!it->asInsetMath()
1816 && (inset_code == NO_CODE
1817 || inset_code == it->lyxCode())) {
1818 Cursor tmpcur = cur;
1819 tmpcur.pushBackward(*it);
1820 it->dispatch(tmpcur, fr);
1823 updateFlags = Update::Force | Update::FitCursor;
1827 case LFUN_BUFFER_LANGUAGE: {
1828 BOOST_ASSERT(lyx_view_);
1829 Buffer & buffer = *lyx_view_->buffer();
1830 Language const * oldL = buffer.params().language;
1831 Language const * newL = languages.getLanguage(argument);
1832 if (!newL || oldL == newL)
1835 if (oldL->rightToLeft() == newL->rightToLeft()
1836 && !buffer.isMultiLingual())
1837 buffer.changeLanguage(oldL, newL);
1841 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1842 string const fname =
1843 addName(addPath(package().user_support().absFilename(), "templates/"),
1845 Buffer defaults(fname);
1847 istringstream ss(argument);
1850 int const unknown_tokens = defaults.readHeader(lex);
1852 if (unknown_tokens != 0) {
1853 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1854 << unknown_tokens << " unknown token"
1855 << (unknown_tokens == 1 ? "" : "s")
1859 if (defaults.writeFile(FileName(defaults.absFileName())))
1860 setMessage(bformat(_("Document defaults saved in %1$s"),
1861 makeDisplayPath(fname)));
1863 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1867 case LFUN_BUFFER_PARAMS_APPLY: {
1868 BOOST_ASSERT(lyx_view_);
1869 biblio::CiteEngine const oldEngine =
1870 lyx_view_->buffer()->params().getEngine();
1872 Buffer * buffer = lyx_view_->buffer();
1874 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1876 Cursor & cur = view()->cursor();
1877 cur.recordUndoFullDocument();
1879 istringstream ss(argument);
1882 int const unknown_tokens = buffer->readHeader(lex);
1884 if (unknown_tokens != 0) {
1885 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1886 << unknown_tokens << " unknown token"
1887 << (unknown_tokens == 1 ? "" : "s")
1891 updateLayout(oldClass, buffer);
1893 biblio::CiteEngine const newEngine =
1894 lyx_view_->buffer()->params().getEngine();
1896 if (oldEngine != newEngine) {
1897 FuncRequest fr(LFUN_INSET_REFRESH);
1899 Inset & inset = lyx_view_->buffer()->inset();
1900 InsetIterator it = inset_iterator_begin(inset);
1901 InsetIterator const end = inset_iterator_end(inset);
1902 for (; it != end; ++it)
1903 if (it->lyxCode() == CITE_CODE)
1904 it->dispatch(cur, fr);
1907 updateFlags = Update::Force | Update::FitCursor;
1911 case LFUN_LAYOUT_MODULES_CLEAR: {
1912 BOOST_ASSERT(lyx_view_);
1913 Buffer * buffer = lyx_view_->buffer();
1914 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1915 view()->cursor().recordUndoFullDocument();
1916 buffer->params().clearLayoutModules();
1917 updateLayout(oldClass, buffer);
1918 updateFlags = Update::Force | Update::FitCursor;
1922 case LFUN_LAYOUT_MODULE_ADD: {
1923 BOOST_ASSERT(lyx_view_);
1924 Buffer * buffer = lyx_view_->buffer();
1925 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1926 view()->cursor().recordUndoFullDocument();
1927 buffer->params().addLayoutModule(argument);
1928 updateLayout(oldClass, buffer);
1929 updateFlags = Update::Force | Update::FitCursor;
1933 case LFUN_TEXTCLASS_APPLY: {
1934 BOOST_ASSERT(lyx_view_);
1935 Buffer * buffer = lyx_view_->buffer();
1937 loadTextClass(argument);
1939 std::pair<bool, textclass_type> const tc_pair =
1940 textclasslist.numberOfClass(argument);
1945 textclass_type const old_class = buffer->params().getBaseClass();
1946 textclass_type const new_class = tc_pair.second;
1948 if (old_class == new_class)
1952 //Save the old, possibly modular, layout for use in conversion.
1953 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1954 view()->cursor().recordUndoFullDocument();
1955 buffer->params().setBaseClass(new_class);
1956 updateLayout(oldClass, buffer);
1957 updateFlags = Update::Force | Update::FitCursor;
1961 case LFUN_LAYOUT_RELOAD: {
1962 BOOST_ASSERT(lyx_view_);
1963 Buffer * buffer = lyx_view_->buffer();
1964 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1965 textclass_type const tc = buffer->params().getBaseClass();
1966 textclasslist.reset(tc);
1967 buffer->params().setBaseClass(tc);
1968 updateLayout(oldClass, buffer);
1969 updateFlags = Update::Force | Update::FitCursor;
1973 case LFUN_TEXTCLASS_LOAD:
1974 loadTextClass(argument);
1977 case LFUN_LYXRC_APPLY: {
1978 LyXRC const lyxrc_orig = lyxrc;
1980 istringstream ss(argument);
1981 bool const success = lyxrc.read(ss) == 0;
1984 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1985 << "Unable to read lyxrc data"
1990 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1992 if (lyx_view_ && lyx_view_->buffer())
1993 lyx_view_->updateLayoutChoice(true);
1995 /// We force the redraw in any case because there might be
1996 /// some screen font changes.
1997 /// FIXME: only the current view will be updated. the Gui
1998 /// class is able to furnish the list of views.
1999 updateFlags = Update::Force;
2003 case LFUN_WINDOW_NEW:
2004 LyX::ref().newLyXView();
2007 case LFUN_WINDOW_CLOSE:
2008 BOOST_ASSERT(lyx_view_);
2009 BOOST_ASSERT(theApp());
2010 // update bookmark pit of the current buffer before window close
2011 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2012 gotoBookmark(i+1, false, false);
2013 // ask the user for saving changes or cancel quit
2014 if (!theBufferList().quitWriteAll())
2019 case LFUN_BOOKMARK_GOTO:
2020 // go to bookmark, open unopened file and switch to buffer if necessary
2021 gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
2024 case LFUN_BOOKMARK_CLEAR:
2025 LyX::ref().session().bookmarks().clear();
2029 BOOST_ASSERT(lyx_view_);
2030 view()->cursor().dispatch(cmd);
2031 updateFlags = view()->cursor().result().update();
2032 if (!view()->cursor().result().dispatched())
2033 updateFlags = view()->dispatch(cmd);
2038 if (lyx_view_ && lyx_view_->buffer()) {
2039 // BufferView::update() updates the ViewMetricsInfo and
2040 // also initializes the position cache for all insets in
2041 // (at least partially) visible top-level paragraphs.
2042 // We will redraw the screen only if needed.
2043 view()->processUpdateFlags(updateFlags);
2044 lyx_view_->updateStatusBar();
2046 // if we executed a mutating lfun, mark the buffer as dirty
2048 && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
2049 && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
2050 lyx_view_->buffer()->markDirty();
2052 //Do we have a selection?
2053 theSelection().haveSelection(view()->cursor().selection());
2055 if (view()->cursor().inTexted()) {
2056 lyx_view_->updateLayoutChoice(false);
2060 if (!quitting && lyx_view_) {
2061 lyx_view_->updateToolbars();
2062 // Some messages may already be translated, so we cannot use _()
2063 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
2068 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
2070 const bool verbose = (cmd.origin == FuncRequest::MENU
2071 || cmd.origin == FuncRequest::TOOLBAR
2072 || cmd.origin == FuncRequest::COMMANDBUFFER);
2074 if (cmd.action == LFUN_SELF_INSERT || !verbose) {
2075 LYXERR(Debug::ACTION, "dispatch msg is " << to_utf8(msg));
2077 lyx_view_->message(msg);
2081 docstring dispatch_msg = msg;
2082 if (!dispatch_msg.empty())
2083 dispatch_msg += ' ';
2085 docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
2087 bool argsadded = false;
2089 if (!cmd.argument().empty()) {
2090 if (cmd.action != LFUN_UNKNOWN_ACTION) {
2091 comname += ' ' + cmd.argument();
2096 docstring const shortcuts = theTopLevelKeymap().printBindings(cmd);
2098 if (!shortcuts.empty())
2099 comname += ": " + shortcuts;
2100 else if (!argsadded && !cmd.argument().empty())
2101 comname += ' ' + cmd.argument();
2103 if (!comname.empty()) {
2104 comname = rtrim(comname);
2105 dispatch_msg += '(' + rtrim(comname) + ')';
2108 LYXERR(Debug::ACTION, "verbose dispatch msg " << to_utf8(dispatch_msg));
2109 if (!dispatch_msg.empty())
2110 lyx_view_->message(dispatch_msg);
2114 void LyXFunc::menuNew(string const & name, bool fromTemplate)
2116 // FIXME: initpath is not used. What to do?
2117 string initpath = lyxrc.document_path;
2118 string filename(name);
2120 if (lyx_view_->buffer()) {
2121 string const trypath = lyx_view_->buffer()->filePath();
2122 // If directory is writeable, use this as default.
2123 if (FileName(trypath).isDirWritable())
2127 static int newfile_number;
2129 if (filename.empty()) {
2130 filename = addName(lyxrc.document_path,
2131 "newfile" + convert<string>(++newfile_number) + ".lyx");
2132 while (theBufferList().exists(filename) ||
2133 FileName(filename).isReadable()) {
2135 filename = addName(lyxrc.document_path,
2136 "newfile" + convert<string>(newfile_number) +
2141 // The template stuff
2144 FileDialog dlg(_("Select template file"));
2145 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
2146 dlg.setButton1(_("Templates|#T#t"), from_utf8(lyxrc.template_path));
2148 FileDialog::Result result =
2149 dlg.open(from_utf8(lyxrc.template_path),
2150 FileFilterList(_("LyX Documents (*.lyx)")),
2153 if (result.first == FileDialog::Later)
2155 if (result.second.empty())
2157 templname = to_utf8(result.second);
2160 Buffer * const b = newFile(filename, templname, !name.empty());
2162 lyx_view_->setBuffer(b);
2166 void LyXFunc::open(string const & fname)
2168 string initpath = lyxrc.document_path;
2170 if (lyx_view_->buffer()) {
2171 string const trypath = lyx_view_->buffer()->filePath();
2172 // If directory is writeable, use this as default.
2173 if (FileName(trypath).isDirWritable())
2179 if (fname.empty()) {
2180 FileDialog dlg(_("Select document to open"), LFUN_FILE_OPEN);
2181 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
2182 dlg.setButton2(_("Examples|#E#e"),
2183 from_utf8(addPath(package().system_support().absFilename(), "examples")));
2185 FileDialog::Result result =
2186 dlg.open(from_utf8(initpath),
2187 FileFilterList(_("LyX Documents (*.lyx)")),
2190 if (result.first == FileDialog::Later)
2193 filename = to_utf8(result.second);
2195 // check selected filename
2196 if (filename.empty()) {
2197 lyx_view_->message(_("Canceled."));
2203 // get absolute path of file and add ".lyx" to the filename if
2205 FileName const fullname = fileSearch(string(), filename, "lyx");
2206 if (!fullname.empty())
2207 filename = fullname.absFilename();
2209 // if the file doesn't exist, let the user create one
2210 if (!fullname.exists()) {
2211 // the user specifically chose this name. Believe him.
2212 Buffer * const b = newFile(filename, string(), true);
2214 lyx_view_->setBuffer(b);
2218 docstring const disp_fn = makeDisplayPath(filename);
2219 lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
2222 Buffer * buf = lyx_view_->loadLyXFile(fullname);
2225 lyx_view_->setBuffer(buf);
2226 lyx_view_->errors("Parse");
2227 str2 = bformat(_("Document %1$s opened."), disp_fn);
2229 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2231 lyx_view_->message(str2);
2235 void LyXFunc::doImport(string const & argument)
2238 string filename = split(argument, format, ' ');
2240 LYXERR(Debug::INFO, "LyXFunc::doImport: " << format
2241 << " file: " << filename);
2243 // need user interaction
2244 if (filename.empty()) {
2245 string initpath = lyxrc.document_path;
2247 if (lyx_view_->buffer()) {
2248 string const trypath = lyx_view_->buffer()->filePath();
2249 // If directory is writeable, use this as default.
2250 if (FileName(trypath).isDirWritable())
2254 docstring const text = bformat(_("Select %1$s file to import"),
2255 formats.prettyName(format));
2257 FileDialog dlg(text, LFUN_BUFFER_IMPORT);
2258 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
2259 dlg.setButton2(_("Examples|#E#e"),
2260 from_utf8(addPath(package().system_support().absFilename(), "examples")));
2262 docstring filter = formats.prettyName(format);
2265 filter += from_utf8(formats.extension(format));
2268 FileDialog::Result result =
2269 dlg.open(from_utf8(initpath),
2270 FileFilterList(filter),
2273 if (result.first == FileDialog::Later)
2276 filename = to_utf8(result.second);
2278 // check selected filename
2279 if (filename.empty())
2280 lyx_view_->message(_("Canceled."));
2283 if (filename.empty())
2286 // get absolute path of file
2287 FileName const fullname(makeAbsPath(filename));
2289 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
2291 // Check if the document already is open
2292 if (use_gui && theBufferList().exists(lyxfile.absFilename())) {
2293 if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) {
2294 lyx_view_->message(_("Canceled."));
2299 // if the file exists already, and we didn't do
2300 // -i lyx thefile.lyx, warn
2301 if (lyxfile.exists() && fullname != lyxfile) {
2302 docstring const file = makeDisplayPath(lyxfile.absFilename(), 30);
2304 docstring text = bformat(_("The document %1$s already exists.\n\n"
2305 "Do you want to overwrite that document?"), file);
2306 int const ret = Alert::prompt(_("Overwrite document?"),
2307 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2310 lyx_view_->message(_("Canceled."));
2315 ErrorList errorList;
2316 import(lyx_view_, fullname, format, errorList);
2317 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2321 void LyXFunc::closeBuffer()
2323 // goto bookmark to update bookmark pit.
2324 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2325 gotoBookmark(i+1, false, false);
2327 theBufferList().close(lyx_view_->buffer(), true);
2331 void LyXFunc::reloadBuffer()
2333 FileName filename(lyx_view_->buffer()->absFileName());
2334 docstring const disp_fn = makeDisplayPath(filename.absFilename());
2337 Buffer * buf = lyx_view_->loadLyXFile(filename);
2340 lyx_view_->setBuffer(buf);
2341 lyx_view_->errors("Parse");
2342 str = bformat(_("Document %1$s reloaded."), disp_fn);
2344 str = bformat(_("Could not reload document %1$s"), disp_fn);
2346 lyx_view_->message(str);
2349 // Each "lyx_view_" should have it's own message method. lyxview and
2350 // the minibuffer would use the minibuffer, but lyxserver would
2351 // send an ERROR signal to its client. Alejandro 970603
2352 // This function is bit problematic when it comes to NLS, to make the
2353 // lyx servers client be language indepenent we must not translate
2354 // strings sent to this func.
2355 void LyXFunc::setErrorMessage(docstring const & m) const
2357 dispatch_buffer = m;
2362 void LyXFunc::setMessage(docstring const & m) const
2364 dispatch_buffer = m;
2368 docstring const LyXFunc::viewStatusMessage()
2370 // When meta-fake key is pressed, show the key sequence so far + "M-".
2372 return keyseq.print(KeySequence::ForGui) + "M-";
2374 // Else, when a non-complete key sequence is pressed,
2375 // show the available options.
2376 if (keyseq.length() > 0 && !keyseq.deleted())
2377 return keyseq.printOptions(true);
2379 BOOST_ASSERT(lyx_view_);
2380 if (!lyx_view_->buffer())
2381 return _("Welcome to LyX!");
2383 return view()->cursor().currentState();
2387 BufferView * LyXFunc::view() const
2389 BOOST_ASSERT(lyx_view_);
2390 return lyx_view_->view();
2394 bool LyXFunc::wasMetaKey() const
2396 return (meta_fake_bit != NoModifier);
2400 void LyXFunc::updateLayout(TextClassPtr const & oldlayout,
2403 lyx_view_->message(_("Converting document to new document class..."));
2405 StableDocIterator backcur(view()->cursor());
2406 ErrorList & el = buffer->errorList("Class Switch");
2407 cap::switchBetweenClasses(
2408 oldlayout, buffer->params().getTextClassPtr(),
2409 static_cast<InsetText &>(buffer->inset()), el);
2411 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
2413 buffer->errors("Class Switch");
2414 updateLabels(*buffer);
2420 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2422 // Why the switch you might ask. It is a trick to ensure that all
2423 // the elements in the LyXRCTags enum is handled. As you can see
2424 // there are no breaks at all. So it is just a huge fall-through.
2425 // The nice thing is that we will get a warning from the compiler
2426 // if we forget an element.
2427 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2429 case LyXRC::RC_ACCEPT_COMPOUND:
2430 case LyXRC::RC_ALT_LANG:
2431 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
2432 case LyXRC::RC_PLAINTEXT_LINELEN:
2433 case LyXRC::RC_AUTOREGIONDELETE:
2434 case LyXRC::RC_AUTORESET_OPTIONS:
2435 case LyXRC::RC_AUTOSAVE:
2436 case LyXRC::RC_AUTO_NUMBER:
2437 case LyXRC::RC_BACKUPDIR_PATH:
2438 case LyXRC::RC_BIBTEX_COMMAND:
2439 case LyXRC::RC_BINDFILE:
2440 case LyXRC::RC_CHECKLASTFILES:
2441 case LyXRC::RC_USELASTFILEPOS:
2442 case LyXRC::RC_LOADSESSION:
2443 case LyXRC::RC_CHKTEX_COMMAND:
2444 case LyXRC::RC_CONVERTER:
2445 case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
2446 case LyXRC::RC_COPIER:
2447 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2448 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2449 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2450 case LyXRC::RC_DATE_INSERT_FORMAT:
2451 case LyXRC::RC_DEFAULT_LANGUAGE:
2452 case LyXRC::RC_DEFAULT_PAPERSIZE:
2453 case LyXRC::RC_DEFFILE:
2454 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2455 case LyXRC::RC_DISPLAY_GRAPHICS:
2456 case LyXRC::RC_DOCUMENTPATH:
2457 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2458 FileName path(lyxrc_new.document_path);
2459 if (path.exists() && path.isDirectory())
2460 support::package().document_dir() = FileName(lyxrc.document_path);
2462 case LyXRC::RC_ESC_CHARS:
2463 case LyXRC::RC_FONT_ENCODING:
2464 case LyXRC::RC_FORMAT:
2465 case LyXRC::RC_INDEX_COMMAND:
2466 case LyXRC::RC_INPUT:
2467 case LyXRC::RC_KBMAP:
2468 case LyXRC::RC_KBMAP_PRIMARY:
2469 case LyXRC::RC_KBMAP_SECONDARY:
2470 case LyXRC::RC_LABEL_INIT_LENGTH:
2471 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2472 case LyXRC::RC_LANGUAGE_AUTO_END:
2473 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2474 case LyXRC::RC_LANGUAGE_COMMAND_END:
2475 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2476 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2477 case LyXRC::RC_LANGUAGE_PACKAGE:
2478 case LyXRC::RC_LANGUAGE_USE_BABEL:
2479 case LyXRC::RC_MAKE_BACKUP:
2480 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2481 case LyXRC::RC_NUMLASTFILES:
2482 case LyXRC::RC_PATH_PREFIX:
2483 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2484 support::prependEnvPath("PATH", lyxrc.path_prefix);
2486 case LyXRC::RC_PERS_DICT:
2487 case LyXRC::RC_PREVIEW:
2488 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2489 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2490 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2491 case LyXRC::RC_PRINTCOPIESFLAG:
2492 case LyXRC::RC_PRINTER:
2493 case LyXRC::RC_PRINTEVENPAGEFLAG:
2494 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2495 case LyXRC::RC_PRINTFILEEXTENSION:
2496 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2497 case LyXRC::RC_PRINTODDPAGEFLAG:
2498 case LyXRC::RC_PRINTPAGERANGEFLAG:
2499 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2500 case LyXRC::RC_PRINTPAPERFLAG:
2501 case LyXRC::RC_PRINTREVERSEFLAG:
2502 case LyXRC::RC_PRINTSPOOL_COMMAND:
2503 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2504 case LyXRC::RC_PRINTTOFILE:
2505 case LyXRC::RC_PRINTTOPRINTER:
2506 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2507 case LyXRC::RC_PRINT_COMMAND:
2508 case LyXRC::RC_RTL_SUPPORT:
2509 case LyXRC::RC_SCREEN_DPI:
2510 case LyXRC::RC_SCREEN_FONT_ROMAN:
2511 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2512 case LyXRC::RC_SCREEN_FONT_SANS:
2513 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2514 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2515 case LyXRC::RC_SCREEN_FONT_SIZES:
2516 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2517 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2518 case LyXRC::RC_GEOMETRY_SESSION:
2519 case LyXRC::RC_SCREEN_ZOOM:
2520 case LyXRC::RC_SERVERPIPE:
2521 case LyXRC::RC_SET_COLOR:
2522 case LyXRC::RC_SHOW_BANNER:
2523 case LyXRC::RC_SPELL_COMMAND:
2524 case LyXRC::RC_TEMPDIRPATH:
2525 case LyXRC::RC_TEMPLATEPATH:
2526 case LyXRC::RC_TEX_ALLOWS_SPACES:
2527 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2528 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2529 support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2531 case LyXRC::RC_UIFILE:
2532 case LyXRC::RC_USER_EMAIL:
2533 case LyXRC::RC_USER_NAME:
2534 case LyXRC::RC_USETEMPDIR:
2535 case LyXRC::RC_USE_ALT_LANG:
2536 case LyXRC::RC_USE_CONVERTER_CACHE:
2537 case LyXRC::RC_USE_ESC_CHARS:
2538 case LyXRC::RC_USE_INP_ENC:
2539 case LyXRC::RC_USE_PERS_DICT:
2540 case LyXRC::RC_USE_PIXMAP_CACHE:
2541 case LyXRC::RC_USE_SPELL_LIB:
2542 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2543 case LyXRC::RC_SORT_LAYOUTS:
2544 case LyXRC::RC_VIEWER:
2545 case LyXRC::RC_LAST: