3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Alfredo Braunstein
7 * \author Lars Gullik Bjønnes
8 * \author Jean-Marc Lasgouttes
9 * \author Angus Leeming
11 * \author André Pönitz
14 * \author Martin Vermeer
15 * \author Jürgen Vigna
17 * Full author contact details are available in file CREDITS.
25 #include "BranchList.h"
26 #include "buffer_funcs.h"
28 #include "BufferList.h"
29 #include "BufferParams.h"
30 #include "BufferView.h"
33 #include "Converter.h"
35 #include "CutAndPaste.h"
37 #include "DispatchResult.h"
39 #include "ErrorList.h"
41 #include "FuncRequest.h"
42 #include "FuncStatus.h"
44 #include "InsetIterator.h"
49 #include "LyXAction.h"
54 #include "Paragraph.h"
55 #include "ParagraphParameters.h"
56 #include "ParIterator.h"
60 #include "TextClassList.h"
61 #include "ToolbarBackend.h"
63 #include "insets/InsetBox.h"
64 #include "insets/InsetBranch.h"
65 #include "insets/InsetCommand.h"
66 #include "insets/InsetERT.h"
67 #include "insets/InsetExternal.h"
68 #include "insets/InsetFloat.h"
69 #include "insets/InsetListings.h"
70 #include "insets/InsetGraphics.h"
71 #include "insets/InsetInclude.h"
72 #include "insets/InsetNote.h"
73 #include "insets/InsetTabular.h"
74 #include "insets/InsetVSpace.h"
75 #include "insets/InsetWrap.h"
77 #include "frontends/Application.h"
78 #include "frontends/alert.h"
79 #include "frontends/Dialogs.h"
80 #include "frontends/FileDialog.h"
81 #include "frontends/FontLoader.h"
82 #include "frontends/Gui.h"
83 #include "frontends/KeySymbol.h"
84 #include "frontends/LyXView.h"
85 #include "frontends/Selection.h"
87 #include "support/environment.h"
88 #include "support/FileFilterList.h"
89 #include "support/filetools.h"
90 #include "support/lstrings.h"
91 #include "support/Path.h"
92 #include "support/Package.h"
93 #include "support/Systemcall.h"
94 #include "support/convert.h"
95 #include "support/os.h"
97 #include <boost/current_function.hpp>
102 using std::make_pair;
105 using std::istringstream;
106 using std::ostringstream;
112 using frontend::LyXView;
114 using support::absolutePath;
115 using support::addName;
116 using support::addPath;
117 using support::bformat;
118 using support::changeExtension;
119 using support::contains;
120 using support::FileFilterList;
121 using support::FileName;
122 using support::fileSearch;
123 using support::i18nLibFileSearch;
124 using support::makeDisplayPath;
125 using support::makeAbsPath;
126 using support::package;
127 using support::quoteName;
128 using support::rtrim;
129 using support::split;
130 using support::subst;
131 using support::Systemcall;
132 using support::token;
134 using support::prefixIs;
137 namespace Alert = frontend::Alert;
139 extern bool quitting;
144 bool import(LyXView * lv, FileName const & filename,
145 string const & format, ErrorList & errorList)
147 docstring const displaypath = makeDisplayPath(filename.absFilename());
148 lv->message(bformat(_("Importing %1$s..."), displaypath));
150 FileName const lyxfile(changeExtension(filename.absFilename(), ".lyx"));
152 string loader_format;
153 vector<string> loaders = theConverters().loaders();
154 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
155 for (vector<string>::const_iterator it = loaders.begin();
156 it != loaders.end(); ++it) {
157 if (theConverters().isReachable(format, *it)) {
158 string const tofile =
159 changeExtension(filename.absFilename(),
160 formats.extension(*it));
161 if (!theConverters().convert(0, filename, FileName(tofile),
162 filename, format, *it, errorList))
168 if (loader_format.empty()) {
169 frontend::Alert::error(_("Couldn't import file"),
170 bformat(_("No information for importing the format %1$s."),
171 formats.prettyName(format)));
175 loader_format = format;
179 if (loader_format == "lyx") {
180 Buffer * buf = lv->loadLyXFile(lyxfile);
183 lv->message(_("file not imported!"));
190 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
195 bool as_paragraphs = loader_format == "textparagraph";
196 string filename2 = (loader_format == format) ? filename.absFilename()
197 : changeExtension(filename.absFilename(),
198 formats.extension(loader_format));
199 lv->view()->insertPlaintextFile(filename2, as_paragraphs);
200 lv->dispatch(FuncRequest(LFUN_MARK_OFF));
204 lv->message(_("imported."));
210 // This function runs "configure" and then rereads lyx.defaults to
211 // reconfigure the automatic settings.
212 void reconfigure(LyXView & lv, string const & option)
214 // emit message signal.
215 lv.message(_("Running configure..."));
217 // Run configure in user lyx directory
218 support::PathChanger p(package().user_support());
219 string configure_command = package().configure_command();
220 configure_command += option;
222 int ret = one.startscript(Systemcall::Wait, configure_command);
224 // emit message signal.
225 lv.message(_("Reloading configuration..."));
226 lyxrc.read(support::libFileSearch(string(), "lyxrc.defaults"));
227 // Re-read packages.lst
228 LaTeXFeatures::getAvailable();
231 Alert::information(_("System reconfiguration failed"),
232 _("The system reconfiguration has failed.\n"
233 "Default textclass is used but LyX may "
234 "not be able to work properly.\n"
235 "Please reconfigure again if needed."));
238 Alert::information(_("System reconfigured"),
239 _("The system has been reconfigured.\n"
240 "You need to restart LyX to make use of any\n"
241 "updated document class specifications."));
245 bool getLocalStatus(Cursor cursor, FuncRequest const & cmd, FuncStatus & status)
247 // Try to fix cursor in case it is broken.
248 cursor.fixIfBroken();
250 // This is, of course, a mess. Better create a new doc iterator and use
251 // this in Inset::getStatus. This might require an additional
252 // BufferView * arg, though (which should be avoided)
253 //Cursor safe = *this;
255 for ( ; cursor.depth(); cursor.pop()) {
256 //lyxerr << "\nCursor::getStatus: cmd: " << cmd << endl << *this << endl;
257 BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
258 BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
259 BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
261 // The inset's getStatus() will return 'true' if it made
262 // a definitive decision on whether it want to handle the
263 // request or not. The result of this decision is put into
264 // the 'status' parameter.
265 if (cursor.inset().getStatus(cursor, cmd, status)) {
274 /** Return the change status at cursor position, taking in account the
275 * status at each level of the document iterator (a table in a deleted
276 * footnote is deleted).
277 * When \param outer is true, the top slice is not looked at.
279 Change::Type lookupChangeType(DocIterator const & dit, bool outer = false)
281 size_t const depth = dit.depth() - (outer ? 1 : 0);
283 for (size_t i = 0 ; i < depth ; ++i) {
284 CursorSlice const & slice = dit[i];
285 if (!slice.inset().inMathed()
286 && slice.pos() < slice.paragraph().size()) {
287 Change::Type const ch = slice.paragraph().lookupChange(slice.pos()).type;
288 if (ch != Change::UNCHANGED)
292 return Change::UNCHANGED;
299 : lyx_view_(0), encoded_last_key(0), meta_fake_bit(NoModifier)
304 void LyXFunc::initKeySequences(KeyMap * kb)
306 keyseq = KeySequence(kb, kb);
307 cancel_meta_seq = KeySequence(kb, kb);
311 void LyXFunc::setLyXView(LyXView * lv)
313 if (!quitting && lyx_view_ && lyx_view_->view() && lyx_view_ != lv)
314 // save current selection to the selection buffer to allow
315 // middle-button paste in another window
316 cap::saveSelection(lyx_view_->view()->cursor());
321 void LyXFunc::handleKeyFunc(kb_action action)
323 char_type c = encoded_last_key;
328 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
329 lyx_view_->view()->getIntl().getTransManager().deadkey(
330 c, get_accent(action).accent, view()->cursor().innerText(), view()->cursor());
331 // Need to clear, in case the minibuffer calls these
334 // copied verbatim from do_accent_char
335 view()->cursor().resetAnchor();
336 view()->processUpdateFlags(Update::FitCursor);
340 void LyXFunc::gotoBookmark(unsigned int idx, bool openFile, bool switchToBuffer)
342 BOOST_ASSERT(lyx_view_);
343 if (!LyX::ref().session().bookmarks().isValid(idx))
345 BookmarksSection::Bookmark const & bm = LyX::ref().session().bookmarks().bookmark(idx);
346 BOOST_ASSERT(!bm.filename.empty());
347 string const file = bm.filename.absFilename();
348 // if the file is not opened, open it.
349 if (!theBufferList().exists(file)) {
351 dispatch(FuncRequest(LFUN_FILE_OPEN, file));
355 // open may fail, so we need to test it again
356 if (!theBufferList().exists(file))
359 // if the current buffer is not that one, switch to it.
360 if (lyx_view_->buffer()->absFileName() != file) {
363 dispatch(FuncRequest(LFUN_BUFFER_SWITCH, file));
365 // moveToPosition try paragraph id first and then paragraph (pit, pos).
366 if (!view()->moveToPosition(bm.bottom_pit, bm.bottom_pos,
367 bm.top_id, bm.top_pos))
370 // Cursor jump succeeded!
371 Cursor const & cur = view()->cursor();
372 pit_type new_pit = cur.pit();
373 pos_type new_pos = cur.pos();
374 int new_id = cur.paragraph().id();
376 // if bottom_pit, bottom_pos or top_id has been changed, update bookmark
377 // see http://bugzilla.lyx.org/show_bug.cgi?id=3092
378 if (bm.bottom_pit != new_pit || bm.bottom_pos != new_pos
379 || bm.top_id != new_id) {
380 const_cast<BookmarksSection::Bookmark &>(bm).updatePos(
381 new_pit, new_pos, new_id);
386 void LyXFunc::processKeySym(KeySymbol const & keysym, KeyModifier state)
388 LYXERR(Debug::KEY) << "KeySym is " << keysym.getSymbolName() << endl;
390 // Do nothing if we have nothing (JMarc)
391 if (!keysym.isOK()) {
392 LYXERR(Debug::KEY) << "Empty kbd action (probably composing)"
394 lyx_view_->restartCursor();
398 if (keysym.isModifier()) {
399 LYXERR(Debug::KEY) << "isModifier true" << endl;
400 lyx_view_->restartCursor();
404 //Encoding const * encoding = view()->cursor().getEncoding();
405 //encoded_last_key = keysym.getISOEncoded(encoding ? encoding->name() : "");
406 // FIXME: encoded_last_key shadows the member variable of the same
407 // name. Is that intended?
408 char_type encoded_last_key = keysym.getUCSEncoded();
410 // Do a one-deep top-level lookup for
411 // cancel and meta-fake keys. RVDK_PATCH_5
412 cancel_meta_seq.reset();
414 FuncRequest func = cancel_meta_seq.addkey(keysym, state);
415 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
416 << " action first set to [" << func.action << ']'
419 // When not cancel or meta-fake, do the normal lookup.
420 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
421 // Mostly, meta_fake_bit = NoModifier. RVDK_PATCH_5.
422 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_PREFIX)) {
423 // remove Caps Lock and Mod2 as a modifiers
424 func = keyseq.addkey(keysym, (state | meta_fake_bit));
425 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
426 << "action now set to ["
427 << func.action << ']' << endl;
430 // Dont remove this unless you know what you are doing.
431 meta_fake_bit = NoModifier;
433 // Can this happen now ?
434 if (func.action == LFUN_NOACTION)
435 func = FuncRequest(LFUN_COMMAND_PREFIX);
437 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
439 << func.action << "]["
440 << to_utf8(keyseq.print(KeySequence::Portable)) << ']'
443 // already here we know if it any point in going further
444 // why not return already here if action == -1 and
445 // num_bytes == 0? (Lgb)
447 if (keyseq.length() > 1)
448 lyx_view_->message(keyseq.print(KeySequence::ForGui));
451 // Maybe user can only reach the key via holding down shift.
452 // Let's see. But only if shift is the only modifier
453 if (func.action == LFUN_UNKNOWN_ACTION && state == ShiftModifier) {
454 LYXERR(Debug::KEY) << "Trying without shift" << endl;
455 func = keyseq.addkey(keysym, NoModifier);
456 LYXERR(Debug::KEY) << "Action now " << func.action << endl;
459 if (func.action == LFUN_UNKNOWN_ACTION) {
460 // Hmm, we didn't match any of the keysequences. See
461 // if it's normal insertable text not already covered
463 if (keysym.isText() && keyseq.length() == 1) {
464 LYXERR(Debug::KEY) << "isText() is true, inserting." << endl;
465 func = FuncRequest(LFUN_SELF_INSERT,
466 FuncRequest::KEYBOARD);
468 LYXERR(Debug::KEY) << "Unknown, !isText() - giving up" << endl;
469 lyx_view_->message(_("Unknown function."));
470 lyx_view_->restartCursor();
475 if (func.action == LFUN_SELF_INSERT) {
476 if (encoded_last_key != 0) {
477 docstring const arg(1, encoded_last_key);
478 dispatch(FuncRequest(LFUN_SELF_INSERT, arg,
479 FuncRequest::KEYBOARD));
481 << "SelfInsert arg[`" << to_utf8(arg) << "']" << endl;
487 lyx_view_->restartCursor();
491 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
493 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
496 /* In LyX/Mac, when a dialog is open, the menus of the
497 application can still be accessed without giving focus to
498 the main window. In this case, we want to disable the menu
499 entries that are buffer-related.
501 Note that this code is not perfect, as bug 1941 attests:
502 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
504 Buffer * buf = lyx_view_? lyx_view_->buffer() : 0;
505 if (lyx_view_ && cmd.origin == FuncRequest::MENU && !lyx_view_->hasFocus())
508 if (cmd.action == LFUN_NOACTION) {
509 flag.message(from_utf8(N_("Nothing to do")));
514 switch (cmd.action) {
515 case LFUN_UNKNOWN_ACTION:
516 #ifndef HAVE_LIBAIKSAURUS
517 case LFUN_THESAURUS_ENTRY:
527 if (flag.unknown()) {
528 flag.message(from_utf8(N_("Unknown action")));
532 if (!flag.enabled()) {
533 if (flag.message().empty())
534 flag.message(from_utf8(N_("Command disabled")));
538 // Check whether we need a buffer
539 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
541 flag.message(from_utf8(N_("Command not allowed with"
542 "out any document open")));
547 // I would really like to avoid having this switch and rather try to
548 // encode this in the function itself.
549 // -- And I'd rather let an inset decide which LFUNs it is willing
550 // to handle (Andre')
552 switch (cmd.action) {
553 case LFUN_BUFFER_TOGGLE_READ_ONLY:
554 flag.setOnOff(buf->isReadonly());
557 case LFUN_BUFFER_SWITCH:
558 // toggle on the current buffer, but do not toggle off
559 // the other ones (is that a good idea?)
560 if (buf && to_utf8(cmd.argument()) == buf->absFileName())
564 case LFUN_BUFFER_EXPORT:
565 enable = cmd.argument() == "custom"
566 || buf->isExportable(to_utf8(cmd.argument()));
569 case LFUN_BUFFER_CHKTEX:
570 enable = buf->isLatex() && !lyxrc.chktex_command.empty();
573 case LFUN_BUILD_PROGRAM:
574 enable = buf->isExportable("program");
577 case LFUN_VC_REGISTER:
578 enable = !buf->lyxvc().inUse();
580 case LFUN_VC_CHECK_IN:
581 enable = buf->lyxvc().inUse() && !buf->isReadonly();
583 case LFUN_VC_CHECK_OUT:
584 enable = buf->lyxvc().inUse() && buf->isReadonly();
587 case LFUN_VC_UNDO_LAST:
588 enable = buf->lyxvc().inUse();
590 case LFUN_BUFFER_RELOAD:
591 enable = !buf->isUnnamed() && buf->fileName().exists()
592 && (!buf->isClean() || buf->isExternallyModified(Buffer::timestamp_method));
595 case LFUN_INSET_APPLY: {
600 string const name = cmd.getArg(0);
601 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
603 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
605 if (!inset->getStatus(view()->cursor(), fr, fs)) {
606 // Every inset is supposed to handle this
611 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
612 flag |= getStatus(fr);
614 enable = flag.enabled();
618 case LFUN_DIALOG_TOGGLE:
619 flag.setOnOff(lyx_view_->getDialogs().visible(cmd.getArg(0)));
620 // fall through to set "enable"
621 case LFUN_DIALOG_SHOW: {
622 string const name = cmd.getArg(0);
624 enable = name == "aboutlyx"
625 || name == "file" //FIXME: should be removed.
627 || name == "texinfo";
628 else if (name == "print")
629 enable = buf->isExportable("dvi")
630 && lyxrc.print_command != "none";
631 else if (name == "character") {
635 InsetCode ic = view()->cursor().inset().lyxCode();
636 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
639 else if (name == "latexlog")
640 enable = FileName(buf->logName()).isFileReadable();
641 else if (name == "spellchecker")
642 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
643 enable = !buf->isReadonly();
647 else if (name == "vclog")
648 enable = buf->lyxvc().inUse();
652 case LFUN_DIALOG_UPDATE: {
653 string const name = cmd.getArg(0);
655 enable = name == "prefs";
659 case LFUN_CITATION_INSERT: {
660 FuncRequest fr(LFUN_INSET_INSERT, "citation");
661 enable = getStatus(fr).enabled();
665 case LFUN_BUFFER_WRITE: {
666 enable = lyx_view_->buffer()->isUnnamed()
667 || !lyx_view_->buffer()->isClean();
672 case LFUN_BUFFER_WRITE_ALL: {
673 // We enable the command only if there are some modified buffers
674 Buffer * first = theBufferList().first();
675 bool modified = false;
679 // We cannot use a for loop as the buffer list is a cycle.
685 b = theBufferList().next(b);
686 } while (b != first);
694 case LFUN_BOOKMARK_GOTO: {
695 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
696 enable = LyX::ref().session().bookmarks().isValid(num);
700 case LFUN_BOOKMARK_CLEAR:
701 enable = LyX::ref().session().bookmarks().size() > 0;
704 case LFUN_TOOLBAR_TOGGLE: {
705 bool const current = lyx_view_->isToolbarVisible(cmd.getArg(0));
706 flag.setOnOff(current);
709 case LFUN_WINDOW_CLOSE: {
710 enable = (theApp()->gui().viewIds().size() > 1);
714 // this one is difficult to get right. As a half-baked
715 // solution, we consider only the first action of the sequence
716 case LFUN_COMMAND_SEQUENCE: {
717 // argument contains ';'-terminated commands
718 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
719 FuncRequest func(lyxaction.lookupFunc(firstcmd));
720 func.origin = cmd.origin;
721 flag = getStatus(func);
727 std::string name(to_utf8(cmd.argument()));
728 if (LyX::ref().topLevelCmdDef().lock(name, func)) {
729 func.origin = cmd.origin;
730 flag = getStatus(func);
731 LyX::ref().topLevelCmdDef().release(name);
733 // catch recursion or unknown command definiton
734 // all operations until the recursion or unknown command
735 // definiton occures are performed, so set the state to enabled
741 case LFUN_BUFFER_NEW:
742 case LFUN_BUFFER_NEW_TEMPLATE:
743 case LFUN_WORD_FIND_FORWARD:
744 case LFUN_WORD_FIND_BACKWARD:
745 case LFUN_COMMAND_PREFIX:
746 case LFUN_COMMAND_EXECUTE:
748 case LFUN_META_PREFIX:
749 case LFUN_BUFFER_CLOSE:
750 case LFUN_BUFFER_WRITE_AS:
751 case LFUN_BUFFER_UPDATE:
752 case LFUN_BUFFER_VIEW:
753 case LFUN_MASTER_BUFFER_UPDATE:
754 case LFUN_MASTER_BUFFER_VIEW:
755 case LFUN_BUFFER_IMPORT:
756 case LFUN_BUFFER_AUTO_SAVE:
757 case LFUN_RECONFIGURE:
761 case LFUN_DROP_LAYOUTS_CHOICE:
763 case LFUN_SERVER_GET_NAME:
764 case LFUN_SERVER_NOTIFY:
765 case LFUN_SERVER_GOTO_FILE_ROW:
766 case LFUN_DIALOG_HIDE:
767 case LFUN_DIALOG_DISCONNECT_INSET:
768 case LFUN_BUFFER_CHILD_OPEN:
769 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
770 case LFUN_KEYMAP_OFF:
771 case LFUN_KEYMAP_PRIMARY:
772 case LFUN_KEYMAP_SECONDARY:
773 case LFUN_KEYMAP_TOGGLE:
775 case LFUN_BUFFER_EXPORT_CUSTOM:
776 case LFUN_BUFFER_PRINT:
777 case LFUN_PREFERENCES_SAVE:
778 case LFUN_SCREEN_FONT_UPDATE:
781 case LFUN_EXTERNAL_EDIT:
782 case LFUN_GRAPHICS_EDIT:
783 case LFUN_ALL_INSETS_TOGGLE:
784 case LFUN_BUFFER_LANGUAGE:
785 case LFUN_TEXTCLASS_APPLY:
786 case LFUN_TEXTCLASS_LOAD:
787 case LFUN_BUFFER_SAVE_AS_DEFAULT:
788 case LFUN_BUFFER_PARAMS_APPLY:
789 case LFUN_LAYOUT_MODULES_CLEAR:
790 case LFUN_LAYOUT_MODULE_ADD:
791 case LFUN_LAYOUT_RELOAD:
792 case LFUN_LYXRC_APPLY:
793 case LFUN_BUFFER_NEXT:
794 case LFUN_BUFFER_PREVIOUS:
795 case LFUN_WINDOW_NEW:
797 // these are handled in our dispatch()
805 if (!getLocalStatus(view()->cursor(), cmd, flag))
806 flag = view()->getStatus(cmd);
812 // Can we use a readonly buffer?
813 if (buf && buf->isReadonly()
814 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
815 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
816 flag.message(from_utf8(N_("Document is read-only")));
820 // Are we in a DELETED change-tracking region?
822 && lookupChangeType(view()->cursor(), true) == Change::DELETED
823 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
824 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
825 flag.message(from_utf8(N_("This portion of the document is deleted.")));
829 // the default error message if we disable the command
830 if (!flag.enabled() && flag.message().empty())
831 flag.message(from_utf8(N_("Command disabled")));
837 bool LyXFunc::ensureBufferClean(BufferView * bv)
839 Buffer & buf = bv->buffer();
843 docstring const file = buf.fileName().displayName(30);
844 docstring text = bformat(_("The document %1$s has unsaved "
845 "changes.\n\nDo you want to save "
846 "the document?"), file);
847 int const ret = Alert::prompt(_("Save changed document?"),
848 text, 0, 1, _("&Save"),
852 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
854 return buf.isClean();
860 void showPrintError(string const & name)
862 docstring str = bformat(_("Could not print the document %1$s.\n"
863 "Check that your printer is set up correctly."),
864 makeDisplayPath(name, 50));
865 Alert::error(_("Print document failed"), str);
869 void loadTextClass(string const & name)
871 std::pair<bool, textclass_type> const tc_pair =
872 textclasslist.numberOfClass(name);
874 if (!tc_pair.first) {
875 lyxerr << "Document class \"" << name
876 << "\" does not exist."
881 textclass_type const tc = tc_pair.second;
883 if (!textclasslist[tc].load()) {
884 docstring s = bformat(_("The document class %1$s."
885 "could not be loaded."),
886 from_utf8(textclasslist[tc].name()));
887 Alert::error(_("Could not load class"), s);
892 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
897 void LyXFunc::dispatch(FuncRequest const & cmd)
899 string const argument = to_utf8(cmd.argument());
900 kb_action const action = cmd.action;
902 LYXERR(Debug::ACTION) << endl << "LyXFunc::dispatch: cmd: " << cmd << endl;
903 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
905 // we have not done anything wrong yet.
907 dispatch_buffer.erase();
909 // redraw the screen at the end (first of the two drawing steps).
910 //This is done unless explicitely requested otherwise
911 Update::flags updateFlags = Update::FitCursor;
913 FuncStatus const flag = getStatus(cmd);
914 if (!flag.enabled()) {
915 // We cannot use this function here
916 LYXERR(Debug::ACTION) << "LyXFunc::dispatch: "
917 << lyxaction.getActionName(action)
918 << " [" << action << "] is disabled at this location"
920 setErrorMessage(flag.message());
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));
952 case LFUN_COMMAND_EXECUTE:
953 BOOST_ASSERT(lyx_view_);
954 lyx_view_->showMiniBuffer(true);
958 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
960 meta_fake_bit = NoModifier;
961 if (lyx_view_->buffer())
962 // cancel any selection
963 dispatch(FuncRequest(LFUN_MARK_OFF));
964 setMessage(from_ascii(N_("Cancel")));
967 case LFUN_META_PREFIX:
968 meta_fake_bit = AltModifier;
969 setMessage(keyseq.print(KeySequence::ForGui));
972 case LFUN_BUFFER_TOGGLE_READ_ONLY: {
973 BOOST_ASSERT(lyx_view_ && lyx_view_->view() && lyx_view_->buffer());
974 Buffer * buf = lyx_view_->buffer();
975 if (buf->lyxvc().inUse())
976 buf->lyxvc().toggleReadOnly();
978 buf->setReadonly(!lyx_view_->buffer()->isReadonly());
982 // --- Menus -----------------------------------------------
983 case LFUN_BUFFER_NEW:
984 menuNew(argument, false);
985 updateFlags = Update::None;
988 case LFUN_BUFFER_NEW_TEMPLATE:
989 menuNew(argument, true);
990 updateFlags = Update::None;
993 case LFUN_BUFFER_CLOSE:
995 updateFlags = Update::None;
998 case LFUN_BUFFER_WRITE:
999 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1000 if (!lyx_view_->buffer()->isUnnamed()) {
1001 docstring const str = bformat(_("Saving document %1$s..."),
1002 makeDisplayPath(lyx_view_->buffer()->absFileName()));
1003 lyx_view_->message(str);
1004 lyx_view_->buffer()->menuWrite();
1005 lyx_view_->message(str + _(" done."));
1007 lyx_view_->buffer()->writeAs();
1009 updateFlags = Update::None;
1012 case LFUN_BUFFER_WRITE_AS:
1013 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1014 lyx_view_->buffer()->writeAs(argument);
1015 updateFlags = Update::None;
1018 case LFUN_BUFFER_WRITE_ALL: {
1019 Buffer * first = theBufferList().first();
1022 lyx_view_->message(_("Saving all documents..."));
1024 // We cannot use a for loop as the buffer list cycles.
1026 if (!b->isClean()) {
1027 if (!b->isUnnamed()) {
1029 lyxerr[Debug::ACTION] << "Saved " << b->absFileName() << endl;
1033 b = theBufferList().next(b);
1034 } while (b != first);
1035 lyx_view_->message(_("All documents saved."));
1038 updateFlags = Update::None;
1042 case LFUN_BUFFER_RELOAD: {
1043 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1044 docstring const file = makeDisplayPath(lyx_view_->buffer()->absFileName(), 20);
1045 docstring text = bformat(_("Any changes will be lost. Are you sure "
1046 "you want to revert to the saved version of the document %1$s?"), file);
1047 int const ret = Alert::prompt(_("Revert to saved document?"),
1048 text, 1, 1, _("&Revert"), _("&Cancel"));
1055 case LFUN_BUFFER_UPDATE:
1056 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1057 lyx_view_->buffer()->doExport(argument, true);
1060 case LFUN_BUFFER_VIEW:
1061 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1062 lyx_view_->buffer()->preview(argument);
1065 case LFUN_MASTER_BUFFER_UPDATE:
1066 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->masterBuffer());
1067 lyx_view_->buffer()->masterBuffer()->doExport(argument, true);
1070 case LFUN_MASTER_BUFFER_VIEW:
1071 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->masterBuffer());
1072 lyx_view_->buffer()->masterBuffer()->preview(argument);
1075 case LFUN_BUILD_PROGRAM:
1076 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1077 lyx_view_->buffer()->doExport("program", true);
1080 case LFUN_BUFFER_CHKTEX:
1081 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1082 lyx_view_->buffer()->runChktex();
1085 case LFUN_BUFFER_EXPORT:
1086 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1087 if (argument == "custom")
1088 lyx_view_->getDialogs().show("sendto");
1090 lyx_view_->buffer()->doExport(argument, false);
1093 case LFUN_BUFFER_EXPORT_CUSTOM: {
1094 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1096 string command = split(argument, format_name, ' ');
1097 Format const * format = formats.getFormat(format_name);
1099 lyxerr << "Format \"" << format_name
1100 << "\" not recognized!"
1105 Buffer * buffer = lyx_view_->buffer();
1107 // The name of the file created by the conversion process
1110 // Output to filename
1111 if (format->name() == "lyx") {
1112 string const latexname = buffer->latexName(false);
1113 filename = changeExtension(latexname,
1114 format->extension());
1115 filename = addName(buffer->temppath(), filename);
1117 if (!buffer->writeFile(FileName(filename)))
1121 buffer->doExport(format_name, true, filename);
1124 // Substitute $$FName for filename
1125 if (!contains(command, "$$FName"))
1126 command = "( " + command + " ) < $$FName";
1127 command = subst(command, "$$FName", filename);
1129 // Execute the command in the background
1131 call.startscript(Systemcall::DontWait, command);
1135 case LFUN_BUFFER_PRINT: {
1136 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1137 // FIXME: cmd.getArg() might fail if one of the arguments
1138 // contains double quotes
1139 string target = cmd.getArg(0);
1140 string target_name = cmd.getArg(1);
1141 string command = cmd.getArg(2);
1144 || target_name.empty()
1145 || command.empty()) {
1146 lyxerr << "Unable to parse \""
1147 << argument << '"' << endl;
1150 if (target != "printer" && target != "file") {
1151 lyxerr << "Unrecognized target \""
1152 << target << '"' << endl;
1156 Buffer * buffer = lyx_view_->buffer();
1158 if (!buffer->doExport("dvi", true)) {
1159 showPrintError(buffer->absFileName());
1163 // Push directory path.
1164 string const path = buffer->temppath();
1165 // Prevent the compiler from optimizing away p
1167 support::PathChanger p(pp);
1169 // there are three cases here:
1170 // 1. we print to a file
1171 // 2. we print directly to a printer
1172 // 3. we print using a spool command (print to file first)
1175 string const dviname =
1176 changeExtension(buffer->latexName(true), "dvi");
1178 if (target == "printer") {
1179 if (!lyxrc.print_spool_command.empty()) {
1180 // case 3: print using a spool
1181 string const psname =
1182 changeExtension(dviname,".ps");
1183 command += ' ' + lyxrc.print_to_file
1186 + quoteName(dviname);
1189 lyxrc.print_spool_command + ' ';
1190 if (target_name != "default") {
1191 command2 += lyxrc.print_spool_printerprefix
1195 command2 += quoteName(psname);
1197 // If successful, then spool command
1198 res = one.startscript(
1203 res = one.startscript(
1204 Systemcall::DontWait,
1207 // case 2: print directly to a printer
1208 if (target_name != "default")
1209 command += ' ' + lyxrc.print_to_printer + target_name + ' ';
1210 res = one.startscript(
1211 Systemcall::DontWait,
1212 command + quoteName(dviname));
1216 // case 1: print to a file
1217 FileName const filename(makeAbsPath(target_name,
1218 lyx_view_->buffer()->filePath()));
1219 FileName const dvifile(makeAbsPath(dviname, path));
1220 if (filename.exists()) {
1221 docstring text = bformat(
1222 _("The file %1$s already exists.\n\n"
1223 "Do you want to overwrite that file?"),
1224 makeDisplayPath(filename.absFilename()));
1225 if (Alert::prompt(_("Overwrite file?"),
1226 text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
1229 command += ' ' + lyxrc.print_to_file
1230 + quoteName(filename.toFilesystemEncoding())
1232 + quoteName(dvifile.toFilesystemEncoding());
1233 res = one.startscript(Systemcall::DontWait,
1238 showPrintError(buffer->absFileName());
1242 case LFUN_BUFFER_IMPORT:
1247 // quitting is triggered by the gui code
1248 // (leaving the event loop).
1249 lyx_view_->message(from_utf8(N_("Exiting.")));
1250 if (theBufferList().quitWriteAll())
1251 theApp()->gui().closeAllViews();
1254 case LFUN_BUFFER_AUTO_SAVE:
1255 lyx_view_->buffer()->autoSave();
1258 case LFUN_RECONFIGURE:
1259 BOOST_ASSERT(lyx_view_);
1260 // argument is any additional parameter to the configure.py command
1261 reconfigure(*lyx_view_, argument);
1264 case LFUN_HELP_OPEN: {
1265 BOOST_ASSERT(lyx_view_);
1266 string const arg = argument;
1268 setErrorMessage(from_ascii(N_("Missing argument")));
1271 FileName const fname = i18nLibFileSearch("doc", arg, "lyx");
1272 if (fname.empty()) {
1273 lyxerr << "LyX: unable to find documentation file `"
1274 << arg << "'. Bad installation?" << endl;
1277 lyx_view_->message(bformat(_("Opening help file %1$s..."),
1278 makeDisplayPath(fname.absFilename())));
1279 Buffer * buf = lyx_view_->loadLyXFile(fname, false);
1282 lyx_view_->setBuffer(buf);
1283 lyx_view_->errors("Parse");
1285 updateFlags = Update::None;
1289 // --- version control -------------------------------
1290 case LFUN_VC_REGISTER:
1291 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1292 if (!ensureBufferClean(view()))
1294 if (!lyx_view_->buffer()->lyxvc().inUse()) {
1295 lyx_view_->buffer()->lyxvc().registrer();
1298 updateFlags = Update::Force;
1301 case LFUN_VC_CHECK_IN:
1302 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1303 if (!ensureBufferClean(view()))
1305 if (lyx_view_->buffer()->lyxvc().inUse()
1306 && !lyx_view_->buffer()->isReadonly()) {
1307 lyx_view_->buffer()->lyxvc().checkIn();
1312 case LFUN_VC_CHECK_OUT:
1313 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1314 if (!ensureBufferClean(view()))
1316 if (lyx_view_->buffer()->lyxvc().inUse()
1317 && lyx_view_->buffer()->isReadonly()) {
1318 lyx_view_->buffer()->lyxvc().checkOut();
1323 case LFUN_VC_REVERT:
1324 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1325 lyx_view_->buffer()->lyxvc().revert();
1329 case LFUN_VC_UNDO_LAST:
1330 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1331 lyx_view_->buffer()->lyxvc().undoLast();
1335 // --- buffers ----------------------------------------
1336 case LFUN_BUFFER_SWITCH:
1337 BOOST_ASSERT(lyx_view_);
1338 lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1339 updateFlags = Update::None;
1342 case LFUN_BUFFER_NEXT:
1343 BOOST_ASSERT(lyx_view_);
1344 lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer()));
1345 updateFlags = Update::None;
1348 case LFUN_BUFFER_PREVIOUS:
1349 BOOST_ASSERT(lyx_view_);
1350 lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer()));
1351 updateFlags = Update::None;
1354 case LFUN_FILE_NEW: {
1355 BOOST_ASSERT(lyx_view_);
1357 string tmpname = split(argument, name, ':'); // Split filename
1358 Buffer * const b = newFile(name, tmpname);
1360 lyx_view_->setBuffer(b);
1361 updateFlags = Update::None;
1365 case LFUN_FILE_OPEN:
1366 BOOST_ASSERT(lyx_view_);
1368 updateFlags = Update::None;
1371 case LFUN_DROP_LAYOUTS_CHOICE:
1372 BOOST_ASSERT(lyx_view_);
1373 lyx_view_->openLayoutList();
1376 case LFUN_MENU_OPEN:
1377 BOOST_ASSERT(lyx_view_);
1378 lyx_view_->openMenu(from_utf8(argument));
1381 // --- lyxserver commands ----------------------------
1382 case LFUN_SERVER_GET_NAME:
1383 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1384 setMessage(from_utf8(lyx_view_->buffer()->absFileName()));
1385 LYXERR(Debug::INFO) << "FNAME["
1386 << lyx_view_->buffer()->absFileName()
1390 case LFUN_SERVER_NOTIFY:
1391 dispatch_buffer = keyseq.print(KeySequence::Portable);
1392 theServer().notifyClient(to_utf8(dispatch_buffer));
1395 case LFUN_SERVER_GOTO_FILE_ROW: {
1396 BOOST_ASSERT(lyx_view_);
1399 istringstream is(argument);
1400 is >> file_name >> row;
1402 bool loaded = false;
1403 if (prefixIs(file_name, package().temp_dir().absFilename()))
1404 // Needed by inverse dvi search. If it is a file
1405 // in tmpdir, call the apropriated function
1406 buf = theBufferList().getBufferFromTmp(file_name);
1408 // Must replace extension of the file to be .lyx
1409 // and get full path
1410 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1411 // Either change buffer or load the file
1412 if (theBufferList().exists(s.absFilename()))
1413 buf = theBufferList().getBuffer(s.absFilename());
1415 buf = lyx_view_->loadLyXFile(s);
1421 updateFlags = Update::None;
1426 lyx_view_->setBuffer(buf);
1427 view()->setCursorFromRow(row);
1429 lyx_view_->errors("Parse");
1430 updateFlags = Update::FitCursor;
1434 case LFUN_DIALOG_SHOW: {
1435 BOOST_ASSERT(lyx_view_);
1436 string const name = cmd.getArg(0);
1437 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1439 if (name == "character") {
1440 data = freefont2string();
1442 lyx_view_->getDialogs().show("character", data);
1443 } else if (name == "latexlog") {
1444 Buffer::LogType type;
1445 string const logfile = lyx_view_->buffer()->logName(&type);
1447 case Buffer::latexlog:
1450 case Buffer::buildlog:
1454 data += Lexer::quoteString(logfile);
1455 lyx_view_->getDialogs().show("log", data);
1456 } else if (name == "vclog") {
1457 string const data = "vc " +
1458 Lexer::quoteString(lyx_view_->buffer()->lyxvc().getLogFile());
1459 lyx_view_->getDialogs().show("log", data);
1461 lyx_view_->getDialogs().show(name, data);
1465 case LFUN_DIALOG_SHOW_NEW_INSET: {
1466 BOOST_ASSERT(lyx_view_);
1467 string const name = cmd.getArg(0);
1468 InsetCode code = insetCode(name);
1469 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1470 bool insetCodeOK = true;
1479 case HYPERLINK_CODE: {
1480 InsetCommandParams p(code);
1481 data = InsetCommandMailer::params2string(name, p);
1484 case INCLUDE_CODE: {
1485 // data is the include type: one of "include",
1486 // "input", "verbatiminput" or "verbatiminput*"
1488 // default type is requested
1490 InsetCommandParams p(INCLUDE_CODE, data);
1491 data = InsetCommandMailer::params2string("include", p);
1495 // \c data == "Boxed" || "Frameless" etc
1496 InsetBoxParams p(data);
1497 data = InsetBoxMailer::params2string(p);
1501 InsetBranchParams p;
1502 data = InsetBranchMailer::params2string(p);
1506 InsetCommandParams p(CITE_CODE);
1507 data = InsetCommandMailer::params2string(name, p);
1511 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1514 case EXTERNAL_CODE: {
1515 InsetExternalParams p;
1516 Buffer const & buffer = *lyx_view_->buffer();
1517 data = InsetExternalMailer::params2string(p, buffer);
1522 data = InsetFloatMailer::params2string(p);
1525 case LISTINGS_CODE: {
1526 InsetListingsParams p;
1527 data = InsetListingsMailer::params2string(p);
1530 case GRAPHICS_CODE: {
1531 InsetGraphicsParams p;
1532 Buffer const & buffer = *lyx_view_->buffer();
1533 data = InsetGraphicsMailer::params2string(p, buffer);
1538 data = InsetNoteMailer::params2string(p);
1543 data = InsetVSpaceMailer::params2string(space);
1548 data = InsetWrapMailer::params2string(p);
1552 lyxerr << "Inset type '" << name <<
1553 "' not recognized in LFUN_DIALOG_SHOW_NEW_INSET" << std:: endl;
1554 insetCodeOK = false;
1556 } // end switch(code)
1558 lyx_view_->getDialogs().show(name, data, 0);
1562 case LFUN_DIALOG_UPDATE: {
1563 BOOST_ASSERT(lyx_view_);
1564 string const & name = argument;
1565 // Can only update a dialog connected to an existing inset
1566 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1568 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1569 inset->dispatch(view()->cursor(), fr);
1570 } else if (name == "paragraph") {
1571 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1572 } else if (name == "prefs") {
1573 lyx_view_->getDialogs().update(name, string());
1578 case LFUN_DIALOG_HIDE:
1579 LyX::cref().hideDialogs(argument, 0);
1582 case LFUN_DIALOG_TOGGLE: {
1583 BOOST_ASSERT(lyx_view_);
1584 if (lyx_view_->getDialogs().visible(cmd.getArg(0)))
1585 dispatch(FuncRequest(LFUN_DIALOG_HIDE, argument));
1587 dispatch(FuncRequest(LFUN_DIALOG_SHOW, argument));
1591 case LFUN_DIALOG_DISCONNECT_INSET:
1592 BOOST_ASSERT(lyx_view_);
1593 lyx_view_->getDialogs().disconnect(argument);
1597 case LFUN_CITATION_INSERT: {
1598 BOOST_ASSERT(lyx_view_);
1599 if (!argument.empty()) {
1600 // we can have one optional argument, delimited by '|'
1601 // citation-insert <key>|<text_before>
1602 // this should be enhanced to also support text_after
1603 // and citation style
1604 string arg = argument;
1606 if (contains(argument, "|")) {
1607 arg = token(argument, '|', 0);
1608 opt1 = token(argument, '|', 1);
1610 InsetCommandParams icp(CITE_CODE);
1611 icp["key"] = from_utf8(arg);
1613 icp["before"] = from_utf8(opt1);
1614 string icstr = InsetCommandMailer::params2string("citation", icp);
1615 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1618 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1622 case LFUN_BUFFER_CHILD_OPEN: {
1623 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1624 Buffer * parent = lyx_view_->buffer();
1625 FileName filename = makeAbsPath(argument, parent->filePath());
1626 view()->saveBookmark(false);
1628 bool parsed = false;
1629 if (theBufferList().exists(filename.absFilename())) {
1630 child = theBufferList().getBuffer(filename.absFilename());
1632 setMessage(bformat(_("Opening child document %1$s..."),
1633 makeDisplayPath(filename.absFilename())));
1634 child = lyx_view_->loadLyXFile(filename, true);
1638 // Set the parent name of the child document.
1639 // This makes insertion of citations and references in the child work,
1640 // when the target is in the parent or another child document.
1641 child->setParentName(parent->absFileName());
1642 updateLabels(*child->masterBuffer());
1643 lyx_view_->setBuffer(child);
1645 lyx_view_->errors("Parse");
1648 // If a screen update is required (in case where auto_open is false),
1649 // setBuffer() would have taken care of it already. Otherwise we shall
1650 // reset the update flag because it can cause a circular problem.
1652 updateFlags = Update::None;
1656 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1657 BOOST_ASSERT(lyx_view_);
1658 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1661 case LFUN_KEYMAP_OFF:
1662 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1663 lyx_view_->view()->getIntl().keyMapOn(false);
1666 case LFUN_KEYMAP_PRIMARY:
1667 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1668 lyx_view_->view()->getIntl().keyMapPrim();
1671 case LFUN_KEYMAP_SECONDARY:
1672 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1673 lyx_view_->view()->getIntl().keyMapSec();
1676 case LFUN_KEYMAP_TOGGLE:
1677 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1678 lyx_view_->view()->getIntl().toggleKeyMap();
1684 string rest = split(argument, countstr, ' ');
1685 istringstream is(countstr);
1688 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1689 for (int i = 0; i < count; ++i)
1690 dispatch(lyxaction.lookupFunc(rest));
1694 case LFUN_COMMAND_SEQUENCE: {
1695 // argument contains ';'-terminated commands
1696 string arg = argument;
1697 while (!arg.empty()) {
1699 arg = split(arg, first, ';');
1700 FuncRequest func(lyxaction.lookupFunc(first));
1701 func.origin = cmd.origin;
1709 if (LyX::ref().topLevelCmdDef().lock(argument, func)) {
1710 func.origin = cmd.origin;
1712 LyX::ref().topLevelCmdDef().release(argument);
1714 if (func.action == LFUN_UNKNOWN_ACTION) {
1715 // unknown command definition
1716 lyxerr << "Warning: unknown command definition `"
1720 // recursion detected
1721 lyxerr << "Warning: Recursion in the command definition `"
1722 << argument << "' detected"
1729 case LFUN_PREFERENCES_SAVE: {
1730 lyxrc.write(makeAbsPath("preferences",
1731 package().user_support().absFilename()),
1736 case LFUN_SCREEN_FONT_UPDATE:
1737 BOOST_ASSERT(lyx_view_);
1738 // handle the screen font changes.
1739 theFontLoader().update();
1740 /// FIXME: only the current view will be updated. the Gui
1741 /// class is able to furnish the list of views.
1742 updateFlags = Update::Force;
1745 case LFUN_SET_COLOR: {
1747 string const x11_name = split(argument, lyx_name, ' ');
1748 if (lyx_name.empty() || x11_name.empty()) {
1749 setErrorMessage(from_ascii(N_(
1750 "Syntax: set-color <lyx_name>"
1755 bool const graphicsbg_changed =
1756 (lyx_name == lcolor.getLyXName(Color_graphicsbg) &&
1757 x11_name != lcolor.getX11Name(Color_graphicsbg));
1759 if (!lcolor.setColor(lyx_name, x11_name)) {
1761 bformat(_("Set-color \"%1$s\" failed "
1762 "- color is undefined or "
1763 "may not be redefined"),
1764 from_utf8(lyx_name)));
1768 theApp()->updateColor(lcolor.getFromLyXName(lyx_name));
1770 if (graphicsbg_changed) {
1771 // FIXME: The graphics cache no longer has a changeDisplay method.
1773 graphics::GCache::get().changeDisplay(true);
1780 BOOST_ASSERT(lyx_view_);
1781 lyx_view_->message(from_utf8(argument));
1784 case LFUN_EXTERNAL_EDIT: {
1785 BOOST_ASSERT(lyx_view_);
1786 FuncRequest fr(action, argument);
1787 InsetExternal().dispatch(view()->cursor(), fr);
1791 case LFUN_GRAPHICS_EDIT: {
1792 FuncRequest fr(action, argument);
1793 InsetGraphics().dispatch(view()->cursor(), fr);
1797 case LFUN_INSET_APPLY: {
1798 BOOST_ASSERT(lyx_view_);
1799 string const name = cmd.getArg(0);
1800 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1802 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1803 inset->dispatch(view()->cursor(), fr);
1805 FuncRequest fr(LFUN_INSET_INSERT, argument);
1808 // ideally, the update flag should be set by the insets,
1809 // but this is not possible currently
1810 updateFlags = Update::Force | Update::FitCursor;
1814 case LFUN_ALL_INSETS_TOGGLE: {
1815 BOOST_ASSERT(lyx_view_);
1817 string const name = split(argument, action, ' ');
1818 InsetCode const inset_code = insetCode(name);
1820 Cursor & cur = view()->cursor();
1821 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1823 Inset & inset = lyx_view_->buffer()->inset();
1824 InsetIterator it = inset_iterator_begin(inset);
1825 InsetIterator const end = inset_iterator_end(inset);
1826 for (; it != end; ++it) {
1827 if (!it->asInsetMath()
1828 && (inset_code == NO_CODE
1829 || inset_code == it->lyxCode())) {
1830 Cursor tmpcur = cur;
1831 tmpcur.pushBackward(*it);
1832 it->dispatch(tmpcur, fr);
1835 updateFlags = Update::Force | Update::FitCursor;
1839 case LFUN_BUFFER_LANGUAGE: {
1840 BOOST_ASSERT(lyx_view_);
1841 Buffer & buffer = *lyx_view_->buffer();
1842 Language const * oldL = buffer.params().language;
1843 Language const * newL = languages.getLanguage(argument);
1844 if (!newL || oldL == newL)
1847 if (oldL->rightToLeft() == newL->rightToLeft()
1848 && !buffer.isMultiLingual())
1849 buffer.changeLanguage(oldL, newL);
1853 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1854 string const fname =
1855 addName(addPath(package().user_support().absFilename(), "templates/"),
1857 Buffer defaults(fname);
1859 istringstream ss(argument);
1862 int const unknown_tokens = defaults.readHeader(lex);
1864 if (unknown_tokens != 0) {
1865 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1866 << unknown_tokens << " unknown token"
1867 << (unknown_tokens == 1 ? "" : "s")
1871 if (defaults.writeFile(FileName(defaults.absFileName())))
1872 setMessage(bformat(_("Document defaults saved in %1$s"),
1873 makeDisplayPath(fname)));
1875 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1879 case LFUN_BUFFER_PARAMS_APPLY: {
1880 BOOST_ASSERT(lyx_view_);
1881 biblio::CiteEngine const oldEngine =
1882 lyx_view_->buffer()->params().getEngine();
1884 Buffer * buffer = lyx_view_->buffer();
1886 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1888 Cursor & cur = view()->cursor();
1889 cur.recordUndoFullDocument();
1891 istringstream ss(argument);
1894 int const unknown_tokens = buffer->readHeader(lex);
1896 if (unknown_tokens != 0) {
1897 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1898 << unknown_tokens << " unknown token"
1899 << (unknown_tokens == 1 ? "" : "s")
1903 updateLayout(oldClass, buffer);
1905 biblio::CiteEngine const newEngine =
1906 lyx_view_->buffer()->params().getEngine();
1908 if (oldEngine != newEngine) {
1909 FuncRequest fr(LFUN_INSET_REFRESH);
1911 Inset & inset = lyx_view_->buffer()->inset();
1912 InsetIterator it = inset_iterator_begin(inset);
1913 InsetIterator const end = inset_iterator_end(inset);
1914 for (; it != end; ++it)
1915 if (it->lyxCode() == CITE_CODE)
1916 it->dispatch(cur, fr);
1919 updateFlags = Update::Force | Update::FitCursor;
1923 case LFUN_LAYOUT_MODULES_CLEAR: {
1924 BOOST_ASSERT(lyx_view_);
1925 Buffer * buffer = lyx_view_->buffer();
1926 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1927 view()->cursor().recordUndoFullDocument();
1928 buffer->params().clearLayoutModules();
1929 updateLayout(oldClass, buffer);
1930 updateFlags = Update::Force | Update::FitCursor;
1934 case LFUN_LAYOUT_MODULE_ADD: {
1935 BOOST_ASSERT(lyx_view_);
1936 Buffer * buffer = lyx_view_->buffer();
1937 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1938 view()->cursor().recordUndoFullDocument();
1939 buffer->params().addLayoutModule(argument);
1940 updateLayout(oldClass, buffer);
1941 updateFlags = Update::Force | Update::FitCursor;
1945 case LFUN_TEXTCLASS_APPLY: {
1946 BOOST_ASSERT(lyx_view_);
1947 Buffer * buffer = lyx_view_->buffer();
1949 loadTextClass(argument);
1951 std::pair<bool, textclass_type> const tc_pair =
1952 textclasslist.numberOfClass(argument);
1957 textclass_type const old_class = buffer->params().getBaseClass();
1958 textclass_type const new_class = tc_pair.second;
1960 if (old_class == new_class)
1964 //Save the old, possibly modular, layout for use in conversion.
1965 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1966 view()->cursor().recordUndoFullDocument();
1967 buffer->params().setBaseClass(new_class);
1968 updateLayout(oldClass, buffer);
1969 updateFlags = Update::Force | Update::FitCursor;
1973 case LFUN_LAYOUT_RELOAD: {
1974 BOOST_ASSERT(lyx_view_);
1975 Buffer * buffer = lyx_view_->buffer();
1976 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1977 textclass_type const tc = buffer->params().getBaseClass();
1978 textclasslist.reset(tc);
1979 buffer->params().setBaseClass(tc);
1980 updateLayout(oldClass, buffer);
1981 updateFlags = Update::Force | Update::FitCursor;
1985 case LFUN_TEXTCLASS_LOAD:
1986 loadTextClass(argument);
1989 case LFUN_LYXRC_APPLY: {
1990 LyXRC const lyxrc_orig = lyxrc;
1992 istringstream ss(argument);
1993 bool const success = lyxrc.read(ss) == 0;
1996 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1997 << "Unable to read lyxrc data"
2002 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
2004 if (lyx_view_ && lyx_view_->buffer())
2005 lyx_view_->updateLayoutChoice(true);
2007 /// We force the redraw in any case because there might be
2008 /// some screen font changes.
2009 /// FIXME: only the current view will be updated. the Gui
2010 /// class is able to furnish the list of views.
2011 updateFlags = Update::Force;
2015 case LFUN_WINDOW_NEW:
2016 LyX::ref().newLyXView();
2019 case LFUN_WINDOW_CLOSE:
2020 BOOST_ASSERT(lyx_view_);
2021 BOOST_ASSERT(theApp());
2022 // update bookmark pit of the current buffer before window close
2023 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2024 gotoBookmark(i+1, false, false);
2025 // ask the user for saving changes or cancel quit
2026 if (!theBufferList().quitWriteAll())
2031 case LFUN_BOOKMARK_GOTO:
2032 // go to bookmark, open unopened file and switch to buffer if necessary
2033 gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
2036 case LFUN_BOOKMARK_CLEAR:
2037 LyX::ref().session().bookmarks().clear();
2040 case LFUN_TOOLBAR_TOGGLE: {
2041 BOOST_ASSERT(lyx_view_);
2042 string const name = cmd.getArg(0);
2043 bool const allowauto = cmd.getArg(1) == "allowauto";
2044 lyx_view_->toggleToolbarState(name, allowauto);
2045 ToolbarInfo * tbi = lyx_view_->getToolbarInfo(name);
2047 setMessage(bformat(_("Unknown toolbar \"%1$s\""),
2052 if (tbi->flags & ToolbarInfo::ON)
2054 else if (tbi->flags & ToolbarInfo::OFF)
2056 else if (tbi->flags & ToolbarInfo::AUTO)
2059 setMessage(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
2060 _(tbi->gui_name), state));
2065 BOOST_ASSERT(lyx_view_);
2066 view()->cursor().dispatch(cmd);
2067 updateFlags = view()->cursor().result().update();
2068 if (!view()->cursor().result().dispatched())
2069 updateFlags = view()->dispatch(cmd);
2074 if (lyx_view_ && lyx_view_->buffer()) {
2075 // BufferView::update() updates the ViewMetricsInfo and
2076 // also initializes the position cache for all insets in
2077 // (at least partially) visible top-level paragraphs.
2078 // We will redraw the screen only if needed.
2079 view()->processUpdateFlags(updateFlags);
2080 lyx_view_->updateStatusBar();
2082 // if we executed a mutating lfun, mark the buffer as dirty
2084 && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
2085 && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
2086 lyx_view_->buffer()->markDirty();
2088 //Do we have a selection?
2089 theSelection().haveSelection(view()->cursor().selection());
2091 if (view()->cursor().inTexted()) {
2092 lyx_view_->updateLayoutChoice(false);
2096 if (!quitting && lyx_view_) {
2097 lyx_view_->updateToolbars();
2098 // Some messages may already be translated, so we cannot use _()
2099 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
2104 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
2106 const bool verbose = (cmd.origin == FuncRequest::MENU
2107 || cmd.origin == FuncRequest::TOOLBAR
2108 || cmd.origin == FuncRequest::COMMANDBUFFER);
2110 if (cmd.action == LFUN_SELF_INSERT || !verbose) {
2111 LYXERR(Debug::ACTION) << "dispatch msg is " << to_utf8(msg) << endl;
2113 lyx_view_->message(msg);
2117 docstring dispatch_msg = msg;
2118 if (!dispatch_msg.empty())
2119 dispatch_msg += ' ';
2121 docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
2123 bool argsadded = false;
2125 if (!cmd.argument().empty()) {
2126 if (cmd.action != LFUN_UNKNOWN_ACTION) {
2127 comname += ' ' + cmd.argument();
2132 docstring const shortcuts = theTopLevelKeymap().printBindings(cmd);
2134 if (!shortcuts.empty())
2135 comname += ": " + shortcuts;
2136 else if (!argsadded && !cmd.argument().empty())
2137 comname += ' ' + cmd.argument();
2139 if (!comname.empty()) {
2140 comname = rtrim(comname);
2141 dispatch_msg += '(' + rtrim(comname) + ')';
2144 LYXERR(Debug::ACTION) << "verbose dispatch msg "
2145 << to_utf8(dispatch_msg) << endl;
2146 if (!dispatch_msg.empty())
2147 lyx_view_->message(dispatch_msg);
2151 void LyXFunc::menuNew(string const & name, bool fromTemplate)
2153 // FIXME: initpath is not used. What to do?
2154 string initpath = lyxrc.document_path;
2155 string filename(name);
2157 if (lyx_view_->buffer()) {
2158 string const trypath = lyx_view_->buffer()->filePath();
2159 // If directory is writeable, use this as default.
2160 if (FileName(trypath).isDirWritable())
2164 static int newfile_number;
2166 if (filename.empty()) {
2167 filename = addName(lyxrc.document_path,
2168 "newfile" + convert<string>(++newfile_number) + ".lyx");
2169 while (theBufferList().exists(filename) ||
2170 FileName(filename).isReadable()) {
2172 filename = addName(lyxrc.document_path,
2173 "newfile" + convert<string>(newfile_number) +
2178 // The template stuff
2181 FileDialog dlg(_("Select template file"));
2182 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
2183 dlg.setButton1(_("Templates|#T#t"), from_utf8(lyxrc.template_path));
2185 FileDialog::Result result =
2186 dlg.open(from_utf8(lyxrc.template_path),
2187 FileFilterList(_("LyX Documents (*.lyx)")),
2190 if (result.first == FileDialog::Later)
2192 if (result.second.empty())
2194 templname = to_utf8(result.second);
2197 Buffer * const b = newFile(filename, templname, !name.empty());
2199 lyx_view_->setBuffer(b);
2203 void LyXFunc::open(string const & fname)
2205 string initpath = lyxrc.document_path;
2207 if (lyx_view_->buffer()) {
2208 string const trypath = lyx_view_->buffer()->filePath();
2209 // If directory is writeable, use this as default.
2210 if (FileName(trypath).isDirWritable())
2216 if (fname.empty()) {
2217 FileDialog dlg(_("Select document to open"), LFUN_FILE_OPEN);
2218 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
2219 dlg.setButton2(_("Examples|#E#e"),
2220 from_utf8(addPath(package().system_support().absFilename(), "examples")));
2222 FileDialog::Result result =
2223 dlg.open(from_utf8(initpath),
2224 FileFilterList(_("LyX Documents (*.lyx)")),
2227 if (result.first == FileDialog::Later)
2230 filename = to_utf8(result.second);
2232 // check selected filename
2233 if (filename.empty()) {
2234 lyx_view_->message(_("Canceled."));
2240 // get absolute path of file and add ".lyx" to the filename if
2242 FileName const fullname = fileSearch(string(), filename, "lyx");
2243 if (!fullname.empty())
2244 filename = fullname.absFilename();
2246 // if the file doesn't exist, let the user create one
2247 if (!fullname.exists()) {
2248 // the user specifically chose this name. Believe him.
2249 Buffer * const b = newFile(filename, string(), true);
2251 lyx_view_->setBuffer(b);
2255 docstring const disp_fn = makeDisplayPath(filename);
2256 lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
2259 Buffer * buf = lyx_view_->loadLyXFile(fullname);
2262 lyx_view_->setBuffer(buf);
2263 lyx_view_->errors("Parse");
2264 str2 = bformat(_("Document %1$s opened."), disp_fn);
2266 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2268 lyx_view_->message(str2);
2272 void LyXFunc::doImport(string const & argument)
2275 string filename = split(argument, format, ' ');
2277 LYXERR(Debug::INFO) << "LyXFunc::doImport: " << format
2278 << " file: " << filename << endl;
2280 // need user interaction
2281 if (filename.empty()) {
2282 string initpath = lyxrc.document_path;
2284 if (lyx_view_->buffer()) {
2285 string const trypath = lyx_view_->buffer()->filePath();
2286 // If directory is writeable, use this as default.
2287 if (FileName(trypath).isDirWritable())
2291 docstring const text = bformat(_("Select %1$s file to import"),
2292 formats.prettyName(format));
2294 FileDialog dlg(text, LFUN_BUFFER_IMPORT);
2295 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
2296 dlg.setButton2(_("Examples|#E#e"),
2297 from_utf8(addPath(package().system_support().absFilename(), "examples")));
2299 docstring filter = formats.prettyName(format);
2302 filter += from_utf8(formats.extension(format));
2305 FileDialog::Result result =
2306 dlg.open(from_utf8(initpath),
2307 FileFilterList(filter),
2310 if (result.first == FileDialog::Later)
2313 filename = to_utf8(result.second);
2315 // check selected filename
2316 if (filename.empty())
2317 lyx_view_->message(_("Canceled."));
2320 if (filename.empty())
2323 // get absolute path of file
2324 FileName const fullname(makeAbsPath(filename));
2326 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
2328 // Check if the document already is open
2329 if (use_gui && theBufferList().exists(lyxfile.absFilename())) {
2330 if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) {
2331 lyx_view_->message(_("Canceled."));
2336 // if the file exists already, and we didn't do
2337 // -i lyx thefile.lyx, warn
2338 if (lyxfile.exists() && fullname != lyxfile) {
2339 docstring const file = makeDisplayPath(lyxfile.absFilename(), 30);
2341 docstring text = bformat(_("The document %1$s already exists.\n\n"
2342 "Do you want to overwrite that document?"), file);
2343 int const ret = Alert::prompt(_("Overwrite document?"),
2344 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2347 lyx_view_->message(_("Canceled."));
2352 ErrorList errorList;
2353 import(lyx_view_, fullname, format, errorList);
2354 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2358 void LyXFunc::closeBuffer()
2360 // goto bookmark to update bookmark pit.
2361 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2362 gotoBookmark(i+1, false, false);
2364 theBufferList().close(lyx_view_->buffer(), true);
2368 void LyXFunc::reloadBuffer()
2370 FileName filename(lyx_view_->buffer()->absFileName());
2371 docstring const disp_fn = makeDisplayPath(filename.absFilename());
2374 Buffer * buf = lyx_view_->loadLyXFile(filename);
2377 lyx_view_->setBuffer(buf);
2378 lyx_view_->errors("Parse");
2379 str = bformat(_("Document %1$s reloaded."), disp_fn);
2381 str = bformat(_("Could not reload document %1$s"), disp_fn);
2383 lyx_view_->message(str);
2386 // Each "lyx_view_" should have it's own message method. lyxview and
2387 // the minibuffer would use the minibuffer, but lyxserver would
2388 // send an ERROR signal to its client. Alejandro 970603
2389 // This function is bit problematic when it comes to NLS, to make the
2390 // lyx servers client be language indepenent we must not translate
2391 // strings sent to this func.
2392 void LyXFunc::setErrorMessage(docstring const & m) const
2394 dispatch_buffer = m;
2399 void LyXFunc::setMessage(docstring const & m) const
2401 dispatch_buffer = m;
2405 docstring const LyXFunc::viewStatusMessage()
2407 // When meta-fake key is pressed, show the key sequence so far + "M-".
2409 return keyseq.print(KeySequence::ForGui) + "M-";
2411 // Else, when a non-complete key sequence is pressed,
2412 // show the available options.
2413 if (keyseq.length() > 0 && !keyseq.deleted())
2414 return keyseq.printOptions(true);
2416 BOOST_ASSERT(lyx_view_);
2417 if (!lyx_view_->buffer())
2418 return _("Welcome to LyX!");
2420 return view()->cursor().currentState();
2424 BufferView * LyXFunc::view() const
2426 BOOST_ASSERT(lyx_view_);
2427 return lyx_view_->view();
2431 bool LyXFunc::wasMetaKey() const
2433 return (meta_fake_bit != NoModifier);
2437 void LyXFunc::updateLayout(TextClassPtr const & oldlayout,
2440 lyx_view_->message(_("Converting document to new document class..."));
2442 StableDocIterator backcur(view()->cursor());
2443 ErrorList & el = buffer->errorList("Class Switch");
2444 cap::switchBetweenClasses(
2445 oldlayout, buffer->params().getTextClassPtr(),
2446 static_cast<InsetText &>(buffer->inset()), el);
2448 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
2450 buffer->errors("Class Switch");
2451 updateLabels(*buffer);
2457 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2459 // Why the switch you might ask. It is a trick to ensure that all
2460 // the elements in the LyXRCTags enum is handled. As you can see
2461 // there are no breaks at all. So it is just a huge fall-through.
2462 // The nice thing is that we will get a warning from the compiler
2463 // if we forget an element.
2464 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2466 case LyXRC::RC_ACCEPT_COMPOUND:
2467 case LyXRC::RC_ALT_LANG:
2468 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
2469 case LyXRC::RC_PLAINTEXT_LINELEN:
2470 case LyXRC::RC_AUTOREGIONDELETE:
2471 case LyXRC::RC_AUTORESET_OPTIONS:
2472 case LyXRC::RC_AUTOSAVE:
2473 case LyXRC::RC_AUTO_NUMBER:
2474 case LyXRC::RC_BACKUPDIR_PATH:
2475 case LyXRC::RC_BIBTEX_COMMAND:
2476 case LyXRC::RC_BINDFILE:
2477 case LyXRC::RC_CHECKLASTFILES:
2478 case LyXRC::RC_USELASTFILEPOS:
2479 case LyXRC::RC_LOADSESSION:
2480 case LyXRC::RC_CHKTEX_COMMAND:
2481 case LyXRC::RC_CONVERTER:
2482 case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
2483 case LyXRC::RC_COPIER:
2484 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2485 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2486 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2487 case LyXRC::RC_DATE_INSERT_FORMAT:
2488 case LyXRC::RC_DEFAULT_LANGUAGE:
2489 case LyXRC::RC_DEFAULT_PAPERSIZE:
2490 case LyXRC::RC_DEFFILE:
2491 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2492 case LyXRC::RC_DISPLAY_GRAPHICS:
2493 case LyXRC::RC_DOCUMENTPATH:
2494 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2495 FileName path(lyxrc_new.document_path);
2496 if (path.exists() && path.isDirectory())
2497 support::package().document_dir() = FileName(lyxrc.document_path);
2499 case LyXRC::RC_ESC_CHARS:
2500 case LyXRC::RC_FONT_ENCODING:
2501 case LyXRC::RC_FORMAT:
2502 case LyXRC::RC_INDEX_COMMAND:
2503 case LyXRC::RC_INPUT:
2504 case LyXRC::RC_KBMAP:
2505 case LyXRC::RC_KBMAP_PRIMARY:
2506 case LyXRC::RC_KBMAP_SECONDARY:
2507 case LyXRC::RC_LABEL_INIT_LENGTH:
2508 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2509 case LyXRC::RC_LANGUAGE_AUTO_END:
2510 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2511 case LyXRC::RC_LANGUAGE_COMMAND_END:
2512 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2513 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2514 case LyXRC::RC_LANGUAGE_PACKAGE:
2515 case LyXRC::RC_LANGUAGE_USE_BABEL:
2516 case LyXRC::RC_MAKE_BACKUP:
2517 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2518 case LyXRC::RC_NUMLASTFILES:
2519 case LyXRC::RC_PATH_PREFIX:
2520 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2521 support::prependEnvPath("PATH", lyxrc.path_prefix);
2523 case LyXRC::RC_PERS_DICT:
2524 case LyXRC::RC_PREVIEW:
2525 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2526 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2527 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2528 case LyXRC::RC_PRINTCOPIESFLAG:
2529 case LyXRC::RC_PRINTER:
2530 case LyXRC::RC_PRINTEVENPAGEFLAG:
2531 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2532 case LyXRC::RC_PRINTFILEEXTENSION:
2533 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2534 case LyXRC::RC_PRINTODDPAGEFLAG:
2535 case LyXRC::RC_PRINTPAGERANGEFLAG:
2536 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2537 case LyXRC::RC_PRINTPAPERFLAG:
2538 case LyXRC::RC_PRINTREVERSEFLAG:
2539 case LyXRC::RC_PRINTSPOOL_COMMAND:
2540 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2541 case LyXRC::RC_PRINTTOFILE:
2542 case LyXRC::RC_PRINTTOPRINTER:
2543 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2544 case LyXRC::RC_PRINT_COMMAND:
2545 case LyXRC::RC_RTL_SUPPORT:
2546 case LyXRC::RC_SCREEN_DPI:
2547 case LyXRC::RC_SCREEN_FONT_ROMAN:
2548 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2549 case LyXRC::RC_SCREEN_FONT_SANS:
2550 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2551 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2552 case LyXRC::RC_SCREEN_FONT_SIZES:
2553 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2554 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2555 case LyXRC::RC_SCREEN_GEOMETRY_HEIGHT:
2556 case LyXRC::RC_SCREEN_GEOMETRY_WIDTH:
2557 case LyXRC::RC_SCREEN_GEOMETRY_XYSAVED:
2558 case LyXRC::RC_SCREEN_ZOOM:
2559 case LyXRC::RC_SERVERPIPE:
2560 case LyXRC::RC_SET_COLOR:
2561 case LyXRC::RC_SHOW_BANNER:
2562 case LyXRC::RC_SPELL_COMMAND:
2563 case LyXRC::RC_TEMPDIRPATH:
2564 case LyXRC::RC_TEMPLATEPATH:
2565 case LyXRC::RC_TEX_ALLOWS_SPACES:
2566 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2567 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2568 support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2570 case LyXRC::RC_UIFILE:
2571 case LyXRC::RC_USER_EMAIL:
2572 case LyXRC::RC_USER_NAME:
2573 case LyXRC::RC_USETEMPDIR:
2574 case LyXRC::RC_USE_ALT_LANG:
2575 case LyXRC::RC_USE_CONVERTER_CACHE:
2576 case LyXRC::RC_USE_ESC_CHARS:
2577 case LyXRC::RC_USE_INP_ENC:
2578 case LyXRC::RC_USE_PERS_DICT:
2579 case LyXRC::RC_USE_PIXMAP_CACHE:
2580 case LyXRC::RC_USE_SPELL_LIB:
2581 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2582 case LyXRC::RC_SORT_LAYOUTS:
2583 case LyXRC::RC_VIEWER:
2584 case LyXRC::RC_LAST: