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"
86 #include "frontends/WorkArea.h"
88 #include "support/environment.h"
89 #include "support/FileFilterList.h"
90 #include "support/filetools.h"
91 #include "support/fs_extras.h"
92 #include "support/lstrings.h"
93 #include "support/Path.h"
94 #include "support/Package.h"
95 #include "support/Systemcall.h"
96 #include "support/convert.h"
97 #include "support/os.h"
99 #include <boost/current_function.hpp>
100 #include <boost/filesystem/operations.hpp>
105 using std::make_pair;
108 using std::istringstream;
109 using std::ostringstream;
113 namespace fs = boost::filesystem;
117 using frontend::LyXView;
119 using support::absolutePath;
120 using support::addName;
121 using support::addPath;
122 using support::bformat;
123 using support::changeExtension;
124 using support::contains;
125 using support::FileFilterList;
126 using support::FileName;
127 using support::fileSearch;
128 using support::i18nLibFileSearch;
129 using support::makeDisplayPath;
130 using support::makeAbsPath;
131 using support::package;
132 using support::quoteName;
133 using support::rtrim;
134 using support::split;
135 using support::subst;
136 using support::Systemcall;
137 using support::token;
139 using support::prefixIs;
142 namespace Alert = frontend::Alert;
144 extern bool quitting;
149 bool import(LyXView * lv, FileName const & filename,
150 string const & format, ErrorList & errorList)
152 docstring const displaypath = makeDisplayPath(filename.absFilename());
153 lv->message(bformat(_("Importing %1$s..."), displaypath));
155 FileName const lyxfile(changeExtension(filename.absFilename(), ".lyx"));
157 string loader_format;
158 vector<string> loaders = theConverters().loaders();
159 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
160 for (vector<string>::const_iterator it = loaders.begin();
161 it != loaders.end(); ++it) {
162 if (theConverters().isReachable(format, *it)) {
163 string const tofile =
164 changeExtension(filename.absFilename(),
165 formats.extension(*it));
166 if (!theConverters().convert(0, filename, FileName(tofile),
167 filename, format, *it, errorList))
173 if (loader_format.empty()) {
174 frontend::Alert::error(_("Couldn't import file"),
175 bformat(_("No information for importing the format %1$s."),
176 formats.prettyName(format)));
180 loader_format = format;
184 if (loader_format == "lyx") {
185 Buffer * buf = lv->loadLyXFile(lyxfile);
188 lv->message(_("file not imported!"));
193 lv->showErrorList("Parse");
195 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
200 bool as_paragraphs = loader_format == "textparagraph";
201 string filename2 = (loader_format == format) ? filename.absFilename()
202 : changeExtension(filename.absFilename(),
203 formats.extension(loader_format));
204 lv->view()->insertPlaintextFile(filename2, as_paragraphs);
205 lv->dispatch(FuncRequest(LFUN_MARK_OFF));
209 lv->message(_("imported."));
215 // This function runs "configure" and then rereads lyx.defaults to
216 // reconfigure the automatic settings.
217 void reconfigure(LyXView & lv, string const & option)
219 // emit message signal.
220 lv.message(_("Running configure..."));
222 // Run configure in user lyx directory
223 support::Path p(package().user_support());
224 string configure_command = package().configure_command();
225 configure_command += option;
227 int ret = one.startscript(Systemcall::Wait, configure_command);
229 // emit message signal.
230 lv.message(_("Reloading configuration..."));
231 lyxrc.read(support::libFileSearch(string(), "lyxrc.defaults"));
232 // Re-read packages.lst
233 LaTeXFeatures::getAvailable();
236 Alert::information(_("System reconfiguration failed"),
237 _("The system reconfiguration has failed.\n"
238 "Default textclass is used but LyX may "
239 "not be able to work properly.\n"
240 "Please reconfigure again if needed."));
243 Alert::information(_("System reconfigured"),
244 _("The system has been reconfigured.\n"
245 "You need to restart LyX to make use of any\n"
246 "updated document class specifications."));
250 bool getLocalStatus(Cursor cursor, FuncRequest const & cmd, FuncStatus & status)
252 // Try to fix cursor in case it is broken.
253 cursor.fixIfBroken();
255 // This is, of course, a mess. Better create a new doc iterator and use
256 // this in Inset::getStatus. This might require an additional
257 // BufferView * arg, though (which should be avoided)
258 //Cursor safe = *this;
260 for ( ; cursor.depth(); cursor.pop()) {
261 //lyxerr << "\nCursor::getStatus: cmd: " << cmd << endl << *this << endl;
262 BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
263 BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
264 BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
266 // The inset's getStatus() will return 'true' if it made
267 // a definitive decision on whether it want to handle the
268 // request or not. The result of this decision is put into
269 // the 'status' parameter.
270 if (cursor.inset().getStatus(cursor, cmd, status)) {
279 /** Return the change status at cursor position, taking in account the
280 * status at each level of the document iterator (a table in a deleted
281 * footnote is deleted).
282 * When \param outer is true, the top slice is not looked at.
284 Change::Type lookupChangeType(DocIterator const & dit, bool outer = false)
286 size_t const depth = dit.depth() - (outer ? 1 : 0);
288 for (size_t i = 0 ; i < depth ; ++i) {
289 CursorSlice const & slice = dit[i];
290 if (!slice.inset().inMathed()
291 && slice.pos() < slice.paragraph().size()) {
292 Change::Type const ch = slice.paragraph().lookupChange(slice.pos()).type;
293 if (ch != Change::UNCHANGED)
297 return Change::UNCHANGED;
304 : lyx_view_(0), encoded_last_key(0), meta_fake_bit(NoModifier)
309 void LyXFunc::initKeySequences(KeyMap * kb)
311 keyseq = KeySequence(kb, kb);
312 cancel_meta_seq = KeySequence(kb, kb);
316 void LyXFunc::setLyXView(LyXView * lv)
318 if (!quitting && lyx_view_ && lyx_view_->view() && lyx_view_ != lv)
319 // save current selection to the selection buffer to allow
320 // middle-button paste in another window
321 cap::saveSelection(lyx_view_->view()->cursor());
326 void LyXFunc::handleKeyFunc(kb_action action)
328 char_type c = encoded_last_key;
333 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
334 lyx_view_->view()->getIntl().getTransManager().deadkey(
335 c, get_accent(action).accent, view()->cursor().innerText(), view()->cursor());
336 // Need to clear, in case the minibuffer calls these
339 // copied verbatim from do_accent_char
340 view()->cursor().resetAnchor();
341 view()->processUpdateFlags(Update::FitCursor);
345 void LyXFunc::gotoBookmark(unsigned int idx, bool openFile, bool switchToBuffer)
347 BOOST_ASSERT(lyx_view_);
348 if (!LyX::ref().session().bookmarks().isValid(idx))
350 BookmarksSection::Bookmark const & bm = LyX::ref().session().bookmarks().bookmark(idx);
351 BOOST_ASSERT(!bm.filename.empty());
352 string const file = bm.filename.absFilename();
353 // if the file is not opened, open it.
354 if (!theBufferList().exists(file)) {
356 dispatch(FuncRequest(LFUN_FILE_OPEN, file));
360 // open may fail, so we need to test it again
361 if (!theBufferList().exists(file))
364 // if the current buffer is not that one, switch to it.
365 if (lyx_view_->buffer()->absFileName() != file) {
368 dispatch(FuncRequest(LFUN_BUFFER_SWITCH, file));
370 // moveToPosition try paragraph id first and then paragraph (pit, pos).
371 if (!view()->moveToPosition(bm.bottom_pit, bm.bottom_pos,
372 bm.top_id, bm.top_pos))
375 // Cursor jump succeeded!
376 Cursor const & cur = view()->cursor();
377 pit_type new_pit = cur.pit();
378 pos_type new_pos = cur.pos();
379 int new_id = cur.paragraph().id();
381 // if bottom_pit, bottom_pos or top_id has been changed, update bookmark
382 // see http://bugzilla.lyx.org/show_bug.cgi?id=3092
383 if (bm.bottom_pit != new_pit || bm.bottom_pos != new_pos
384 || bm.top_id != new_id) {
385 const_cast<BookmarksSection::Bookmark &>(bm).updatePos(
386 new_pit, new_pos, new_id);
392 void restartCursor(LyXView * lv)
394 /* When we move around, or type, it's nice to be able to see
395 * the cursor immediately after the keypress.
397 if (lv && lv->currentWorkArea())
398 lv->currentWorkArea()->startBlinkingCursor();
402 void LyXFunc::processKeySym(KeySymbol const & keysym, KeyModifier state)
404 LYXERR(Debug::KEY) << "KeySym is " << keysym.getSymbolName() << endl;
406 // Do nothing if we have nothing (JMarc)
407 if (!keysym.isOK()) {
408 LYXERR(Debug::KEY) << "Empty kbd action (probably composing)"
410 restartCursor(lyx_view_);
414 if (keysym.isModifier()) {
415 LYXERR(Debug::KEY) << "isModifier true" << endl;
416 restartCursor(lyx_view_);
420 //Encoding const * encoding = view()->cursor().getEncoding();
421 //encoded_last_key = keysym.getISOEncoded(encoding ? encoding->name() : "");
422 // FIXME: encoded_last_key shadows the member variable of the same
423 // name. Is that intended?
424 char_type encoded_last_key = keysym.getUCSEncoded();
426 // Do a one-deep top-level lookup for
427 // cancel and meta-fake keys. RVDK_PATCH_5
428 cancel_meta_seq.reset();
430 FuncRequest func = cancel_meta_seq.addkey(keysym, state);
431 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
432 << " action first set to [" << func.action << ']'
435 // When not cancel or meta-fake, do the normal lookup.
436 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
437 // Mostly, meta_fake_bit = NoModifier. RVDK_PATCH_5.
438 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_PREFIX)) {
439 // remove Caps Lock and Mod2 as a modifiers
440 func = keyseq.addkey(keysym, (state | meta_fake_bit));
441 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
442 << "action now set to ["
443 << func.action << ']' << endl;
446 // Dont remove this unless you know what you are doing.
447 meta_fake_bit = NoModifier;
449 // Can this happen now ?
450 if (func.action == LFUN_NOACTION)
451 func = FuncRequest(LFUN_COMMAND_PREFIX);
453 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
455 << func.action << "]["
456 << to_utf8(keyseq.print(KeySequence::Portable)) << ']'
459 // already here we know if it any point in going further
460 // why not return already here if action == -1 and
461 // num_bytes == 0? (Lgb)
463 if (keyseq.length() > 1)
464 lyx_view_->message(keyseq.print(KeySequence::ForGui));
467 // Maybe user can only reach the key via holding down shift.
468 // Let's see. But only if shift is the only modifier
469 if (func.action == LFUN_UNKNOWN_ACTION && state == ShiftModifier) {
470 LYXERR(Debug::KEY) << "Trying without shift" << endl;
471 func = keyseq.addkey(keysym, NoModifier);
472 LYXERR(Debug::KEY) << "Action now " << func.action << endl;
475 if (func.action == LFUN_UNKNOWN_ACTION) {
476 // Hmm, we didn't match any of the keysequences. See
477 // if it's normal insertable text not already covered
479 if (keysym.isText() && keyseq.length() == 1) {
480 LYXERR(Debug::KEY) << "isText() is true, inserting." << endl;
481 func = FuncRequest(LFUN_SELF_INSERT,
482 FuncRequest::KEYBOARD);
484 LYXERR(Debug::KEY) << "Unknown, !isText() - giving up" << endl;
485 lyx_view_->message(_("Unknown function."));
486 restartCursor(lyx_view_);
491 if (func.action == LFUN_SELF_INSERT) {
492 if (encoded_last_key != 0) {
493 docstring const arg(1, encoded_last_key);
494 dispatch(FuncRequest(LFUN_SELF_INSERT, arg,
495 FuncRequest::KEYBOARD));
497 << "SelfInsert arg[`" << to_utf8(arg) << "']" << endl;
503 restartCursor(lyx_view_);
507 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
509 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
512 /* In LyX/Mac, when a dialog is open, the menus of the
513 application can still be accessed without giving focus to
514 the main window. In this case, we want to disable the menu
515 entries that are buffer-related.
517 Note that this code is not perfect, as bug 1941 attests:
518 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
520 Buffer * buf = lyx_view_? lyx_view_->buffer() : 0;
521 if (lyx_view_ && cmd.origin == FuncRequest::MENU && !lyx_view_->hasFocus())
524 if (cmd.action == LFUN_NOACTION) {
525 flag.message(from_utf8(N_("Nothing to do")));
530 switch (cmd.action) {
531 case LFUN_UNKNOWN_ACTION:
532 #ifndef HAVE_LIBAIKSAURUS
533 case LFUN_THESAURUS_ENTRY:
543 if (flag.unknown()) {
544 flag.message(from_utf8(N_("Unknown action")));
548 if (!flag.enabled()) {
549 if (flag.message().empty())
550 flag.message(from_utf8(N_("Command disabled")));
554 // Check whether we need a buffer
555 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
557 flag.message(from_utf8(N_("Command not allowed with"
558 "out any document open")));
563 // I would really like to avoid having this switch and rather try to
564 // encode this in the function itself.
565 // -- And I'd rather let an inset decide which LFUNs it is willing
566 // to handle (Andre')
568 switch (cmd.action) {
569 case LFUN_BUFFER_TOGGLE_READ_ONLY:
570 flag.setOnOff(buf->isReadonly());
573 case LFUN_BUFFER_SWITCH:
574 // toggle on the current buffer, but do not toggle off
575 // the other ones (is that a good idea?)
576 if (buf && to_utf8(cmd.argument()) == buf->absFileName())
580 case LFUN_BUFFER_EXPORT:
581 enable = cmd.argument() == "custom"
582 || buf->isExportable(to_utf8(cmd.argument()));
585 case LFUN_BUFFER_CHKTEX:
586 enable = buf->isLatex() && !lyxrc.chktex_command.empty();
589 case LFUN_BUILD_PROGRAM:
590 enable = buf->isExportable("program");
593 case LFUN_VC_REGISTER:
594 enable = !buf->lyxvc().inUse();
596 case LFUN_VC_CHECK_IN:
597 enable = buf->lyxvc().inUse() && !buf->isReadonly();
599 case LFUN_VC_CHECK_OUT:
600 enable = buf->lyxvc().inUse() && buf->isReadonly();
603 case LFUN_VC_UNDO_LAST:
604 enable = buf->lyxvc().inUse();
606 case LFUN_BUFFER_RELOAD:
607 enable = !buf->isUnnamed() && fs::exists(buf->absFileName())
608 && (!buf->isClean() || buf->isExternallyModified(Buffer::timestamp_method));
611 case LFUN_INSET_APPLY: {
616 string const name = cmd.getArg(0);
617 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
619 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
621 if (!inset->getStatus(view()->cursor(), fr, fs)) {
622 // Every inset is supposed to handle this
627 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
628 flag |= getStatus(fr);
630 enable = flag.enabled();
634 case LFUN_DIALOG_TOGGLE:
635 flag.setOnOff(lyx_view_->getDialogs().visible(cmd.getArg(0)));
636 // fall through to set "enable"
637 case LFUN_DIALOG_SHOW: {
638 string const name = cmd.getArg(0);
640 enable = name == "aboutlyx"
641 || name == "file" //FIXME: should be removed.
643 || name == "texinfo";
644 else if (name == "print")
645 enable = buf->isExportable("dvi")
646 && lyxrc.print_command != "none";
647 else if (name == "character") {
651 InsetCode ic = view()->cursor().inset().lyxCode();
652 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
655 else if (name == "latexlog")
656 enable = FileName(buf->logName()).isFileReadable();
657 else if (name == "spellchecker")
658 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
659 enable = !buf->isReadonly();
663 else if (name == "vclog")
664 enable = buf->lyxvc().inUse();
668 case LFUN_DIALOG_UPDATE: {
669 string const name = cmd.getArg(0);
671 enable = name == "prefs";
675 case LFUN_CITATION_INSERT: {
676 FuncRequest fr(LFUN_INSET_INSERT, "citation");
677 enable = getStatus(fr).enabled();
681 case LFUN_BUFFER_WRITE: {
682 enable = lyx_view_->buffer()->isUnnamed()
683 || !lyx_view_->buffer()->isClean();
688 case LFUN_BUFFER_WRITE_ALL: {
689 // We enable the command only if there are some modified buffers
690 Buffer * first = theBufferList().first();
691 bool modified = false;
695 // We cannot use a for loop as the buffer list is a cycle.
701 b = theBufferList().next(b);
702 } while (b != first);
710 case LFUN_BOOKMARK_GOTO: {
711 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
712 enable = LyX::ref().session().bookmarks().isValid(num);
716 case LFUN_BOOKMARK_CLEAR:
717 enable = LyX::ref().session().bookmarks().size() > 0;
720 case LFUN_TOOLBAR_TOGGLE: {
721 bool const current = lyx_view_->isToolbarVisible(cmd.getArg(0));
722 flag.setOnOff(current);
725 case LFUN_WINDOW_CLOSE: {
726 enable = (theApp()->gui().viewIds().size() > 1);
730 // this one is difficult to get right. As a half-baked
731 // solution, we consider only the first action of the sequence
732 case LFUN_COMMAND_SEQUENCE: {
733 // argument contains ';'-terminated commands
734 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
735 FuncRequest func(lyxaction.lookupFunc(firstcmd));
736 func.origin = cmd.origin;
737 flag = getStatus(func);
743 std::string name(to_utf8(cmd.argument()));
744 if (LyX::ref().topLevelCmdDef().lock(name, func)) {
745 func.origin = cmd.origin;
746 flag = getStatus(func);
747 LyX::ref().topLevelCmdDef().release(name);
749 // catch recursion or unknown command definiton
750 // all operations until the recursion or unknown command
751 // definiton occures are performed, so set the state to enabled
757 case LFUN_BUFFER_NEW:
758 case LFUN_BUFFER_NEW_TEMPLATE:
759 case LFUN_WORD_FIND_FORWARD:
760 case LFUN_WORD_FIND_BACKWARD:
761 case LFUN_COMMAND_PREFIX:
762 case LFUN_COMMAND_EXECUTE:
764 case LFUN_META_PREFIX:
765 case LFUN_BUFFER_CLOSE:
766 case LFUN_BUFFER_WRITE_AS:
767 case LFUN_BUFFER_UPDATE:
768 case LFUN_BUFFER_VIEW:
769 case LFUN_MASTER_BUFFER_UPDATE:
770 case LFUN_MASTER_BUFFER_VIEW:
771 case LFUN_BUFFER_IMPORT:
772 case LFUN_BUFFER_AUTO_SAVE:
773 case LFUN_RECONFIGURE:
777 case LFUN_DROP_LAYOUTS_CHOICE:
779 case LFUN_SERVER_GET_NAME:
780 case LFUN_SERVER_NOTIFY:
781 case LFUN_SERVER_GOTO_FILE_ROW:
782 case LFUN_DIALOG_HIDE:
783 case LFUN_DIALOG_DISCONNECT_INSET:
784 case LFUN_BUFFER_CHILD_OPEN:
785 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
786 case LFUN_KEYMAP_OFF:
787 case LFUN_KEYMAP_PRIMARY:
788 case LFUN_KEYMAP_SECONDARY:
789 case LFUN_KEYMAP_TOGGLE:
791 case LFUN_BUFFER_EXPORT_CUSTOM:
792 case LFUN_BUFFER_PRINT:
793 case LFUN_PREFERENCES_SAVE:
794 case LFUN_SCREEN_FONT_UPDATE:
797 case LFUN_EXTERNAL_EDIT:
798 case LFUN_GRAPHICS_EDIT:
799 case LFUN_ALL_INSETS_TOGGLE:
800 case LFUN_BUFFER_LANGUAGE:
801 case LFUN_TEXTCLASS_APPLY:
802 case LFUN_TEXTCLASS_LOAD:
803 case LFUN_BUFFER_SAVE_AS_DEFAULT:
804 case LFUN_BUFFER_PARAMS_APPLY:
805 case LFUN_LAYOUT_MODULES_CLEAR:
806 case LFUN_LAYOUT_MODULE_ADD:
807 case LFUN_LAYOUT_RELOAD:
808 case LFUN_LYXRC_APPLY:
809 case LFUN_BUFFER_NEXT:
810 case LFUN_BUFFER_PREVIOUS:
811 case LFUN_WINDOW_NEW:
813 // these are handled in our dispatch()
821 if (!getLocalStatus(view()->cursor(), cmd, flag))
822 flag = view()->getStatus(cmd);
828 // Can we use a readonly buffer?
829 if (buf && buf->isReadonly()
830 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
831 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
832 flag.message(from_utf8(N_("Document is read-only")));
836 // Are we in a DELETED change-tracking region?
838 && lookupChangeType(view()->cursor(), true) == Change::DELETED
839 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
840 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
841 flag.message(from_utf8(N_("This portion of the document is deleted.")));
845 // the default error message if we disable the command
846 if (!flag.enabled() && flag.message().empty())
847 flag.message(from_utf8(N_("Command disabled")));
853 bool LyXFunc::ensureBufferClean(BufferView * bv)
855 Buffer & buf = bv->buffer();
859 docstring const file = makeDisplayPath(buf.absFileName(), 30);
860 docstring text = bformat(_("The document %1$s has unsaved "
861 "changes.\n\nDo you want to save "
862 "the document?"), file);
863 int const ret = Alert::prompt(_("Save changed document?"),
864 text, 0, 1, _("&Save"),
868 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
870 return buf.isClean();
876 void showPrintError(string const & name)
878 docstring str = bformat(_("Could not print the document %1$s.\n"
879 "Check that your printer is set up correctly."),
880 makeDisplayPath(name, 50));
881 Alert::error(_("Print document failed"), str);
885 void loadTextClass(string const & name)
887 std::pair<bool, textclass_type> const tc_pair =
888 textclasslist.numberOfClass(name);
890 if (!tc_pair.first) {
891 lyxerr << "Document class \"" << name
892 << "\" does not exist."
897 textclass_type const tc = tc_pair.second;
899 if (!textclasslist[tc].load()) {
900 docstring s = bformat(_("The document class %1$s."
901 "could not be loaded."),
902 from_utf8(textclasslist[tc].name()));
903 Alert::error(_("Could not load class"), s);
908 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
913 void LyXFunc::dispatch(FuncRequest const & cmd)
915 string const argument = to_utf8(cmd.argument());
916 kb_action const action = cmd.action;
918 LYXERR(Debug::ACTION) << endl << "LyXFunc::dispatch: cmd: " << cmd << endl;
919 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
921 // we have not done anything wrong yet.
923 dispatch_buffer.erase();
925 // redraw the screen at the end (first of the two drawing steps).
926 //This is done unless explicitely requested otherwise
927 Update::flags updateFlags = Update::FitCursor;
929 FuncStatus const flag = getStatus(cmd);
930 if (!flag.enabled()) {
931 // We cannot use this function here
932 LYXERR(Debug::ACTION) << "LyXFunc::dispatch: "
933 << lyxaction.getActionName(action)
934 << " [" << action << "] is disabled at this location"
936 setErrorMessage(flag.message());
940 case LFUN_WORD_FIND_FORWARD:
941 case LFUN_WORD_FIND_BACKWARD: {
942 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
943 static docstring last_search;
944 docstring searched_string;
946 if (!cmd.argument().empty()) {
947 last_search = cmd.argument();
948 searched_string = cmd.argument();
950 searched_string = last_search;
953 if (searched_string.empty())
956 bool const fw = action == LFUN_WORD_FIND_FORWARD;
957 docstring const data =
958 find2string(searched_string, true, false, fw);
959 find(view(), FuncRequest(LFUN_WORD_FIND, data));
963 case LFUN_COMMAND_PREFIX:
964 BOOST_ASSERT(lyx_view_);
965 lyx_view_->message(keyseq.printOptions(true));
968 case LFUN_COMMAND_EXECUTE:
969 BOOST_ASSERT(lyx_view_);
970 lyx_view_->showMiniBuffer(true);
974 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
976 meta_fake_bit = NoModifier;
977 if (lyx_view_->buffer())
978 // cancel any selection
979 dispatch(FuncRequest(LFUN_MARK_OFF));
980 setMessage(from_ascii(N_("Cancel")));
983 case LFUN_META_PREFIX:
984 meta_fake_bit = AltModifier;
985 setMessage(keyseq.print(KeySequence::ForGui));
988 case LFUN_BUFFER_TOGGLE_READ_ONLY: {
989 BOOST_ASSERT(lyx_view_ && lyx_view_->view() && lyx_view_->buffer());
990 Buffer * buf = lyx_view_->buffer();
991 if (buf->lyxvc().inUse())
992 buf->lyxvc().toggleReadOnly();
994 buf->setReadonly(!lyx_view_->buffer()->isReadonly());
998 // --- Menus -----------------------------------------------
999 case LFUN_BUFFER_NEW:
1000 menuNew(argument, false);
1001 updateFlags = Update::None;
1004 case LFUN_BUFFER_NEW_TEMPLATE:
1005 menuNew(argument, true);
1006 updateFlags = Update::None;
1009 case LFUN_BUFFER_CLOSE:
1011 updateFlags = Update::None;
1014 case LFUN_BUFFER_WRITE:
1015 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1016 if (!lyx_view_->buffer()->isUnnamed()) {
1017 docstring const str = bformat(_("Saving document %1$s..."),
1018 makeDisplayPath(lyx_view_->buffer()->absFileName()));
1019 lyx_view_->message(str);
1020 lyx_view_->buffer()->menuWrite();
1021 lyx_view_->message(str + _(" done."));
1023 lyx_view_->buffer()->writeAs();
1025 updateFlags = Update::None;
1028 case LFUN_BUFFER_WRITE_AS:
1029 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1030 lyx_view_->buffer()->writeAs(argument);
1031 updateFlags = Update::None;
1034 case LFUN_BUFFER_WRITE_ALL: {
1035 Buffer * first = theBufferList().first();
1038 lyx_view_->message(_("Saving all documents..."));
1040 // We cannot use a for loop as the buffer list cycles.
1042 if (!b->isClean()) {
1043 if (!b->isUnnamed()) {
1045 lyxerr[Debug::ACTION] << "Saved " << b->absFileName() << endl;
1049 b = theBufferList().next(b);
1050 } while (b != first);
1051 lyx_view_->message(_("All documents saved."));
1054 updateFlags = Update::None;
1058 case LFUN_BUFFER_RELOAD: {
1059 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1060 docstring const file = makeDisplayPath(lyx_view_->buffer()->absFileName(), 20);
1061 docstring text = bformat(_("Any changes will be lost. Are you sure "
1062 "you want to revert to the saved version of the document %1$s?"), file);
1063 int const ret = Alert::prompt(_("Revert to saved document?"),
1064 text, 1, 1, _("&Revert"), _("&Cancel"));
1071 case LFUN_BUFFER_UPDATE:
1072 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1073 lyx_view_->buffer()->doExport(argument, true);
1076 case LFUN_BUFFER_VIEW:
1077 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1078 lyx_view_->buffer()->preview(argument);
1081 case LFUN_MASTER_BUFFER_UPDATE:
1082 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->masterBuffer());
1083 lyx_view_->buffer()->masterBuffer()->doExport(argument, true);
1086 case LFUN_MASTER_BUFFER_VIEW:
1087 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->masterBuffer());
1088 lyx_view_->buffer()->masterBuffer()->preview(argument);
1091 case LFUN_BUILD_PROGRAM:
1092 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1093 lyx_view_->buffer()->doExport("program", true);
1096 case LFUN_BUFFER_CHKTEX:
1097 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1098 lyx_view_->buffer()->runChktex();
1101 case LFUN_BUFFER_EXPORT:
1102 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1103 if (argument == "custom")
1104 lyx_view_->getDialogs().show("sendto");
1106 lyx_view_->buffer()->doExport(argument, false);
1109 case LFUN_BUFFER_EXPORT_CUSTOM: {
1110 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1112 string command = split(argument, format_name, ' ');
1113 Format const * format = formats.getFormat(format_name);
1115 lyxerr << "Format \"" << format_name
1116 << "\" not recognized!"
1121 Buffer * buffer = lyx_view_->buffer();
1123 // The name of the file created by the conversion process
1126 // Output to filename
1127 if (format->name() == "lyx") {
1128 string const latexname = buffer->latexName(false);
1129 filename = changeExtension(latexname,
1130 format->extension());
1131 filename = addName(buffer->temppath(), filename);
1133 if (!buffer->writeFile(FileName(filename)))
1137 buffer->doExport(format_name, true, filename);
1140 // Substitute $$FName for filename
1141 if (!contains(command, "$$FName"))
1142 command = "( " + command + " ) < $$FName";
1143 command = subst(command, "$$FName", filename);
1145 // Execute the command in the background
1147 call.startscript(Systemcall::DontWait, command);
1151 case LFUN_BUFFER_PRINT: {
1152 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1153 // FIXME: cmd.getArg() might fail if one of the arguments
1154 // contains double quotes
1155 string target = cmd.getArg(0);
1156 string target_name = cmd.getArg(1);
1157 string command = cmd.getArg(2);
1160 || target_name.empty()
1161 || command.empty()) {
1162 lyxerr << "Unable to parse \""
1163 << argument << '"' << endl;
1166 if (target != "printer" && target != "file") {
1167 lyxerr << "Unrecognized target \""
1168 << target << '"' << endl;
1172 Buffer * buffer = lyx_view_->buffer();
1174 if (!buffer->doExport("dvi", true)) {
1175 showPrintError(buffer->absFileName());
1179 // Push directory path.
1180 string const path = buffer->temppath();
1181 // Prevent the compiler from optimizing away p
1183 support::Path p(pp);
1185 // there are three cases here:
1186 // 1. we print to a file
1187 // 2. we print directly to a printer
1188 // 3. we print using a spool command (print to file first)
1191 string const dviname =
1192 changeExtension(buffer->latexName(true), "dvi");
1194 if (target == "printer") {
1195 if (!lyxrc.print_spool_command.empty()) {
1196 // case 3: print using a spool
1197 string const psname =
1198 changeExtension(dviname,".ps");
1199 command += ' ' + lyxrc.print_to_file
1202 + quoteName(dviname);
1205 lyxrc.print_spool_command + ' ';
1206 if (target_name != "default") {
1207 command2 += lyxrc.print_spool_printerprefix
1211 command2 += quoteName(psname);
1213 // If successful, then spool command
1214 res = one.startscript(
1219 res = one.startscript(
1220 Systemcall::DontWait,
1223 // case 2: print directly to a printer
1224 if (target_name != "default")
1225 command += ' ' + lyxrc.print_to_printer + target_name + ' ';
1226 res = one.startscript(
1227 Systemcall::DontWait,
1228 command + quoteName(dviname));
1232 // case 1: print to a file
1233 FileName const filename(makeAbsPath(target_name,
1234 lyx_view_->buffer()->filePath()));
1235 FileName const dvifile(makeAbsPath(dviname, path));
1236 if (filename.exists()) {
1237 docstring text = bformat(
1238 _("The file %1$s already exists.\n\n"
1239 "Do you want to overwrite that file?"),
1240 makeDisplayPath(filename.absFilename()));
1241 if (Alert::prompt(_("Overwrite file?"),
1242 text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
1245 command += ' ' + lyxrc.print_to_file
1246 + quoteName(filename.toFilesystemEncoding())
1248 + quoteName(dvifile.toFilesystemEncoding());
1249 res = one.startscript(Systemcall::DontWait,
1254 showPrintError(buffer->absFileName());
1258 case LFUN_BUFFER_IMPORT:
1263 // quitting is triggered by the gui code
1264 // (leaving the event loop).
1265 lyx_view_->message(from_utf8(N_("Exiting.")));
1266 if (theBufferList().quitWriteAll())
1267 theApp()->gui().closeAllViews();
1270 case LFUN_BUFFER_AUTO_SAVE:
1271 lyx_view_->buffer()->autoSave();
1274 case LFUN_RECONFIGURE:
1275 BOOST_ASSERT(lyx_view_);
1276 // argument is any additional parameter to the configure.py command
1277 reconfigure(*lyx_view_, argument);
1280 case LFUN_HELP_OPEN: {
1281 BOOST_ASSERT(lyx_view_);
1282 string const arg = argument;
1284 setErrorMessage(from_ascii(N_("Missing argument")));
1287 FileName const fname = i18nLibFileSearch("doc", arg, "lyx");
1288 if (fname.empty()) {
1289 lyxerr << "LyX: unable to find documentation file `"
1290 << arg << "'. Bad installation?" << endl;
1293 lyx_view_->message(bformat(_("Opening help file %1$s..."),
1294 makeDisplayPath(fname.absFilename())));
1295 Buffer * buf = lyx_view_->loadLyXFile(fname, false);
1298 lyx_view_->setBuffer(buf);
1299 lyx_view_->showErrorList("Parse");
1301 updateFlags = Update::None;
1305 // --- version control -------------------------------
1306 case LFUN_VC_REGISTER:
1307 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1308 if (!ensureBufferClean(view()))
1310 if (!lyx_view_->buffer()->lyxvc().inUse()) {
1311 lyx_view_->buffer()->lyxvc().registrer();
1314 updateFlags = Update::Force;
1317 case LFUN_VC_CHECK_IN:
1318 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1319 if (!ensureBufferClean(view()))
1321 if (lyx_view_->buffer()->lyxvc().inUse()
1322 && !lyx_view_->buffer()->isReadonly()) {
1323 lyx_view_->buffer()->lyxvc().checkIn();
1328 case LFUN_VC_CHECK_OUT:
1329 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1330 if (!ensureBufferClean(view()))
1332 if (lyx_view_->buffer()->lyxvc().inUse()
1333 && lyx_view_->buffer()->isReadonly()) {
1334 lyx_view_->buffer()->lyxvc().checkOut();
1339 case LFUN_VC_REVERT:
1340 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1341 lyx_view_->buffer()->lyxvc().revert();
1345 case LFUN_VC_UNDO_LAST:
1346 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1347 lyx_view_->buffer()->lyxvc().undoLast();
1351 // --- buffers ----------------------------------------
1352 case LFUN_BUFFER_SWITCH:
1353 BOOST_ASSERT(lyx_view_);
1354 lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1355 updateFlags = Update::None;
1358 case LFUN_BUFFER_NEXT:
1359 BOOST_ASSERT(lyx_view_);
1360 lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer()));
1361 updateFlags = Update::None;
1364 case LFUN_BUFFER_PREVIOUS:
1365 BOOST_ASSERT(lyx_view_);
1366 lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer()));
1367 updateFlags = Update::None;
1370 case LFUN_FILE_NEW: {
1371 BOOST_ASSERT(lyx_view_);
1373 string tmpname = split(argument, name, ':'); // Split filename
1374 Buffer * const b = newFile(name, tmpname);
1376 lyx_view_->setBuffer(b);
1377 updateFlags = Update::None;
1381 case LFUN_FILE_OPEN:
1382 BOOST_ASSERT(lyx_view_);
1384 updateFlags = Update::None;
1387 case LFUN_DROP_LAYOUTS_CHOICE:
1388 BOOST_ASSERT(lyx_view_);
1389 lyx_view_->openLayoutList();
1392 case LFUN_MENU_OPEN:
1393 BOOST_ASSERT(lyx_view_);
1394 lyx_view_->openMenu(from_utf8(argument));
1397 // --- lyxserver commands ----------------------------
1398 case LFUN_SERVER_GET_NAME:
1399 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1400 setMessage(from_utf8(lyx_view_->buffer()->absFileName()));
1401 LYXERR(Debug::INFO) << "FNAME["
1402 << lyx_view_->buffer()->absFileName()
1406 case LFUN_SERVER_NOTIFY:
1407 dispatch_buffer = keyseq.print(KeySequence::Portable);
1408 theServer().notifyClient(to_utf8(dispatch_buffer));
1411 case LFUN_SERVER_GOTO_FILE_ROW: {
1412 BOOST_ASSERT(lyx_view_);
1415 istringstream is(argument);
1416 is >> file_name >> row;
1418 bool loaded = false;
1419 if (prefixIs(file_name, package().temp_dir().absFilename()))
1420 // Needed by inverse dvi search. If it is a file
1421 // in tmpdir, call the apropriated function
1422 buf = theBufferList().getBufferFromTmp(file_name);
1424 // Must replace extension of the file to be .lyx
1425 // and get full path
1426 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1427 // Either change buffer or load the file
1428 if (theBufferList().exists(s.absFilename()))
1429 buf = theBufferList().getBuffer(s.absFilename());
1431 buf = lyx_view_->loadLyXFile(s);
1437 updateFlags = Update::None;
1442 lyx_view_->setBuffer(buf);
1443 view()->setCursorFromRow(row);
1445 lyx_view_->showErrorList("Parse");
1446 updateFlags = Update::FitCursor;
1450 case LFUN_DIALOG_SHOW: {
1451 BOOST_ASSERT(lyx_view_);
1452 string const name = cmd.getArg(0);
1453 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1455 if (name == "character") {
1456 data = freefont2string();
1458 lyx_view_->getDialogs().show("character", data);
1459 } else if (name == "latexlog") {
1460 Buffer::LogType type;
1461 string const logfile = lyx_view_->buffer()->logName(&type);
1463 case Buffer::latexlog:
1466 case Buffer::buildlog:
1470 data += Lexer::quoteString(logfile);
1471 lyx_view_->getDialogs().show("log", data);
1472 } else if (name == "vclog") {
1473 string const data = "vc " +
1474 Lexer::quoteString(lyx_view_->buffer()->lyxvc().getLogFile());
1475 lyx_view_->getDialogs().show("log", data);
1477 lyx_view_->getDialogs().show(name, data);
1481 case LFUN_DIALOG_SHOW_NEW_INSET: {
1482 BOOST_ASSERT(lyx_view_);
1483 string const name = cmd.getArg(0);
1484 InsetCode code = insetCode(name);
1485 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1486 bool insetCodeOK = true;
1495 case HYPERLINK_CODE: {
1496 InsetCommandParams p(code);
1497 data = InsetCommandMailer::params2string(name, p);
1500 case INCLUDE_CODE: {
1501 // data is the include type: one of "include",
1502 // "input", "verbatiminput" or "verbatiminput*"
1504 // default type is requested
1506 InsetCommandParams p(INCLUDE_CODE, data);
1507 data = InsetCommandMailer::params2string("include", p);
1511 // \c data == "Boxed" || "Frameless" etc
1512 InsetBoxParams p(data);
1513 data = InsetBoxMailer::params2string(p);
1517 InsetBranchParams p;
1518 data = InsetBranchMailer::params2string(p);
1522 InsetCommandParams p(CITE_CODE);
1523 data = InsetCommandMailer::params2string(name, p);
1527 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1530 case EXTERNAL_CODE: {
1531 InsetExternalParams p;
1532 Buffer const & buffer = *lyx_view_->buffer();
1533 data = InsetExternalMailer::params2string(p, buffer);
1538 data = InsetFloatMailer::params2string(p);
1541 case LISTINGS_CODE: {
1542 InsetListingsParams p;
1543 data = InsetListingsMailer::params2string(p);
1546 case GRAPHICS_CODE: {
1547 InsetGraphicsParams p;
1548 Buffer const & buffer = *lyx_view_->buffer();
1549 data = InsetGraphicsMailer::params2string(p, buffer);
1554 data = InsetNoteMailer::params2string(p);
1559 data = InsetVSpaceMailer::params2string(space);
1564 data = InsetWrapMailer::params2string(p);
1568 lyxerr << "Inset type '" << name <<
1569 "' not recognized in LFUN_DIALOG_SHOW_NEW_INSET" << std:: endl;
1570 insetCodeOK = false;
1572 } // end switch(code)
1574 lyx_view_->getDialogs().show(name, data, 0);
1578 case LFUN_DIALOG_UPDATE: {
1579 BOOST_ASSERT(lyx_view_);
1580 string const & name = argument;
1581 // Can only update a dialog connected to an existing inset
1582 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1584 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1585 inset->dispatch(view()->cursor(), fr);
1586 } else if (name == "paragraph") {
1587 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1588 } else if (name == "prefs") {
1589 lyx_view_->getDialogs().update(name, string());
1594 case LFUN_DIALOG_HIDE:
1595 LyX::cref().hideDialogs(argument, 0);
1598 case LFUN_DIALOG_TOGGLE: {
1599 BOOST_ASSERT(lyx_view_);
1600 if (lyx_view_->getDialogs().visible(cmd.getArg(0)))
1601 dispatch(FuncRequest(LFUN_DIALOG_HIDE, argument));
1603 dispatch(FuncRequest(LFUN_DIALOG_SHOW, argument));
1607 case LFUN_DIALOG_DISCONNECT_INSET:
1608 BOOST_ASSERT(lyx_view_);
1609 lyx_view_->getDialogs().disconnect(argument);
1613 case LFUN_CITATION_INSERT: {
1614 BOOST_ASSERT(lyx_view_);
1615 if (!argument.empty()) {
1616 // we can have one optional argument, delimited by '|'
1617 // citation-insert <key>|<text_before>
1618 // this should be enhanced to also support text_after
1619 // and citation style
1620 string arg = argument;
1622 if (contains(argument, "|")) {
1623 arg = token(argument, '|', 0);
1624 opt1 = token(argument, '|', 1);
1626 InsetCommandParams icp(CITE_CODE);
1627 icp["key"] = from_utf8(arg);
1629 icp["before"] = from_utf8(opt1);
1630 string icstr = InsetCommandMailer::params2string("citation", icp);
1631 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1634 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1638 case LFUN_BUFFER_CHILD_OPEN: {
1639 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1640 Buffer * parent = lyx_view_->buffer();
1641 FileName filename = makeAbsPath(argument, parent->filePath());
1642 view()->saveBookmark(false);
1644 bool parsed = false;
1645 if (theBufferList().exists(filename.absFilename())) {
1646 child = theBufferList().getBuffer(filename.absFilename());
1648 setMessage(bformat(_("Opening child document %1$s..."),
1649 makeDisplayPath(filename.absFilename())));
1650 child = lyx_view_->loadLyXFile(filename, true);
1654 // Set the parent name of the child document.
1655 // This makes insertion of citations and references in the child work,
1656 // when the target is in the parent or another child document.
1657 child->setParentName(parent->absFileName());
1658 updateLabels(*child->masterBuffer());
1659 lyx_view_->setBuffer(child);
1661 lyx_view_->showErrorList("Parse");
1664 // If a screen update is required (in case where auto_open is false),
1665 // setBuffer() would have taken care of it already. Otherwise we shall
1666 // reset the update flag because it can cause a circular problem.
1668 updateFlags = Update::None;
1672 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1673 BOOST_ASSERT(lyx_view_);
1674 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1677 case LFUN_KEYMAP_OFF:
1678 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1679 lyx_view_->view()->getIntl().keyMapOn(false);
1682 case LFUN_KEYMAP_PRIMARY:
1683 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1684 lyx_view_->view()->getIntl().keyMapPrim();
1687 case LFUN_KEYMAP_SECONDARY:
1688 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1689 lyx_view_->view()->getIntl().keyMapSec();
1692 case LFUN_KEYMAP_TOGGLE:
1693 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1694 lyx_view_->view()->getIntl().toggleKeyMap();
1700 string rest = split(argument, countstr, ' ');
1701 istringstream is(countstr);
1704 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1705 for (int i = 0; i < count; ++i)
1706 dispatch(lyxaction.lookupFunc(rest));
1710 case LFUN_COMMAND_SEQUENCE: {
1711 // argument contains ';'-terminated commands
1712 string arg = argument;
1713 while (!arg.empty()) {
1715 arg = split(arg, first, ';');
1716 FuncRequest func(lyxaction.lookupFunc(first));
1717 func.origin = cmd.origin;
1725 if (LyX::ref().topLevelCmdDef().lock(argument, func)) {
1726 func.origin = cmd.origin;
1728 LyX::ref().topLevelCmdDef().release(argument);
1730 if (func.action == LFUN_UNKNOWN_ACTION) {
1731 // unknown command definition
1732 lyxerr << "Warning: unknown command definition `"
1736 // recursion detected
1737 lyxerr << "Warning: Recursion in the command definition `"
1738 << argument << "' detected"
1745 case LFUN_PREFERENCES_SAVE: {
1746 lyxrc.write(makeAbsPath("preferences",
1747 package().user_support().absFilename()),
1752 case LFUN_SCREEN_FONT_UPDATE:
1753 BOOST_ASSERT(lyx_view_);
1754 // handle the screen font changes.
1755 theFontLoader().update();
1756 /// FIXME: only the current view will be updated. the Gui
1757 /// class is able to furnish the list of views.
1758 updateFlags = Update::Force;
1761 case LFUN_SET_COLOR: {
1763 string const x11_name = split(argument, lyx_name, ' ');
1764 if (lyx_name.empty() || x11_name.empty()) {
1765 setErrorMessage(from_ascii(N_(
1766 "Syntax: set-color <lyx_name>"
1771 bool const graphicsbg_changed =
1772 (lyx_name == lcolor.getLyXName(Color_graphicsbg) &&
1773 x11_name != lcolor.getX11Name(Color_graphicsbg));
1775 if (!lcolor.setColor(lyx_name, x11_name)) {
1777 bformat(_("Set-color \"%1$s\" failed "
1778 "- color is undefined or "
1779 "may not be redefined"),
1780 from_utf8(lyx_name)));
1784 theApp()->updateColor(lcolor.getFromLyXName(lyx_name));
1786 if (graphicsbg_changed) {
1787 // FIXME: The graphics cache no longer has a changeDisplay method.
1789 graphics::GCache::get().changeDisplay(true);
1796 BOOST_ASSERT(lyx_view_);
1797 lyx_view_->message(from_utf8(argument));
1800 case LFUN_EXTERNAL_EDIT: {
1801 BOOST_ASSERT(lyx_view_);
1802 FuncRequest fr(action, argument);
1803 InsetExternal().dispatch(view()->cursor(), fr);
1807 case LFUN_GRAPHICS_EDIT: {
1808 FuncRequest fr(action, argument);
1809 InsetGraphics().dispatch(view()->cursor(), fr);
1813 case LFUN_INSET_APPLY: {
1814 BOOST_ASSERT(lyx_view_);
1815 string const name = cmd.getArg(0);
1816 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1818 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1819 inset->dispatch(view()->cursor(), fr);
1821 FuncRequest fr(LFUN_INSET_INSERT, argument);
1824 // ideally, the update flag should be set by the insets,
1825 // but this is not possible currently
1826 updateFlags = Update::Force | Update::FitCursor;
1830 case LFUN_ALL_INSETS_TOGGLE: {
1831 BOOST_ASSERT(lyx_view_);
1833 string const name = split(argument, action, ' ');
1834 InsetCode const inset_code = insetCode(name);
1836 Cursor & cur = view()->cursor();
1837 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1839 Inset & inset = lyx_view_->buffer()->inset();
1840 InsetIterator it = inset_iterator_begin(inset);
1841 InsetIterator const end = inset_iterator_end(inset);
1842 for (; it != end; ++it) {
1843 if (!it->asInsetMath()
1844 && (inset_code == NO_CODE
1845 || inset_code == it->lyxCode())) {
1846 Cursor tmpcur = cur;
1847 tmpcur.pushLeft(*it);
1848 it->dispatch(tmpcur, fr);
1851 updateFlags = Update::Force | Update::FitCursor;
1855 case LFUN_BUFFER_LANGUAGE: {
1856 BOOST_ASSERT(lyx_view_);
1857 Buffer & buffer = *lyx_view_->buffer();
1858 Language const * oldL = buffer.params().language;
1859 Language const * newL = languages.getLanguage(argument);
1860 if (!newL || oldL == newL)
1863 if (oldL->rightToLeft() == newL->rightToLeft()
1864 && !buffer.isMultiLingual())
1865 buffer.changeLanguage(oldL, newL);
1869 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1870 string const fname =
1871 addName(addPath(package().user_support().absFilename(), "templates/"),
1873 Buffer defaults(fname);
1875 istringstream ss(argument);
1878 int const unknown_tokens = defaults.readHeader(lex);
1880 if (unknown_tokens != 0) {
1881 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1882 << unknown_tokens << " unknown token"
1883 << (unknown_tokens == 1 ? "" : "s")
1887 if (defaults.writeFile(FileName(defaults.absFileName())))
1888 setMessage(bformat(_("Document defaults saved in %1$s"),
1889 makeDisplayPath(fname)));
1891 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1895 case LFUN_BUFFER_PARAMS_APPLY: {
1896 BOOST_ASSERT(lyx_view_);
1897 biblio::CiteEngine const oldEngine =
1898 lyx_view_->buffer()->params().getEngine();
1900 Buffer * buffer = lyx_view_->buffer();
1902 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1904 Cursor & cur = view()->cursor();
1905 cur.recordUndoFullDocument();
1907 istringstream ss(argument);
1910 int const unknown_tokens = buffer->readHeader(lex);
1912 if (unknown_tokens != 0) {
1913 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1914 << unknown_tokens << " unknown token"
1915 << (unknown_tokens == 1 ? "" : "s")
1919 updateLayout(oldClass, buffer);
1921 biblio::CiteEngine const newEngine =
1922 lyx_view_->buffer()->params().getEngine();
1924 if (oldEngine != newEngine) {
1925 FuncRequest fr(LFUN_INSET_REFRESH);
1927 Inset & inset = lyx_view_->buffer()->inset();
1928 InsetIterator it = inset_iterator_begin(inset);
1929 InsetIterator const end = inset_iterator_end(inset);
1930 for (; it != end; ++it)
1931 if (it->lyxCode() == CITE_CODE)
1932 it->dispatch(cur, fr);
1935 updateFlags = Update::Force | Update::FitCursor;
1939 case LFUN_LAYOUT_MODULES_CLEAR: {
1940 BOOST_ASSERT(lyx_view_);
1941 Buffer * buffer = lyx_view_->buffer();
1942 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1943 view()->cursor().recordUndoFullDocument();
1944 buffer->params().clearLayoutModules();
1945 updateLayout(oldClass, buffer);
1946 updateFlags = Update::Force | Update::FitCursor;
1950 case LFUN_LAYOUT_MODULE_ADD: {
1951 BOOST_ASSERT(lyx_view_);
1952 Buffer * buffer = lyx_view_->buffer();
1953 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1954 view()->cursor().recordUndoFullDocument();
1955 buffer->params().addLayoutModule(argument);
1956 updateLayout(oldClass, buffer);
1957 updateFlags = Update::Force | Update::FitCursor;
1961 case LFUN_TEXTCLASS_APPLY: {
1962 BOOST_ASSERT(lyx_view_);
1963 Buffer * buffer = lyx_view_->buffer();
1965 loadTextClass(argument);
1967 std::pair<bool, textclass_type> const tc_pair =
1968 textclasslist.numberOfClass(argument);
1973 textclass_type const old_class = buffer->params().getBaseClass();
1974 textclass_type const new_class = tc_pair.second;
1976 if (old_class == new_class)
1980 //Save the old, possibly modular, layout for use in conversion.
1981 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1982 view()->cursor().recordUndoFullDocument();
1983 buffer->params().setBaseClass(new_class);
1984 updateLayout(oldClass, buffer);
1985 updateFlags = Update::Force | Update::FitCursor;
1989 case LFUN_LAYOUT_RELOAD: {
1990 BOOST_ASSERT(lyx_view_);
1991 Buffer * buffer = lyx_view_->buffer();
1992 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1993 textclass_type const tc = buffer->params().getBaseClass();
1994 textclasslist.reset(tc);
1995 buffer->params().setBaseClass(tc);
1996 updateLayout(oldClass, buffer);
1997 updateFlags = Update::Force | Update::FitCursor;
2001 case LFUN_TEXTCLASS_LOAD:
2002 loadTextClass(argument);
2005 case LFUN_LYXRC_APPLY: {
2006 LyXRC const lyxrc_orig = lyxrc;
2008 istringstream ss(argument);
2009 bool const success = lyxrc.read(ss) == 0;
2012 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
2013 << "Unable to read lyxrc data"
2018 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
2020 /// We force the redraw in any case because there might be
2021 /// some screen font changes.
2022 /// FIXME: only the current view will be updated. the Gui
2023 /// class is able to furnish the list of views.
2024 updateFlags = Update::Force;
2028 case LFUN_WINDOW_NEW:
2029 LyX::ref().newLyXView();
2032 case LFUN_WINDOW_CLOSE:
2033 BOOST_ASSERT(lyx_view_);
2034 BOOST_ASSERT(theApp());
2035 // update bookmark pit of the current buffer before window close
2036 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2037 gotoBookmark(i+1, false, false);
2038 // ask the user for saving changes or cancel quit
2039 if (!theBufferList().quitWriteAll())
2044 case LFUN_BOOKMARK_GOTO:
2045 // go to bookmark, open unopened file and switch to buffer if necessary
2046 gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
2049 case LFUN_BOOKMARK_CLEAR:
2050 LyX::ref().session().bookmarks().clear();
2053 case LFUN_TOOLBAR_TOGGLE: {
2054 BOOST_ASSERT(lyx_view_);
2055 string const name = cmd.getArg(0);
2056 bool const allowauto = cmd.getArg(1) == "allowauto";
2057 lyx_view_->toggleToolbarState(name, allowauto);
2058 ToolbarInfo * tbi = lyx_view_->getToolbarInfo(name);
2060 setMessage(bformat(_("Unknown toolbar \"%1$s\""),
2065 if (tbi->flags & ToolbarInfo::ON)
2067 else if (tbi->flags & ToolbarInfo::OFF)
2069 else if (tbi->flags & ToolbarInfo::AUTO)
2072 setMessage(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
2073 _(tbi->gui_name), state));
2078 BOOST_ASSERT(lyx_view_);
2079 view()->cursor().dispatch(cmd);
2080 updateFlags = view()->cursor().result().update();
2081 if (!view()->cursor().result().dispatched())
2082 updateFlags = view()->dispatch(cmd);
2087 if (lyx_view_ && lyx_view_->buffer()) {
2088 // BufferView::update() updates the ViewMetricsInfo and
2089 // also initializes the position cache for all insets in
2090 // (at least partially) visible top-level paragraphs.
2091 // We will redraw the screen only if needed.
2092 view()->processUpdateFlags(updateFlags);
2093 lyx_view_->updateStatusBar();
2095 // if we executed a mutating lfun, mark the buffer as dirty
2097 && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
2098 && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
2099 lyx_view_->buffer()->markDirty();
2101 //Do we have a selection?
2102 theSelection().haveSelection(view()->cursor().selection());
2104 if (view()->cursor().inTexted()) {
2105 lyx_view_->updateLayoutChoice();
2109 if (!quitting && lyx_view_) {
2110 lyx_view_->updateToolbars();
2111 // Some messages may already be translated, so we cannot use _()
2112 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
2117 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
2119 const bool verbose = (cmd.origin == FuncRequest::MENU
2120 || cmd.origin == FuncRequest::TOOLBAR
2121 || cmd.origin == FuncRequest::COMMANDBUFFER);
2123 if (cmd.action == LFUN_SELF_INSERT || !verbose) {
2124 LYXERR(Debug::ACTION) << "dispatch msg is " << to_utf8(msg) << endl;
2126 lyx_view_->message(msg);
2130 docstring dispatch_msg = msg;
2131 if (!dispatch_msg.empty())
2132 dispatch_msg += ' ';
2134 docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
2136 bool argsadded = false;
2138 if (!cmd.argument().empty()) {
2139 if (cmd.action != LFUN_UNKNOWN_ACTION) {
2140 comname += ' ' + cmd.argument();
2145 docstring const shortcuts = theTopLevelKeymap().printBindings(cmd);
2147 if (!shortcuts.empty())
2148 comname += ": " + shortcuts;
2149 else if (!argsadded && !cmd.argument().empty())
2150 comname += ' ' + cmd.argument();
2152 if (!comname.empty()) {
2153 comname = rtrim(comname);
2154 dispatch_msg += '(' + rtrim(comname) + ')';
2157 LYXERR(Debug::ACTION) << "verbose dispatch msg "
2158 << to_utf8(dispatch_msg) << endl;
2159 if (!dispatch_msg.empty())
2160 lyx_view_->message(dispatch_msg);
2164 void LyXFunc::menuNew(string const & name, bool fromTemplate)
2166 // FIXME: initpath is not used. What to do?
2167 string initpath = lyxrc.document_path;
2168 string filename(name);
2170 if (lyx_view_->buffer()) {
2171 string const trypath = lyx_view_->buffer()->filePath();
2172 // If directory is writeable, use this as default.
2173 if (FileName(trypath).isDirWritable())
2177 static int newfile_number;
2179 if (filename.empty()) {
2180 filename = addName(lyxrc.document_path,
2181 "newfile" + convert<string>(++newfile_number) + ".lyx");
2182 while (theBufferList().exists(filename) ||
2183 FileName(filename).isReadable()) {
2185 filename = addName(lyxrc.document_path,
2186 "newfile" + convert<string>(newfile_number) +
2191 // The template stuff
2194 FileDialog dlg(_("Select template file"));
2195 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
2196 dlg.setButton1(_("Templates|#T#t"), from_utf8(lyxrc.template_path));
2198 FileDialog::Result result =
2199 dlg.open(from_utf8(lyxrc.template_path),
2200 FileFilterList(_("LyX Documents (*.lyx)")),
2203 if (result.first == FileDialog::Later)
2205 if (result.second.empty())
2207 templname = to_utf8(result.second);
2210 Buffer * const b = newFile(filename, templname, !name.empty());
2212 lyx_view_->setBuffer(b);
2216 void LyXFunc::open(string const & fname)
2218 string initpath = lyxrc.document_path;
2220 if (lyx_view_->buffer()) {
2221 string const trypath = lyx_view_->buffer()->filePath();
2222 // If directory is writeable, use this as default.
2223 if (FileName(trypath).isDirWritable())
2229 if (fname.empty()) {
2230 FileDialog dlg(_("Select document to open"), LFUN_FILE_OPEN);
2231 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
2232 dlg.setButton2(_("Examples|#E#e"),
2233 from_utf8(addPath(package().system_support().absFilename(), "examples")));
2235 FileDialog::Result result =
2236 dlg.open(from_utf8(initpath),
2237 FileFilterList(_("LyX Documents (*.lyx)")),
2240 if (result.first == FileDialog::Later)
2243 filename = to_utf8(result.second);
2245 // check selected filename
2246 if (filename.empty()) {
2247 lyx_view_->message(_("Canceled."));
2253 // get absolute path of file and add ".lyx" to the filename if
2255 FileName const fullname = fileSearch(string(), filename, "lyx");
2256 if (!fullname.empty())
2257 filename = fullname.absFilename();
2259 // if the file doesn't exist, let the user create one
2260 if (!fullname.exists()) {
2261 // the user specifically chose this name. Believe him.
2262 Buffer * const b = newFile(filename, string(), true);
2264 lyx_view_->setBuffer(b);
2268 docstring const disp_fn = makeDisplayPath(filename);
2269 lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
2272 Buffer * buf = lyx_view_->loadLyXFile(fullname);
2275 lyx_view_->setBuffer(buf);
2276 lyx_view_->showErrorList("Parse");
2277 str2 = bformat(_("Document %1$s opened."), disp_fn);
2279 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2281 lyx_view_->message(str2);
2285 void LyXFunc::doImport(string const & argument)
2288 string filename = split(argument, format, ' ');
2290 LYXERR(Debug::INFO) << "LyXFunc::doImport: " << format
2291 << " file: " << filename << endl;
2293 // need user interaction
2294 if (filename.empty()) {
2295 string initpath = lyxrc.document_path;
2297 if (lyx_view_->buffer()) {
2298 string const trypath = lyx_view_->buffer()->filePath();
2299 // If directory is writeable, use this as default.
2300 if (FileName(trypath).isDirWritable())
2304 docstring const text = bformat(_("Select %1$s file to import"),
2305 formats.prettyName(format));
2307 FileDialog dlg(text, LFUN_BUFFER_IMPORT);
2308 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
2309 dlg.setButton2(_("Examples|#E#e"),
2310 from_utf8(addPath(package().system_support().absFilename(), "examples")));
2312 docstring filter = formats.prettyName(format);
2315 filter += from_utf8(formats.extension(format));
2318 FileDialog::Result result =
2319 dlg.open(from_utf8(initpath),
2320 FileFilterList(filter),
2323 if (result.first == FileDialog::Later)
2326 filename = to_utf8(result.second);
2328 // check selected filename
2329 if (filename.empty())
2330 lyx_view_->message(_("Canceled."));
2333 if (filename.empty())
2336 // get absolute path of file
2337 FileName const fullname(makeAbsPath(filename));
2339 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
2341 // Check if the document already is open
2342 if (use_gui && theBufferList().exists(lyxfile.absFilename())) {
2343 if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) {
2344 lyx_view_->message(_("Canceled."));
2349 // if the file exists already, and we didn't do
2350 // -i lyx thefile.lyx, warn
2351 if (lyxfile.exists() && fullname != lyxfile) {
2352 docstring const file = makeDisplayPath(lyxfile.absFilename(), 30);
2354 docstring text = bformat(_("The document %1$s already exists.\n\n"
2355 "Do you want to overwrite that document?"), file);
2356 int const ret = Alert::prompt(_("Overwrite document?"),
2357 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2360 lyx_view_->message(_("Canceled."));
2365 ErrorList errorList;
2366 import(lyx_view_, fullname, format, errorList);
2367 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2371 void LyXFunc::closeBuffer()
2373 // goto bookmark to update bookmark pit.
2374 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2375 gotoBookmark(i+1, false, false);
2377 theBufferList().close(lyx_view_->buffer(), true);
2381 void LyXFunc::reloadBuffer()
2383 FileName filename(lyx_view_->buffer()->absFileName());
2384 docstring const disp_fn = makeDisplayPath(filename.absFilename());
2387 Buffer * buf = lyx_view_->loadLyXFile(filename);
2390 lyx_view_->setBuffer(buf);
2391 lyx_view_->showErrorList("Parse");
2392 str = bformat(_("Document %1$s reloaded."), disp_fn);
2394 str = bformat(_("Could not reload document %1$s"), disp_fn);
2396 lyx_view_->message(str);
2399 // Each "lyx_view_" should have it's own message method. lyxview and
2400 // the minibuffer would use the minibuffer, but lyxserver would
2401 // send an ERROR signal to its client. Alejandro 970603
2402 // This function is bit problematic when it comes to NLS, to make the
2403 // lyx servers client be language indepenent we must not translate
2404 // strings sent to this func.
2405 void LyXFunc::setErrorMessage(docstring const & m) const
2407 dispatch_buffer = m;
2412 void LyXFunc::setMessage(docstring const & m) const
2414 dispatch_buffer = m;
2418 docstring const LyXFunc::viewStatusMessage()
2420 // When meta-fake key is pressed, show the key sequence so far + "M-".
2422 return keyseq.print(KeySequence::ForGui) + "M-";
2424 // Else, when a non-complete key sequence is pressed,
2425 // show the available options.
2426 if (keyseq.length() > 0 && !keyseq.deleted())
2427 return keyseq.printOptions(true);
2429 BOOST_ASSERT(lyx_view_);
2430 if (!lyx_view_->buffer())
2431 return _("Welcome to LyX!");
2433 return view()->cursor().currentState();
2437 BufferView * LyXFunc::view() const
2439 BOOST_ASSERT(lyx_view_);
2440 return lyx_view_->view();
2444 bool LyXFunc::wasMetaKey() const
2446 return (meta_fake_bit != NoModifier);
2450 void LyXFunc::updateLayout(TextClassPtr const & oldlayout,
2453 lyx_view_->message(_("Converting document to new document class..."));
2455 StableDocIterator backcur(view()->cursor());
2456 ErrorList & el = buffer->errorList("Class Switch");
2457 cap::switchBetweenClasses(
2458 oldlayout, buffer->params().getTextClassPtr(),
2459 static_cast<InsetText &>(buffer->inset()), el);
2461 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
2463 buffer->errors("Class Switch");
2464 updateLabels(*buffer);
2470 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2472 // Why the switch you might ask. It is a trick to ensure that all
2473 // the elements in the LyXRCTags enum is handled. As you can see
2474 // there are no breaks at all. So it is just a huge fall-through.
2475 // The nice thing is that we will get a warning from the compiler
2476 // if we forget an element.
2477 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2479 case LyXRC::RC_ACCEPT_COMPOUND:
2480 case LyXRC::RC_ALT_LANG:
2481 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
2482 case LyXRC::RC_PLAINTEXT_LINELEN:
2483 case LyXRC::RC_AUTOREGIONDELETE:
2484 case LyXRC::RC_AUTORESET_OPTIONS:
2485 case LyXRC::RC_AUTOSAVE:
2486 case LyXRC::RC_AUTO_NUMBER:
2487 case LyXRC::RC_BACKUPDIR_PATH:
2488 case LyXRC::RC_BIBTEX_COMMAND:
2489 case LyXRC::RC_BINDFILE:
2490 case LyXRC::RC_CHECKLASTFILES:
2491 case LyXRC::RC_USELASTFILEPOS:
2492 case LyXRC::RC_LOADSESSION:
2493 case LyXRC::RC_CHKTEX_COMMAND:
2494 case LyXRC::RC_CONVERTER:
2495 case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
2496 case LyXRC::RC_COPIER:
2497 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2498 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2499 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2500 case LyXRC::RC_DATE_INSERT_FORMAT:
2501 case LyXRC::RC_DEFAULT_LANGUAGE:
2502 case LyXRC::RC_DEFAULT_PAPERSIZE:
2503 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2504 case LyXRC::RC_DISPLAY_GRAPHICS:
2505 case LyXRC::RC_DOCUMENTPATH:
2506 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2507 FileName path(lyxrc_new.document_path);
2508 if (path.exists() && path.isDirectory())
2509 support::package().document_dir() = FileName(lyxrc.document_path);
2511 case LyXRC::RC_ESC_CHARS:
2512 case LyXRC::RC_FONT_ENCODING:
2513 case LyXRC::RC_FORMAT:
2514 case LyXRC::RC_INDEX_COMMAND:
2515 case LyXRC::RC_INPUT:
2516 case LyXRC::RC_KBMAP:
2517 case LyXRC::RC_KBMAP_PRIMARY:
2518 case LyXRC::RC_KBMAP_SECONDARY:
2519 case LyXRC::RC_LABEL_INIT_LENGTH:
2520 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2521 case LyXRC::RC_LANGUAGE_AUTO_END:
2522 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2523 case LyXRC::RC_LANGUAGE_COMMAND_END:
2524 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2525 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2526 case LyXRC::RC_LANGUAGE_PACKAGE:
2527 case LyXRC::RC_LANGUAGE_USE_BABEL:
2528 case LyXRC::RC_MAKE_BACKUP:
2529 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2530 case LyXRC::RC_NUMLASTFILES:
2531 case LyXRC::RC_PATH_PREFIX:
2532 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2533 support::prependEnvPath("PATH", lyxrc.path_prefix);
2535 case LyXRC::RC_PERS_DICT:
2536 case LyXRC::RC_PREVIEW:
2537 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2538 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2539 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2540 case LyXRC::RC_PRINTCOPIESFLAG:
2541 case LyXRC::RC_PRINTER:
2542 case LyXRC::RC_PRINTEVENPAGEFLAG:
2543 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2544 case LyXRC::RC_PRINTFILEEXTENSION:
2545 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2546 case LyXRC::RC_PRINTODDPAGEFLAG:
2547 case LyXRC::RC_PRINTPAGERANGEFLAG:
2548 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2549 case LyXRC::RC_PRINTPAPERFLAG:
2550 case LyXRC::RC_PRINTREVERSEFLAG:
2551 case LyXRC::RC_PRINTSPOOL_COMMAND:
2552 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2553 case LyXRC::RC_PRINTTOFILE:
2554 case LyXRC::RC_PRINTTOPRINTER:
2555 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2556 case LyXRC::RC_PRINT_COMMAND:
2557 case LyXRC::RC_RTL_SUPPORT:
2558 case LyXRC::RC_SCREEN_DPI:
2559 case LyXRC::RC_SCREEN_FONT_ROMAN:
2560 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2561 case LyXRC::RC_SCREEN_FONT_SANS:
2562 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2563 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2564 case LyXRC::RC_SCREEN_FONT_SIZES:
2565 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2566 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2567 case LyXRC::RC_SCREEN_GEOMETRY_HEIGHT:
2568 case LyXRC::RC_SCREEN_GEOMETRY_WIDTH:
2569 case LyXRC::RC_SCREEN_GEOMETRY_XYSAVED:
2570 case LyXRC::RC_SCREEN_ZOOM:
2571 case LyXRC::RC_SERVERPIPE:
2572 case LyXRC::RC_SET_COLOR:
2573 case LyXRC::RC_SHOW_BANNER:
2574 case LyXRC::RC_SPELL_COMMAND:
2575 case LyXRC::RC_TEMPDIRPATH:
2576 case LyXRC::RC_TEMPLATEPATH:
2577 case LyXRC::RC_TEX_ALLOWS_SPACES:
2578 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2579 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2580 support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2582 case LyXRC::RC_UIFILE:
2583 case LyXRC::RC_USER_EMAIL:
2584 case LyXRC::RC_USER_NAME:
2585 case LyXRC::RC_USETEMPDIR:
2586 case LyXRC::RC_USE_ALT_LANG:
2587 case LyXRC::RC_USE_CONVERTER_CACHE:
2588 case LyXRC::RC_USE_ESC_CHARS:
2589 case LyXRC::RC_USE_INP_ENC:
2590 case LyXRC::RC_USE_PERS_DICT:
2591 case LyXRC::RC_USE_SPELL_LIB:
2592 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2593 case LyXRC::RC_VIEWER:
2594 case LyXRC::RC_LAST: