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/alert.h"
78 #include "frontends/Application.h"
79 #include "frontends/FileDialog.h"
80 #include "frontends/FontLoader.h"
81 #include "frontends/KeySymbol.h"
82 #include "frontends/LyXView.h"
83 #include "frontends/Selection.h"
85 #include "support/environment.h"
86 #include "support/FileFilterList.h"
87 #include "support/filetools.h"
88 #include "support/lstrings.h"
89 #include "support/Path.h"
90 #include "support/Package.h"
91 #include "support/Systemcall.h"
92 #include "support/convert.h"
93 #include "support/os.h"
95 #include <boost/current_function.hpp>
100 using std::make_pair;
103 using std::istringstream;
104 using std::ostringstream;
110 using frontend::LyXView;
112 using support::absolutePath;
113 using support::addName;
114 using support::addPath;
115 using support::bformat;
116 using support::changeExtension;
117 using support::contains;
118 using support::FileFilterList;
119 using support::FileName;
120 using support::fileSearch;
121 using support::i18nLibFileSearch;
122 using support::makeDisplayPath;
123 using support::makeAbsPath;
124 using support::package;
125 using support::quoteName;
126 using support::rtrim;
127 using support::split;
128 using support::subst;
129 using support::Systemcall;
130 using support::token;
132 using support::prefixIs;
135 namespace Alert = frontend::Alert;
137 extern bool quitting;
143 bool import(LyXView * lv, FileName const & filename,
144 string const & format, ErrorList & errorList)
146 docstring const displaypath = makeDisplayPath(filename.absFilename());
147 lv->message(bformat(_("Importing %1$s..."), displaypath));
149 FileName const lyxfile(changeExtension(filename.absFilename(), ".lyx"));
151 string loader_format;
152 vector<string> loaders = theConverters().loaders();
153 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
154 for (vector<string>::const_iterator it = loaders.begin();
155 it != loaders.end(); ++it) {
156 if (theConverters().isReachable(format, *it)) {
157 string const tofile =
158 changeExtension(filename.absFilename(),
159 formats.extension(*it));
160 if (!theConverters().convert(0, filename, FileName(tofile),
161 filename, format, *it, errorList))
167 if (loader_format.empty()) {
168 frontend::Alert::error(_("Couldn't import file"),
169 bformat(_("No information for importing the format %1$s."),
170 formats.prettyName(format)));
174 loader_format = format;
178 if (loader_format == "lyx") {
179 Buffer * buf = lv->loadLyXFile(lyxfile);
182 lv->message(_("file not imported!"));
189 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
194 bool as_paragraphs = loader_format == "textparagraph";
195 string filename2 = (loader_format == format) ? filename.absFilename()
196 : changeExtension(filename.absFilename(),
197 formats.extension(loader_format));
198 lv->view()->insertPlaintextFile(filename2, as_paragraphs);
199 lv->dispatch(FuncRequest(LFUN_MARK_OFF));
203 lv->message(_("imported."));
209 // This function runs "configure" and then rereads lyx.defaults to
210 // reconfigure the automatic settings.
211 void reconfigure(LyXView & lv, string const & option)
213 // emit message signal.
214 lv.message(_("Running configure..."));
216 // Run configure in user lyx directory
217 support::PathChanger p(package().user_support());
218 string configure_command = package().configure_command();
219 configure_command += option;
221 int ret = one.startscript(Systemcall::Wait, configure_command);
223 // emit message signal.
224 lv.message(_("Reloading configuration..."));
225 lyxrc.read(support::libFileSearch(string(), "lyxrc.defaults"));
226 // Re-read packages.lst
227 LaTeXFeatures::getAvailable();
230 Alert::information(_("System reconfiguration failed"),
231 _("The system reconfiguration has failed.\n"
232 "Default textclass is used but LyX may "
233 "not be able to work properly.\n"
234 "Please reconfigure again if needed."));
237 Alert::information(_("System reconfigured"),
238 _("The system has been reconfigured.\n"
239 "You need to restart LyX to make use of any\n"
240 "updated document class specifications."));
244 bool getLocalStatus(Cursor cursor, FuncRequest const & cmd, FuncStatus & status)
246 // Try to fix cursor in case it is broken.
247 cursor.fixIfBroken();
249 // This is, of course, a mess. Better create a new doc iterator and use
250 // this in Inset::getStatus. This might require an additional
251 // BufferView * arg, though (which should be avoided)
252 //Cursor safe = *this;
254 for ( ; cursor.depth(); cursor.pop()) {
255 //lyxerr << "\nCursor::getStatus: cmd: " << cmd << endl << *this << endl;
256 BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
257 BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
258 BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
260 // The inset's getStatus() will return 'true' if it made
261 // a definitive decision on whether it want to handle the
262 // request or not. The result of this decision is put into
263 // the 'status' parameter.
264 if (cursor.inset().getStatus(cursor, cmd, status)) {
273 /** Return the change status at cursor position, taking in account the
274 * status at each level of the document iterator (a table in a deleted
275 * footnote is deleted).
276 * When \param outer is true, the top slice is not looked at.
278 Change::Type lookupChangeType(DocIterator const & dit, bool outer = false)
280 size_t const depth = dit.depth() - (outer ? 1 : 0);
282 for (size_t i = 0 ; i < depth ; ++i) {
283 CursorSlice const & slice = dit[i];
284 if (!slice.inset().inMathed()
285 && slice.pos() < slice.paragraph().size()) {
286 Change::Type const ch = slice.paragraph().lookupChange(slice.pos()).type;
287 if (ch != Change::UNCHANGED)
291 return Change::UNCHANGED;
298 : lyx_view_(0), encoded_last_key(0), meta_fake_bit(NoModifier)
303 void LyXFunc::initKeySequences(KeyMap * kb)
305 keyseq = KeySequence(kb, kb);
306 cancel_meta_seq = KeySequence(kb, kb);
310 void LyXFunc::setLyXView(LyXView * lv)
312 if (!quitting && lyx_view_ && lyx_view_->view() && lyx_view_ != lv)
313 // save current selection to the selection buffer to allow
314 // middle-button paste in another window
315 cap::saveSelection(lyx_view_->view()->cursor());
320 void LyXFunc::handleKeyFunc(kb_action action)
322 char_type c = encoded_last_key;
327 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
328 lyx_view_->view()->getIntl().getTransManager().deadkey(
329 c, get_accent(action).accent, view()->cursor().innerText(), view()->cursor());
330 // Need to clear, in case the minibuffer calls these
333 // copied verbatim from do_accent_char
334 view()->cursor().resetAnchor();
335 view()->processUpdateFlags(Update::FitCursor);
339 void LyXFunc::gotoBookmark(unsigned int idx, bool openFile, bool switchToBuffer)
341 BOOST_ASSERT(lyx_view_);
342 if (!LyX::ref().session().bookmarks().isValid(idx))
344 BookmarksSection::Bookmark const & bm = LyX::ref().session().bookmarks().bookmark(idx);
345 BOOST_ASSERT(!bm.filename.empty());
346 string const file = bm.filename.absFilename();
347 // if the file is not opened, open it.
348 if (!theBufferList().exists(file)) {
350 dispatch(FuncRequest(LFUN_FILE_OPEN, file));
354 // open may fail, so we need to test it again
355 if (!theBufferList().exists(file))
358 // if the current buffer is not that one, switch to it.
359 if (lyx_view_->buffer()->absFileName() != file) {
362 dispatch(FuncRequest(LFUN_BUFFER_SWITCH, file));
364 // moveToPosition try paragraph id first and then paragraph (pit, pos).
365 if (!view()->moveToPosition(bm.bottom_pit, bm.bottom_pos,
366 bm.top_id, bm.top_pos))
369 // Cursor jump succeeded!
370 Cursor const & cur = view()->cursor();
371 pit_type new_pit = cur.pit();
372 pos_type new_pos = cur.pos();
373 int new_id = cur.paragraph().id();
375 // if bottom_pit, bottom_pos or top_id has been changed, update bookmark
376 // see http://bugzilla.lyx.org/show_bug.cgi?id=3092
377 if (bm.bottom_pit != new_pit || bm.bottom_pos != new_pos
378 || bm.top_id != new_id) {
379 const_cast<BookmarksSection::Bookmark &>(bm).updatePos(
380 new_pit, new_pos, new_id);
385 void LyXFunc::processKeySym(KeySymbol const & keysym, KeyModifier state)
387 LYXERR(Debug::KEY, "KeySym is " << keysym.getSymbolName());
389 // Do nothing if we have nothing (JMarc)
390 if (!keysym.isOK()) {
391 LYXERR(Debug::KEY, "Empty kbd action (probably composing)");
392 lyx_view_->restartCursor();
396 if (keysym.isModifier()) {
397 LYXERR(Debug::KEY, "isModifier true");
398 lyx_view_->restartCursor();
402 //Encoding const * encoding = view()->cursor().getEncoding();
403 //encoded_last_key = keysym.getISOEncoded(encoding ? encoding->name() : "");
404 // FIXME: encoded_last_key shadows the member variable of the same
405 // name. Is that intended?
406 char_type encoded_last_key = keysym.getUCSEncoded();
408 // Do a one-deep top-level lookup for
409 // cancel and meta-fake keys. RVDK_PATCH_5
410 cancel_meta_seq.reset();
412 FuncRequest func = cancel_meta_seq.addkey(keysym, state);
413 LYXERR(Debug::KEY, BOOST_CURRENT_FUNCTION
414 << " action first set to [" << func.action << ']');
416 // When not cancel or meta-fake, do the normal lookup.
417 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
418 // Mostly, meta_fake_bit = NoModifier. RVDK_PATCH_5.
419 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_PREFIX)) {
420 // remove Caps Lock and Mod2 as a modifiers
421 func = keyseq.addkey(keysym, (state | meta_fake_bit));
422 LYXERR(Debug::KEY, BOOST_CURRENT_FUNCTION
423 << "action now set to [" << func.action << ']');
426 // Dont remove this unless you know what you are doing.
427 meta_fake_bit = NoModifier;
429 // Can this happen now ?
430 if (func.action == LFUN_NOACTION)
431 func = FuncRequest(LFUN_COMMAND_PREFIX);
433 LYXERR(Debug::KEY, BOOST_CURRENT_FUNCTION
434 << " Key [action=" << func.action << "]["
435 << to_utf8(keyseq.print(KeySequence::Portable)) << ']');
437 // already here we know if it any point in going further
438 // why not return already here if action == -1 and
439 // num_bytes == 0? (Lgb)
441 if (keyseq.length() > 1)
442 lyx_view_->message(keyseq.print(KeySequence::ForGui));
445 // Maybe user can only reach the key via holding down shift.
446 // Let's see. But only if shift is the only modifier
447 if (func.action == LFUN_UNKNOWN_ACTION && state == ShiftModifier) {
448 LYXERR(Debug::KEY, "Trying without shift");
449 func = keyseq.addkey(keysym, NoModifier);
450 LYXERR(Debug::KEY, "Action now " << func.action);
453 if (func.action == LFUN_UNKNOWN_ACTION) {
454 // Hmm, we didn't match any of the keysequences. See
455 // if it's normal insertable text not already covered
457 if (keysym.isText() && keyseq.length() == 1) {
458 LYXERR(Debug::KEY, "isText() is true, inserting.");
459 func = FuncRequest(LFUN_SELF_INSERT,
460 FuncRequest::KEYBOARD);
462 LYXERR(Debug::KEY, "Unknown, !isText() - giving up");
463 lyx_view_->message(_("Unknown function."));
464 lyx_view_->restartCursor();
469 if (func.action == LFUN_SELF_INSERT) {
470 if (encoded_last_key != 0) {
471 docstring const arg(1, encoded_last_key);
472 dispatch(FuncRequest(LFUN_SELF_INSERT, arg,
473 FuncRequest::KEYBOARD));
474 LYXERR(Debug::KEY, "SelfInsert arg[`" << to_utf8(arg) << "']");
480 lyx_view_->restartCursor();
484 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
486 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
489 /* In LyX/Mac, when a dialog is open, the menus of the
490 application can still be accessed without giving focus to
491 the main window. In this case, we want to disable the menu
492 entries that are buffer-related.
494 Note that this code is not perfect, as bug 1941 attests:
495 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
497 Buffer * buf = lyx_view_? lyx_view_->buffer() : 0;
498 if (lyx_view_ && cmd.origin == FuncRequest::MENU && !lyx_view_->hasFocus())
501 if (cmd.action == LFUN_NOACTION) {
502 flag.message(from_utf8(N_("Nothing to do")));
507 switch (cmd.action) {
508 case LFUN_UNKNOWN_ACTION:
509 #ifndef HAVE_LIBAIKSAURUS
510 case LFUN_THESAURUS_ENTRY:
520 if (flag.unknown()) {
521 flag.message(from_utf8(N_("Unknown action")));
525 if (!flag.enabled()) {
526 if (flag.message().empty())
527 flag.message(from_utf8(N_("Command disabled")));
531 // Check whether we need a buffer
532 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
534 flag.message(from_utf8(N_("Command not allowed with"
535 "out any document open")));
540 // I would really like to avoid having this switch and rather try to
541 // encode this in the function itself.
542 // -- And I'd rather let an inset decide which LFUNs it is willing
543 // to handle (Andre')
545 switch (cmd.action) {
546 case LFUN_BUFFER_TOGGLE_READ_ONLY:
547 flag.setOnOff(buf->isReadonly());
550 case LFUN_BUFFER_SWITCH:
551 // toggle on the current buffer, but do not toggle off
552 // the other ones (is that a good idea?)
553 if (buf && to_utf8(cmd.argument()) == buf->absFileName())
557 case LFUN_BUFFER_EXPORT:
558 enable = cmd.argument() == "custom"
559 || buf->isExportable(to_utf8(cmd.argument()));
562 case LFUN_BUFFER_CHKTEX:
563 enable = buf->isLatex() && !lyxrc.chktex_command.empty();
566 case LFUN_BUILD_PROGRAM:
567 enable = buf->isExportable("program");
570 case LFUN_VC_REGISTER:
571 enable = !buf->lyxvc().inUse();
573 case LFUN_VC_CHECK_IN:
574 enable = buf->lyxvc().inUse() && !buf->isReadonly();
576 case LFUN_VC_CHECK_OUT:
577 enable = buf->lyxvc().inUse() && buf->isReadonly();
580 case LFUN_VC_UNDO_LAST:
581 enable = buf->lyxvc().inUse();
583 case LFUN_BUFFER_RELOAD:
584 enable = !buf->isUnnamed() && buf->fileName().exists()
585 && (!buf->isClean() || buf->isExternallyModified(Buffer::timestamp_method));
588 case LFUN_INSET_APPLY: {
593 string const name = cmd.getArg(0);
594 Inset * inset = lyx_view_->getOpenInset(name);
596 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
598 if (!inset->getStatus(view()->cursor(), fr, fs)) {
599 // Every inset is supposed to handle this
604 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
605 flag |= getStatus(fr);
607 enable = flag.enabled();
611 case LFUN_DIALOG_TOGGLE:
612 flag.setOnOff(lyx_view_->isDialogVisible(cmd.getArg(0)));
613 // fall through to set "enable"
614 case LFUN_DIALOG_SHOW: {
615 string const name = cmd.getArg(0);
617 enable = name == "aboutlyx"
618 || name == "file" //FIXME: should be removed.
620 || name == "texinfo";
621 else if (name == "print")
622 enable = buf->isExportable("dvi")
623 && lyxrc.print_command != "none";
624 else if (name == "character") {
628 InsetCode ic = view()->cursor().inset().lyxCode();
629 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
632 else if (name == "latexlog")
633 enable = FileName(buf->logName()).isFileReadable();
634 else if (name == "spellchecker")
635 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
636 enable = !buf->isReadonly();
640 else if (name == "vclog")
641 enable = buf->lyxvc().inUse();
645 case LFUN_DIALOG_UPDATE: {
646 string const name = cmd.getArg(0);
648 enable = name == "prefs";
652 case LFUN_CITATION_INSERT: {
653 FuncRequest fr(LFUN_INSET_INSERT, "citation");
654 enable = getStatus(fr).enabled();
658 case LFUN_BUFFER_WRITE: {
659 enable = lyx_view_->buffer()->isUnnamed()
660 || !lyx_view_->buffer()->isClean();
665 case LFUN_BUFFER_WRITE_ALL: {
666 // We enable the command only if there are some modified buffers
667 Buffer * first = theBufferList().first();
668 bool modified = false;
672 // We cannot use a for loop as the buffer list is a cycle.
678 b = theBufferList().next(b);
679 } while (b != first);
687 case LFUN_BOOKMARK_GOTO: {
688 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
689 enable = LyX::ref().session().bookmarks().isValid(num);
693 case LFUN_BOOKMARK_CLEAR:
694 enable = LyX::ref().session().bookmarks().size() > 0;
697 case LFUN_TOOLBAR_TOGGLE: {
698 bool const current = lyx_view_->isToolbarVisible(cmd.getArg(0));
699 flag.setOnOff(current);
702 case LFUN_WINDOW_CLOSE: {
703 enable = theApp()->viewCount() > 0;
707 // this one is difficult to get right. As a half-baked
708 // solution, we consider only the first action of the sequence
709 case LFUN_COMMAND_SEQUENCE: {
710 // argument contains ';'-terminated commands
711 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
712 FuncRequest func(lyxaction.lookupFunc(firstcmd));
713 func.origin = cmd.origin;
714 flag = getStatus(func);
720 std::string name = to_utf8(cmd.argument());
721 if (LyX::ref().topLevelCmdDef().lock(name, func)) {
722 func.origin = cmd.origin;
723 flag = getStatus(func);
724 LyX::ref().topLevelCmdDef().release(name);
726 // catch recursion or unknown command definiton
727 // all operations until the recursion or unknown command
728 // definiton occures are performed, so set the state to enabled
734 case LFUN_BUFFER_NEW:
735 case LFUN_BUFFER_NEW_TEMPLATE:
736 case LFUN_WORD_FIND_FORWARD:
737 case LFUN_WORD_FIND_BACKWARD:
738 case LFUN_COMMAND_PREFIX:
739 case LFUN_COMMAND_EXECUTE:
741 case LFUN_META_PREFIX:
742 case LFUN_BUFFER_CLOSE:
743 case LFUN_BUFFER_WRITE_AS:
744 case LFUN_BUFFER_UPDATE:
745 case LFUN_BUFFER_VIEW:
746 case LFUN_MASTER_BUFFER_UPDATE:
747 case LFUN_MASTER_BUFFER_VIEW:
748 case LFUN_BUFFER_IMPORT:
749 case LFUN_BUFFER_AUTO_SAVE:
750 case LFUN_RECONFIGURE:
754 case LFUN_DROP_LAYOUTS_CHOICE:
756 case LFUN_SERVER_GET_NAME:
757 case LFUN_SERVER_NOTIFY:
758 case LFUN_SERVER_GOTO_FILE_ROW:
759 case LFUN_DIALOG_HIDE:
760 case LFUN_DIALOG_DISCONNECT_INSET:
761 case LFUN_BUFFER_CHILD_OPEN:
762 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
763 case LFUN_KEYMAP_OFF:
764 case LFUN_KEYMAP_PRIMARY:
765 case LFUN_KEYMAP_SECONDARY:
766 case LFUN_KEYMAP_TOGGLE:
768 case LFUN_BUFFER_EXPORT_CUSTOM:
769 case LFUN_BUFFER_PRINT:
770 case LFUN_PREFERENCES_SAVE:
771 case LFUN_SCREEN_FONT_UPDATE:
774 case LFUN_EXTERNAL_EDIT:
775 case LFUN_GRAPHICS_EDIT:
776 case LFUN_ALL_INSETS_TOGGLE:
777 case LFUN_BUFFER_LANGUAGE:
778 case LFUN_TEXTCLASS_APPLY:
779 case LFUN_TEXTCLASS_LOAD:
780 case LFUN_BUFFER_SAVE_AS_DEFAULT:
781 case LFUN_BUFFER_PARAMS_APPLY:
782 case LFUN_LAYOUT_MODULES_CLEAR:
783 case LFUN_LAYOUT_MODULE_ADD:
784 case LFUN_LAYOUT_RELOAD:
785 case LFUN_LYXRC_APPLY:
786 case LFUN_BUFFER_NEXT:
787 case LFUN_BUFFER_PREVIOUS:
788 case LFUN_WINDOW_NEW:
790 // these are handled in our dispatch()
798 if (!getLocalStatus(view()->cursor(), cmd, flag))
799 flag = view()->getStatus(cmd);
805 // Can we use a readonly buffer?
806 if (buf && buf->isReadonly()
807 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
808 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
809 flag.message(from_utf8(N_("Document is read-only")));
813 // Are we in a DELETED change-tracking region?
815 && lookupChangeType(view()->cursor(), true) == Change::DELETED
816 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
817 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
818 flag.message(from_utf8(N_("This portion of the document is deleted.")));
822 // the default error message if we disable the command
823 if (!flag.enabled() && flag.message().empty())
824 flag.message(from_utf8(N_("Command disabled")));
830 bool LyXFunc::ensureBufferClean(BufferView * bv)
832 Buffer & buf = bv->buffer();
836 docstring const file = buf.fileName().displayName(30);
837 docstring text = bformat(_("The document %1$s has unsaved "
838 "changes.\n\nDo you want to save "
839 "the document?"), file);
840 int const ret = Alert::prompt(_("Save changed document?"),
841 text, 0, 1, _("&Save"),
845 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
847 return buf.isClean();
853 void showPrintError(string const & name)
855 docstring str = bformat(_("Could not print the document %1$s.\n"
856 "Check that your printer is set up correctly."),
857 makeDisplayPath(name, 50));
858 Alert::error(_("Print document failed"), str);
862 void loadTextClass(string const & name)
864 std::pair<bool, textclass_type> const tc_pair =
865 textclasslist.numberOfClass(name);
867 if (!tc_pair.first) {
868 lyxerr << "Document class \"" << name
869 << "\" does not exist."
874 textclass_type const tc = tc_pair.second;
876 if (!textclasslist[tc].load()) {
877 docstring s = bformat(_("The document class %1$s."
878 "could not be loaded."),
879 from_utf8(textclasslist[tc].name()));
880 Alert::error(_("Could not load class"), s);
885 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
890 void LyXFunc::dispatch(FuncRequest const & cmd)
892 string const argument = to_utf8(cmd.argument());
893 kb_action const action = cmd.action;
895 LYXERR(Debug::ACTION, "\nLyXFunc::dispatch: cmd: " << cmd);
896 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
898 // we have not done anything wrong yet.
900 dispatch_buffer.erase();
902 // redraw the screen at the end (first of the two drawing steps).
903 //This is done unless explicitely requested otherwise
904 Update::flags updateFlags = Update::FitCursor;
906 FuncStatus const flag = getStatus(cmd);
907 if (!flag.enabled()) {
908 // We cannot use this function here
909 LYXERR(Debug::ACTION, "LyXFunc::dispatch: "
910 << lyxaction.getActionName(action)
911 << " [" << action << "] is disabled at this location");
912 setErrorMessage(flag.message());
915 // Let lyx_view_ dispatch its own actions.
916 case LFUN_COMMAND_EXECUTE:
917 case LFUN_DROP_LAYOUTS_CHOICE:
919 case LFUN_TOOLBAR_TOGGLE:
920 BOOST_ASSERT(lyx_view_);
921 lyx_view_->dispatch(cmd);
924 case LFUN_WORD_FIND_FORWARD:
925 case LFUN_WORD_FIND_BACKWARD: {
926 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
927 static docstring last_search;
928 docstring searched_string;
930 if (!cmd.argument().empty()) {
931 last_search = cmd.argument();
932 searched_string = cmd.argument();
934 searched_string = last_search;
937 if (searched_string.empty())
940 bool const fw = action == LFUN_WORD_FIND_FORWARD;
941 docstring const data =
942 find2string(searched_string, true, false, fw);
943 find(view(), FuncRequest(LFUN_WORD_FIND, data));
947 case LFUN_COMMAND_PREFIX:
948 BOOST_ASSERT(lyx_view_);
949 lyx_view_->message(keyseq.printOptions(true));
953 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
955 meta_fake_bit = NoModifier;
956 if (lyx_view_->buffer())
957 // cancel any selection
958 dispatch(FuncRequest(LFUN_MARK_OFF));
959 setMessage(from_ascii(N_("Cancel")));
962 case LFUN_META_PREFIX:
963 meta_fake_bit = AltModifier;
964 setMessage(keyseq.print(KeySequence::ForGui));
967 case LFUN_BUFFER_TOGGLE_READ_ONLY: {
968 BOOST_ASSERT(lyx_view_ && lyx_view_->view() && lyx_view_->buffer());
969 Buffer * buf = lyx_view_->buffer();
970 if (buf->lyxvc().inUse())
971 buf->lyxvc().toggleReadOnly();
973 buf->setReadonly(!lyx_view_->buffer()->isReadonly());
977 // --- Menus -----------------------------------------------
978 case LFUN_BUFFER_NEW:
979 menuNew(argument, false);
980 updateFlags = Update::None;
983 case LFUN_BUFFER_NEW_TEMPLATE:
984 menuNew(argument, true);
985 updateFlags = Update::None;
988 case LFUN_BUFFER_CLOSE:
990 updateFlags = Update::None;
993 case LFUN_BUFFER_WRITE:
994 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
995 if (!lyx_view_->buffer()->isUnnamed()) {
996 docstring const str = bformat(_("Saving document %1$s..."),
997 makeDisplayPath(lyx_view_->buffer()->absFileName()));
998 lyx_view_->message(str);
999 lyx_view_->buffer()->menuWrite();
1000 lyx_view_->message(str + _(" done."));
1002 lyx_view_->buffer()->writeAs();
1004 updateFlags = Update::None;
1007 case LFUN_BUFFER_WRITE_AS:
1008 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1009 lyx_view_->buffer()->writeAs(argument);
1010 updateFlags = Update::None;
1013 case LFUN_BUFFER_WRITE_ALL: {
1014 Buffer * first = theBufferList().first();
1017 lyx_view_->message(_("Saving all documents..."));
1019 // We cannot use a for loop as the buffer list cycles.
1021 if (!b->isClean()) {
1022 if (!b->isUnnamed()) {
1024 lyxerr[Debug::ACTION] << "Saved " << b->absFileName() << endl;
1028 b = theBufferList().next(b);
1029 } while (b != first);
1030 lyx_view_->message(_("All documents saved."));
1033 updateFlags = Update::None;
1037 case LFUN_BUFFER_RELOAD: {
1038 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1039 docstring const file = makeDisplayPath(lyx_view_->buffer()->absFileName(), 20);
1040 docstring text = bformat(_("Any changes will be lost. Are you sure "
1041 "you want to revert to the saved version of the document %1$s?"), file);
1042 int const ret = Alert::prompt(_("Revert to saved document?"),
1043 text, 1, 1, _("&Revert"), _("&Cancel"));
1050 case LFUN_BUFFER_UPDATE:
1051 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1052 lyx_view_->buffer()->doExport(argument, true);
1055 case LFUN_BUFFER_VIEW:
1056 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1057 lyx_view_->buffer()->preview(argument);
1060 case LFUN_MASTER_BUFFER_UPDATE:
1061 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->masterBuffer());
1062 lyx_view_->buffer()->masterBuffer()->doExport(argument, true);
1065 case LFUN_MASTER_BUFFER_VIEW:
1066 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->masterBuffer());
1067 lyx_view_->buffer()->masterBuffer()->preview(argument);
1070 case LFUN_BUILD_PROGRAM:
1071 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1072 lyx_view_->buffer()->doExport("program", true);
1075 case LFUN_BUFFER_CHKTEX:
1076 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1077 lyx_view_->buffer()->runChktex();
1080 case LFUN_BUFFER_EXPORT:
1081 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1082 if (argument == "custom")
1083 lyx_view_->showDialog("sendto");
1085 lyx_view_->buffer()->doExport(argument, false);
1088 case LFUN_BUFFER_EXPORT_CUSTOM: {
1089 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1091 string command = split(argument, format_name, ' ');
1092 Format const * format = formats.getFormat(format_name);
1094 lyxerr << "Format \"" << format_name
1095 << "\" not recognized!"
1100 Buffer * buffer = lyx_view_->buffer();
1102 // The name of the file created by the conversion process
1105 // Output to filename
1106 if (format->name() == "lyx") {
1107 string const latexname = buffer->latexName(false);
1108 filename = changeExtension(latexname,
1109 format->extension());
1110 filename = addName(buffer->temppath(), filename);
1112 if (!buffer->writeFile(FileName(filename)))
1116 buffer->doExport(format_name, true, filename);
1119 // Substitute $$FName for filename
1120 if (!contains(command, "$$FName"))
1121 command = "( " + command + " ) < $$FName";
1122 command = subst(command, "$$FName", filename);
1124 // Execute the command in the background
1126 call.startscript(Systemcall::DontWait, command);
1130 case LFUN_BUFFER_PRINT: {
1131 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1132 // FIXME: cmd.getArg() might fail if one of the arguments
1133 // contains double quotes
1134 string target = cmd.getArg(0);
1135 string target_name = cmd.getArg(1);
1136 string command = cmd.getArg(2);
1139 || target_name.empty()
1140 || command.empty()) {
1141 lyxerr << "Unable to parse \""
1142 << argument << '"' << endl;
1145 if (target != "printer" && target != "file") {
1146 lyxerr << "Unrecognized target \""
1147 << target << '"' << endl;
1151 Buffer * buffer = lyx_view_->buffer();
1153 if (!buffer->doExport("dvi", true)) {
1154 showPrintError(buffer->absFileName());
1158 // Push directory path.
1159 string const path = buffer->temppath();
1160 // Prevent the compiler from optimizing away p
1162 support::PathChanger p(pp);
1164 // there are three cases here:
1165 // 1. we print to a file
1166 // 2. we print directly to a printer
1167 // 3. we print using a spool command (print to file first)
1170 string const dviname =
1171 changeExtension(buffer->latexName(true), "dvi");
1173 if (target == "printer") {
1174 if (!lyxrc.print_spool_command.empty()) {
1175 // case 3: print using a spool
1176 string const psname =
1177 changeExtension(dviname,".ps");
1178 command += ' ' + lyxrc.print_to_file
1181 + quoteName(dviname);
1184 lyxrc.print_spool_command + ' ';
1185 if (target_name != "default") {
1186 command2 += lyxrc.print_spool_printerprefix
1190 command2 += quoteName(psname);
1192 // If successful, then spool command
1193 res = one.startscript(
1198 res = one.startscript(
1199 Systemcall::DontWait,
1202 // case 2: print directly to a printer
1203 if (target_name != "default")
1204 command += ' ' + lyxrc.print_to_printer + target_name + ' ';
1205 res = one.startscript(
1206 Systemcall::DontWait,
1207 command + quoteName(dviname));
1211 // case 1: print to a file
1212 FileName const filename(makeAbsPath(target_name,
1213 lyx_view_->buffer()->filePath()));
1214 FileName const dvifile(makeAbsPath(dviname, path));
1215 if (filename.exists()) {
1216 docstring text = bformat(
1217 _("The file %1$s already exists.\n\n"
1218 "Do you want to overwrite that file?"),
1219 makeDisplayPath(filename.absFilename()));
1220 if (Alert::prompt(_("Overwrite file?"),
1221 text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
1224 command += ' ' + lyxrc.print_to_file
1225 + quoteName(filename.toFilesystemEncoding())
1227 + quoteName(dvifile.toFilesystemEncoding());
1228 res = one.startscript(Systemcall::DontWait,
1233 showPrintError(buffer->absFileName());
1237 case LFUN_BUFFER_IMPORT:
1242 // quitting is triggered by the gui code
1243 // (leaving the event loop).
1244 lyx_view_->message(from_utf8(N_("Exiting.")));
1245 if (theBufferList().quitWriteAll())
1246 theApp()->closeAllViews();
1249 case LFUN_BUFFER_AUTO_SAVE:
1250 lyx_view_->buffer()->autoSave();
1253 case LFUN_RECONFIGURE:
1254 BOOST_ASSERT(lyx_view_);
1255 // argument is any additional parameter to the configure.py command
1256 reconfigure(*lyx_view_, argument);
1259 case LFUN_HELP_OPEN: {
1260 BOOST_ASSERT(lyx_view_);
1261 string const arg = argument;
1263 setErrorMessage(from_ascii(N_("Missing argument")));
1266 FileName const fname = i18nLibFileSearch("doc", arg, "lyx");
1267 if (fname.empty()) {
1268 lyxerr << "LyX: unable to find documentation file `"
1269 << arg << "'. Bad installation?" << endl;
1272 lyx_view_->message(bformat(_("Opening help file %1$s..."),
1273 makeDisplayPath(fname.absFilename())));
1274 Buffer * buf = lyx_view_->loadLyXFile(fname, false);
1277 lyx_view_->setBuffer(buf);
1278 lyx_view_->errors("Parse");
1280 updateFlags = Update::None;
1284 // --- version control -------------------------------
1285 case LFUN_VC_REGISTER:
1286 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1287 if (!ensureBufferClean(view()))
1289 if (!lyx_view_->buffer()->lyxvc().inUse()) {
1290 lyx_view_->buffer()->lyxvc().registrer();
1293 updateFlags = Update::Force;
1296 case LFUN_VC_CHECK_IN:
1297 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1298 if (!ensureBufferClean(view()))
1300 if (lyx_view_->buffer()->lyxvc().inUse()
1301 && !lyx_view_->buffer()->isReadonly()) {
1302 lyx_view_->buffer()->lyxvc().checkIn();
1307 case LFUN_VC_CHECK_OUT:
1308 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1309 if (!ensureBufferClean(view()))
1311 if (lyx_view_->buffer()->lyxvc().inUse()
1312 && lyx_view_->buffer()->isReadonly()) {
1313 lyx_view_->buffer()->lyxvc().checkOut();
1318 case LFUN_VC_REVERT:
1319 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1320 lyx_view_->buffer()->lyxvc().revert();
1324 case LFUN_VC_UNDO_LAST:
1325 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1326 lyx_view_->buffer()->lyxvc().undoLast();
1330 // --- buffers ----------------------------------------
1331 case LFUN_BUFFER_SWITCH:
1332 BOOST_ASSERT(lyx_view_);
1333 lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1334 updateFlags = Update::None;
1337 case LFUN_BUFFER_NEXT:
1338 BOOST_ASSERT(lyx_view_);
1339 lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer()));
1340 updateFlags = Update::None;
1343 case LFUN_BUFFER_PREVIOUS:
1344 BOOST_ASSERT(lyx_view_);
1345 lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer()));
1346 updateFlags = Update::None;
1349 case LFUN_FILE_NEW: {
1350 BOOST_ASSERT(lyx_view_);
1352 string tmpname = split(argument, name, ':'); // Split filename
1353 Buffer * const b = newFile(name, tmpname);
1355 lyx_view_->setBuffer(b);
1356 updateFlags = Update::None;
1360 case LFUN_FILE_OPEN:
1361 BOOST_ASSERT(lyx_view_);
1363 updateFlags = Update::None;
1366 // --- lyxserver commands ----------------------------
1367 case LFUN_SERVER_GET_NAME:
1368 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1369 setMessage(from_utf8(lyx_view_->buffer()->absFileName()));
1370 LYXERR(Debug::INFO, "FNAME["
1371 << lyx_view_->buffer()->absFileName() << ']');
1374 case LFUN_SERVER_NOTIFY:
1375 dispatch_buffer = keyseq.print(KeySequence::Portable);
1376 theServer().notifyClient(to_utf8(dispatch_buffer));
1379 case LFUN_SERVER_GOTO_FILE_ROW: {
1380 BOOST_ASSERT(lyx_view_);
1383 istringstream is(argument);
1384 is >> file_name >> row;
1386 bool loaded = false;
1387 if (prefixIs(file_name, package().temp_dir().absFilename()))
1388 // Needed by inverse dvi search. If it is a file
1389 // in tmpdir, call the apropriated function
1390 buf = theBufferList().getBufferFromTmp(file_name);
1392 // Must replace extension of the file to be .lyx
1393 // and get full path
1394 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1395 // Either change buffer or load the file
1396 if (theBufferList().exists(s.absFilename()))
1397 buf = theBufferList().getBuffer(s.absFilename());
1399 buf = lyx_view_->loadLyXFile(s);
1405 updateFlags = Update::None;
1410 lyx_view_->setBuffer(buf);
1411 view()->setCursorFromRow(row);
1413 lyx_view_->errors("Parse");
1414 updateFlags = Update::FitCursor;
1418 case LFUN_DIALOG_SHOW: {
1419 BOOST_ASSERT(lyx_view_);
1420 string const name = cmd.getArg(0);
1421 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1423 if (name == "character") {
1424 data = freefont2string();
1426 lyx_view_->showDialogWithData("character", data);
1427 } else if (name == "latexlog") {
1428 Buffer::LogType type;
1429 string const logfile = lyx_view_->buffer()->logName(&type);
1431 case Buffer::latexlog:
1434 case Buffer::buildlog:
1438 data += Lexer::quoteString(logfile);
1439 lyx_view_->showDialogWithData("log", data);
1440 } else if (name == "vclog") {
1441 string const data = "vc " +
1442 Lexer::quoteString(lyx_view_->buffer()->lyxvc().getLogFile());
1443 lyx_view_->showDialogWithData("log", data);
1445 lyx_view_->showDialogWithData(name, data);
1449 case LFUN_DIALOG_SHOW_NEW_INSET: {
1450 BOOST_ASSERT(lyx_view_);
1451 string const name = cmd.getArg(0);
1452 InsetCode code = insetCode(name);
1453 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1454 bool insetCodeOK = true;
1463 case HYPERLINK_CODE: {
1464 InsetCommandParams p(code);
1465 data = InsetCommandMailer::params2string(name, p);
1468 case INCLUDE_CODE: {
1469 // data is the include type: one of "include",
1470 // "input", "verbatiminput" or "verbatiminput*"
1472 // default type is requested
1474 InsetCommandParams p(INCLUDE_CODE, data);
1475 data = InsetCommandMailer::params2string("include", p);
1479 // \c data == "Boxed" || "Frameless" etc
1480 InsetBoxParams p(data);
1481 data = InsetBoxMailer::params2string(p);
1485 InsetBranchParams p;
1486 data = InsetBranchMailer::params2string(p);
1490 InsetCommandParams p(CITE_CODE);
1491 data = InsetCommandMailer::params2string(name, p);
1495 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1498 case EXTERNAL_CODE: {
1499 InsetExternalParams p;
1500 Buffer const & buffer = *lyx_view_->buffer();
1501 data = InsetExternalMailer::params2string(p, buffer);
1506 data = InsetFloatMailer::params2string(p);
1509 case LISTINGS_CODE: {
1510 InsetListingsParams p;
1511 data = InsetListingsMailer::params2string(p);
1514 case GRAPHICS_CODE: {
1515 InsetGraphicsParams p;
1516 Buffer const & buffer = *lyx_view_->buffer();
1517 data = InsetGraphicsMailer::params2string(p, buffer);
1522 data = InsetNoteMailer::params2string(p);
1527 data = InsetVSpaceMailer::params2string(space);
1532 data = InsetWrapMailer::params2string(p);
1536 lyxerr << "Inset type '" << name <<
1537 "' not recognized in LFUN_DIALOG_SHOW_NEW_INSET" << std:: endl;
1538 insetCodeOK = false;
1540 } // end switch(code)
1542 lyx_view_->showDialog(name, data, 0);
1546 case LFUN_DIALOG_UPDATE: {
1547 BOOST_ASSERT(lyx_view_);
1548 string const & name = argument;
1549 // Can only update a dialog connected to an existing inset
1550 Inset * inset = lyx_view_->getOpenInset(name);
1552 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1553 inset->dispatch(view()->cursor(), fr);
1554 } else if (name == "paragraph") {
1555 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1556 } else if (name == "prefs") {
1557 lyx_view_->updateDialog(name, string());
1562 case LFUN_DIALOG_HIDE: {
1563 if (quitting || !use_gui)
1565 theApp()->hideDialogs(argument, 0);
1569 case LFUN_DIALOG_TOGGLE: {
1570 BOOST_ASSERT(lyx_view_);
1571 if (lyx_view_->isDialogVisible(cmd.getArg(0)))
1572 dispatch(FuncRequest(LFUN_DIALOG_HIDE, argument));
1574 dispatch(FuncRequest(LFUN_DIALOG_SHOW, argument));
1578 case LFUN_DIALOG_DISCONNECT_INSET:
1579 BOOST_ASSERT(lyx_view_);
1580 lyx_view_->disconnectDialog(argument);
1584 case LFUN_CITATION_INSERT: {
1585 BOOST_ASSERT(lyx_view_);
1586 if (!argument.empty()) {
1587 // we can have one optional argument, delimited by '|'
1588 // citation-insert <key>|<text_before>
1589 // this should be enhanced to also support text_after
1590 // and citation style
1591 string arg = argument;
1593 if (contains(argument, "|")) {
1594 arg = token(argument, '|', 0);
1595 opt1 = token(argument, '|', 1);
1597 InsetCommandParams icp(CITE_CODE);
1598 icp["key"] = from_utf8(arg);
1600 icp["before"] = from_utf8(opt1);
1601 string icstr = InsetCommandMailer::params2string("citation", icp);
1602 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1605 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1609 case LFUN_BUFFER_CHILD_OPEN: {
1610 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1611 Buffer * parent = lyx_view_->buffer();
1612 FileName filename = makeAbsPath(argument, parent->filePath());
1613 view()->saveBookmark(false);
1615 bool parsed = false;
1616 if (theBufferList().exists(filename.absFilename())) {
1617 child = theBufferList().getBuffer(filename.absFilename());
1619 setMessage(bformat(_("Opening child document %1$s..."),
1620 makeDisplayPath(filename.absFilename())));
1621 child = lyx_view_->loadLyXFile(filename, true);
1625 // Set the parent name of the child document.
1626 // This makes insertion of citations and references in the child work,
1627 // when the target is in the parent or another child document.
1628 child->setParentName(parent->absFileName());
1629 updateLabels(*child->masterBuffer());
1630 lyx_view_->setBuffer(child);
1632 lyx_view_->errors("Parse");
1635 // If a screen update is required (in case where auto_open is false),
1636 // setBuffer() would have taken care of it already. Otherwise we shall
1637 // reset the update flag because it can cause a circular problem.
1639 updateFlags = Update::None;
1643 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1644 BOOST_ASSERT(lyx_view_);
1645 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1648 case LFUN_KEYMAP_OFF:
1649 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1650 lyx_view_->view()->getIntl().keyMapOn(false);
1653 case LFUN_KEYMAP_PRIMARY:
1654 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1655 lyx_view_->view()->getIntl().keyMapPrim();
1658 case LFUN_KEYMAP_SECONDARY:
1659 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1660 lyx_view_->view()->getIntl().keyMapSec();
1663 case LFUN_KEYMAP_TOGGLE:
1664 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1665 lyx_view_->view()->getIntl().toggleKeyMap();
1671 string rest = split(argument, countstr, ' ');
1672 istringstream is(countstr);
1675 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1676 for (int i = 0; i < count; ++i)
1677 dispatch(lyxaction.lookupFunc(rest));
1681 case LFUN_COMMAND_SEQUENCE: {
1682 // argument contains ';'-terminated commands
1683 string arg = argument;
1684 while (!arg.empty()) {
1686 arg = split(arg, first, ';');
1687 FuncRequest func(lyxaction.lookupFunc(first));
1688 func.origin = cmd.origin;
1696 if (LyX::ref().topLevelCmdDef().lock(argument, func)) {
1697 func.origin = cmd.origin;
1699 LyX::ref().topLevelCmdDef().release(argument);
1701 if (func.action == LFUN_UNKNOWN_ACTION) {
1702 // unknown command definition
1703 lyxerr << "Warning: unknown command definition `"
1707 // recursion detected
1708 lyxerr << "Warning: Recursion in the command definition `"
1709 << argument << "' detected"
1716 case LFUN_PREFERENCES_SAVE: {
1717 lyxrc.write(makeAbsPath("preferences",
1718 package().user_support().absFilename()),
1723 case LFUN_SCREEN_FONT_UPDATE:
1724 BOOST_ASSERT(lyx_view_);
1725 // handle the screen font changes.
1726 theFontLoader().update();
1727 /// FIXME: only the current view will be updated. the Gui
1728 /// class is able to furnish the list of views.
1729 updateFlags = Update::Force;
1732 case LFUN_SET_COLOR: {
1734 string const x11_name = split(argument, lyx_name, ' ');
1735 if (lyx_name.empty() || x11_name.empty()) {
1736 setErrorMessage(from_ascii(N_(
1737 "Syntax: set-color <lyx_name>"
1742 bool const graphicsbg_changed =
1743 (lyx_name == lcolor.getLyXName(Color_graphicsbg) &&
1744 x11_name != lcolor.getX11Name(Color_graphicsbg));
1746 if (!lcolor.setColor(lyx_name, x11_name)) {
1748 bformat(_("Set-color \"%1$s\" failed "
1749 "- color is undefined or "
1750 "may not be redefined"),
1751 from_utf8(lyx_name)));
1755 theApp()->updateColor(lcolor.getFromLyXName(lyx_name));
1757 if (graphicsbg_changed) {
1758 // FIXME: The graphics cache no longer has a changeDisplay method.
1760 graphics::GCache::get().changeDisplay(true);
1767 BOOST_ASSERT(lyx_view_);
1768 lyx_view_->message(from_utf8(argument));
1771 case LFUN_EXTERNAL_EDIT: {
1772 BOOST_ASSERT(lyx_view_);
1773 FuncRequest fr(action, argument);
1774 InsetExternal().dispatch(view()->cursor(), fr);
1778 case LFUN_GRAPHICS_EDIT: {
1779 FuncRequest fr(action, argument);
1780 InsetGraphics().dispatch(view()->cursor(), fr);
1784 case LFUN_INSET_APPLY: {
1785 BOOST_ASSERT(lyx_view_);
1786 string const name = cmd.getArg(0);
1787 Inset * inset = lyx_view_->getOpenInset(name);
1789 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1790 inset->dispatch(view()->cursor(), fr);
1792 FuncRequest fr(LFUN_INSET_INSERT, argument);
1795 // ideally, the update flag should be set by the insets,
1796 // but this is not possible currently
1797 updateFlags = Update::Force | Update::FitCursor;
1801 case LFUN_ALL_INSETS_TOGGLE: {
1802 BOOST_ASSERT(lyx_view_);
1804 string const name = split(argument, action, ' ');
1805 InsetCode const inset_code = insetCode(name);
1807 Cursor & cur = view()->cursor();
1808 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1810 Inset & inset = lyx_view_->buffer()->inset();
1811 InsetIterator it = inset_iterator_begin(inset);
1812 InsetIterator const end = inset_iterator_end(inset);
1813 for (; it != end; ++it) {
1814 if (!it->asInsetMath()
1815 && (inset_code == NO_CODE
1816 || inset_code == it->lyxCode())) {
1817 Cursor tmpcur = cur;
1818 tmpcur.pushBackward(*it);
1819 it->dispatch(tmpcur, fr);
1822 updateFlags = Update::Force | Update::FitCursor;
1826 case LFUN_BUFFER_LANGUAGE: {
1827 BOOST_ASSERT(lyx_view_);
1828 Buffer & buffer = *lyx_view_->buffer();
1829 Language const * oldL = buffer.params().language;
1830 Language const * newL = languages.getLanguage(argument);
1831 if (!newL || oldL == newL)
1834 if (oldL->rightToLeft() == newL->rightToLeft()
1835 && !buffer.isMultiLingual())
1836 buffer.changeLanguage(oldL, newL);
1840 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1841 string const fname =
1842 addName(addPath(package().user_support().absFilename(), "templates/"),
1844 Buffer defaults(fname);
1846 istringstream ss(argument);
1849 int const unknown_tokens = defaults.readHeader(lex);
1851 if (unknown_tokens != 0) {
1852 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1853 << unknown_tokens << " unknown token"
1854 << (unknown_tokens == 1 ? "" : "s")
1858 if (defaults.writeFile(FileName(defaults.absFileName())))
1859 setMessage(bformat(_("Document defaults saved in %1$s"),
1860 makeDisplayPath(fname)));
1862 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1866 case LFUN_BUFFER_PARAMS_APPLY: {
1867 BOOST_ASSERT(lyx_view_);
1868 biblio::CiteEngine const oldEngine =
1869 lyx_view_->buffer()->params().getEngine();
1871 Buffer * buffer = lyx_view_->buffer();
1873 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1875 Cursor & cur = view()->cursor();
1876 cur.recordUndoFullDocument();
1878 istringstream ss(argument);
1881 int const unknown_tokens = buffer->readHeader(lex);
1883 if (unknown_tokens != 0) {
1884 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1885 << unknown_tokens << " unknown token"
1886 << (unknown_tokens == 1 ? "" : "s")
1890 updateLayout(oldClass, buffer);
1892 biblio::CiteEngine const newEngine =
1893 lyx_view_->buffer()->params().getEngine();
1895 if (oldEngine != newEngine) {
1896 FuncRequest fr(LFUN_INSET_REFRESH);
1898 Inset & inset = lyx_view_->buffer()->inset();
1899 InsetIterator it = inset_iterator_begin(inset);
1900 InsetIterator const end = inset_iterator_end(inset);
1901 for (; it != end; ++it)
1902 if (it->lyxCode() == CITE_CODE)
1903 it->dispatch(cur, fr);
1906 updateFlags = Update::Force | Update::FitCursor;
1910 case LFUN_LAYOUT_MODULES_CLEAR: {
1911 BOOST_ASSERT(lyx_view_);
1912 Buffer * buffer = lyx_view_->buffer();
1913 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1914 view()->cursor().recordUndoFullDocument();
1915 buffer->params().clearLayoutModules();
1916 updateLayout(oldClass, buffer);
1917 updateFlags = Update::Force | Update::FitCursor;
1921 case LFUN_LAYOUT_MODULE_ADD: {
1922 BOOST_ASSERT(lyx_view_);
1923 Buffer * buffer = lyx_view_->buffer();
1924 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1925 view()->cursor().recordUndoFullDocument();
1926 buffer->params().addLayoutModule(argument);
1927 updateLayout(oldClass, buffer);
1928 updateFlags = Update::Force | Update::FitCursor;
1932 case LFUN_TEXTCLASS_APPLY: {
1933 BOOST_ASSERT(lyx_view_);
1934 Buffer * buffer = lyx_view_->buffer();
1936 loadTextClass(argument);
1938 std::pair<bool, textclass_type> const tc_pair =
1939 textclasslist.numberOfClass(argument);
1944 textclass_type const old_class = buffer->params().getBaseClass();
1945 textclass_type const new_class = tc_pair.second;
1947 if (old_class == new_class)
1951 //Save the old, possibly modular, layout for use in conversion.
1952 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1953 view()->cursor().recordUndoFullDocument();
1954 buffer->params().setBaseClass(new_class);
1955 updateLayout(oldClass, buffer);
1956 updateFlags = Update::Force | Update::FitCursor;
1960 case LFUN_LAYOUT_RELOAD: {
1961 BOOST_ASSERT(lyx_view_);
1962 Buffer * buffer = lyx_view_->buffer();
1963 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1964 textclass_type const tc = buffer->params().getBaseClass();
1965 textclasslist.reset(tc);
1966 buffer->params().setBaseClass(tc);
1967 updateLayout(oldClass, buffer);
1968 updateFlags = Update::Force | Update::FitCursor;
1972 case LFUN_TEXTCLASS_LOAD:
1973 loadTextClass(argument);
1976 case LFUN_LYXRC_APPLY: {
1977 LyXRC const lyxrc_orig = lyxrc;
1979 istringstream ss(argument);
1980 bool const success = lyxrc.read(ss) == 0;
1983 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1984 << "Unable to read lyxrc data"
1989 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1991 if (lyx_view_ && lyx_view_->buffer())
1992 lyx_view_->updateLayoutChoice(true);
1994 /// We force the redraw in any case because there might be
1995 /// some screen font changes.
1996 /// FIXME: only the current view will be updated. the Gui
1997 /// class is able to furnish the list of views.
1998 updateFlags = Update::Force;
2002 case LFUN_WINDOW_NEW:
2003 LyX::ref().newLyXView();
2006 case LFUN_WINDOW_CLOSE:
2007 BOOST_ASSERT(lyx_view_);
2008 BOOST_ASSERT(theApp());
2009 // update bookmark pit of the current buffer before window close
2010 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2011 gotoBookmark(i+1, false, false);
2012 // ask the user for saving changes or cancel quit
2013 if (!theBufferList().quitWriteAll())
2018 case LFUN_BOOKMARK_GOTO:
2019 // go to bookmark, open unopened file and switch to buffer if necessary
2020 gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
2023 case LFUN_BOOKMARK_CLEAR:
2024 LyX::ref().session().bookmarks().clear();
2028 BOOST_ASSERT(lyx_view_);
2029 view()->cursor().dispatch(cmd);
2030 updateFlags = view()->cursor().result().update();
2031 if (!view()->cursor().result().dispatched())
2032 updateFlags = view()->dispatch(cmd);
2037 if (lyx_view_ && lyx_view_->buffer()) {
2038 // BufferView::update() updates the ViewMetricsInfo and
2039 // also initializes the position cache for all insets in
2040 // (at least partially) visible top-level paragraphs.
2041 // We will redraw the screen only if needed.
2042 view()->processUpdateFlags(updateFlags);
2043 lyx_view_->updateStatusBar();
2045 // if we executed a mutating lfun, mark the buffer as dirty
2047 && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
2048 && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
2049 lyx_view_->buffer()->markDirty();
2051 //Do we have a selection?
2052 theSelection().haveSelection(view()->cursor().selection());
2054 if (view()->cursor().inTexted()) {
2055 lyx_view_->updateLayoutChoice(false);
2059 if (!quitting && lyx_view_) {
2060 lyx_view_->updateToolbars();
2061 // Some messages may already be translated, so we cannot use _()
2062 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
2067 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
2069 const bool verbose = (cmd.origin == FuncRequest::MENU
2070 || cmd.origin == FuncRequest::TOOLBAR
2071 || cmd.origin == FuncRequest::COMMANDBUFFER);
2073 if (cmd.action == LFUN_SELF_INSERT || !verbose) {
2074 LYXERR(Debug::ACTION, "dispatch msg is " << to_utf8(msg));
2076 lyx_view_->message(msg);
2080 docstring dispatch_msg = msg;
2081 if (!dispatch_msg.empty())
2082 dispatch_msg += ' ';
2084 docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
2086 bool argsadded = false;
2088 if (!cmd.argument().empty()) {
2089 if (cmd.action != LFUN_UNKNOWN_ACTION) {
2090 comname += ' ' + cmd.argument();
2095 docstring const shortcuts = theTopLevelKeymap().printBindings(cmd);
2097 if (!shortcuts.empty())
2098 comname += ": " + shortcuts;
2099 else if (!argsadded && !cmd.argument().empty())
2100 comname += ' ' + cmd.argument();
2102 if (!comname.empty()) {
2103 comname = rtrim(comname);
2104 dispatch_msg += '(' + rtrim(comname) + ')';
2107 LYXERR(Debug::ACTION, "verbose dispatch msg " << to_utf8(dispatch_msg));
2108 if (!dispatch_msg.empty())
2109 lyx_view_->message(dispatch_msg);
2113 void LyXFunc::menuNew(string const & name, bool fromTemplate)
2115 // FIXME: initpath is not used. What to do?
2116 string initpath = lyxrc.document_path;
2117 string filename(name);
2119 if (lyx_view_->buffer()) {
2120 string const trypath = lyx_view_->buffer()->filePath();
2121 // If directory is writeable, use this as default.
2122 if (FileName(trypath).isDirWritable())
2126 static int newfile_number;
2128 if (filename.empty()) {
2129 filename = addName(lyxrc.document_path,
2130 "newfile" + convert<string>(++newfile_number) + ".lyx");
2131 while (theBufferList().exists(filename) ||
2132 FileName(filename).isReadable()) {
2134 filename = addName(lyxrc.document_path,
2135 "newfile" + convert<string>(newfile_number) +
2140 // The template stuff
2143 FileDialog dlg(_("Select template file"));
2144 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
2145 dlg.setButton1(_("Templates|#T#t"), from_utf8(lyxrc.template_path));
2147 FileDialog::Result result =
2148 dlg.open(from_utf8(lyxrc.template_path),
2149 FileFilterList(_("LyX Documents (*.lyx)")),
2152 if (result.first == FileDialog::Later)
2154 if (result.second.empty())
2156 templname = to_utf8(result.second);
2159 Buffer * const b = newFile(filename, templname, !name.empty());
2161 lyx_view_->setBuffer(b);
2165 void LyXFunc::open(string const & fname)
2167 string initpath = lyxrc.document_path;
2169 if (lyx_view_->buffer()) {
2170 string const trypath = lyx_view_->buffer()->filePath();
2171 // If directory is writeable, use this as default.
2172 if (FileName(trypath).isDirWritable())
2178 if (fname.empty()) {
2179 FileDialog dlg(_("Select document to open"), LFUN_FILE_OPEN);
2180 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
2181 dlg.setButton2(_("Examples|#E#e"),
2182 from_utf8(addPath(package().system_support().absFilename(), "examples")));
2184 FileDialog::Result result =
2185 dlg.open(from_utf8(initpath),
2186 FileFilterList(_("LyX Documents (*.lyx)")),
2189 if (result.first == FileDialog::Later)
2192 filename = to_utf8(result.second);
2194 // check selected filename
2195 if (filename.empty()) {
2196 lyx_view_->message(_("Canceled."));
2202 // get absolute path of file and add ".lyx" to the filename if
2204 FileName const fullname = fileSearch(string(), filename, "lyx");
2205 if (!fullname.empty())
2206 filename = fullname.absFilename();
2208 // if the file doesn't exist, let the user create one
2209 if (!fullname.exists()) {
2210 // the user specifically chose this name. Believe him.
2211 Buffer * const b = newFile(filename, string(), true);
2213 lyx_view_->setBuffer(b);
2217 docstring const disp_fn = makeDisplayPath(filename);
2218 lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
2221 Buffer * buf = lyx_view_->loadLyXFile(fullname);
2224 lyx_view_->setBuffer(buf);
2225 lyx_view_->errors("Parse");
2226 str2 = bformat(_("Document %1$s opened."), disp_fn);
2228 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2230 lyx_view_->message(str2);
2234 void LyXFunc::doImport(string const & argument)
2237 string filename = split(argument, format, ' ');
2239 LYXERR(Debug::INFO, "LyXFunc::doImport: " << format
2240 << " file: " << filename);
2242 // need user interaction
2243 if (filename.empty()) {
2244 string initpath = lyxrc.document_path;
2246 if (lyx_view_->buffer()) {
2247 string const trypath = lyx_view_->buffer()->filePath();
2248 // If directory is writeable, use this as default.
2249 if (FileName(trypath).isDirWritable())
2253 docstring const text = bformat(_("Select %1$s file to import"),
2254 formats.prettyName(format));
2256 FileDialog dlg(text, LFUN_BUFFER_IMPORT);
2257 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
2258 dlg.setButton2(_("Examples|#E#e"),
2259 from_utf8(addPath(package().system_support().absFilename(), "examples")));
2261 docstring filter = formats.prettyName(format);
2264 filter += from_utf8(formats.extension(format));
2267 FileDialog::Result result =
2268 dlg.open(from_utf8(initpath),
2269 FileFilterList(filter),
2272 if (result.first == FileDialog::Later)
2275 filename = to_utf8(result.second);
2277 // check selected filename
2278 if (filename.empty())
2279 lyx_view_->message(_("Canceled."));
2282 if (filename.empty())
2285 // get absolute path of file
2286 FileName const fullname(makeAbsPath(filename));
2288 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
2290 // Check if the document already is open
2291 if (use_gui && theBufferList().exists(lyxfile.absFilename())) {
2292 if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) {
2293 lyx_view_->message(_("Canceled."));
2298 // if the file exists already, and we didn't do
2299 // -i lyx thefile.lyx, warn
2300 if (lyxfile.exists() && fullname != lyxfile) {
2301 docstring const file = makeDisplayPath(lyxfile.absFilename(), 30);
2303 docstring text = bformat(_("The document %1$s already exists.\n\n"
2304 "Do you want to overwrite that document?"), file);
2305 int const ret = Alert::prompt(_("Overwrite document?"),
2306 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2309 lyx_view_->message(_("Canceled."));
2314 ErrorList errorList;
2315 import(lyx_view_, fullname, format, errorList);
2316 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2320 void LyXFunc::closeBuffer()
2322 // goto bookmark to update bookmark pit.
2323 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2324 gotoBookmark(i+1, false, false);
2326 theBufferList().close(lyx_view_->buffer(), true);
2330 void LyXFunc::reloadBuffer()
2332 FileName filename(lyx_view_->buffer()->absFileName());
2333 docstring const disp_fn = makeDisplayPath(filename.absFilename());
2336 Buffer * buf = lyx_view_->loadLyXFile(filename);
2339 lyx_view_->setBuffer(buf);
2340 lyx_view_->errors("Parse");
2341 str = bformat(_("Document %1$s reloaded."), disp_fn);
2343 str = bformat(_("Could not reload document %1$s"), disp_fn);
2345 lyx_view_->message(str);
2348 // Each "lyx_view_" should have it's own message method. lyxview and
2349 // the minibuffer would use the minibuffer, but lyxserver would
2350 // send an ERROR signal to its client. Alejandro 970603
2351 // This function is bit problematic when it comes to NLS, to make the
2352 // lyx servers client be language indepenent we must not translate
2353 // strings sent to this func.
2354 void LyXFunc::setErrorMessage(docstring const & m) const
2356 dispatch_buffer = m;
2361 void LyXFunc::setMessage(docstring const & m) const
2363 dispatch_buffer = m;
2367 docstring const LyXFunc::viewStatusMessage()
2369 // When meta-fake key is pressed, show the key sequence so far + "M-".
2371 return keyseq.print(KeySequence::ForGui) + "M-";
2373 // Else, when a non-complete key sequence is pressed,
2374 // show the available options.
2375 if (keyseq.length() > 0 && !keyseq.deleted())
2376 return keyseq.printOptions(true);
2378 BOOST_ASSERT(lyx_view_);
2379 if (!lyx_view_->buffer())
2380 return _("Welcome to LyX!");
2382 return view()->cursor().currentState();
2386 BufferView * LyXFunc::view() const
2388 BOOST_ASSERT(lyx_view_);
2389 return lyx_view_->view();
2393 bool LyXFunc::wasMetaKey() const
2395 return (meta_fake_bit != NoModifier);
2399 void LyXFunc::updateLayout(TextClassPtr const & oldlayout,
2402 lyx_view_->message(_("Converting document to new document class..."));
2404 StableDocIterator backcur(view()->cursor());
2405 ErrorList & el = buffer->errorList("Class Switch");
2406 cap::switchBetweenClasses(
2407 oldlayout, buffer->params().getTextClassPtr(),
2408 static_cast<InsetText &>(buffer->inset()), el);
2410 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
2412 buffer->errors("Class Switch");
2413 updateLabels(*buffer);
2419 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2421 // Why the switch you might ask. It is a trick to ensure that all
2422 // the elements in the LyXRCTags enum is handled. As you can see
2423 // there are no breaks at all. So it is just a huge fall-through.
2424 // The nice thing is that we will get a warning from the compiler
2425 // if we forget an element.
2426 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2428 case LyXRC::RC_ACCEPT_COMPOUND:
2429 case LyXRC::RC_ALT_LANG:
2430 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
2431 case LyXRC::RC_PLAINTEXT_LINELEN:
2432 case LyXRC::RC_AUTOREGIONDELETE:
2433 case LyXRC::RC_AUTORESET_OPTIONS:
2434 case LyXRC::RC_AUTOSAVE:
2435 case LyXRC::RC_AUTO_NUMBER:
2436 case LyXRC::RC_BACKUPDIR_PATH:
2437 case LyXRC::RC_BIBTEX_COMMAND:
2438 case LyXRC::RC_BINDFILE:
2439 case LyXRC::RC_CHECKLASTFILES:
2440 case LyXRC::RC_USELASTFILEPOS:
2441 case LyXRC::RC_LOADSESSION:
2442 case LyXRC::RC_CHKTEX_COMMAND:
2443 case LyXRC::RC_CONVERTER:
2444 case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
2445 case LyXRC::RC_COPIER:
2446 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2447 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2448 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2449 case LyXRC::RC_DATE_INSERT_FORMAT:
2450 case LyXRC::RC_DEFAULT_LANGUAGE:
2451 case LyXRC::RC_DEFAULT_PAPERSIZE:
2452 case LyXRC::RC_DEFFILE:
2453 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2454 case LyXRC::RC_DISPLAY_GRAPHICS:
2455 case LyXRC::RC_DOCUMENTPATH:
2456 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2457 FileName path(lyxrc_new.document_path);
2458 if (path.exists() && path.isDirectory())
2459 support::package().document_dir() = FileName(lyxrc.document_path);
2461 case LyXRC::RC_ESC_CHARS:
2462 case LyXRC::RC_FONT_ENCODING:
2463 case LyXRC::RC_FORMAT:
2464 case LyXRC::RC_INDEX_COMMAND:
2465 case LyXRC::RC_INPUT:
2466 case LyXRC::RC_KBMAP:
2467 case LyXRC::RC_KBMAP_PRIMARY:
2468 case LyXRC::RC_KBMAP_SECONDARY:
2469 case LyXRC::RC_LABEL_INIT_LENGTH:
2470 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2471 case LyXRC::RC_LANGUAGE_AUTO_END:
2472 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2473 case LyXRC::RC_LANGUAGE_COMMAND_END:
2474 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2475 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2476 case LyXRC::RC_LANGUAGE_PACKAGE:
2477 case LyXRC::RC_LANGUAGE_USE_BABEL:
2478 case LyXRC::RC_MAKE_BACKUP:
2479 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2480 case LyXRC::RC_NUMLASTFILES:
2481 case LyXRC::RC_PATH_PREFIX:
2482 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2483 support::prependEnvPath("PATH", lyxrc.path_prefix);
2485 case LyXRC::RC_PERS_DICT:
2486 case LyXRC::RC_PREVIEW:
2487 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2488 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2489 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2490 case LyXRC::RC_PRINTCOPIESFLAG:
2491 case LyXRC::RC_PRINTER:
2492 case LyXRC::RC_PRINTEVENPAGEFLAG:
2493 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2494 case LyXRC::RC_PRINTFILEEXTENSION:
2495 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2496 case LyXRC::RC_PRINTODDPAGEFLAG:
2497 case LyXRC::RC_PRINTPAGERANGEFLAG:
2498 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2499 case LyXRC::RC_PRINTPAPERFLAG:
2500 case LyXRC::RC_PRINTREVERSEFLAG:
2501 case LyXRC::RC_PRINTSPOOL_COMMAND:
2502 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2503 case LyXRC::RC_PRINTTOFILE:
2504 case LyXRC::RC_PRINTTOPRINTER:
2505 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2506 case LyXRC::RC_PRINT_COMMAND:
2507 case LyXRC::RC_RTL_SUPPORT:
2508 case LyXRC::RC_SCREEN_DPI:
2509 case LyXRC::RC_SCREEN_FONT_ROMAN:
2510 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2511 case LyXRC::RC_SCREEN_FONT_SANS:
2512 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2513 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2514 case LyXRC::RC_SCREEN_FONT_SIZES:
2515 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2516 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2517 case LyXRC::RC_GEOMETRY_SESSION:
2518 case LyXRC::RC_SCREEN_ZOOM:
2519 case LyXRC::RC_SERVERPIPE:
2520 case LyXRC::RC_SET_COLOR:
2521 case LyXRC::RC_SHOW_BANNER:
2522 case LyXRC::RC_SPELL_COMMAND:
2523 case LyXRC::RC_TEMPDIRPATH:
2524 case LyXRC::RC_TEMPLATEPATH:
2525 case LyXRC::RC_TEX_ALLOWS_SPACES:
2526 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2527 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2528 support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2530 case LyXRC::RC_UIFILE:
2531 case LyXRC::RC_USER_EMAIL:
2532 case LyXRC::RC_USER_NAME:
2533 case LyXRC::RC_USETEMPDIR:
2534 case LyXRC::RC_USE_ALT_LANG:
2535 case LyXRC::RC_USE_CONVERTER_CACHE:
2536 case LyXRC::RC_USE_ESC_CHARS:
2537 case LyXRC::RC_USE_INP_ENC:
2538 case LyXRC::RC_USE_PERS_DICT:
2539 case LyXRC::RC_USE_PIXMAP_CACHE:
2540 case LyXRC::RC_USE_SPELL_LIB:
2541 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2542 case LyXRC::RC_SORT_LAYOUTS:
2543 case LyXRC::RC_VIEWER:
2544 case LyXRC::RC_LAST: