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"
32 #include "Converter.h"
34 #include "CutAndPaste.h"
36 #include "DispatchResult.h"
38 #include "ErrorList.h"
40 #include "FuncRequest.h"
41 #include "FuncStatus.h"
43 #include "InsetIterator.h"
48 #include "LyXAction.h"
53 #include "Paragraph.h"
54 #include "ParagraphParameters.h"
55 #include "ParIterator.h"
59 #include "TextClassList.h"
60 #include "ToolbarBackend.h"
62 #include "insets/InsetBox.h"
63 #include "insets/InsetBranch.h"
64 #include "insets/InsetCommand.h"
65 #include "insets/InsetERT.h"
66 #include "insets/InsetExternal.h"
67 #include "insets/InsetFloat.h"
68 #include "insets/InsetListings.h"
69 #include "insets/InsetGraphics.h"
70 #include "insets/InsetInclude.h"
71 #include "insets/InsetNote.h"
72 #include "insets/InsetTabular.h"
73 #include "insets/InsetVSpace.h"
74 #include "insets/InsetWrap.h"
76 #include "frontends/Application.h"
77 #include "frontends/alert.h"
78 #include "frontends/Dialogs.h"
79 #include "frontends/FileDialog.h"
80 #include "frontends/FontLoader.h"
81 #include "frontends/Gui.h"
82 #include "frontends/KeySymbol.h"
83 #include "frontends/LyXView.h"
84 #include "frontends/Selection.h"
85 #include "frontends/WorkArea.h"
87 #include "support/environment.h"
88 #include "support/FileFilterList.h"
89 #include "support/filetools.h"
90 #include "support/fs_extras.h"
91 #include "support/lstrings.h"
92 #include "support/Path.h"
93 #include "support/Package.h"
94 #include "support/Systemcall.h"
95 #include "support/convert.h"
96 #include "support/os.h"
98 #include <boost/current_function.hpp>
99 #include <boost/filesystem/operations.hpp>
104 using std::make_pair;
107 using std::istringstream;
108 using std::ostringstream;
112 namespace fs = boost::filesystem;
116 using frontend::LyXView;
118 using support::absolutePath;
119 using support::addName;
120 using support::addPath;
121 using support::bformat;
122 using support::changeExtension;
123 using support::contains;
124 using support::FileFilterList;
125 using support::FileName;
126 using support::fileSearch;
127 using support::i18nLibFileSearch;
128 using support::makeDisplayPath;
129 using support::makeAbsPath;
130 using support::package;
131 using support::quoteName;
132 using support::rtrim;
133 using support::split;
134 using support::subst;
135 using support::Systemcall;
136 using support::token;
138 using support::prefixIs;
141 namespace Alert = frontend::Alert;
143 extern bool quitting;
148 bool import(LyXView * lv, FileName const & filename,
149 string const & format, ErrorList & errorList)
151 docstring const displaypath = makeDisplayPath(filename.absFilename());
152 lv->message(bformat(_("Importing %1$s..."), displaypath));
154 FileName const lyxfile(changeExtension(filename.absFilename(), ".lyx"));
156 string loader_format;
157 vector<string> loaders = theConverters().loaders();
158 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
159 for (vector<string>::const_iterator it = loaders.begin();
160 it != loaders.end(); ++it) {
161 if (theConverters().isReachable(format, *it)) {
162 string const tofile =
163 changeExtension(filename.absFilename(),
164 formats.extension(*it));
165 if (!theConverters().convert(0, filename, FileName(tofile),
166 filename, format, *it, errorList))
172 if (loader_format.empty()) {
173 frontend::Alert::error(_("Couldn't import file"),
174 bformat(_("No information for importing the format %1$s."),
175 formats.prettyName(format)));
179 loader_format = format;
183 if (loader_format == "lyx") {
184 Buffer * buf = lv->loadLyXFile(lyxfile);
187 lv->message(_("file not imported!"));
192 lv->showErrorList("Parse");
194 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
199 bool as_paragraphs = loader_format == "textparagraph";
200 string filename2 = (loader_format == format) ? filename.absFilename()
201 : changeExtension(filename.absFilename(),
202 formats.extension(loader_format));
203 lv->view()->insertPlaintextFile(filename2, as_paragraphs);
204 lv->dispatch(FuncRequest(LFUN_MARK_OFF));
208 lv->message(_("imported."));
214 // This function runs "configure" and then rereads lyx.defaults to
215 // reconfigure the automatic settings.
216 void reconfigure(LyXView & lv, string const & option)
218 // emit message signal.
219 lv.message(_("Running configure..."));
221 // Run configure in user lyx directory
222 support::Path p(package().user_support());
223 string configure_command = package().configure_command();
224 configure_command += option;
226 int ret = one.startscript(Systemcall::Wait, configure_command);
228 // emit message signal.
229 lv.message(_("Reloading configuration..."));
230 lyxrc.read(support::libFileSearch(string(), "lyxrc.defaults"));
231 // Re-read packages.lst
232 LaTeXFeatures::getAvailable();
235 Alert::information(_("System reconfiguration failed"),
236 _("The system reconfiguration has failed.\n"
237 "Default textclass is used but LyX may "
238 "not be able to work properly.\n"
239 "Please reconfigure again if needed."));
242 Alert::information(_("System reconfigured"),
243 _("The system has been reconfigured.\n"
244 "You need to restart LyX to make use of any\n"
245 "updated document class specifications."));
249 bool getLocalStatus(Cursor cursor, FuncRequest const & cmd, FuncStatus & status)
251 // Try to fix cursor in case it is broken.
252 cursor.fixIfBroken();
254 // This is, of course, a mess. Better create a new doc iterator and use
255 // this in Inset::getStatus. This might require an additional
256 // BufferView * arg, though (which should be avoided)
257 //Cursor safe = *this;
259 for ( ; cursor.depth(); cursor.pop()) {
260 //lyxerr << "\nCursor::getStatus: cmd: " << cmd << endl << *this << endl;
261 BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
262 BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
263 BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
265 // The inset's getStatus() will return 'true' if it made
266 // a definitive decision on whether it want to handle the
267 // request or not. The result of this decision is put into
268 // the 'status' parameter.
269 if (cursor.inset().getStatus(cursor, cmd, status)) {
278 /** Return the change status at cursor position, taking in account the
279 * status at each level of the document iterator (a table in a deleted
280 * footnote is deleted).
281 * When \param outer is true, the top slice is not looked at.
283 Change::Type lookupChangeType(DocIterator const & dit, bool outer = false)
285 size_t const depth = dit.depth() - (outer ? 1 : 0);
287 for (size_t i = 0 ; i < depth ; ++i) {
288 CursorSlice const & slice = dit[i];
289 if (!slice.inset().inMathed()
290 && slice.pos() < slice.paragraph().size()) {
291 Change::Type const ch = slice.paragraph().lookupChange(slice.pos()).type;
292 if (ch != Change::UNCHANGED)
296 return Change::UNCHANGED;
303 : lyx_view_(0), encoded_last_key(0), meta_fake_bit(NoModifier)
308 void LyXFunc::initKeySequences(KeyMap * kb)
310 keyseq = KeySequence(kb, kb);
311 cancel_meta_seq = KeySequence(kb, kb);
315 void LyXFunc::setLyXView(LyXView * lv)
317 if (!quitting && lyx_view_ && lyx_view_->view() && lyx_view_ != lv)
318 // save current selection to the selection buffer to allow
319 // middle-button paste in another window
320 cap::saveSelection(lyx_view_->view()->cursor());
325 void LyXFunc::handleKeyFunc(kb_action action)
327 char_type c = encoded_last_key;
332 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
333 lyx_view_->view()->getIntl().getTransManager().deadkey(
334 c, get_accent(action).accent, view()->cursor().innerText(), view()->cursor());
335 // Need to clear, in case the minibuffer calls these
338 // copied verbatim from do_accent_char
339 view()->cursor().resetAnchor();
340 view()->processUpdateFlags(Update::FitCursor);
344 void LyXFunc::gotoBookmark(unsigned int idx, bool openFile, bool switchToBuffer)
346 BOOST_ASSERT(lyx_view_);
347 if (!LyX::ref().session().bookmarks().isValid(idx))
349 BookmarksSection::Bookmark const & bm = LyX::ref().session().bookmarks().bookmark(idx);
350 BOOST_ASSERT(!bm.filename.empty());
351 string const file = bm.filename.absFilename();
352 // if the file is not opened, open it.
353 if (!theBufferList().exists(file)) {
355 dispatch(FuncRequest(LFUN_FILE_OPEN, file));
359 // open may fail, so we need to test it again
360 if (!theBufferList().exists(file))
363 // if the current buffer is not that one, switch to it.
364 if (lyx_view_->buffer()->absFileName() != file) {
367 dispatch(FuncRequest(LFUN_BUFFER_SWITCH, file));
369 // moveToPosition try paragraph id first and then paragraph (pit, pos).
370 if (!view()->moveToPosition(bm.bottom_pit, bm.bottom_pos,
371 bm.top_id, bm.top_pos))
374 // Cursor jump succeeded!
375 Cursor const & cur = view()->cursor();
376 pit_type new_pit = cur.pit();
377 pos_type new_pos = cur.pos();
378 int new_id = cur.paragraph().id();
380 // if bottom_pit, bottom_pos or top_id has been changed, update bookmark
381 // see http://bugzilla.lyx.org/show_bug.cgi?id=3092
382 if (bm.bottom_pit != new_pit || bm.bottom_pos != new_pos
383 || bm.top_id != new_id) {
384 const_cast<BookmarksSection::Bookmark &>(bm).updatePos(
385 new_pit, new_pos, new_id);
391 void restartCursor(LyXView * lv)
393 /* When we move around, or type, it's nice to be able to see
394 * the cursor immediately after the keypress.
396 if (lv && lv->currentWorkArea())
397 lv->currentWorkArea()->startBlinkingCursor();
401 void LyXFunc::processKeySym(KeySymbol const & keysym, KeyModifier state)
403 LYXERR(Debug::KEY) << "KeySym is " << keysym.getSymbolName() << endl;
405 // Do nothing if we have nothing (JMarc)
406 if (!keysym.isOK()) {
407 LYXERR(Debug::KEY) << "Empty kbd action (probably composing)"
409 restartCursor(lyx_view_);
413 if (keysym.isModifier()) {
414 LYXERR(Debug::KEY) << "isModifier true" << endl;
415 restartCursor(lyx_view_);
419 //Encoding const * encoding = view()->cursor().getEncoding();
420 //encoded_last_key = keysym.getISOEncoded(encoding ? encoding->name() : "");
421 // FIXME: encoded_last_key shadows the member variable of the same
422 // name. Is that intended?
423 char_type encoded_last_key = keysym.getUCSEncoded();
425 // Do a one-deep top-level lookup for
426 // cancel and meta-fake keys. RVDK_PATCH_5
427 cancel_meta_seq.reset();
429 FuncRequest func = cancel_meta_seq.addkey(keysym, state);
430 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
431 << " action first set to [" << func.action << ']'
434 // When not cancel or meta-fake, do the normal lookup.
435 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
436 // Mostly, meta_fake_bit = NoModifier. RVDK_PATCH_5.
437 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_PREFIX)) {
438 // remove Caps Lock and Mod2 as a modifiers
439 func = keyseq.addkey(keysym, (state | meta_fake_bit));
440 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
441 << "action now set to ["
442 << func.action << ']' << endl;
445 // Dont remove this unless you know what you are doing.
446 meta_fake_bit = NoModifier;
448 // Can this happen now ?
449 if (func.action == LFUN_NOACTION)
450 func = FuncRequest(LFUN_COMMAND_PREFIX);
452 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
454 << func.action << "]["
455 << to_utf8(keyseq.print(KeySequence::Portable)) << ']'
458 // already here we know if it any point in going further
459 // why not return already here if action == -1 and
460 // num_bytes == 0? (Lgb)
462 if (keyseq.length() > 1)
463 lyx_view_->message(keyseq.print(KeySequence::ForGui));
466 // Maybe user can only reach the key via holding down shift.
467 // Let's see. But only if shift is the only modifier
468 if (func.action == LFUN_UNKNOWN_ACTION && state == ShiftModifier) {
469 LYXERR(Debug::KEY) << "Trying without shift" << endl;
470 func = keyseq.addkey(keysym, NoModifier);
471 LYXERR(Debug::KEY) << "Action now " << func.action << endl;
474 if (func.action == LFUN_UNKNOWN_ACTION) {
475 // Hmm, we didn't match any of the keysequences. See
476 // if it's normal insertable text not already covered
478 if (keysym.isText() && keyseq.length() == 1) {
479 LYXERR(Debug::KEY) << "isText() is true, inserting." << endl;
480 func = FuncRequest(LFUN_SELF_INSERT,
481 FuncRequest::KEYBOARD);
483 LYXERR(Debug::KEY) << "Unknown, !isText() - giving up" << endl;
484 lyx_view_->message(_("Unknown function."));
485 restartCursor(lyx_view_);
490 if (func.action == LFUN_SELF_INSERT) {
491 if (encoded_last_key != 0) {
492 docstring const arg(1, encoded_last_key);
493 dispatch(FuncRequest(LFUN_SELF_INSERT, arg,
494 FuncRequest::KEYBOARD));
496 << "SelfInsert arg[`" << to_utf8(arg) << "']" << endl;
502 restartCursor(lyx_view_);
506 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
508 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
511 /* In LyX/Mac, when a dialog is open, the menus of the
512 application can still be accessed without giving focus to
513 the main window. In this case, we want to disable the menu
514 entries that are buffer-related.
516 Note that this code is not perfect, as bug 1941 attests:
517 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
519 Buffer * buf = lyx_view_? lyx_view_->buffer() : 0;
520 if (lyx_view_ && cmd.origin == FuncRequest::MENU && !lyx_view_->hasFocus())
523 if (cmd.action == LFUN_NOACTION) {
524 flag.message(from_utf8(N_("Nothing to do")));
529 switch (cmd.action) {
530 case LFUN_UNKNOWN_ACTION:
531 #ifndef HAVE_LIBAIKSAURUS
532 case LFUN_THESAURUS_ENTRY:
542 if (flag.unknown()) {
543 flag.message(from_utf8(N_("Unknown action")));
547 if (!flag.enabled()) {
548 if (flag.message().empty())
549 flag.message(from_utf8(N_("Command disabled")));
553 // Check whether we need a buffer
554 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
556 flag.message(from_utf8(N_("Command not allowed with"
557 "out any document open")));
562 // I would really like to avoid having this switch and rather try to
563 // encode this in the function itself.
564 // -- And I'd rather let an inset decide which LFUNs it is willing
565 // to handle (Andre')
567 switch (cmd.action) {
568 case LFUN_BUFFER_TOGGLE_READ_ONLY:
569 flag.setOnOff(buf->isReadonly());
572 case LFUN_BUFFER_SWITCH:
573 // toggle on the current buffer, but do not toggle off
574 // the other ones (is that a good idea?)
575 if (buf && to_utf8(cmd.argument()) == buf->absFileName())
579 case LFUN_BUFFER_EXPORT:
580 enable = cmd.argument() == "custom"
581 || buf->isExportable(to_utf8(cmd.argument()));
584 case LFUN_BUFFER_CHKTEX:
585 enable = buf->isLatex() && !lyxrc.chktex_command.empty();
588 case LFUN_BUILD_PROGRAM:
589 enable = buf->isExportable("program");
592 case LFUN_VC_REGISTER:
593 enable = !buf->lyxvc().inUse();
595 case LFUN_VC_CHECK_IN:
596 enable = buf->lyxvc().inUse() && !buf->isReadonly();
598 case LFUN_VC_CHECK_OUT:
599 enable = buf->lyxvc().inUse() && buf->isReadonly();
602 case LFUN_VC_UNDO_LAST:
603 enable = buf->lyxvc().inUse();
605 case LFUN_BUFFER_RELOAD:
606 enable = !buf->isUnnamed() && fs::exists(buf->absFileName())
607 && (!buf->isClean() || buf->isExternallyModified(Buffer::timestamp_method));
610 case LFUN_INSET_APPLY: {
615 string const name = cmd.getArg(0);
616 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
618 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
620 if (!inset->getStatus(view()->cursor(), fr, fs)) {
621 // Every inset is supposed to handle this
626 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
627 flag |= getStatus(fr);
629 enable = flag.enabled();
633 case LFUN_DIALOG_TOGGLE:
634 flag.setOnOff(lyx_view_->getDialogs().visible(cmd.getArg(0)));
635 // fall through to set "enable"
636 case LFUN_DIALOG_SHOW: {
637 string const name = cmd.getArg(0);
639 enable = name == "aboutlyx"
640 || name == "file" //FIXME: should be removed.
642 || name == "texinfo";
643 else if (name == "print")
644 enable = buf->isExportable("dvi")
645 && lyxrc.print_command != "none";
646 else if (name == "character") {
650 InsetCode ic = view()->cursor().inset().lyxCode();
651 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
654 else if (name == "latexlog")
655 enable = FileName(buf->logName()).isFileReadable();
656 else if (name == "spellchecker")
657 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
658 enable = !buf->isReadonly();
662 else if (name == "vclog")
663 enable = buf->lyxvc().inUse();
667 case LFUN_DIALOG_UPDATE: {
668 string const name = cmd.getArg(0);
670 enable = name == "prefs";
674 case LFUN_CITATION_INSERT: {
675 FuncRequest fr(LFUN_INSET_INSERT, "citation");
676 enable = getStatus(fr).enabled();
680 case LFUN_BUFFER_WRITE: {
681 enable = lyx_view_->buffer()->isUnnamed()
682 || !lyx_view_->buffer()->isClean();
687 case LFUN_BUFFER_WRITE_ALL: {
688 // We enable the command only if there are some modified buffers
689 Buffer * first = theBufferList().first();
690 bool modified = false;
694 // We cannot use a for loop as the buffer list is a cycle.
700 b = theBufferList().next(b);
701 } while (b != first);
709 case LFUN_BOOKMARK_GOTO: {
710 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
711 enable = LyX::ref().session().bookmarks().isValid(num);
715 case LFUN_BOOKMARK_CLEAR:
716 enable = LyX::ref().session().bookmarks().size() > 0;
719 case LFUN_TOOLBAR_TOGGLE: {
720 bool const current = lyx_view_->isToolbarVisible(cmd.getArg(0));
721 flag.setOnOff(current);
724 case LFUN_WINDOW_CLOSE: {
725 enable = (theApp()->gui().viewIds().size() > 1);
729 // this one is difficult to get right. As a half-baked
730 // solution, we consider only the first action of the sequence
731 case LFUN_COMMAND_SEQUENCE: {
732 // argument contains ';'-terminated commands
733 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
734 FuncRequest func(lyxaction.lookupFunc(firstcmd));
735 func.origin = cmd.origin;
736 flag = getStatus(func);
742 std::string name(to_utf8(cmd.argument()));
743 if (LyX::ref().topLevelCmdDef().lock(name, func)) {
744 func.origin = cmd.origin;
745 flag = getStatus(func);
746 LyX::ref().topLevelCmdDef().release(name);
748 // catch recursion or unknown command definiton
749 // all operations until the recursion or unknown command
750 // definiton occures are performed, so set the state to enabled
756 case LFUN_BUFFER_NEW:
757 case LFUN_BUFFER_NEW_TEMPLATE:
758 case LFUN_WORD_FIND_FORWARD:
759 case LFUN_WORD_FIND_BACKWARD:
760 case LFUN_COMMAND_PREFIX:
761 case LFUN_COMMAND_EXECUTE:
763 case LFUN_META_PREFIX:
764 case LFUN_BUFFER_CLOSE:
765 case LFUN_BUFFER_WRITE_AS:
766 case LFUN_BUFFER_UPDATE:
767 case LFUN_BUFFER_VIEW:
768 case LFUN_MASTER_BUFFER_UPDATE:
769 case LFUN_MASTER_BUFFER_VIEW:
770 case LFUN_BUFFER_IMPORT:
771 case LFUN_BUFFER_AUTO_SAVE:
772 case LFUN_RECONFIGURE:
776 case LFUN_DROP_LAYOUTS_CHOICE:
778 case LFUN_SERVER_GET_NAME:
779 case LFUN_SERVER_NOTIFY:
780 case LFUN_SERVER_GOTO_FILE_ROW:
781 case LFUN_DIALOG_HIDE:
782 case LFUN_DIALOG_DISCONNECT_INSET:
783 case LFUN_BUFFER_CHILD_OPEN:
784 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
785 case LFUN_KEYMAP_OFF:
786 case LFUN_KEYMAP_PRIMARY:
787 case LFUN_KEYMAP_SECONDARY:
788 case LFUN_KEYMAP_TOGGLE:
790 case LFUN_BUFFER_EXPORT_CUSTOM:
791 case LFUN_BUFFER_PRINT:
792 case LFUN_PREFERENCES_SAVE:
793 case LFUN_SCREEN_FONT_UPDATE:
796 case LFUN_EXTERNAL_EDIT:
797 case LFUN_GRAPHICS_EDIT:
798 case LFUN_ALL_INSETS_TOGGLE:
799 case LFUN_BUFFER_LANGUAGE:
800 case LFUN_TEXTCLASS_APPLY:
801 case LFUN_TEXTCLASS_LOAD:
802 case LFUN_BUFFER_SAVE_AS_DEFAULT:
803 case LFUN_BUFFER_PARAMS_APPLY:
804 case LFUN_LAYOUT_MODULES_CLEAR:
805 case LFUN_LAYOUT_MODULE_ADD:
806 case LFUN_LAYOUT_RELOAD:
807 case LFUN_LYXRC_APPLY:
808 case LFUN_BUFFER_NEXT:
809 case LFUN_BUFFER_PREVIOUS:
810 case LFUN_WINDOW_NEW:
812 // these are handled in our dispatch()
820 if (!getLocalStatus(view()->cursor(), cmd, flag))
821 flag = view()->getStatus(cmd);
827 // Can we use a readonly buffer?
828 if (buf && buf->isReadonly()
829 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
830 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
831 flag.message(from_utf8(N_("Document is read-only")));
835 // Are we in a DELETED change-tracking region?
837 && lookupChangeType(view()->cursor(), true) == Change::DELETED
838 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
839 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
840 flag.message(from_utf8(N_("This portion of the document is deleted.")));
844 // the default error message if we disable the command
845 if (!flag.enabled() && flag.message().empty())
846 flag.message(from_utf8(N_("Command disabled")));
852 bool LyXFunc::ensureBufferClean(BufferView * bv)
854 Buffer & buf = bv->buffer();
858 docstring const file = makeDisplayPath(buf.absFileName(), 30);
859 docstring text = bformat(_("The document %1$s has unsaved "
860 "changes.\n\nDo you want to save "
861 "the document?"), file);
862 int const ret = Alert::prompt(_("Save changed document?"),
863 text, 0, 1, _("&Save"),
867 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
869 return buf.isClean();
875 void showPrintError(string const & name)
877 docstring str = bformat(_("Could not print the document %1$s.\n"
878 "Check that your printer is set up correctly."),
879 makeDisplayPath(name, 50));
880 Alert::error(_("Print document failed"), str);
884 void loadTextClass(string const & name)
886 std::pair<bool, textclass_type> const tc_pair =
887 textclasslist.numberOfClass(name);
889 if (!tc_pair.first) {
890 lyxerr << "Document class \"" << name
891 << "\" does not exist."
896 textclass_type const tc = tc_pair.second;
898 if (!textclasslist[tc].load()) {
899 docstring s = bformat(_("The document class %1$s."
900 "could not be loaded."),
901 from_utf8(textclasslist[tc].name()));
902 Alert::error(_("Could not load class"), s);
907 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
912 void LyXFunc::dispatch(FuncRequest const & cmd)
914 string const argument = to_utf8(cmd.argument());
915 kb_action const action = cmd.action;
917 LYXERR(Debug::ACTION) << endl << "LyXFunc::dispatch: cmd: " << cmd << endl;
918 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
920 // we have not done anything wrong yet.
922 dispatch_buffer.erase();
924 // redraw the screen at the end (first of the two drawing steps).
925 //This is done unless explicitely requested otherwise
926 Update::flags updateFlags = Update::FitCursor;
928 FuncStatus const flag = getStatus(cmd);
929 if (!flag.enabled()) {
930 // We cannot use this function here
931 LYXERR(Debug::ACTION) << "LyXFunc::dispatch: "
932 << lyxaction.getActionName(action)
933 << " [" << action << "] is disabled at this location"
935 setErrorMessage(flag.message());
939 case LFUN_WORD_FIND_FORWARD:
940 case LFUN_WORD_FIND_BACKWARD: {
941 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
942 static docstring last_search;
943 docstring searched_string;
945 if (!cmd.argument().empty()) {
946 last_search = cmd.argument();
947 searched_string = cmd.argument();
949 searched_string = last_search;
952 if (searched_string.empty())
955 bool const fw = action == LFUN_WORD_FIND_FORWARD;
956 docstring const data =
957 find2string(searched_string, true, false, fw);
958 find(view(), FuncRequest(LFUN_WORD_FIND, data));
962 case LFUN_COMMAND_PREFIX:
963 BOOST_ASSERT(lyx_view_);
964 lyx_view_->message(keyseq.printOptions(true));
967 case LFUN_COMMAND_EXECUTE:
968 BOOST_ASSERT(lyx_view_);
969 lyx_view_->showMiniBuffer(true);
973 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
975 meta_fake_bit = NoModifier;
976 if (lyx_view_->buffer())
977 // cancel any selection
978 dispatch(FuncRequest(LFUN_MARK_OFF));
979 setMessage(from_ascii(N_("Cancel")));
982 case LFUN_META_PREFIX:
983 meta_fake_bit = AltModifier;
984 setMessage(keyseq.print(KeySequence::ForGui));
987 case LFUN_BUFFER_TOGGLE_READ_ONLY: {
988 BOOST_ASSERT(lyx_view_ && lyx_view_->view() && lyx_view_->buffer());
989 Buffer * buf = lyx_view_->buffer();
990 if (buf->lyxvc().inUse())
991 buf->lyxvc().toggleReadOnly();
993 buf->setReadonly(!lyx_view_->buffer()->isReadonly());
997 // --- Menus -----------------------------------------------
998 case LFUN_BUFFER_NEW:
999 menuNew(argument, false);
1000 updateFlags = Update::None;
1003 case LFUN_BUFFER_NEW_TEMPLATE:
1004 menuNew(argument, true);
1005 updateFlags = Update::None;
1008 case LFUN_BUFFER_CLOSE:
1010 updateFlags = Update::None;
1013 case LFUN_BUFFER_WRITE:
1014 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1015 if (!lyx_view_->buffer()->isUnnamed()) {
1016 docstring const str = bformat(_("Saving document %1$s..."),
1017 makeDisplayPath(lyx_view_->buffer()->absFileName()));
1018 lyx_view_->message(str);
1019 lyx_view_->buffer()->menuWrite();
1020 lyx_view_->message(str + _(" done."));
1022 lyx_view_->buffer()->writeAs();
1024 updateFlags = Update::None;
1027 case LFUN_BUFFER_WRITE_AS:
1028 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1029 lyx_view_->buffer()->writeAs(argument);
1030 updateFlags = Update::None;
1033 case LFUN_BUFFER_WRITE_ALL: {
1034 Buffer * first = theBufferList().first();
1037 lyx_view_->message(_("Saving all documents..."));
1039 // We cannot use a for loop as the buffer list cycles.
1041 if (!b->isClean()) {
1042 if (!b->isUnnamed()) {
1044 lyxerr[Debug::ACTION] << "Saved " << b->absFileName() << endl;
1048 b = theBufferList().next(b);
1049 } while (b != first);
1050 lyx_view_->message(_("All documents saved."));
1053 updateFlags = Update::None;
1057 case LFUN_BUFFER_RELOAD: {
1058 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1059 docstring const file = makeDisplayPath(lyx_view_->buffer()->absFileName(), 20);
1060 docstring text = bformat(_("Any changes will be lost. Are you sure "
1061 "you want to revert to the saved version of the document %1$s?"), file);
1062 int const ret = Alert::prompt(_("Revert to saved document?"),
1063 text, 1, 1, _("&Revert"), _("&Cancel"));
1070 case LFUN_BUFFER_UPDATE:
1071 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1072 lyx_view_->buffer()->doExport(argument, true);
1075 case LFUN_BUFFER_VIEW:
1076 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1077 lyx_view_->buffer()->preview(argument);
1080 case LFUN_MASTER_BUFFER_UPDATE:
1081 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->masterBuffer());
1082 lyx_view_->buffer()->masterBuffer()->doExport(argument, true);
1085 case LFUN_MASTER_BUFFER_VIEW:
1086 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->masterBuffer());
1087 lyx_view_->buffer()->masterBuffer()->preview(argument);
1090 case LFUN_BUILD_PROGRAM:
1091 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1092 lyx_view_->buffer()->doExport("program", true);
1095 case LFUN_BUFFER_CHKTEX:
1096 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1097 lyx_view_->buffer()->runChktex();
1100 case LFUN_BUFFER_EXPORT:
1101 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1102 if (argument == "custom")
1103 lyx_view_->getDialogs().show("sendto");
1105 lyx_view_->buffer()->doExport(argument, false);
1108 case LFUN_BUFFER_EXPORT_CUSTOM: {
1109 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1111 string command = split(argument, format_name, ' ');
1112 Format const * format = formats.getFormat(format_name);
1114 lyxerr << "Format \"" << format_name
1115 << "\" not recognized!"
1120 Buffer * buffer = lyx_view_->buffer();
1122 // The name of the file created by the conversion process
1125 // Output to filename
1126 if (format->name() == "lyx") {
1127 string const latexname = buffer->latexName(false);
1128 filename = changeExtension(latexname,
1129 format->extension());
1130 filename = addName(buffer->temppath(), filename);
1132 if (!buffer->writeFile(FileName(filename)))
1136 buffer->doExport(format_name, true, filename);
1139 // Substitute $$FName for filename
1140 if (!contains(command, "$$FName"))
1141 command = "( " + command + " ) < $$FName";
1142 command = subst(command, "$$FName", filename);
1144 // Execute the command in the background
1146 call.startscript(Systemcall::DontWait, command);
1150 case LFUN_BUFFER_PRINT: {
1151 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1152 // FIXME: cmd.getArg() might fail if one of the arguments
1153 // contains double quotes
1154 string target = cmd.getArg(0);
1155 string target_name = cmd.getArg(1);
1156 string command = cmd.getArg(2);
1159 || target_name.empty()
1160 || command.empty()) {
1161 lyxerr << "Unable to parse \""
1162 << argument << '"' << endl;
1165 if (target != "printer" && target != "file") {
1166 lyxerr << "Unrecognized target \""
1167 << target << '"' << endl;
1171 Buffer * buffer = lyx_view_->buffer();
1173 if (!buffer->doExport("dvi", true)) {
1174 showPrintError(buffer->absFileName());
1178 // Push directory path.
1179 string const path = buffer->temppath();
1180 // Prevent the compiler from optimizing away p
1182 support::Path p(pp);
1184 // there are three cases here:
1185 // 1. we print to a file
1186 // 2. we print directly to a printer
1187 // 3. we print using a spool command (print to file first)
1190 string const dviname =
1191 changeExtension(buffer->latexName(true), "dvi");
1193 if (target == "printer") {
1194 if (!lyxrc.print_spool_command.empty()) {
1195 // case 3: print using a spool
1196 string const psname =
1197 changeExtension(dviname,".ps");
1198 command += ' ' + lyxrc.print_to_file
1201 + quoteName(dviname);
1204 lyxrc.print_spool_command + ' ';
1205 if (target_name != "default") {
1206 command2 += lyxrc.print_spool_printerprefix
1210 command2 += quoteName(psname);
1212 // If successful, then spool command
1213 res = one.startscript(
1218 res = one.startscript(
1219 Systemcall::DontWait,
1222 // case 2: print directly to a printer
1223 if (target_name != "default")
1224 command += ' ' + lyxrc.print_to_printer + target_name + ' ';
1225 res = one.startscript(
1226 Systemcall::DontWait,
1227 command + quoteName(dviname));
1231 // case 1: print to a file
1232 FileName const filename(makeAbsPath(target_name,
1233 lyx_view_->buffer()->filePath()));
1234 FileName const dvifile(makeAbsPath(dviname, path));
1235 if (filename.exists()) {
1236 docstring text = bformat(
1237 _("The file %1$s already exists.\n\n"
1238 "Do you want to overwrite that file?"),
1239 makeDisplayPath(filename.absFilename()));
1240 if (Alert::prompt(_("Overwrite file?"),
1241 text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
1244 command += ' ' + lyxrc.print_to_file
1245 + quoteName(filename.toFilesystemEncoding())
1247 + quoteName(dvifile.toFilesystemEncoding());
1248 res = one.startscript(Systemcall::DontWait,
1253 showPrintError(buffer->absFileName());
1257 case LFUN_BUFFER_IMPORT:
1262 // quitting is triggered by the gui code
1263 // (leaving the event loop).
1264 lyx_view_->message(from_utf8(N_("Exiting.")));
1265 if (theBufferList().quitWriteAll())
1266 theApp()->gui().closeAllViews();
1269 case LFUN_BUFFER_AUTO_SAVE:
1270 lyx_view_->buffer()->autoSave();
1273 case LFUN_RECONFIGURE:
1274 BOOST_ASSERT(lyx_view_);
1275 // argument is any additional parameter to the configure.py command
1276 reconfigure(*lyx_view_, argument);
1279 case LFUN_HELP_OPEN: {
1280 BOOST_ASSERT(lyx_view_);
1281 string const arg = argument;
1283 setErrorMessage(from_ascii(N_("Missing argument")));
1286 FileName const fname = i18nLibFileSearch("doc", arg, "lyx");
1287 if (fname.empty()) {
1288 lyxerr << "LyX: unable to find documentation file `"
1289 << arg << "'. Bad installation?" << endl;
1292 lyx_view_->message(bformat(_("Opening help file %1$s..."),
1293 makeDisplayPath(fname.absFilename())));
1294 Buffer * buf = lyx_view_->loadLyXFile(fname, false);
1297 lyx_view_->setBuffer(buf);
1298 lyx_view_->showErrorList("Parse");
1300 updateFlags = Update::None;
1304 // --- version control -------------------------------
1305 case LFUN_VC_REGISTER:
1306 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1307 if (!ensureBufferClean(view()))
1309 if (!lyx_view_->buffer()->lyxvc().inUse()) {
1310 lyx_view_->buffer()->lyxvc().registrer();
1313 updateFlags = Update::Force;
1316 case LFUN_VC_CHECK_IN:
1317 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1318 if (!ensureBufferClean(view()))
1320 if (lyx_view_->buffer()->lyxvc().inUse()
1321 && !lyx_view_->buffer()->isReadonly()) {
1322 lyx_view_->buffer()->lyxvc().checkIn();
1327 case LFUN_VC_CHECK_OUT:
1328 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1329 if (!ensureBufferClean(view()))
1331 if (lyx_view_->buffer()->lyxvc().inUse()
1332 && lyx_view_->buffer()->isReadonly()) {
1333 lyx_view_->buffer()->lyxvc().checkOut();
1338 case LFUN_VC_REVERT:
1339 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1340 lyx_view_->buffer()->lyxvc().revert();
1344 case LFUN_VC_UNDO_LAST:
1345 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1346 lyx_view_->buffer()->lyxvc().undoLast();
1350 // --- buffers ----------------------------------------
1351 case LFUN_BUFFER_SWITCH:
1352 BOOST_ASSERT(lyx_view_);
1353 lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1354 updateFlags = Update::None;
1357 case LFUN_BUFFER_NEXT:
1358 BOOST_ASSERT(lyx_view_);
1359 lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer()));
1360 updateFlags = Update::None;
1363 case LFUN_BUFFER_PREVIOUS:
1364 BOOST_ASSERT(lyx_view_);
1365 lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer()));
1366 updateFlags = Update::None;
1369 case LFUN_FILE_NEW: {
1370 BOOST_ASSERT(lyx_view_);
1372 string tmpname = split(argument, name, ':'); // Split filename
1373 Buffer * const b = newFile(name, tmpname);
1375 lyx_view_->setBuffer(b);
1376 updateFlags = Update::None;
1380 case LFUN_FILE_OPEN:
1381 BOOST_ASSERT(lyx_view_);
1383 updateFlags = Update::None;
1386 case LFUN_DROP_LAYOUTS_CHOICE:
1387 BOOST_ASSERT(lyx_view_);
1388 lyx_view_->openLayoutList();
1391 case LFUN_MENU_OPEN:
1392 BOOST_ASSERT(lyx_view_);
1393 lyx_view_->openMenu(from_utf8(argument));
1396 // --- lyxserver commands ----------------------------
1397 case LFUN_SERVER_GET_NAME:
1398 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1399 setMessage(from_utf8(lyx_view_->buffer()->absFileName()));
1400 LYXERR(Debug::INFO) << "FNAME["
1401 << lyx_view_->buffer()->absFileName()
1405 case LFUN_SERVER_NOTIFY:
1406 dispatch_buffer = keyseq.print(KeySequence::Portable);
1407 theServer().notifyClient(to_utf8(dispatch_buffer));
1410 case LFUN_SERVER_GOTO_FILE_ROW: {
1411 BOOST_ASSERT(lyx_view_);
1414 istringstream is(argument);
1415 is >> file_name >> row;
1417 bool loaded = false;
1418 if (prefixIs(file_name, package().temp_dir().absFilename()))
1419 // Needed by inverse dvi search. If it is a file
1420 // in tmpdir, call the apropriated function
1421 buf = theBufferList().getBufferFromTmp(file_name);
1423 // Must replace extension of the file to be .lyx
1424 // and get full path
1425 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1426 // Either change buffer or load the file
1427 if (theBufferList().exists(s.absFilename()))
1428 buf = theBufferList().getBuffer(s.absFilename());
1430 buf = lyx_view_->loadLyXFile(s);
1436 updateFlags = Update::None;
1441 lyx_view_->setBuffer(buf);
1442 view()->setCursorFromRow(row);
1444 lyx_view_->showErrorList("Parse");
1445 updateFlags = Update::FitCursor;
1449 case LFUN_DIALOG_SHOW: {
1450 BOOST_ASSERT(lyx_view_);
1451 string const name = cmd.getArg(0);
1452 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1454 if (name == "character") {
1455 data = freefont2string();
1457 lyx_view_->getDialogs().show("character", data);
1458 } else if (name == "latexlog") {
1459 Buffer::LogType type;
1460 string const logfile = lyx_view_->buffer()->logName(&type);
1462 case Buffer::latexlog:
1465 case Buffer::buildlog:
1469 data += Lexer::quoteString(logfile);
1470 lyx_view_->getDialogs().show("log", data);
1471 } else if (name == "vclog") {
1472 string const data = "vc " +
1473 Lexer::quoteString(lyx_view_->buffer()->lyxvc().getLogFile());
1474 lyx_view_->getDialogs().show("log", data);
1476 lyx_view_->getDialogs().show(name, data);
1480 case LFUN_DIALOG_SHOW_NEW_INSET: {
1481 BOOST_ASSERT(lyx_view_);
1482 string const name = cmd.getArg(0);
1483 InsetCode code = insetCode(name);
1484 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1485 bool insetCodeOK = true;
1494 case HYPERLINK_CODE: {
1495 InsetCommandParams p(code);
1496 data = InsetCommandMailer::params2string(name, p);
1499 case INCLUDE_CODE: {
1500 // data is the include type: one of "include",
1501 // "input", "verbatiminput" or "verbatiminput*"
1503 // default type is requested
1505 InsetCommandParams p(INCLUDE_CODE, data);
1506 data = InsetCommandMailer::params2string("include", p);
1510 // \c data == "Boxed" || "Frameless" etc
1511 InsetBoxParams p(data);
1512 data = InsetBoxMailer::params2string(p);
1516 InsetBranchParams p;
1517 data = InsetBranchMailer::params2string(p);
1521 InsetCommandParams p(CITE_CODE);
1522 data = InsetCommandMailer::params2string(name, p);
1526 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1529 case EXTERNAL_CODE: {
1530 InsetExternalParams p;
1531 Buffer const & buffer = *lyx_view_->buffer();
1532 data = InsetExternalMailer::params2string(p, buffer);
1537 data = InsetFloatMailer::params2string(p);
1540 case LISTINGS_CODE: {
1541 InsetListingsParams p;
1542 data = InsetListingsMailer::params2string(p);
1545 case GRAPHICS_CODE: {
1546 InsetGraphicsParams p;
1547 Buffer const & buffer = *lyx_view_->buffer();
1548 data = InsetGraphicsMailer::params2string(p, buffer);
1553 data = InsetNoteMailer::params2string(p);
1558 data = InsetVSpaceMailer::params2string(space);
1563 data = InsetWrapMailer::params2string(p);
1567 lyxerr << "Inset type '" << name <<
1568 "' not recognized in LFUN_DIALOG_SHOW_NEW_INSET" << std:: endl;
1569 insetCodeOK = false;
1571 } // end switch(code)
1573 lyx_view_->getDialogs().show(name, data, 0);
1577 case LFUN_DIALOG_UPDATE: {
1578 BOOST_ASSERT(lyx_view_);
1579 string const & name = argument;
1580 // Can only update a dialog connected to an existing inset
1581 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1583 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1584 inset->dispatch(view()->cursor(), fr);
1585 } else if (name == "paragraph") {
1586 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1587 } else if (name == "prefs") {
1588 lyx_view_->getDialogs().update(name, string());
1593 case LFUN_DIALOG_HIDE:
1594 LyX::cref().hideDialogs(argument, 0);
1597 case LFUN_DIALOG_TOGGLE: {
1598 BOOST_ASSERT(lyx_view_);
1599 if (lyx_view_->getDialogs().visible(cmd.getArg(0)))
1600 dispatch(FuncRequest(LFUN_DIALOG_HIDE, argument));
1602 dispatch(FuncRequest(LFUN_DIALOG_SHOW, argument));
1606 case LFUN_DIALOG_DISCONNECT_INSET:
1607 BOOST_ASSERT(lyx_view_);
1608 lyx_view_->getDialogs().disconnect(argument);
1612 case LFUN_CITATION_INSERT: {
1613 BOOST_ASSERT(lyx_view_);
1614 if (!argument.empty()) {
1615 // we can have one optional argument, delimited by '|'
1616 // citation-insert <key>|<text_before>
1617 // this should be enhanced to also support text_after
1618 // and citation style
1619 string arg = argument;
1621 if (contains(argument, "|")) {
1622 arg = token(argument, '|', 0);
1623 opt1 = token(argument, '|', 1);
1625 InsetCommandParams icp(CITE_CODE);
1626 icp["key"] = from_utf8(arg);
1628 icp["before"] = from_utf8(opt1);
1629 string icstr = InsetCommandMailer::params2string("citation", icp);
1630 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1633 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1637 case LFUN_BUFFER_CHILD_OPEN: {
1638 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1639 Buffer * parent = lyx_view_->buffer();
1640 FileName filename = makeAbsPath(argument, parent->filePath());
1641 view()->saveBookmark(false);
1643 bool parsed = false;
1644 if (theBufferList().exists(filename.absFilename())) {
1645 child = theBufferList().getBuffer(filename.absFilename());
1647 setMessage(bformat(_("Opening child document %1$s..."),
1648 makeDisplayPath(filename.absFilename())));
1649 child = lyx_view_->loadLyXFile(filename, true);
1653 // Set the parent name of the child document.
1654 // This makes insertion of citations and references in the child work,
1655 // when the target is in the parent or another child document.
1656 child->setParentName(parent->absFileName());
1657 updateLabels(*child->masterBuffer());
1658 lyx_view_->setBuffer(child);
1660 lyx_view_->showErrorList("Parse");
1663 // If a screen update is required (in case where auto_open is false),
1664 // setBuffer() would have taken care of it already. Otherwise we shall
1665 // reset the update flag because it can cause a circular problem.
1667 updateFlags = Update::None;
1671 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1672 BOOST_ASSERT(lyx_view_);
1673 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1676 case LFUN_KEYMAP_OFF:
1677 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1678 lyx_view_->view()->getIntl().keyMapOn(false);
1681 case LFUN_KEYMAP_PRIMARY:
1682 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1683 lyx_view_->view()->getIntl().keyMapPrim();
1686 case LFUN_KEYMAP_SECONDARY:
1687 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1688 lyx_view_->view()->getIntl().keyMapSec();
1691 case LFUN_KEYMAP_TOGGLE:
1692 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1693 lyx_view_->view()->getIntl().toggleKeyMap();
1699 string rest = split(argument, countstr, ' ');
1700 istringstream is(countstr);
1703 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1704 for (int i = 0; i < count; ++i)
1705 dispatch(lyxaction.lookupFunc(rest));
1709 case LFUN_COMMAND_SEQUENCE: {
1710 // argument contains ';'-terminated commands
1711 string arg = argument;
1712 while (!arg.empty()) {
1714 arg = split(arg, first, ';');
1715 FuncRequest func(lyxaction.lookupFunc(first));
1716 func.origin = cmd.origin;
1724 if (LyX::ref().topLevelCmdDef().lock(argument, func)) {
1725 func.origin = cmd.origin;
1727 LyX::ref().topLevelCmdDef().release(argument);
1729 if (func.action == LFUN_UNKNOWN_ACTION) {
1730 // unknown command definition
1731 lyxerr << "Warning: unknown command definition `"
1735 // recursion detected
1736 lyxerr << "Warning: Recursion in the command definition `"
1737 << argument << "' detected"
1744 case LFUN_PREFERENCES_SAVE: {
1745 lyxrc.write(makeAbsPath("preferences",
1746 package().user_support().absFilename()),
1751 case LFUN_SCREEN_FONT_UPDATE:
1752 BOOST_ASSERT(lyx_view_);
1753 // handle the screen font changes.
1754 theFontLoader().update();
1755 /// FIXME: only the current view will be updated. the Gui
1756 /// class is able to furnish the list of views.
1757 updateFlags = Update::Force;
1760 case LFUN_SET_COLOR: {
1762 string const x11_name = split(argument, lyx_name, ' ');
1763 if (lyx_name.empty() || x11_name.empty()) {
1764 setErrorMessage(from_ascii(N_(
1765 "Syntax: set-color <lyx_name>"
1770 bool const graphicsbg_changed =
1771 (lyx_name == lcolor.getLyXName(Color_graphicsbg) &&
1772 x11_name != lcolor.getX11Name(Color_graphicsbg));
1774 if (!lcolor.setColor(lyx_name, x11_name)) {
1776 bformat(_("Set-color \"%1$s\" failed "
1777 "- color is undefined or "
1778 "may not be redefined"),
1779 from_utf8(lyx_name)));
1783 theApp()->updateColor(lcolor.getFromLyXName(lyx_name));
1785 if (graphicsbg_changed) {
1786 // FIXME: The graphics cache no longer has a changeDisplay method.
1788 graphics::GCache::get().changeDisplay(true);
1795 BOOST_ASSERT(lyx_view_);
1796 lyx_view_->message(from_utf8(argument));
1799 case LFUN_EXTERNAL_EDIT: {
1800 BOOST_ASSERT(lyx_view_);
1801 FuncRequest fr(action, argument);
1802 InsetExternal().dispatch(view()->cursor(), fr);
1806 case LFUN_GRAPHICS_EDIT: {
1807 FuncRequest fr(action, argument);
1808 InsetGraphics().dispatch(view()->cursor(), fr);
1812 case LFUN_INSET_APPLY: {
1813 BOOST_ASSERT(lyx_view_);
1814 string const name = cmd.getArg(0);
1815 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1817 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1818 inset->dispatch(view()->cursor(), fr);
1820 FuncRequest fr(LFUN_INSET_INSERT, argument);
1823 // ideally, the update flag should be set by the insets,
1824 // but this is not possible currently
1825 updateFlags = Update::Force | Update::FitCursor;
1829 case LFUN_ALL_INSETS_TOGGLE: {
1830 BOOST_ASSERT(lyx_view_);
1832 string const name = split(argument, action, ' ');
1833 InsetCode const inset_code = insetCode(name);
1835 Cursor & cur = view()->cursor();
1836 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1838 Inset & inset = lyx_view_->buffer()->inset();
1839 InsetIterator it = inset_iterator_begin(inset);
1840 InsetIterator const end = inset_iterator_end(inset);
1841 for (; it != end; ++it) {
1842 if (!it->asInsetMath()
1843 && (inset_code == NO_CODE
1844 || inset_code == it->lyxCode())) {
1845 Cursor tmpcur = cur;
1846 tmpcur.pushLeft(*it);
1847 it->dispatch(tmpcur, fr);
1850 updateFlags = Update::Force | Update::FitCursor;
1854 case LFUN_BUFFER_LANGUAGE: {
1855 BOOST_ASSERT(lyx_view_);
1856 Buffer & buffer = *lyx_view_->buffer();
1857 Language const * oldL = buffer.params().language;
1858 Language const * newL = languages.getLanguage(argument);
1859 if (!newL || oldL == newL)
1862 if (oldL->rightToLeft() == newL->rightToLeft()
1863 && !buffer.isMultiLingual())
1864 buffer.changeLanguage(oldL, newL);
1868 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1869 string const fname =
1870 addName(addPath(package().user_support().absFilename(), "templates/"),
1872 Buffer defaults(fname);
1874 istringstream ss(argument);
1877 int const unknown_tokens = defaults.readHeader(lex);
1879 if (unknown_tokens != 0) {
1880 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1881 << unknown_tokens << " unknown token"
1882 << (unknown_tokens == 1 ? "" : "s")
1886 if (defaults.writeFile(FileName(defaults.absFileName())))
1887 setMessage(bformat(_("Document defaults saved in %1$s"),
1888 makeDisplayPath(fname)));
1890 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1894 case LFUN_BUFFER_PARAMS_APPLY: {
1895 BOOST_ASSERT(lyx_view_);
1896 biblio::CiteEngine const oldEngine =
1897 lyx_view_->buffer()->params().getEngine();
1899 Buffer * buffer = lyx_view_->buffer();
1901 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1903 Cursor & cur = view()->cursor();
1904 cur.recordUndoFullDocument();
1906 istringstream ss(argument);
1909 int const unknown_tokens = buffer->readHeader(lex);
1911 if (unknown_tokens != 0) {
1912 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1913 << unknown_tokens << " unknown token"
1914 << (unknown_tokens == 1 ? "" : "s")
1918 updateLayout(oldClass, buffer);
1920 biblio::CiteEngine const newEngine =
1921 lyx_view_->buffer()->params().getEngine();
1923 if (oldEngine != newEngine) {
1924 FuncRequest fr(LFUN_INSET_REFRESH);
1926 Inset & inset = lyx_view_->buffer()->inset();
1927 InsetIterator it = inset_iterator_begin(inset);
1928 InsetIterator const end = inset_iterator_end(inset);
1929 for (; it != end; ++it)
1930 if (it->lyxCode() == CITE_CODE)
1931 it->dispatch(cur, fr);
1934 updateFlags = Update::Force | Update::FitCursor;
1938 case LFUN_LAYOUT_MODULES_CLEAR: {
1939 BOOST_ASSERT(lyx_view_);
1940 Buffer * buffer = lyx_view_->buffer();
1941 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1942 view()->cursor().recordUndoFullDocument();
1943 buffer->params().clearLayoutModules();
1944 updateLayout(oldClass, buffer);
1945 updateFlags = Update::Force | Update::FitCursor;
1949 case LFUN_LAYOUT_MODULE_ADD: {
1950 BOOST_ASSERT(lyx_view_);
1951 Buffer * buffer = lyx_view_->buffer();
1952 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1953 view()->cursor().recordUndoFullDocument();
1954 buffer->params().addLayoutModule(argument);
1955 updateLayout(oldClass, buffer);
1956 updateFlags = Update::Force | Update::FitCursor;
1960 case LFUN_TEXTCLASS_APPLY: {
1961 BOOST_ASSERT(lyx_view_);
1962 Buffer * buffer = lyx_view_->buffer();
1964 loadTextClass(argument);
1966 std::pair<bool, textclass_type> const tc_pair =
1967 textclasslist.numberOfClass(argument);
1972 textclass_type const old_class = buffer->params().getBaseClass();
1973 textclass_type const new_class = tc_pair.second;
1975 if (old_class == new_class)
1979 //Save the old, possibly modular, layout for use in conversion.
1980 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1981 view()->cursor().recordUndoFullDocument();
1982 buffer->params().setBaseClass(new_class);
1983 updateLayout(oldClass, buffer);
1984 updateFlags = Update::Force | Update::FitCursor;
1988 case LFUN_LAYOUT_RELOAD: {
1989 BOOST_ASSERT(lyx_view_);
1990 Buffer * buffer = lyx_view_->buffer();
1991 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1992 textclass_type const tc = buffer->params().getBaseClass();
1993 textclasslist.reset(tc);
1994 buffer->params().setBaseClass(tc);
1995 updateLayout(oldClass, buffer);
1996 updateFlags = Update::Force | Update::FitCursor;
2000 case LFUN_TEXTCLASS_LOAD:
2001 loadTextClass(argument);
2004 case LFUN_LYXRC_APPLY: {
2005 LyXRC const lyxrc_orig = lyxrc;
2007 istringstream ss(argument);
2008 bool const success = lyxrc.read(ss) == 0;
2011 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
2012 << "Unable to read lyxrc data"
2017 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
2019 /// We force the redraw in any case because there might be
2020 /// some screen font changes.
2021 /// FIXME: only the current view will be updated. the Gui
2022 /// class is able to furnish the list of views.
2023 updateFlags = Update::Force;
2027 case LFUN_WINDOW_NEW:
2028 LyX::ref().newLyXView();
2031 case LFUN_WINDOW_CLOSE:
2032 BOOST_ASSERT(lyx_view_);
2033 BOOST_ASSERT(theApp());
2034 // update bookmark pit of the current buffer before window close
2035 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2036 gotoBookmark(i+1, false, false);
2037 // ask the user for saving changes or cancel quit
2038 if (!theBufferList().quitWriteAll())
2043 case LFUN_BOOKMARK_GOTO:
2044 // go to bookmark, open unopened file and switch to buffer if necessary
2045 gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
2048 case LFUN_BOOKMARK_CLEAR:
2049 LyX::ref().session().bookmarks().clear();
2052 case LFUN_TOOLBAR_TOGGLE: {
2053 BOOST_ASSERT(lyx_view_);
2054 string const name = cmd.getArg(0);
2055 bool const allowauto = cmd.getArg(1) == "allowauto";
2056 lyx_view_->toggleToolbarState(name, allowauto);
2057 ToolbarInfo * tbi = lyx_view_->getToolbarInfo(name);
2059 setMessage(bformat(_("Unknown toolbar \"%1$s\""),
2064 if (tbi->flags & ToolbarInfo::ON)
2066 else if (tbi->flags & ToolbarInfo::OFF)
2068 else if (tbi->flags & ToolbarInfo::AUTO)
2071 setMessage(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
2072 _(tbi->gui_name), state));
2077 BOOST_ASSERT(lyx_view_);
2078 view()->cursor().dispatch(cmd);
2079 updateFlags = view()->cursor().result().update();
2080 if (!view()->cursor().result().dispatched())
2081 updateFlags = view()->dispatch(cmd);
2086 if (lyx_view_ && lyx_view_->buffer()) {
2087 // BufferView::update() updates the ViewMetricsInfo and
2088 // also initializes the position cache for all insets in
2089 // (at least partially) visible top-level paragraphs.
2090 // We will redraw the screen only if needed.
2091 view()->processUpdateFlags(updateFlags);
2092 lyx_view_->updateStatusBar();
2094 // if we executed a mutating lfun, mark the buffer as dirty
2096 && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
2097 && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
2098 lyx_view_->buffer()->markDirty();
2100 //Do we have a selection?
2101 theSelection().haveSelection(view()->cursor().selection());
2103 if (view()->cursor().inTexted()) {
2104 lyx_view_->updateLayoutChoice();
2108 if (!quitting && lyx_view_) {
2109 lyx_view_->updateToolbars();
2110 // Some messages may already be translated, so we cannot use _()
2111 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
2116 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
2118 const bool verbose = (cmd.origin == FuncRequest::MENU
2119 || cmd.origin == FuncRequest::TOOLBAR
2120 || cmd.origin == FuncRequest::COMMANDBUFFER);
2122 if (cmd.action == LFUN_SELF_INSERT || !verbose) {
2123 LYXERR(Debug::ACTION) << "dispatch msg is " << to_utf8(msg) << endl;
2125 lyx_view_->message(msg);
2129 docstring dispatch_msg = msg;
2130 if (!dispatch_msg.empty())
2131 dispatch_msg += ' ';
2133 docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
2135 bool argsadded = false;
2137 if (!cmd.argument().empty()) {
2138 if (cmd.action != LFUN_UNKNOWN_ACTION) {
2139 comname += ' ' + cmd.argument();
2144 docstring const shortcuts = theTopLevelKeymap().printBindings(cmd);
2146 if (!shortcuts.empty())
2147 comname += ": " + shortcuts;
2148 else if (!argsadded && !cmd.argument().empty())
2149 comname += ' ' + cmd.argument();
2151 if (!comname.empty()) {
2152 comname = rtrim(comname);
2153 dispatch_msg += '(' + rtrim(comname) + ')';
2156 LYXERR(Debug::ACTION) << "verbose dispatch msg "
2157 << to_utf8(dispatch_msg) << endl;
2158 if (!dispatch_msg.empty())
2159 lyx_view_->message(dispatch_msg);
2163 void LyXFunc::menuNew(string const & name, bool fromTemplate)
2165 // FIXME: initpath is not used. What to do?
2166 string initpath = lyxrc.document_path;
2167 string filename(name);
2169 if (lyx_view_->buffer()) {
2170 string const trypath = lyx_view_->buffer()->filePath();
2171 // If directory is writeable, use this as default.
2172 if (FileName(trypath).isDirWritable())
2176 static int newfile_number;
2178 if (filename.empty()) {
2179 filename = addName(lyxrc.document_path,
2180 "newfile" + convert<string>(++newfile_number) + ".lyx");
2181 while (theBufferList().exists(filename) ||
2182 FileName(filename).isReadable()) {
2184 filename = addName(lyxrc.document_path,
2185 "newfile" + convert<string>(newfile_number) +
2190 // The template stuff
2193 FileDialog dlg(_("Select template file"));
2194 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
2195 dlg.setButton1(_("Templates|#T#t"), from_utf8(lyxrc.template_path));
2197 FileDialog::Result result =
2198 dlg.open(from_utf8(lyxrc.template_path),
2199 FileFilterList(_("LyX Documents (*.lyx)")),
2202 if (result.first == FileDialog::Later)
2204 if (result.second.empty())
2206 templname = to_utf8(result.second);
2209 Buffer * const b = newFile(filename, templname, !name.empty());
2211 lyx_view_->setBuffer(b);
2215 void LyXFunc::open(string const & fname)
2217 string initpath = lyxrc.document_path;
2219 if (lyx_view_->buffer()) {
2220 string const trypath = lyx_view_->buffer()->filePath();
2221 // If directory is writeable, use this as default.
2222 if (FileName(trypath).isDirWritable())
2228 if (fname.empty()) {
2229 FileDialog dlg(_("Select document to open"), LFUN_FILE_OPEN);
2230 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
2231 dlg.setButton2(_("Examples|#E#e"),
2232 from_utf8(addPath(package().system_support().absFilename(), "examples")));
2234 FileDialog::Result result =
2235 dlg.open(from_utf8(initpath),
2236 FileFilterList(_("LyX Documents (*.lyx)")),
2239 if (result.first == FileDialog::Later)
2242 filename = to_utf8(result.second);
2244 // check selected filename
2245 if (filename.empty()) {
2246 lyx_view_->message(_("Canceled."));
2252 // get absolute path of file and add ".lyx" to the filename if
2254 FileName const fullname = fileSearch(string(), filename, "lyx");
2255 if (!fullname.empty())
2256 filename = fullname.absFilename();
2258 // if the file doesn't exist, let the user create one
2259 if (!fullname.exists()) {
2260 // the user specifically chose this name. Believe him.
2261 Buffer * const b = newFile(filename, string(), true);
2263 lyx_view_->setBuffer(b);
2267 docstring const disp_fn = makeDisplayPath(filename);
2268 lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
2271 Buffer * buf = lyx_view_->loadLyXFile(fullname);
2274 lyx_view_->setBuffer(buf);
2275 lyx_view_->showErrorList("Parse");
2276 str2 = bformat(_("Document %1$s opened."), disp_fn);
2278 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2280 lyx_view_->message(str2);
2284 void LyXFunc::doImport(string const & argument)
2287 string filename = split(argument, format, ' ');
2289 LYXERR(Debug::INFO) << "LyXFunc::doImport: " << format
2290 << " file: " << filename << endl;
2292 // need user interaction
2293 if (filename.empty()) {
2294 string initpath = lyxrc.document_path;
2296 if (lyx_view_->buffer()) {
2297 string const trypath = lyx_view_->buffer()->filePath();
2298 // If directory is writeable, use this as default.
2299 if (FileName(trypath).isDirWritable())
2303 docstring const text = bformat(_("Select %1$s file to import"),
2304 formats.prettyName(format));
2306 FileDialog dlg(text, LFUN_BUFFER_IMPORT);
2307 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
2308 dlg.setButton2(_("Examples|#E#e"),
2309 from_utf8(addPath(package().system_support().absFilename(), "examples")));
2311 docstring filter = formats.prettyName(format);
2314 filter += from_utf8(formats.extension(format));
2317 FileDialog::Result result =
2318 dlg.open(from_utf8(initpath),
2319 FileFilterList(filter),
2322 if (result.first == FileDialog::Later)
2325 filename = to_utf8(result.second);
2327 // check selected filename
2328 if (filename.empty())
2329 lyx_view_->message(_("Canceled."));
2332 if (filename.empty())
2335 // get absolute path of file
2336 FileName const fullname(makeAbsPath(filename));
2338 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
2340 // Check if the document already is open
2341 if (use_gui && theBufferList().exists(lyxfile.absFilename())) {
2342 if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) {
2343 lyx_view_->message(_("Canceled."));
2348 // if the file exists already, and we didn't do
2349 // -i lyx thefile.lyx, warn
2350 if (lyxfile.exists() && fullname != lyxfile) {
2351 docstring const file = makeDisplayPath(lyxfile.absFilename(), 30);
2353 docstring text = bformat(_("The document %1$s already exists.\n\n"
2354 "Do you want to overwrite that document?"), file);
2355 int const ret = Alert::prompt(_("Overwrite document?"),
2356 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2359 lyx_view_->message(_("Canceled."));
2364 ErrorList errorList;
2365 import(lyx_view_, fullname, format, errorList);
2366 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2370 void LyXFunc::closeBuffer()
2372 // goto bookmark to update bookmark pit.
2373 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2374 gotoBookmark(i+1, false, false);
2376 theBufferList().close(lyx_view_->buffer(), true);
2380 void LyXFunc::reloadBuffer()
2382 FileName filename(lyx_view_->buffer()->absFileName());
2383 docstring const disp_fn = makeDisplayPath(filename.absFilename());
2386 Buffer * buf = lyx_view_->loadLyXFile(filename);
2389 lyx_view_->setBuffer(buf);
2390 lyx_view_->showErrorList("Parse");
2391 str = bformat(_("Document %1$s reloaded."), disp_fn);
2393 str = bformat(_("Could not reload document %1$s"), disp_fn);
2395 lyx_view_->message(str);
2398 // Each "lyx_view_" should have it's own message method. lyxview and
2399 // the minibuffer would use the minibuffer, but lyxserver would
2400 // send an ERROR signal to its client. Alejandro 970603
2401 // This function is bit problematic when it comes to NLS, to make the
2402 // lyx servers client be language indepenent we must not translate
2403 // strings sent to this func.
2404 void LyXFunc::setErrorMessage(docstring const & m) const
2406 dispatch_buffer = m;
2411 void LyXFunc::setMessage(docstring const & m) const
2413 dispatch_buffer = m;
2417 docstring const LyXFunc::viewStatusMessage()
2419 // When meta-fake key is pressed, show the key sequence so far + "M-".
2421 return keyseq.print(KeySequence::ForGui) + "M-";
2423 // Else, when a non-complete key sequence is pressed,
2424 // show the available options.
2425 if (keyseq.length() > 0 && !keyseq.deleted())
2426 return keyseq.printOptions(true);
2428 BOOST_ASSERT(lyx_view_);
2429 if (!lyx_view_->buffer())
2430 return _("Welcome to LyX!");
2432 return view()->cursor().currentState();
2436 BufferView * LyXFunc::view() const
2438 BOOST_ASSERT(lyx_view_);
2439 return lyx_view_->view();
2443 bool LyXFunc::wasMetaKey() const
2445 return (meta_fake_bit != NoModifier);
2449 void LyXFunc::updateLayout(TextClassPtr const & oldlayout,
2452 lyx_view_->message(_("Converting document to new document class..."));
2454 StableDocIterator backcur(view()->cursor());
2455 ErrorList & el = buffer->errorList("Class Switch");
2456 cap::switchBetweenClasses(
2457 oldlayout, buffer->params().getTextClassPtr(),
2458 static_cast<InsetText &>(buffer->inset()), el);
2460 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
2462 buffer->errors("Class Switch");
2463 updateLabels(*buffer);
2469 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2471 // Why the switch you might ask. It is a trick to ensure that all
2472 // the elements in the LyXRCTags enum is handled. As you can see
2473 // there are no breaks at all. So it is just a huge fall-through.
2474 // The nice thing is that we will get a warning from the compiler
2475 // if we forget an element.
2476 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2478 case LyXRC::RC_ACCEPT_COMPOUND:
2479 case LyXRC::RC_ALT_LANG:
2480 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
2481 case LyXRC::RC_PLAINTEXT_LINELEN:
2482 case LyXRC::RC_AUTOREGIONDELETE:
2483 case LyXRC::RC_AUTORESET_OPTIONS:
2484 case LyXRC::RC_AUTOSAVE:
2485 case LyXRC::RC_AUTO_NUMBER:
2486 case LyXRC::RC_BACKUPDIR_PATH:
2487 case LyXRC::RC_BIBTEX_COMMAND:
2488 case LyXRC::RC_BINDFILE:
2489 case LyXRC::RC_CHECKLASTFILES:
2490 case LyXRC::RC_USELASTFILEPOS:
2491 case LyXRC::RC_LOADSESSION:
2492 case LyXRC::RC_CHKTEX_COMMAND:
2493 case LyXRC::RC_CONVERTER:
2494 case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
2495 case LyXRC::RC_COPIER:
2496 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2497 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2498 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2499 case LyXRC::RC_DATE_INSERT_FORMAT:
2500 case LyXRC::RC_DEFAULT_LANGUAGE:
2501 case LyXRC::RC_DEFAULT_PAPERSIZE:
2502 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2503 case LyXRC::RC_DISPLAY_GRAPHICS:
2504 case LyXRC::RC_DOCUMENTPATH:
2505 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2506 FileName path(lyxrc_new.document_path);
2507 if (path.exists() && path.isDirectory())
2508 support::package().document_dir() = FileName(lyxrc.document_path);
2510 case LyXRC::RC_ESC_CHARS:
2511 case LyXRC::RC_FONT_ENCODING:
2512 case LyXRC::RC_FORMAT:
2513 case LyXRC::RC_INDEX_COMMAND:
2514 case LyXRC::RC_INPUT:
2515 case LyXRC::RC_KBMAP:
2516 case LyXRC::RC_KBMAP_PRIMARY:
2517 case LyXRC::RC_KBMAP_SECONDARY:
2518 case LyXRC::RC_LABEL_INIT_LENGTH:
2519 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2520 case LyXRC::RC_LANGUAGE_AUTO_END:
2521 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2522 case LyXRC::RC_LANGUAGE_COMMAND_END:
2523 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2524 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2525 case LyXRC::RC_LANGUAGE_PACKAGE:
2526 case LyXRC::RC_LANGUAGE_USE_BABEL:
2527 case LyXRC::RC_MAKE_BACKUP:
2528 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2529 case LyXRC::RC_NUMLASTFILES:
2530 case LyXRC::RC_PATH_PREFIX:
2531 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2532 support::prependEnvPath("PATH", lyxrc.path_prefix);
2534 case LyXRC::RC_PERS_DICT:
2535 case LyXRC::RC_PREVIEW:
2536 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2537 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2538 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2539 case LyXRC::RC_PRINTCOPIESFLAG:
2540 case LyXRC::RC_PRINTER:
2541 case LyXRC::RC_PRINTEVENPAGEFLAG:
2542 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2543 case LyXRC::RC_PRINTFILEEXTENSION:
2544 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2545 case LyXRC::RC_PRINTODDPAGEFLAG:
2546 case LyXRC::RC_PRINTPAGERANGEFLAG:
2547 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2548 case LyXRC::RC_PRINTPAPERFLAG:
2549 case LyXRC::RC_PRINTREVERSEFLAG:
2550 case LyXRC::RC_PRINTSPOOL_COMMAND:
2551 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2552 case LyXRC::RC_PRINTTOFILE:
2553 case LyXRC::RC_PRINTTOPRINTER:
2554 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2555 case LyXRC::RC_PRINT_COMMAND:
2556 case LyXRC::RC_RTL_SUPPORT:
2557 case LyXRC::RC_SCREEN_DPI:
2558 case LyXRC::RC_SCREEN_FONT_ROMAN:
2559 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2560 case LyXRC::RC_SCREEN_FONT_SANS:
2561 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2562 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2563 case LyXRC::RC_SCREEN_FONT_SIZES:
2564 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2565 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2566 case LyXRC::RC_SCREEN_GEOMETRY_HEIGHT:
2567 case LyXRC::RC_SCREEN_GEOMETRY_WIDTH:
2568 case LyXRC::RC_SCREEN_GEOMETRY_XYSAVED:
2569 case LyXRC::RC_SCREEN_ZOOM:
2570 case LyXRC::RC_SERVERPIPE:
2571 case LyXRC::RC_SET_COLOR:
2572 case LyXRC::RC_SHOW_BANNER:
2573 case LyXRC::RC_SPELL_COMMAND:
2574 case LyXRC::RC_TEMPDIRPATH:
2575 case LyXRC::RC_TEMPLATEPATH:
2576 case LyXRC::RC_TEX_ALLOWS_SPACES:
2577 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2578 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2579 support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2581 case LyXRC::RC_UIFILE:
2582 case LyXRC::RC_USER_EMAIL:
2583 case LyXRC::RC_USER_NAME:
2584 case LyXRC::RC_USETEMPDIR:
2585 case LyXRC::RC_USE_ALT_LANG:
2586 case LyXRC::RC_USE_CONVERTER_CACHE:
2587 case LyXRC::RC_USE_ESC_CHARS:
2588 case LyXRC::RC_USE_INP_ENC:
2589 case LyXRC::RC_USE_PERS_DICT:
2590 case LyXRC::RC_USE_SPELL_LIB:
2591 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2592 case LyXRC::RC_VIEWER:
2593 case LyXRC::RC_LAST: