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_?
613 lyx_view_->isDialogVisible(cmd.getArg(0)) : false);
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_?
700 lyx_view_->isToolbarVisible(cmd.getArg(0)) : false;
701 flag.setOnOff(current);
704 case LFUN_WINDOW_CLOSE: {
705 enable = theApp()->viewCount() > 0;
709 // this one is difficult to get right. As a half-baked
710 // solution, we consider only the first action of the sequence
711 case LFUN_COMMAND_SEQUENCE: {
712 // argument contains ';'-terminated commands
713 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
714 FuncRequest func(lyxaction.lookupFunc(firstcmd));
715 func.origin = cmd.origin;
716 flag = getStatus(func);
722 std::string name = to_utf8(cmd.argument());
723 if (LyX::ref().topLevelCmdDef().lock(name, func)) {
724 func.origin = cmd.origin;
725 flag = getStatus(func);
726 LyX::ref().topLevelCmdDef().release(name);
728 // catch recursion or unknown command definiton
729 // all operations until the recursion or unknown command
730 // definiton occures are performed, so set the state to enabled
736 case LFUN_BUFFER_NEW:
737 case LFUN_BUFFER_NEW_TEMPLATE:
738 case LFUN_WORD_FIND_FORWARD:
739 case LFUN_WORD_FIND_BACKWARD:
740 case LFUN_COMMAND_PREFIX:
741 case LFUN_COMMAND_EXECUTE:
743 case LFUN_META_PREFIX:
744 case LFUN_BUFFER_CLOSE:
745 case LFUN_BUFFER_WRITE_AS:
746 case LFUN_BUFFER_UPDATE:
747 case LFUN_BUFFER_VIEW:
748 case LFUN_MASTER_BUFFER_UPDATE:
749 case LFUN_MASTER_BUFFER_VIEW:
750 case LFUN_BUFFER_IMPORT:
751 case LFUN_BUFFER_AUTO_SAVE:
752 case LFUN_RECONFIGURE:
756 case LFUN_DROP_LAYOUTS_CHOICE:
758 case LFUN_SERVER_GET_NAME:
759 case LFUN_SERVER_NOTIFY:
760 case LFUN_SERVER_GOTO_FILE_ROW:
761 case LFUN_DIALOG_HIDE:
762 case LFUN_DIALOG_DISCONNECT_INSET:
763 case LFUN_BUFFER_CHILD_OPEN:
764 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
765 case LFUN_KEYMAP_OFF:
766 case LFUN_KEYMAP_PRIMARY:
767 case LFUN_KEYMAP_SECONDARY:
768 case LFUN_KEYMAP_TOGGLE:
770 case LFUN_BUFFER_EXPORT_CUSTOM:
771 case LFUN_BUFFER_PRINT:
772 case LFUN_PREFERENCES_SAVE:
773 case LFUN_SCREEN_FONT_UPDATE:
776 case LFUN_EXTERNAL_EDIT:
777 case LFUN_GRAPHICS_EDIT:
778 case LFUN_ALL_INSETS_TOGGLE:
779 case LFUN_BUFFER_LANGUAGE:
780 case LFUN_TEXTCLASS_APPLY:
781 case LFUN_TEXTCLASS_LOAD:
782 case LFUN_BUFFER_SAVE_AS_DEFAULT:
783 case LFUN_BUFFER_PARAMS_APPLY:
784 case LFUN_LAYOUT_MODULES_CLEAR:
785 case LFUN_LAYOUT_MODULE_ADD:
786 case LFUN_LAYOUT_RELOAD:
787 case LFUN_LYXRC_APPLY:
788 case LFUN_BUFFER_NEXT:
789 case LFUN_BUFFER_PREVIOUS:
790 case LFUN_WINDOW_NEW:
792 // these are handled in our dispatch()
800 if (!getLocalStatus(view()->cursor(), cmd, flag))
801 flag = view()->getStatus(cmd);
807 // Can we use a readonly buffer?
808 if (buf && buf->isReadonly()
809 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
810 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
811 flag.message(from_utf8(N_("Document is read-only")));
815 // Are we in a DELETED change-tracking region?
817 && lookupChangeType(view()->cursor(), true) == Change::DELETED
818 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
819 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
820 flag.message(from_utf8(N_("This portion of the document is deleted.")));
824 // the default error message if we disable the command
825 if (!flag.enabled() && flag.message().empty())
826 flag.message(from_utf8(N_("Command disabled")));
832 bool LyXFunc::ensureBufferClean(BufferView * bv)
834 Buffer & buf = bv->buffer();
838 docstring const file = buf.fileName().displayName(30);
839 docstring text = bformat(_("The document %1$s has unsaved "
840 "changes.\n\nDo you want to save "
841 "the document?"), file);
842 int const ret = Alert::prompt(_("Save changed document?"),
843 text, 0, 1, _("&Save"),
847 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
849 return buf.isClean();
855 void showPrintError(string const & name)
857 docstring str = bformat(_("Could not print the document %1$s.\n"
858 "Check that your printer is set up correctly."),
859 makeDisplayPath(name, 50));
860 Alert::error(_("Print document failed"), str);
864 void loadTextClass(string const & name)
866 std::pair<bool, textclass_type> const tc_pair =
867 textclasslist.numberOfClass(name);
869 if (!tc_pair.first) {
870 lyxerr << "Document class \"" << name
871 << "\" does not exist."
876 textclass_type const tc = tc_pair.second;
878 if (!textclasslist[tc].load()) {
879 docstring s = bformat(_("The document class %1$s."
880 "could not be loaded."),
881 from_utf8(textclasslist[tc].name()));
882 Alert::error(_("Could not load class"), s);
887 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
892 void LyXFunc::dispatch(FuncRequest const & cmd)
894 string const argument = to_utf8(cmd.argument());
895 kb_action const action = cmd.action;
897 LYXERR(Debug::ACTION, "\nLyXFunc::dispatch: cmd: " << cmd);
898 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
900 // we have not done anything wrong yet.
902 dispatch_buffer.erase();
904 // redraw the screen at the end (first of the two drawing steps).
905 //This is done unless explicitely requested otherwise
906 Update::flags updateFlags = Update::FitCursor;
908 FuncStatus const flag = getStatus(cmd);
909 if (!flag.enabled()) {
910 // We cannot use this function here
911 LYXERR(Debug::ACTION, "LyXFunc::dispatch: "
912 << lyxaction.getActionName(action)
913 << " [" << action << "] is disabled at this location");
914 setErrorMessage(flag.message());
917 // Let lyx_view_ dispatch its own actions.
918 case LFUN_COMMAND_EXECUTE:
919 case LFUN_DROP_LAYOUTS_CHOICE:
921 case LFUN_TOOLBAR_TOGGLE:
922 BOOST_ASSERT(lyx_view_);
923 lyx_view_->dispatch(cmd);
926 case LFUN_WORD_FIND_FORWARD:
927 case LFUN_WORD_FIND_BACKWARD: {
928 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
929 static docstring last_search;
930 docstring searched_string;
932 if (!cmd.argument().empty()) {
933 last_search = cmd.argument();
934 searched_string = cmd.argument();
936 searched_string = last_search;
939 if (searched_string.empty())
942 bool const fw = action == LFUN_WORD_FIND_FORWARD;
943 docstring const data =
944 find2string(searched_string, true, false, fw);
945 find(view(), FuncRequest(LFUN_WORD_FIND, data));
949 case LFUN_COMMAND_PREFIX:
950 BOOST_ASSERT(lyx_view_);
951 lyx_view_->message(keyseq.printOptions(true));
955 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
957 meta_fake_bit = NoModifier;
958 if (lyx_view_->buffer())
959 // cancel any selection
960 dispatch(FuncRequest(LFUN_MARK_OFF));
961 setMessage(from_ascii(N_("Cancel")));
964 case LFUN_META_PREFIX:
965 meta_fake_bit = AltModifier;
966 setMessage(keyseq.print(KeySequence::ForGui));
969 case LFUN_BUFFER_TOGGLE_READ_ONLY: {
970 BOOST_ASSERT(lyx_view_ && lyx_view_->view() && lyx_view_->buffer());
971 Buffer * buf = lyx_view_->buffer();
972 if (buf->lyxvc().inUse())
973 buf->lyxvc().toggleReadOnly();
975 buf->setReadonly(!lyx_view_->buffer()->isReadonly());
979 // --- Menus -----------------------------------------------
980 case LFUN_BUFFER_NEW:
981 menuNew(argument, false);
982 updateFlags = Update::None;
985 case LFUN_BUFFER_NEW_TEMPLATE:
986 menuNew(argument, true);
987 updateFlags = Update::None;
990 case LFUN_BUFFER_CLOSE:
992 updateFlags = Update::None;
995 case LFUN_BUFFER_WRITE:
996 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
997 if (!lyx_view_->buffer()->isUnnamed()) {
998 docstring const str = bformat(_("Saving document %1$s..."),
999 makeDisplayPath(lyx_view_->buffer()->absFileName()));
1000 lyx_view_->message(str);
1001 lyx_view_->buffer()->menuWrite();
1002 lyx_view_->message(str + _(" done."));
1004 lyx_view_->buffer()->writeAs();
1006 updateFlags = Update::None;
1009 case LFUN_BUFFER_WRITE_AS:
1010 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1011 lyx_view_->buffer()->writeAs(argument);
1012 updateFlags = Update::None;
1015 case LFUN_BUFFER_WRITE_ALL: {
1016 Buffer * first = theBufferList().first();
1019 lyx_view_->message(_("Saving all documents..."));
1021 // We cannot use a for loop as the buffer list cycles.
1023 if (!b->isClean()) {
1024 if (!b->isUnnamed()) {
1026 lyxerr[Debug::ACTION] << "Saved " << b->absFileName() << endl;
1030 b = theBufferList().next(b);
1031 } while (b != first);
1032 lyx_view_->message(_("All documents saved."));
1035 updateFlags = Update::None;
1039 case LFUN_BUFFER_RELOAD: {
1040 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1041 docstring const file = makeDisplayPath(lyx_view_->buffer()->absFileName(), 20);
1042 docstring text = bformat(_("Any changes will be lost. Are you sure "
1043 "you want to revert to the saved version of the document %1$s?"), file);
1044 int const ret = Alert::prompt(_("Revert to saved document?"),
1045 text, 1, 1, _("&Revert"), _("&Cancel"));
1052 case LFUN_BUFFER_UPDATE:
1053 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1054 lyx_view_->buffer()->doExport(argument, true);
1057 case LFUN_BUFFER_VIEW:
1058 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1059 lyx_view_->buffer()->preview(argument);
1062 case LFUN_MASTER_BUFFER_UPDATE:
1063 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->masterBuffer());
1064 lyx_view_->buffer()->masterBuffer()->doExport(argument, true);
1067 case LFUN_MASTER_BUFFER_VIEW:
1068 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->masterBuffer());
1069 lyx_view_->buffer()->masterBuffer()->preview(argument);
1072 case LFUN_BUILD_PROGRAM:
1073 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1074 lyx_view_->buffer()->doExport("program", true);
1077 case LFUN_BUFFER_CHKTEX:
1078 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1079 lyx_view_->buffer()->runChktex();
1082 case LFUN_BUFFER_EXPORT:
1083 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1084 if (argument == "custom")
1085 lyx_view_->showDialog("sendto", string());
1087 lyx_view_->buffer()->doExport(argument, false);
1090 case LFUN_BUFFER_EXPORT_CUSTOM: {
1091 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1093 string command = split(argument, format_name, ' ');
1094 Format const * format = formats.getFormat(format_name);
1096 lyxerr << "Format \"" << format_name
1097 << "\" not recognized!"
1102 Buffer * buffer = lyx_view_->buffer();
1104 // The name of the file created by the conversion process
1107 // Output to filename
1108 if (format->name() == "lyx") {
1109 string const latexname = buffer->latexName(false);
1110 filename = changeExtension(latexname,
1111 format->extension());
1112 filename = addName(buffer->temppath(), filename);
1114 if (!buffer->writeFile(FileName(filename)))
1118 buffer->doExport(format_name, true, filename);
1121 // Substitute $$FName for filename
1122 if (!contains(command, "$$FName"))
1123 command = "( " + command + " ) < $$FName";
1124 command = subst(command, "$$FName", filename);
1126 // Execute the command in the background
1128 call.startscript(Systemcall::DontWait, command);
1132 case LFUN_BUFFER_PRINT: {
1133 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1134 // FIXME: cmd.getArg() might fail if one of the arguments
1135 // contains double quotes
1136 string target = cmd.getArg(0);
1137 string target_name = cmd.getArg(1);
1138 string command = cmd.getArg(2);
1141 || target_name.empty()
1142 || command.empty()) {
1143 lyxerr << "Unable to parse \""
1144 << argument << '"' << endl;
1147 if (target != "printer" && target != "file") {
1148 lyxerr << "Unrecognized target \""
1149 << target << '"' << endl;
1153 Buffer * buffer = lyx_view_->buffer();
1155 if (!buffer->doExport("dvi", true)) {
1156 showPrintError(buffer->absFileName());
1160 // Push directory path.
1161 string const path = buffer->temppath();
1162 // Prevent the compiler from optimizing away p
1164 support::PathChanger p(pp);
1166 // there are three cases here:
1167 // 1. we print to a file
1168 // 2. we print directly to a printer
1169 // 3. we print using a spool command (print to file first)
1172 string const dviname =
1173 changeExtension(buffer->latexName(true), "dvi");
1175 if (target == "printer") {
1176 if (!lyxrc.print_spool_command.empty()) {
1177 // case 3: print using a spool
1178 string const psname =
1179 changeExtension(dviname,".ps");
1180 command += ' ' + lyxrc.print_to_file
1183 + quoteName(dviname);
1186 lyxrc.print_spool_command + ' ';
1187 if (target_name != "default") {
1188 command2 += lyxrc.print_spool_printerprefix
1192 command2 += quoteName(psname);
1194 // If successful, then spool command
1195 res = one.startscript(
1200 res = one.startscript(
1201 Systemcall::DontWait,
1204 // case 2: print directly to a printer
1205 if (target_name != "default")
1206 command += ' ' + lyxrc.print_to_printer + target_name + ' ';
1207 res = one.startscript(
1208 Systemcall::DontWait,
1209 command + quoteName(dviname));
1213 // case 1: print to a file
1214 FileName const filename(makeAbsPath(target_name,
1215 lyx_view_->buffer()->filePath()));
1216 FileName const dvifile(makeAbsPath(dviname, path));
1217 if (filename.exists()) {
1218 docstring text = bformat(
1219 _("The file %1$s already exists.\n\n"
1220 "Do you want to overwrite that file?"),
1221 makeDisplayPath(filename.absFilename()));
1222 if (Alert::prompt(_("Overwrite file?"),
1223 text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
1226 command += ' ' + lyxrc.print_to_file
1227 + quoteName(filename.toFilesystemEncoding())
1229 + quoteName(dvifile.toFilesystemEncoding());
1230 res = one.startscript(Systemcall::DontWait,
1235 showPrintError(buffer->absFileName());
1239 case LFUN_BUFFER_IMPORT:
1244 // quitting is triggered by the gui code
1245 // (leaving the event loop).
1246 lyx_view_->message(from_utf8(N_("Exiting.")));
1247 if (theBufferList().quitWriteAll())
1248 theApp()->closeAllViews();
1251 case LFUN_BUFFER_AUTO_SAVE:
1252 lyx_view_->buffer()->autoSave();
1255 case LFUN_RECONFIGURE:
1256 BOOST_ASSERT(lyx_view_);
1257 // argument is any additional parameter to the configure.py command
1258 reconfigure(*lyx_view_, argument);
1261 case LFUN_HELP_OPEN: {
1262 BOOST_ASSERT(lyx_view_);
1263 string const arg = argument;
1265 setErrorMessage(from_ascii(N_("Missing argument")));
1268 FileName const fname = i18nLibFileSearch("doc", arg, "lyx");
1269 if (fname.empty()) {
1270 lyxerr << "LyX: unable to find documentation file `"
1271 << arg << "'. Bad installation?" << endl;
1274 lyx_view_->message(bformat(_("Opening help file %1$s..."),
1275 makeDisplayPath(fname.absFilename())));
1276 Buffer * buf = lyx_view_->loadLyXFile(fname, false);
1279 lyx_view_->setBuffer(buf);
1280 lyx_view_->errors("Parse");
1282 updateFlags = Update::None;
1286 // --- version control -------------------------------
1287 case LFUN_VC_REGISTER:
1288 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1289 if (!ensureBufferClean(view()))
1291 if (!lyx_view_->buffer()->lyxvc().inUse()) {
1292 lyx_view_->buffer()->lyxvc().registrer();
1295 updateFlags = Update::Force;
1298 case LFUN_VC_CHECK_IN:
1299 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1300 if (!ensureBufferClean(view()))
1302 if (lyx_view_->buffer()->lyxvc().inUse()
1303 && !lyx_view_->buffer()->isReadonly()) {
1304 lyx_view_->buffer()->lyxvc().checkIn();
1309 case LFUN_VC_CHECK_OUT:
1310 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1311 if (!ensureBufferClean(view()))
1313 if (lyx_view_->buffer()->lyxvc().inUse()
1314 && lyx_view_->buffer()->isReadonly()) {
1315 lyx_view_->buffer()->lyxvc().checkOut();
1320 case LFUN_VC_REVERT:
1321 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1322 lyx_view_->buffer()->lyxvc().revert();
1326 case LFUN_VC_UNDO_LAST:
1327 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1328 lyx_view_->buffer()->lyxvc().undoLast();
1332 // --- buffers ----------------------------------------
1333 case LFUN_BUFFER_SWITCH:
1334 BOOST_ASSERT(lyx_view_);
1335 lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1336 updateFlags = Update::None;
1339 case LFUN_BUFFER_NEXT:
1340 BOOST_ASSERT(lyx_view_);
1341 lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer()));
1342 updateFlags = Update::None;
1345 case LFUN_BUFFER_PREVIOUS:
1346 BOOST_ASSERT(lyx_view_);
1347 lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer()));
1348 updateFlags = Update::None;
1351 case LFUN_FILE_NEW: {
1352 BOOST_ASSERT(lyx_view_);
1354 string tmpname = split(argument, name, ':'); // Split filename
1355 Buffer * const b = newFile(name, tmpname);
1357 lyx_view_->setBuffer(b);
1358 updateFlags = Update::None;
1362 case LFUN_FILE_OPEN:
1363 BOOST_ASSERT(lyx_view_);
1365 updateFlags = Update::None;
1368 // --- lyxserver commands ----------------------------
1369 case LFUN_SERVER_GET_NAME:
1370 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1371 setMessage(from_utf8(lyx_view_->buffer()->absFileName()));
1372 LYXERR(Debug::INFO, "FNAME["
1373 << lyx_view_->buffer()->absFileName() << ']');
1376 case LFUN_SERVER_NOTIFY:
1377 dispatch_buffer = keyseq.print(KeySequence::Portable);
1378 theServer().notifyClient(to_utf8(dispatch_buffer));
1381 case LFUN_SERVER_GOTO_FILE_ROW: {
1382 BOOST_ASSERT(lyx_view_);
1385 istringstream is(argument);
1386 is >> file_name >> row;
1388 bool loaded = false;
1389 if (prefixIs(file_name, package().temp_dir().absFilename()))
1390 // Needed by inverse dvi search. If it is a file
1391 // in tmpdir, call the apropriated function
1392 buf = theBufferList().getBufferFromTmp(file_name);
1394 // Must replace extension of the file to be .lyx
1395 // and get full path
1396 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1397 // Either change buffer or load the file
1398 if (theBufferList().exists(s.absFilename()))
1399 buf = theBufferList().getBuffer(s.absFilename());
1401 buf = lyx_view_->loadLyXFile(s);
1407 updateFlags = Update::None;
1412 lyx_view_->setBuffer(buf);
1413 view()->setCursorFromRow(row);
1415 lyx_view_->errors("Parse");
1416 updateFlags = Update::FitCursor;
1420 case LFUN_DIALOG_SHOW: {
1421 BOOST_ASSERT(lyx_view_);
1422 string const name = cmd.getArg(0);
1423 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1425 if (name == "character") {
1426 data = freefont2string();
1428 lyx_view_->showDialog("character", data);
1429 } else if (name == "latexlog") {
1430 Buffer::LogType type;
1431 string const logfile = lyx_view_->buffer()->logName(&type);
1433 case Buffer::latexlog:
1436 case Buffer::buildlog:
1440 data += Lexer::quoteString(logfile);
1441 lyx_view_->showDialog("log", data);
1442 } else if (name == "vclog") {
1443 string const data = "vc " +
1444 Lexer::quoteString(lyx_view_->buffer()->lyxvc().getLogFile());
1445 lyx_view_->showDialog("log", data);
1447 lyx_view_->showDialog(name, data);
1451 case LFUN_DIALOG_SHOW_NEW_INSET: {
1452 BOOST_ASSERT(lyx_view_);
1453 string const name = cmd.getArg(0);
1454 InsetCode code = insetCode(name);
1455 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1456 bool insetCodeOK = true;
1465 case HYPERLINK_CODE: {
1466 InsetCommandParams p(code);
1467 data = InsetCommandMailer::params2string(name, p);
1470 case INCLUDE_CODE: {
1471 // data is the include type: one of "include",
1472 // "input", "verbatiminput" or "verbatiminput*"
1474 // default type is requested
1476 InsetCommandParams p(INCLUDE_CODE, data);
1477 data = InsetCommandMailer::params2string("include", p);
1481 // \c data == "Boxed" || "Frameless" etc
1482 InsetBoxParams p(data);
1483 data = InsetBoxMailer::params2string(p);
1487 InsetBranchParams p;
1488 data = InsetBranchMailer::params2string(p);
1492 InsetCommandParams p(CITE_CODE);
1493 data = InsetCommandMailer::params2string(name, p);
1497 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1500 case EXTERNAL_CODE: {
1501 InsetExternalParams p;
1502 Buffer const & buffer = *lyx_view_->buffer();
1503 data = InsetExternalMailer::params2string(p, buffer);
1508 data = InsetFloatMailer::params2string(p);
1511 case LISTINGS_CODE: {
1512 InsetListingsParams p;
1513 data = InsetListingsMailer::params2string(p);
1516 case GRAPHICS_CODE: {
1517 InsetGraphicsParams p;
1518 Buffer const & buffer = *lyx_view_->buffer();
1519 data = InsetGraphicsMailer::params2string(p, buffer);
1524 data = InsetNoteMailer::params2string(p);
1529 data = InsetVSpaceMailer::params2string(space);
1534 data = InsetWrapMailer::params2string(p);
1538 lyxerr << "Inset type '" << name <<
1539 "' not recognized in LFUN_DIALOG_SHOW_NEW_INSET" << std:: endl;
1540 insetCodeOK = false;
1542 } // end switch(code)
1544 lyx_view_->showDialog(name, data, 0);
1548 case LFUN_DIALOG_UPDATE: {
1549 BOOST_ASSERT(lyx_view_);
1550 string const & name = argument;
1551 // Can only update a dialog connected to an existing inset
1552 Inset * inset = lyx_view_->getOpenInset(name);
1554 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1555 inset->dispatch(view()->cursor(), fr);
1556 } else if (name == "paragraph") {
1557 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1558 } else if (name == "prefs") {
1559 lyx_view_->updateDialog(name, string());
1564 case LFUN_DIALOG_HIDE: {
1565 if (quitting || !use_gui)
1567 theApp()->hideDialogs(argument, 0);
1571 case LFUN_DIALOG_TOGGLE: {
1572 BOOST_ASSERT(lyx_view_);
1573 if (lyx_view_->isDialogVisible(cmd.getArg(0)))
1574 dispatch(FuncRequest(LFUN_DIALOG_HIDE, argument));
1576 dispatch(FuncRequest(LFUN_DIALOG_SHOW, argument));
1580 case LFUN_DIALOG_DISCONNECT_INSET:
1581 BOOST_ASSERT(lyx_view_);
1582 lyx_view_->disconnectDialog(argument);
1586 case LFUN_CITATION_INSERT: {
1587 BOOST_ASSERT(lyx_view_);
1588 if (!argument.empty()) {
1589 // we can have one optional argument, delimited by '|'
1590 // citation-insert <key>|<text_before>
1591 // this should be enhanced to also support text_after
1592 // and citation style
1593 string arg = argument;
1595 if (contains(argument, "|")) {
1596 arg = token(argument, '|', 0);
1597 opt1 = token(argument, '|', 1);
1599 InsetCommandParams icp(CITE_CODE);
1600 icp["key"] = from_utf8(arg);
1602 icp["before"] = from_utf8(opt1);
1603 string icstr = InsetCommandMailer::params2string("citation", icp);
1604 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1607 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1611 case LFUN_BUFFER_CHILD_OPEN: {
1612 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1613 Buffer * parent = lyx_view_->buffer();
1614 FileName filename = makeAbsPath(argument, parent->filePath());
1615 view()->saveBookmark(false);
1617 bool parsed = false;
1618 if (theBufferList().exists(filename.absFilename())) {
1619 child = theBufferList().getBuffer(filename.absFilename());
1621 setMessage(bformat(_("Opening child document %1$s..."),
1622 makeDisplayPath(filename.absFilename())));
1623 child = lyx_view_->loadLyXFile(filename, true);
1627 // Set the parent name of the child document.
1628 // This makes insertion of citations and references in the child work,
1629 // when the target is in the parent or another child document.
1630 child->setParentName(parent->absFileName());
1631 updateLabels(*child->masterBuffer());
1632 lyx_view_->setBuffer(child);
1634 lyx_view_->errors("Parse");
1637 // If a screen update is required (in case where auto_open is false),
1638 // setBuffer() would have taken care of it already. Otherwise we shall
1639 // reset the update flag because it can cause a circular problem.
1641 updateFlags = Update::None;
1645 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1646 BOOST_ASSERT(lyx_view_);
1647 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1650 case LFUN_KEYMAP_OFF:
1651 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1652 lyx_view_->view()->getIntl().keyMapOn(false);
1655 case LFUN_KEYMAP_PRIMARY:
1656 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1657 lyx_view_->view()->getIntl().keyMapPrim();
1660 case LFUN_KEYMAP_SECONDARY:
1661 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1662 lyx_view_->view()->getIntl().keyMapSec();
1665 case LFUN_KEYMAP_TOGGLE:
1666 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1667 lyx_view_->view()->getIntl().toggleKeyMap();
1673 string rest = split(argument, countstr, ' ');
1674 istringstream is(countstr);
1677 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1678 for (int i = 0; i < count; ++i)
1679 dispatch(lyxaction.lookupFunc(rest));
1683 case LFUN_COMMAND_SEQUENCE: {
1684 // argument contains ';'-terminated commands
1685 string arg = argument;
1686 while (!arg.empty()) {
1688 arg = split(arg, first, ';');
1689 FuncRequest func(lyxaction.lookupFunc(first));
1690 func.origin = cmd.origin;
1698 if (LyX::ref().topLevelCmdDef().lock(argument, func)) {
1699 func.origin = cmd.origin;
1701 LyX::ref().topLevelCmdDef().release(argument);
1703 if (func.action == LFUN_UNKNOWN_ACTION) {
1704 // unknown command definition
1705 lyxerr << "Warning: unknown command definition `"
1709 // recursion detected
1710 lyxerr << "Warning: Recursion in the command definition `"
1711 << argument << "' detected"
1718 case LFUN_PREFERENCES_SAVE: {
1719 lyxrc.write(makeAbsPath("preferences",
1720 package().user_support().absFilename()),
1725 case LFUN_SCREEN_FONT_UPDATE:
1726 BOOST_ASSERT(lyx_view_);
1727 // handle the screen font changes.
1728 theFontLoader().update();
1729 /// FIXME: only the current view will be updated. the Gui
1730 /// class is able to furnish the list of views.
1731 updateFlags = Update::Force;
1734 case LFUN_SET_COLOR: {
1736 string const x11_name = split(argument, lyx_name, ' ');
1737 if (lyx_name.empty() || x11_name.empty()) {
1738 setErrorMessage(from_ascii(N_(
1739 "Syntax: set-color <lyx_name>"
1744 bool const graphicsbg_changed =
1745 (lyx_name == lcolor.getLyXName(Color_graphicsbg) &&
1746 x11_name != lcolor.getX11Name(Color_graphicsbg));
1748 if (!lcolor.setColor(lyx_name, x11_name)) {
1750 bformat(_("Set-color \"%1$s\" failed "
1751 "- color is undefined or "
1752 "may not be redefined"),
1753 from_utf8(lyx_name)));
1757 theApp()->updateColor(lcolor.getFromLyXName(lyx_name));
1759 if (graphicsbg_changed) {
1760 // FIXME: The graphics cache no longer has a changeDisplay method.
1762 graphics::GCache::get().changeDisplay(true);
1769 BOOST_ASSERT(lyx_view_);
1770 lyx_view_->message(from_utf8(argument));
1773 case LFUN_EXTERNAL_EDIT: {
1774 BOOST_ASSERT(lyx_view_);
1775 FuncRequest fr(action, argument);
1776 InsetExternal().dispatch(view()->cursor(), fr);
1780 case LFUN_GRAPHICS_EDIT: {
1781 FuncRequest fr(action, argument);
1782 InsetGraphics().dispatch(view()->cursor(), fr);
1786 case LFUN_INSET_APPLY: {
1787 BOOST_ASSERT(lyx_view_);
1788 string const name = cmd.getArg(0);
1789 Inset * inset = lyx_view_->getOpenInset(name);
1791 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1792 inset->dispatch(view()->cursor(), fr);
1794 FuncRequest fr(LFUN_INSET_INSERT, argument);
1797 // ideally, the update flag should be set by the insets,
1798 // but this is not possible currently
1799 updateFlags = Update::Force | Update::FitCursor;
1803 case LFUN_ALL_INSETS_TOGGLE: {
1804 BOOST_ASSERT(lyx_view_);
1806 string const name = split(argument, action, ' ');
1807 InsetCode const inset_code = insetCode(name);
1809 Cursor & cur = view()->cursor();
1810 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1812 Inset & inset = lyx_view_->buffer()->inset();
1813 InsetIterator it = inset_iterator_begin(inset);
1814 InsetIterator const end = inset_iterator_end(inset);
1815 for (; it != end; ++it) {
1816 if (!it->asInsetMath()
1817 && (inset_code == NO_CODE
1818 || inset_code == it->lyxCode())) {
1819 Cursor tmpcur = cur;
1820 tmpcur.pushBackward(*it);
1821 it->dispatch(tmpcur, fr);
1824 updateFlags = Update::Force | Update::FitCursor;
1828 case LFUN_BUFFER_LANGUAGE: {
1829 BOOST_ASSERT(lyx_view_);
1830 Buffer & buffer = *lyx_view_->buffer();
1831 Language const * oldL = buffer.params().language;
1832 Language const * newL = languages.getLanguage(argument);
1833 if (!newL || oldL == newL)
1836 if (oldL->rightToLeft() == newL->rightToLeft()
1837 && !buffer.isMultiLingual())
1838 buffer.changeLanguage(oldL, newL);
1842 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1843 string const fname =
1844 addName(addPath(package().user_support().absFilename(), "templates/"),
1846 Buffer defaults(fname);
1848 istringstream ss(argument);
1851 int const unknown_tokens = defaults.readHeader(lex);
1853 if (unknown_tokens != 0) {
1854 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1855 << unknown_tokens << " unknown token"
1856 << (unknown_tokens == 1 ? "" : "s")
1860 if (defaults.writeFile(FileName(defaults.absFileName())))
1861 setMessage(bformat(_("Document defaults saved in %1$s"),
1862 makeDisplayPath(fname)));
1864 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1868 case LFUN_BUFFER_PARAMS_APPLY: {
1869 BOOST_ASSERT(lyx_view_);
1870 biblio::CiteEngine const oldEngine =
1871 lyx_view_->buffer()->params().getEngine();
1873 Buffer * buffer = lyx_view_->buffer();
1875 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1877 Cursor & cur = view()->cursor();
1878 cur.recordUndoFullDocument();
1880 istringstream ss(argument);
1883 int const unknown_tokens = buffer->readHeader(lex);
1885 if (unknown_tokens != 0) {
1886 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1887 << unknown_tokens << " unknown token"
1888 << (unknown_tokens == 1 ? "" : "s")
1892 updateLayout(oldClass, buffer);
1894 biblio::CiteEngine const newEngine =
1895 lyx_view_->buffer()->params().getEngine();
1897 if (oldEngine != newEngine) {
1898 FuncRequest fr(LFUN_INSET_REFRESH);
1900 Inset & inset = lyx_view_->buffer()->inset();
1901 InsetIterator it = inset_iterator_begin(inset);
1902 InsetIterator const end = inset_iterator_end(inset);
1903 for (; it != end; ++it)
1904 if (it->lyxCode() == CITE_CODE)
1905 it->dispatch(cur, fr);
1908 updateFlags = Update::Force | Update::FitCursor;
1912 case LFUN_LAYOUT_MODULES_CLEAR: {
1913 BOOST_ASSERT(lyx_view_);
1914 Buffer * buffer = lyx_view_->buffer();
1915 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1916 view()->cursor().recordUndoFullDocument();
1917 buffer->params().clearLayoutModules();
1918 updateLayout(oldClass, buffer);
1919 updateFlags = Update::Force | Update::FitCursor;
1923 case LFUN_LAYOUT_MODULE_ADD: {
1924 BOOST_ASSERT(lyx_view_);
1925 Buffer * buffer = lyx_view_->buffer();
1926 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1927 view()->cursor().recordUndoFullDocument();
1928 buffer->params().addLayoutModule(argument);
1929 updateLayout(oldClass, buffer);
1930 updateFlags = Update::Force | Update::FitCursor;
1934 case LFUN_TEXTCLASS_APPLY: {
1935 BOOST_ASSERT(lyx_view_);
1936 Buffer * buffer = lyx_view_->buffer();
1938 loadTextClass(argument);
1940 std::pair<bool, textclass_type> const tc_pair =
1941 textclasslist.numberOfClass(argument);
1946 textclass_type const old_class = buffer->params().getBaseClass();
1947 textclass_type const new_class = tc_pair.second;
1949 if (old_class == new_class)
1953 //Save the old, possibly modular, layout for use in conversion.
1954 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1955 view()->cursor().recordUndoFullDocument();
1956 buffer->params().setBaseClass(new_class);
1957 updateLayout(oldClass, buffer);
1958 updateFlags = Update::Force | Update::FitCursor;
1962 case LFUN_LAYOUT_RELOAD: {
1963 BOOST_ASSERT(lyx_view_);
1964 Buffer * buffer = lyx_view_->buffer();
1965 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1966 textclass_type const tc = buffer->params().getBaseClass();
1967 textclasslist.reset(tc);
1968 buffer->params().setBaseClass(tc);
1969 updateLayout(oldClass, buffer);
1970 updateFlags = Update::Force | Update::FitCursor;
1974 case LFUN_TEXTCLASS_LOAD:
1975 loadTextClass(argument);
1978 case LFUN_LYXRC_APPLY: {
1979 LyXRC const lyxrc_orig = lyxrc;
1981 istringstream ss(argument);
1982 bool const success = lyxrc.read(ss) == 0;
1985 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1986 << "Unable to read lyxrc data"
1991 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1993 if (lyx_view_ && lyx_view_->buffer())
1994 lyx_view_->updateLayoutChoice(true);
1996 /// We force the redraw in any case because there might be
1997 /// some screen font changes.
1998 /// FIXME: only the current view will be updated. the Gui
1999 /// class is able to furnish the list of views.
2000 updateFlags = Update::Force;
2004 case LFUN_WINDOW_NEW:
2005 LyX::ref().newLyXView();
2008 case LFUN_WINDOW_CLOSE:
2009 BOOST_ASSERT(lyx_view_);
2010 BOOST_ASSERT(theApp());
2011 // update bookmark pit of the current buffer before window close
2012 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2013 gotoBookmark(i+1, false, false);
2014 // ask the user for saving changes or cancel quit
2015 if (!theBufferList().quitWriteAll())
2020 case LFUN_BOOKMARK_GOTO:
2021 // go to bookmark, open unopened file and switch to buffer if necessary
2022 gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
2025 case LFUN_BOOKMARK_CLEAR:
2026 LyX::ref().session().bookmarks().clear();
2030 BOOST_ASSERT(lyx_view_);
2031 view()->cursor().dispatch(cmd);
2032 updateFlags = view()->cursor().result().update();
2033 if (!view()->cursor().result().dispatched())
2034 updateFlags = view()->dispatch(cmd);
2039 if (lyx_view_ && lyx_view_->buffer()) {
2040 // BufferView::update() updates the ViewMetricsInfo and
2041 // also initializes the position cache for all insets in
2042 // (at least partially) visible top-level paragraphs.
2043 // We will redraw the screen only if needed.
2044 view()->processUpdateFlags(updateFlags);
2045 lyx_view_->updateStatusBar();
2047 // if we executed a mutating lfun, mark the buffer as dirty
2049 && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
2050 && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
2051 lyx_view_->buffer()->markDirty();
2053 //Do we have a selection?
2054 theSelection().haveSelection(view()->cursor().selection());
2056 if (view()->cursor().inTexted()) {
2057 lyx_view_->updateLayoutChoice(false);
2061 if (!quitting && lyx_view_) {
2062 lyx_view_->updateToolbars();
2063 // Some messages may already be translated, so we cannot use _()
2064 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
2069 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
2071 const bool verbose = (cmd.origin == FuncRequest::MENU
2072 || cmd.origin == FuncRequest::TOOLBAR
2073 || cmd.origin == FuncRequest::COMMANDBUFFER);
2075 if (cmd.action == LFUN_SELF_INSERT || !verbose) {
2076 LYXERR(Debug::ACTION, "dispatch msg is " << to_utf8(msg));
2078 lyx_view_->message(msg);
2082 docstring dispatch_msg = msg;
2083 if (!dispatch_msg.empty())
2084 dispatch_msg += ' ';
2086 docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
2088 bool argsadded = false;
2090 if (!cmd.argument().empty()) {
2091 if (cmd.action != LFUN_UNKNOWN_ACTION) {
2092 comname += ' ' + cmd.argument();
2097 docstring const shortcuts = theTopLevelKeymap().printBindings(cmd);
2099 if (!shortcuts.empty())
2100 comname += ": " + shortcuts;
2101 else if (!argsadded && !cmd.argument().empty())
2102 comname += ' ' + cmd.argument();
2104 if (!comname.empty()) {
2105 comname = rtrim(comname);
2106 dispatch_msg += '(' + rtrim(comname) + ')';
2109 LYXERR(Debug::ACTION, "verbose dispatch msg " << to_utf8(dispatch_msg));
2110 if (!dispatch_msg.empty())
2111 lyx_view_->message(dispatch_msg);
2115 void LyXFunc::menuNew(string const & name, bool fromTemplate)
2117 // FIXME: initpath is not used. What to do?
2118 string initpath = lyxrc.document_path;
2119 string filename(name);
2121 if (lyx_view_->buffer()) {
2122 string const trypath = lyx_view_->buffer()->filePath();
2123 // If directory is writeable, use this as default.
2124 if (FileName(trypath).isDirWritable())
2128 static int newfile_number;
2130 if (filename.empty()) {
2131 filename = addName(lyxrc.document_path,
2132 "newfile" + convert<string>(++newfile_number) + ".lyx");
2133 while (theBufferList().exists(filename) ||
2134 FileName(filename).isReadable()) {
2136 filename = addName(lyxrc.document_path,
2137 "newfile" + convert<string>(newfile_number) +
2142 // The template stuff
2145 FileDialog dlg(_("Select template file"));
2146 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
2147 dlg.setButton1(_("Templates|#T#t"), from_utf8(lyxrc.template_path));
2149 FileDialog::Result result =
2150 dlg.open(from_utf8(lyxrc.template_path),
2151 FileFilterList(_("LyX Documents (*.lyx)")),
2154 if (result.first == FileDialog::Later)
2156 if (result.second.empty())
2158 templname = to_utf8(result.second);
2161 Buffer * const b = newFile(filename, templname, !name.empty());
2163 lyx_view_->setBuffer(b);
2167 void LyXFunc::open(string const & fname)
2169 string initpath = lyxrc.document_path;
2171 if (lyx_view_->buffer()) {
2172 string const trypath = lyx_view_->buffer()->filePath();
2173 // If directory is writeable, use this as default.
2174 if (FileName(trypath).isDirWritable())
2180 if (fname.empty()) {
2181 FileDialog dlg(_("Select document to open"), LFUN_FILE_OPEN);
2182 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
2183 dlg.setButton2(_("Examples|#E#e"),
2184 from_utf8(addPath(package().system_support().absFilename(), "examples")));
2186 FileDialog::Result result =
2187 dlg.open(from_utf8(initpath),
2188 FileFilterList(_("LyX Documents (*.lyx)")),
2191 if (result.first == FileDialog::Later)
2194 filename = to_utf8(result.second);
2196 // check selected filename
2197 if (filename.empty()) {
2198 lyx_view_->message(_("Canceled."));
2204 // get absolute path of file and add ".lyx" to the filename if
2206 FileName const fullname = fileSearch(string(), filename, "lyx");
2207 if (!fullname.empty())
2208 filename = fullname.absFilename();
2210 // if the file doesn't exist, let the user create one
2211 if (!fullname.exists()) {
2212 // the user specifically chose this name. Believe him.
2213 Buffer * const b = newFile(filename, string(), true);
2215 lyx_view_->setBuffer(b);
2219 docstring const disp_fn = makeDisplayPath(filename);
2220 lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
2223 Buffer * buf = lyx_view_->loadLyXFile(fullname);
2226 lyx_view_->setBuffer(buf);
2227 lyx_view_->errors("Parse");
2228 str2 = bformat(_("Document %1$s opened."), disp_fn);
2230 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2232 lyx_view_->message(str2);
2236 void LyXFunc::doImport(string const & argument)
2239 string filename = split(argument, format, ' ');
2241 LYXERR(Debug::INFO, "LyXFunc::doImport: " << format
2242 << " file: " << filename);
2244 // need user interaction
2245 if (filename.empty()) {
2246 string initpath = lyxrc.document_path;
2248 if (lyx_view_->buffer()) {
2249 string const trypath = lyx_view_->buffer()->filePath();
2250 // If directory is writeable, use this as default.
2251 if (FileName(trypath).isDirWritable())
2255 docstring const text = bformat(_("Select %1$s file to import"),
2256 formats.prettyName(format));
2258 FileDialog dlg(text, LFUN_BUFFER_IMPORT);
2259 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
2260 dlg.setButton2(_("Examples|#E#e"),
2261 from_utf8(addPath(package().system_support().absFilename(), "examples")));
2263 docstring filter = formats.prettyName(format);
2266 filter += from_utf8(formats.extension(format));
2269 FileDialog::Result result =
2270 dlg.open(from_utf8(initpath),
2271 FileFilterList(filter),
2274 if (result.first == FileDialog::Later)
2277 filename = to_utf8(result.second);
2279 // check selected filename
2280 if (filename.empty())
2281 lyx_view_->message(_("Canceled."));
2284 if (filename.empty())
2287 // get absolute path of file
2288 FileName const fullname(makeAbsPath(filename));
2290 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
2292 // Check if the document already is open
2293 if (use_gui && theBufferList().exists(lyxfile.absFilename())) {
2294 if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) {
2295 lyx_view_->message(_("Canceled."));
2300 // if the file exists already, and we didn't do
2301 // -i lyx thefile.lyx, warn
2302 if (lyxfile.exists() && fullname != lyxfile) {
2303 docstring const file = makeDisplayPath(lyxfile.absFilename(), 30);
2305 docstring text = bformat(_("The document %1$s already exists.\n\n"
2306 "Do you want to overwrite that document?"), file);
2307 int const ret = Alert::prompt(_("Overwrite document?"),
2308 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2311 lyx_view_->message(_("Canceled."));
2316 ErrorList errorList;
2317 import(lyx_view_, fullname, format, errorList);
2318 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2322 void LyXFunc::closeBuffer()
2324 // goto bookmark to update bookmark pit.
2325 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2326 gotoBookmark(i+1, false, false);
2328 theBufferList().close(lyx_view_->buffer(), true);
2332 void LyXFunc::reloadBuffer()
2334 FileName filename(lyx_view_->buffer()->absFileName());
2335 docstring const disp_fn = makeDisplayPath(filename.absFilename());
2338 Buffer * buf = lyx_view_->loadLyXFile(filename);
2341 lyx_view_->setBuffer(buf);
2342 lyx_view_->errors("Parse");
2343 str = bformat(_("Document %1$s reloaded."), disp_fn);
2345 str = bformat(_("Could not reload document %1$s"), disp_fn);
2347 lyx_view_->message(str);
2350 // Each "lyx_view_" should have it's own message method. lyxview and
2351 // the minibuffer would use the minibuffer, but lyxserver would
2352 // send an ERROR signal to its client. Alejandro 970603
2353 // This function is bit problematic when it comes to NLS, to make the
2354 // lyx servers client be language indepenent we must not translate
2355 // strings sent to this func.
2356 void LyXFunc::setErrorMessage(docstring const & m) const
2358 dispatch_buffer = m;
2363 void LyXFunc::setMessage(docstring const & m) const
2365 dispatch_buffer = m;
2369 docstring const LyXFunc::viewStatusMessage()
2371 // When meta-fake key is pressed, show the key sequence so far + "M-".
2373 return keyseq.print(KeySequence::ForGui) + "M-";
2375 // Else, when a non-complete key sequence is pressed,
2376 // show the available options.
2377 if (keyseq.length() > 0 && !keyseq.deleted())
2378 return keyseq.printOptions(true);
2380 BOOST_ASSERT(lyx_view_);
2381 if (!lyx_view_->buffer())
2382 return _("Welcome to LyX!");
2384 return view()->cursor().currentState();
2388 BufferView * LyXFunc::view() const
2390 BOOST_ASSERT(lyx_view_);
2391 return lyx_view_->view();
2395 bool LyXFunc::wasMetaKey() const
2397 return (meta_fake_bit != NoModifier);
2401 void LyXFunc::updateLayout(TextClassPtr const & oldlayout,
2404 lyx_view_->message(_("Converting document to new document class..."));
2406 StableDocIterator backcur(view()->cursor());
2407 ErrorList & el = buffer->errorList("Class Switch");
2408 cap::switchBetweenClasses(
2409 oldlayout, buffer->params().getTextClassPtr(),
2410 static_cast<InsetText &>(buffer->inset()), el);
2412 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
2414 buffer->errors("Class Switch");
2415 updateLabels(*buffer);
2421 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2423 // Why the switch you might ask. It is a trick to ensure that all
2424 // the elements in the LyXRCTags enum is handled. As you can see
2425 // there are no breaks at all. So it is just a huge fall-through.
2426 // The nice thing is that we will get a warning from the compiler
2427 // if we forget an element.
2428 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2430 case LyXRC::RC_ACCEPT_COMPOUND:
2431 case LyXRC::RC_ALT_LANG:
2432 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
2433 case LyXRC::RC_PLAINTEXT_LINELEN:
2434 case LyXRC::RC_AUTOREGIONDELETE:
2435 case LyXRC::RC_AUTORESET_OPTIONS:
2436 case LyXRC::RC_AUTOSAVE:
2437 case LyXRC::RC_AUTO_NUMBER:
2438 case LyXRC::RC_BACKUPDIR_PATH:
2439 case LyXRC::RC_BIBTEX_COMMAND:
2440 case LyXRC::RC_BINDFILE:
2441 case LyXRC::RC_CHECKLASTFILES:
2442 case LyXRC::RC_USELASTFILEPOS:
2443 case LyXRC::RC_LOADSESSION:
2444 case LyXRC::RC_CHKTEX_COMMAND:
2445 case LyXRC::RC_CONVERTER:
2446 case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
2447 case LyXRC::RC_COPIER:
2448 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2449 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2450 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2451 case LyXRC::RC_DATE_INSERT_FORMAT:
2452 case LyXRC::RC_DEFAULT_LANGUAGE:
2453 case LyXRC::RC_DEFAULT_PAPERSIZE:
2454 case LyXRC::RC_DEFFILE:
2455 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2456 case LyXRC::RC_DISPLAY_GRAPHICS:
2457 case LyXRC::RC_DOCUMENTPATH:
2458 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2459 FileName path(lyxrc_new.document_path);
2460 if (path.exists() && path.isDirectory())
2461 support::package().document_dir() = FileName(lyxrc.document_path);
2463 case LyXRC::RC_ESC_CHARS:
2464 case LyXRC::RC_FONT_ENCODING:
2465 case LyXRC::RC_FORMAT:
2466 case LyXRC::RC_INDEX_COMMAND:
2467 case LyXRC::RC_INPUT:
2468 case LyXRC::RC_KBMAP:
2469 case LyXRC::RC_KBMAP_PRIMARY:
2470 case LyXRC::RC_KBMAP_SECONDARY:
2471 case LyXRC::RC_LABEL_INIT_LENGTH:
2472 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2473 case LyXRC::RC_LANGUAGE_AUTO_END:
2474 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2475 case LyXRC::RC_LANGUAGE_COMMAND_END:
2476 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2477 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2478 case LyXRC::RC_LANGUAGE_PACKAGE:
2479 case LyXRC::RC_LANGUAGE_USE_BABEL:
2480 case LyXRC::RC_MAKE_BACKUP:
2481 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2482 case LyXRC::RC_NUMLASTFILES:
2483 case LyXRC::RC_PATH_PREFIX:
2484 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2485 support::prependEnvPath("PATH", lyxrc.path_prefix);
2487 case LyXRC::RC_PERS_DICT:
2488 case LyXRC::RC_PREVIEW:
2489 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2490 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2491 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2492 case LyXRC::RC_PRINTCOPIESFLAG:
2493 case LyXRC::RC_PRINTER:
2494 case LyXRC::RC_PRINTEVENPAGEFLAG:
2495 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2496 case LyXRC::RC_PRINTFILEEXTENSION:
2497 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2498 case LyXRC::RC_PRINTODDPAGEFLAG:
2499 case LyXRC::RC_PRINTPAGERANGEFLAG:
2500 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2501 case LyXRC::RC_PRINTPAPERFLAG:
2502 case LyXRC::RC_PRINTREVERSEFLAG:
2503 case LyXRC::RC_PRINTSPOOL_COMMAND:
2504 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2505 case LyXRC::RC_PRINTTOFILE:
2506 case LyXRC::RC_PRINTTOPRINTER:
2507 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2508 case LyXRC::RC_PRINT_COMMAND:
2509 case LyXRC::RC_RTL_SUPPORT:
2510 case LyXRC::RC_SCREEN_DPI:
2511 case LyXRC::RC_SCREEN_FONT_ROMAN:
2512 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2513 case LyXRC::RC_SCREEN_FONT_SANS:
2514 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2515 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2516 case LyXRC::RC_SCREEN_FONT_SIZES:
2517 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2518 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2519 case LyXRC::RC_GEOMETRY_SESSION:
2520 case LyXRC::RC_SCREEN_ZOOM:
2521 case LyXRC::RC_SERVERPIPE:
2522 case LyXRC::RC_SET_COLOR:
2523 case LyXRC::RC_SHOW_BANNER:
2524 case LyXRC::RC_SPELL_COMMAND:
2525 case LyXRC::RC_TEMPDIRPATH:
2526 case LyXRC::RC_TEMPLATEPATH:
2527 case LyXRC::RC_TEX_ALLOWS_SPACES:
2528 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2529 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2530 support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2532 case LyXRC::RC_UIFILE:
2533 case LyXRC::RC_USER_EMAIL:
2534 case LyXRC::RC_USER_NAME:
2535 case LyXRC::RC_USETEMPDIR:
2536 case LyXRC::RC_USE_ALT_LANG:
2537 case LyXRC::RC_USE_CONVERTER_CACHE:
2538 case LyXRC::RC_USE_ESC_CHARS:
2539 case LyXRC::RC_USE_INP_ENC:
2540 case LyXRC::RC_USE_PERS_DICT:
2541 case LyXRC::RC_USE_PIXMAP_CACHE:
2542 case LyXRC::RC_USE_SPELL_LIB:
2543 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2544 case LyXRC::RC_SORT_LAYOUTS:
2545 case LyXRC::RC_VIEWER:
2546 case LyXRC::RC_LAST: