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/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>
103 using std::make_pair;
106 using std::istringstream;
107 using std::ostringstream;
113 using frontend::LyXView;
115 using support::absolutePath;
116 using support::addName;
117 using support::addPath;
118 using support::bformat;
119 using support::changeExtension;
120 using support::contains;
121 using support::FileFilterList;
122 using support::FileName;
123 using support::fileSearch;
124 using support::i18nLibFileSearch;
125 using support::makeDisplayPath;
126 using support::makeAbsPath;
127 using support::package;
128 using support::quoteName;
129 using support::rtrim;
130 using support::split;
131 using support::subst;
132 using support::Systemcall;
133 using support::token;
135 using support::prefixIs;
138 namespace Alert = frontend::Alert;
140 extern bool quitting;
145 bool import(LyXView * lv, FileName const & filename,
146 string const & format, ErrorList & errorList)
148 docstring const displaypath = makeDisplayPath(filename.absFilename());
149 lv->message(bformat(_("Importing %1$s..."), displaypath));
151 FileName const lyxfile(changeExtension(filename.absFilename(), ".lyx"));
153 string loader_format;
154 vector<string> loaders = theConverters().loaders();
155 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
156 for (vector<string>::const_iterator it = loaders.begin();
157 it != loaders.end(); ++it) {
158 if (theConverters().isReachable(format, *it)) {
159 string const tofile =
160 changeExtension(filename.absFilename(),
161 formats.extension(*it));
162 if (!theConverters().convert(0, filename, FileName(tofile),
163 filename, format, *it, errorList))
169 if (loader_format.empty()) {
170 frontend::Alert::error(_("Couldn't import file"),
171 bformat(_("No information for importing the format %1$s."),
172 formats.prettyName(format)));
176 loader_format = format;
180 if (loader_format == "lyx") {
181 Buffer * buf = lv->loadLyXFile(lyxfile);
184 lv->message(_("file not imported!"));
189 lv->showErrorList("Parse");
191 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
196 bool as_paragraphs = loader_format == "textparagraph";
197 string filename2 = (loader_format == format) ? filename.absFilename()
198 : changeExtension(filename.absFilename(),
199 formats.extension(loader_format));
200 lv->view()->insertPlaintextFile(filename2, as_paragraphs);
201 lv->dispatch(FuncRequest(LFUN_MARK_OFF));
205 lv->message(_("imported."));
211 // This function runs "configure" and then rereads lyx.defaults to
212 // reconfigure the automatic settings.
213 void reconfigure(LyXView & lv, string const & option)
215 // emit message signal.
216 lv.message(_("Running configure..."));
218 // Run configure in user lyx directory
219 support::Path p(package().user_support());
220 string configure_command = package().configure_command();
221 configure_command += option;
223 int ret = one.startscript(Systemcall::Wait, configure_command);
225 // emit message signal.
226 lv.message(_("Reloading configuration..."));
227 lyxrc.read(support::libFileSearch(string(), "lyxrc.defaults"));
228 // Re-read packages.lst
229 LaTeXFeatures::getAvailable();
232 Alert::information(_("System reconfiguration failed"),
233 _("The system reconfiguration has failed.\n"
234 "Default textclass is used but LyX may "
235 "not be able to work properly.\n"
236 "Please reconfigure again if needed."));
239 Alert::information(_("System reconfigured"),
240 _("The system has been reconfigured.\n"
241 "You need to restart LyX to make use of any\n"
242 "updated document class specifications."));
246 bool getLocalStatus(Cursor cursor, FuncRequest const & cmd, FuncStatus & status)
248 // Try to fix cursor in case it is broken.
249 cursor.fixIfBroken();
251 // This is, of course, a mess. Better create a new doc iterator and use
252 // this in Inset::getStatus. This might require an additional
253 // BufferView * arg, though (which should be avoided)
254 //Cursor safe = *this;
256 for ( ; cursor.depth(); cursor.pop()) {
257 //lyxerr << "\nCursor::getStatus: cmd: " << cmd << endl << *this << endl;
258 BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
259 BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
260 BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
262 // The inset's getStatus() will return 'true' if it made
263 // a definitive decision on whether it want to handle the
264 // request or not. The result of this decision is put into
265 // the 'status' parameter.
266 if (cursor.inset().getStatus(cursor, cmd, status)) {
275 /** Return the change status at cursor position, taking in account the
276 * status at each level of the document iterator (a table in a deleted
277 * footnote is deleted).
278 * When \param outer is true, the top slice is not looked at.
280 Change::Type lookupChangeType(DocIterator const & dit, bool outer = false)
282 size_t const depth = dit.depth() - (outer ? 1 : 0);
284 for (size_t i = 0 ; i < depth ; ++i) {
285 CursorSlice const & slice = dit[i];
286 if (!slice.inset().inMathed()
287 && slice.pos() < slice.paragraph().size()) {
288 Change::Type const ch = slice.paragraph().lookupChange(slice.pos()).type;
289 if (ch != Change::UNCHANGED)
293 return Change::UNCHANGED;
300 : lyx_view_(0), encoded_last_key(0), meta_fake_bit(NoModifier)
305 void LyXFunc::initKeySequences(KeyMap * kb)
307 keyseq = KeySequence(kb, kb);
308 cancel_meta_seq = KeySequence(kb, kb);
312 void LyXFunc::setLyXView(LyXView * lv)
314 if (!quitting && lyx_view_ && lyx_view_->view() && lyx_view_ != lv)
315 // save current selection to the selection buffer to allow
316 // middle-button paste in another window
317 cap::saveSelection(lyx_view_->view()->cursor());
322 void LyXFunc::handleKeyFunc(kb_action action)
324 char_type c = encoded_last_key;
329 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
330 lyx_view_->view()->getIntl().getTransManager().deadkey(
331 c, get_accent(action).accent, view()->cursor().innerText(), view()->cursor());
332 // Need to clear, in case the minibuffer calls these
335 // copied verbatim from do_accent_char
336 view()->cursor().resetAnchor();
337 view()->processUpdateFlags(Update::FitCursor);
341 void LyXFunc::gotoBookmark(unsigned int idx, bool openFile, bool switchToBuffer)
343 BOOST_ASSERT(lyx_view_);
344 if (!LyX::ref().session().bookmarks().isValid(idx))
346 BookmarksSection::Bookmark const & bm = LyX::ref().session().bookmarks().bookmark(idx);
347 BOOST_ASSERT(!bm.filename.empty());
348 string const file = bm.filename.absFilename();
349 // if the file is not opened, open it.
350 if (!theBufferList().exists(file)) {
352 dispatch(FuncRequest(LFUN_FILE_OPEN, file));
356 // open may fail, so we need to test it again
357 if (!theBufferList().exists(file))
360 // if the current buffer is not that one, switch to it.
361 if (lyx_view_->buffer()->absFileName() != file) {
364 dispatch(FuncRequest(LFUN_BUFFER_SWITCH, file));
366 // moveToPosition try paragraph id first and then paragraph (pit, pos).
367 if (!view()->moveToPosition(bm.bottom_pit, bm.bottom_pos,
368 bm.top_id, bm.top_pos))
371 // Cursor jump succeeded!
372 Cursor const & cur = view()->cursor();
373 pit_type new_pit = cur.pit();
374 pos_type new_pos = cur.pos();
375 int new_id = cur.paragraph().id();
377 // if bottom_pit, bottom_pos or top_id has been changed, update bookmark
378 // see http://bugzilla.lyx.org/show_bug.cgi?id=3092
379 if (bm.bottom_pit != new_pit || bm.bottom_pos != new_pos
380 || bm.top_id != new_id) {
381 const_cast<BookmarksSection::Bookmark &>(bm).updatePos(
382 new_pit, new_pos, new_id);
388 void restartCursor(LyXView * lv)
390 /* When we move around, or type, it's nice to be able to see
391 * the cursor immediately after the keypress.
393 if (lv && lv->currentWorkArea())
394 lv->currentWorkArea()->startBlinkingCursor();
398 void LyXFunc::processKeySym(KeySymbol const & keysym, KeyModifier state)
400 LYXERR(Debug::KEY) << "KeySym is " << keysym.getSymbolName() << endl;
402 // Do nothing if we have nothing (JMarc)
403 if (!keysym.isOK()) {
404 LYXERR(Debug::KEY) << "Empty kbd action (probably composing)"
406 restartCursor(lyx_view_);
410 if (keysym.isModifier()) {
411 LYXERR(Debug::KEY) << "isModifier true" << endl;
412 restartCursor(lyx_view_);
416 //Encoding const * encoding = view()->cursor().getEncoding();
417 //encoded_last_key = keysym.getISOEncoded(encoding ? encoding->name() : "");
418 // FIXME: encoded_last_key shadows the member variable of the same
419 // name. Is that intended?
420 char_type encoded_last_key = keysym.getUCSEncoded();
422 // Do a one-deep top-level lookup for
423 // cancel and meta-fake keys. RVDK_PATCH_5
424 cancel_meta_seq.reset();
426 FuncRequest func = cancel_meta_seq.addkey(keysym, state);
427 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
428 << " action first set to [" << func.action << ']'
431 // When not cancel or meta-fake, do the normal lookup.
432 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
433 // Mostly, meta_fake_bit = NoModifier. RVDK_PATCH_5.
434 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_PREFIX)) {
435 // remove Caps Lock and Mod2 as a modifiers
436 func = keyseq.addkey(keysym, (state | meta_fake_bit));
437 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
438 << "action now set to ["
439 << func.action << ']' << endl;
442 // Dont remove this unless you know what you are doing.
443 meta_fake_bit = NoModifier;
445 // Can this happen now ?
446 if (func.action == LFUN_NOACTION)
447 func = FuncRequest(LFUN_COMMAND_PREFIX);
449 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
451 << func.action << "]["
452 << to_utf8(keyseq.print(KeySequence::Portable)) << ']'
455 // already here we know if it any point in going further
456 // why not return already here if action == -1 and
457 // num_bytes == 0? (Lgb)
459 if (keyseq.length() > 1)
460 lyx_view_->message(keyseq.print(KeySequence::ForGui));
463 // Maybe user can only reach the key via holding down shift.
464 // Let's see. But only if shift is the only modifier
465 if (func.action == LFUN_UNKNOWN_ACTION && state == ShiftModifier) {
466 LYXERR(Debug::KEY) << "Trying without shift" << endl;
467 func = keyseq.addkey(keysym, NoModifier);
468 LYXERR(Debug::KEY) << "Action now " << func.action << endl;
471 if (func.action == LFUN_UNKNOWN_ACTION) {
472 // Hmm, we didn't match any of the keysequences. See
473 // if it's normal insertable text not already covered
475 if (keysym.isText() && keyseq.length() == 1) {
476 LYXERR(Debug::KEY) << "isText() is true, inserting." << endl;
477 func = FuncRequest(LFUN_SELF_INSERT,
478 FuncRequest::KEYBOARD);
480 LYXERR(Debug::KEY) << "Unknown, !isText() - giving up" << endl;
481 lyx_view_->message(_("Unknown function."));
482 restartCursor(lyx_view_);
487 if (func.action == LFUN_SELF_INSERT) {
488 if (encoded_last_key != 0) {
489 docstring const arg(1, encoded_last_key);
490 dispatch(FuncRequest(LFUN_SELF_INSERT, arg,
491 FuncRequest::KEYBOARD));
493 << "SelfInsert arg[`" << to_utf8(arg) << "']" << endl;
499 restartCursor(lyx_view_);
503 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
505 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
508 /* In LyX/Mac, when a dialog is open, the menus of the
509 application can still be accessed without giving focus to
510 the main window. In this case, we want to disable the menu
511 entries that are buffer-related.
513 Note that this code is not perfect, as bug 1941 attests:
514 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
516 Buffer * buf = lyx_view_? lyx_view_->buffer() : 0;
517 if (lyx_view_ && cmd.origin == FuncRequest::MENU && !lyx_view_->hasFocus())
520 if (cmd.action == LFUN_NOACTION) {
521 flag.message(from_utf8(N_("Nothing to do")));
526 switch (cmd.action) {
527 case LFUN_UNKNOWN_ACTION:
528 #ifndef HAVE_LIBAIKSAURUS
529 case LFUN_THESAURUS_ENTRY:
539 if (flag.unknown()) {
540 flag.message(from_utf8(N_("Unknown action")));
544 if (!flag.enabled()) {
545 if (flag.message().empty())
546 flag.message(from_utf8(N_("Command disabled")));
550 // Check whether we need a buffer
551 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
553 flag.message(from_utf8(N_("Command not allowed with"
554 "out any document open")));
559 // I would really like to avoid having this switch and rather try to
560 // encode this in the function itself.
561 // -- And I'd rather let an inset decide which LFUNs it is willing
562 // to handle (Andre')
564 switch (cmd.action) {
565 case LFUN_BUFFER_TOGGLE_READ_ONLY:
566 flag.setOnOff(buf->isReadonly());
569 case LFUN_BUFFER_SWITCH:
570 // toggle on the current buffer, but do not toggle off
571 // the other ones (is that a good idea?)
572 if (buf && to_utf8(cmd.argument()) == buf->absFileName())
576 case LFUN_BUFFER_EXPORT:
577 enable = cmd.argument() == "custom"
578 || buf->isExportable(to_utf8(cmd.argument()));
581 case LFUN_BUFFER_CHKTEX:
582 enable = buf->isLatex() && !lyxrc.chktex_command.empty();
585 case LFUN_BUILD_PROGRAM:
586 enable = buf->isExportable("program");
589 case LFUN_VC_REGISTER:
590 enable = !buf->lyxvc().inUse();
592 case LFUN_VC_CHECK_IN:
593 enable = buf->lyxvc().inUse() && !buf->isReadonly();
595 case LFUN_VC_CHECK_OUT:
596 enable = buf->lyxvc().inUse() && buf->isReadonly();
599 case LFUN_VC_UNDO_LAST:
600 enable = buf->lyxvc().inUse();
602 case LFUN_BUFFER_RELOAD:
603 enable = !buf->isUnnamed() && buf->fileName().exists()
604 && (!buf->isClean() || buf->isExternallyModified(Buffer::timestamp_method));
607 case LFUN_INSET_APPLY: {
612 string const name = cmd.getArg(0);
613 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
615 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
617 if (!inset->getStatus(view()->cursor(), fr, fs)) {
618 // Every inset is supposed to handle this
623 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
624 flag |= getStatus(fr);
626 enable = flag.enabled();
630 case LFUN_DIALOG_TOGGLE:
631 flag.setOnOff(lyx_view_->getDialogs().visible(cmd.getArg(0)));
632 // fall through to set "enable"
633 case LFUN_DIALOG_SHOW: {
634 string const name = cmd.getArg(0);
636 enable = name == "aboutlyx"
637 || name == "file" //FIXME: should be removed.
639 || name == "texinfo";
640 else if (name == "print")
641 enable = buf->isExportable("dvi")
642 && lyxrc.print_command != "none";
643 else if (name == "character") {
647 InsetCode ic = view()->cursor().inset().lyxCode();
648 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
651 else if (name == "latexlog")
652 enable = FileName(buf->logName()).isFileReadable();
653 else if (name == "spellchecker")
654 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
655 enable = !buf->isReadonly();
659 else if (name == "vclog")
660 enable = buf->lyxvc().inUse();
664 case LFUN_DIALOG_UPDATE: {
665 string const name = cmd.getArg(0);
667 enable = name == "prefs";
671 case LFUN_CITATION_INSERT: {
672 FuncRequest fr(LFUN_INSET_INSERT, "citation");
673 enable = getStatus(fr).enabled();
677 case LFUN_BUFFER_WRITE: {
678 enable = lyx_view_->buffer()->isUnnamed()
679 || !lyx_view_->buffer()->isClean();
684 case LFUN_BUFFER_WRITE_ALL: {
685 // We enable the command only if there are some modified buffers
686 Buffer * first = theBufferList().first();
687 bool modified = false;
691 // We cannot use a for loop as the buffer list is a cycle.
697 b = theBufferList().next(b);
698 } while (b != first);
706 case LFUN_BOOKMARK_GOTO: {
707 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
708 enable = LyX::ref().session().bookmarks().isValid(num);
712 case LFUN_BOOKMARK_CLEAR:
713 enable = LyX::ref().session().bookmarks().size() > 0;
716 case LFUN_TOOLBAR_TOGGLE: {
717 bool const current = lyx_view_->isToolbarVisible(cmd.getArg(0));
718 flag.setOnOff(current);
721 case LFUN_WINDOW_CLOSE: {
722 enable = (theApp()->gui().viewIds().size() > 1);
726 // this one is difficult to get right. As a half-baked
727 // solution, we consider only the first action of the sequence
728 case LFUN_COMMAND_SEQUENCE: {
729 // argument contains ';'-terminated commands
730 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
731 FuncRequest func(lyxaction.lookupFunc(firstcmd));
732 func.origin = cmd.origin;
733 flag = getStatus(func);
739 std::string name(to_utf8(cmd.argument()));
740 if (LyX::ref().topLevelCmdDef().lock(name, func)) {
741 func.origin = cmd.origin;
742 flag = getStatus(func);
743 LyX::ref().topLevelCmdDef().release(name);
745 // catch recursion or unknown command definiton
746 // all operations until the recursion or unknown command
747 // definiton occures are performed, so set the state to enabled
753 case LFUN_BUFFER_NEW:
754 case LFUN_BUFFER_NEW_TEMPLATE:
755 case LFUN_WORD_FIND_FORWARD:
756 case LFUN_WORD_FIND_BACKWARD:
757 case LFUN_COMMAND_PREFIX:
758 case LFUN_COMMAND_EXECUTE:
760 case LFUN_META_PREFIX:
761 case LFUN_BUFFER_CLOSE:
762 case LFUN_BUFFER_WRITE_AS:
763 case LFUN_BUFFER_UPDATE:
764 case LFUN_BUFFER_VIEW:
765 case LFUN_MASTER_BUFFER_UPDATE:
766 case LFUN_MASTER_BUFFER_VIEW:
767 case LFUN_BUFFER_IMPORT:
768 case LFUN_BUFFER_AUTO_SAVE:
769 case LFUN_RECONFIGURE:
773 case LFUN_DROP_LAYOUTS_CHOICE:
775 case LFUN_SERVER_GET_NAME:
776 case LFUN_SERVER_NOTIFY:
777 case LFUN_SERVER_GOTO_FILE_ROW:
778 case LFUN_DIALOG_HIDE:
779 case LFUN_DIALOG_DISCONNECT_INSET:
780 case LFUN_BUFFER_CHILD_OPEN:
781 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
782 case LFUN_KEYMAP_OFF:
783 case LFUN_KEYMAP_PRIMARY:
784 case LFUN_KEYMAP_SECONDARY:
785 case LFUN_KEYMAP_TOGGLE:
787 case LFUN_BUFFER_EXPORT_CUSTOM:
788 case LFUN_BUFFER_PRINT:
789 case LFUN_PREFERENCES_SAVE:
790 case LFUN_SCREEN_FONT_UPDATE:
793 case LFUN_EXTERNAL_EDIT:
794 case LFUN_GRAPHICS_EDIT:
795 case LFUN_ALL_INSETS_TOGGLE:
796 case LFUN_BUFFER_LANGUAGE:
797 case LFUN_TEXTCLASS_APPLY:
798 case LFUN_TEXTCLASS_LOAD:
799 case LFUN_BUFFER_SAVE_AS_DEFAULT:
800 case LFUN_BUFFER_PARAMS_APPLY:
801 case LFUN_LAYOUT_MODULES_CLEAR:
802 case LFUN_LAYOUT_MODULE_ADD:
803 case LFUN_LAYOUT_RELOAD:
804 case LFUN_LYXRC_APPLY:
805 case LFUN_BUFFER_NEXT:
806 case LFUN_BUFFER_PREVIOUS:
807 case LFUN_WINDOW_NEW:
809 // these are handled in our dispatch()
817 if (!getLocalStatus(view()->cursor(), cmd, flag))
818 flag = view()->getStatus(cmd);
824 // Can we use a readonly buffer?
825 if (buf && buf->isReadonly()
826 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
827 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
828 flag.message(from_utf8(N_("Document is read-only")));
832 // Are we in a DELETED change-tracking region?
834 && lookupChangeType(view()->cursor(), true) == Change::DELETED
835 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
836 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
837 flag.message(from_utf8(N_("This portion of the document is deleted.")));
841 // the default error message if we disable the command
842 if (!flag.enabled() && flag.message().empty())
843 flag.message(from_utf8(N_("Command disabled")));
849 bool LyXFunc::ensureBufferClean(BufferView * bv)
851 Buffer & buf = bv->buffer();
855 docstring const file = buf.fileName().displayName(30);
856 docstring text = bformat(_("The document %1$s has unsaved "
857 "changes.\n\nDo you want to save "
858 "the document?"), file);
859 int const ret = Alert::prompt(_("Save changed document?"),
860 text, 0, 1, _("&Save"),
864 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
866 return buf.isClean();
872 void showPrintError(string const & name)
874 docstring str = bformat(_("Could not print the document %1$s.\n"
875 "Check that your printer is set up correctly."),
876 makeDisplayPath(name, 50));
877 Alert::error(_("Print document failed"), str);
881 void loadTextClass(string const & name)
883 std::pair<bool, textclass_type> const tc_pair =
884 textclasslist.numberOfClass(name);
886 if (!tc_pair.first) {
887 lyxerr << "Document class \"" << name
888 << "\" does not exist."
893 textclass_type const tc = tc_pair.second;
895 if (!textclasslist[tc].load()) {
896 docstring s = bformat(_("The document class %1$s."
897 "could not be loaded."),
898 from_utf8(textclasslist[tc].name()));
899 Alert::error(_("Could not load class"), s);
904 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
909 void LyXFunc::dispatch(FuncRequest const & cmd)
911 string const argument = to_utf8(cmd.argument());
912 kb_action const action = cmd.action;
914 LYXERR(Debug::ACTION) << endl << "LyXFunc::dispatch: cmd: " << cmd << endl;
915 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
917 // we have not done anything wrong yet.
919 dispatch_buffer.erase();
921 // redraw the screen at the end (first of the two drawing steps).
922 //This is done unless explicitely requested otherwise
923 Update::flags updateFlags = Update::FitCursor;
925 FuncStatus const flag = getStatus(cmd);
926 if (!flag.enabled()) {
927 // We cannot use this function here
928 LYXERR(Debug::ACTION) << "LyXFunc::dispatch: "
929 << lyxaction.getActionName(action)
930 << " [" << action << "] is disabled at this location"
932 setErrorMessage(flag.message());
936 case LFUN_WORD_FIND_FORWARD:
937 case LFUN_WORD_FIND_BACKWARD: {
938 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
939 static docstring last_search;
940 docstring searched_string;
942 if (!cmd.argument().empty()) {
943 last_search = cmd.argument();
944 searched_string = cmd.argument();
946 searched_string = last_search;
949 if (searched_string.empty())
952 bool const fw = action == LFUN_WORD_FIND_FORWARD;
953 docstring const data =
954 find2string(searched_string, true, false, fw);
955 find(view(), FuncRequest(LFUN_WORD_FIND, data));
959 case LFUN_COMMAND_PREFIX:
960 BOOST_ASSERT(lyx_view_);
961 lyx_view_->message(keyseq.printOptions(true));
964 case LFUN_COMMAND_EXECUTE:
965 BOOST_ASSERT(lyx_view_);
966 lyx_view_->showMiniBuffer(true);
970 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
972 meta_fake_bit = NoModifier;
973 if (lyx_view_->buffer())
974 // cancel any selection
975 dispatch(FuncRequest(LFUN_MARK_OFF));
976 setMessage(from_ascii(N_("Cancel")));
979 case LFUN_META_PREFIX:
980 meta_fake_bit = AltModifier;
981 setMessage(keyseq.print(KeySequence::ForGui));
984 case LFUN_BUFFER_TOGGLE_READ_ONLY: {
985 BOOST_ASSERT(lyx_view_ && lyx_view_->view() && lyx_view_->buffer());
986 Buffer * buf = lyx_view_->buffer();
987 if (buf->lyxvc().inUse())
988 buf->lyxvc().toggleReadOnly();
990 buf->setReadonly(!lyx_view_->buffer()->isReadonly());
994 // --- Menus -----------------------------------------------
995 case LFUN_BUFFER_NEW:
996 menuNew(argument, false);
997 updateFlags = Update::None;
1000 case LFUN_BUFFER_NEW_TEMPLATE:
1001 menuNew(argument, true);
1002 updateFlags = Update::None;
1005 case LFUN_BUFFER_CLOSE:
1007 updateFlags = Update::None;
1010 case LFUN_BUFFER_WRITE:
1011 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1012 if (!lyx_view_->buffer()->isUnnamed()) {
1013 docstring const str = bformat(_("Saving document %1$s..."),
1014 makeDisplayPath(lyx_view_->buffer()->absFileName()));
1015 lyx_view_->message(str);
1016 lyx_view_->buffer()->menuWrite();
1017 lyx_view_->message(str + _(" done."));
1019 lyx_view_->buffer()->writeAs();
1021 updateFlags = Update::None;
1024 case LFUN_BUFFER_WRITE_AS:
1025 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1026 lyx_view_->buffer()->writeAs(argument);
1027 updateFlags = Update::None;
1030 case LFUN_BUFFER_WRITE_ALL: {
1031 Buffer * first = theBufferList().first();
1034 lyx_view_->message(_("Saving all documents..."));
1036 // We cannot use a for loop as the buffer list cycles.
1038 if (!b->isClean()) {
1039 if (!b->isUnnamed()) {
1041 lyxerr[Debug::ACTION] << "Saved " << b->absFileName() << endl;
1045 b = theBufferList().next(b);
1046 } while (b != first);
1047 lyx_view_->message(_("All documents saved."));
1050 updateFlags = Update::None;
1054 case LFUN_BUFFER_RELOAD: {
1055 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1056 docstring const file = makeDisplayPath(lyx_view_->buffer()->absFileName(), 20);
1057 docstring text = bformat(_("Any changes will be lost. Are you sure "
1058 "you want to revert to the saved version of the document %1$s?"), file);
1059 int const ret = Alert::prompt(_("Revert to saved document?"),
1060 text, 1, 1, _("&Revert"), _("&Cancel"));
1067 case LFUN_BUFFER_UPDATE:
1068 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1069 lyx_view_->buffer()->doExport(argument, true);
1072 case LFUN_BUFFER_VIEW:
1073 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1074 lyx_view_->buffer()->preview(argument);
1077 case LFUN_MASTER_BUFFER_UPDATE:
1078 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->masterBuffer());
1079 lyx_view_->buffer()->masterBuffer()->doExport(argument, true);
1082 case LFUN_MASTER_BUFFER_VIEW:
1083 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->masterBuffer());
1084 lyx_view_->buffer()->masterBuffer()->preview(argument);
1087 case LFUN_BUILD_PROGRAM:
1088 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1089 lyx_view_->buffer()->doExport("program", true);
1092 case LFUN_BUFFER_CHKTEX:
1093 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1094 lyx_view_->buffer()->runChktex();
1097 case LFUN_BUFFER_EXPORT:
1098 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1099 if (argument == "custom")
1100 lyx_view_->getDialogs().show("sendto");
1102 lyx_view_->buffer()->doExport(argument, false);
1105 case LFUN_BUFFER_EXPORT_CUSTOM: {
1106 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1108 string command = split(argument, format_name, ' ');
1109 Format const * format = formats.getFormat(format_name);
1111 lyxerr << "Format \"" << format_name
1112 << "\" not recognized!"
1117 Buffer * buffer = lyx_view_->buffer();
1119 // The name of the file created by the conversion process
1122 // Output to filename
1123 if (format->name() == "lyx") {
1124 string const latexname = buffer->latexName(false);
1125 filename = changeExtension(latexname,
1126 format->extension());
1127 filename = addName(buffer->temppath(), filename);
1129 if (!buffer->writeFile(FileName(filename)))
1133 buffer->doExport(format_name, true, filename);
1136 // Substitute $$FName for filename
1137 if (!contains(command, "$$FName"))
1138 command = "( " + command + " ) < $$FName";
1139 command = subst(command, "$$FName", filename);
1141 // Execute the command in the background
1143 call.startscript(Systemcall::DontWait, command);
1147 case LFUN_BUFFER_PRINT: {
1148 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1149 // FIXME: cmd.getArg() might fail if one of the arguments
1150 // contains double quotes
1151 string target = cmd.getArg(0);
1152 string target_name = cmd.getArg(1);
1153 string command = cmd.getArg(2);
1156 || target_name.empty()
1157 || command.empty()) {
1158 lyxerr << "Unable to parse \""
1159 << argument << '"' << endl;
1162 if (target != "printer" && target != "file") {
1163 lyxerr << "Unrecognized target \""
1164 << target << '"' << endl;
1168 Buffer * buffer = lyx_view_->buffer();
1170 if (!buffer->doExport("dvi", true)) {
1171 showPrintError(buffer->absFileName());
1175 // Push directory path.
1176 string const path = buffer->temppath();
1177 // Prevent the compiler from optimizing away p
1179 support::Path p(pp);
1181 // there are three cases here:
1182 // 1. we print to a file
1183 // 2. we print directly to a printer
1184 // 3. we print using a spool command (print to file first)
1187 string const dviname =
1188 changeExtension(buffer->latexName(true), "dvi");
1190 if (target == "printer") {
1191 if (!lyxrc.print_spool_command.empty()) {
1192 // case 3: print using a spool
1193 string const psname =
1194 changeExtension(dviname,".ps");
1195 command += ' ' + lyxrc.print_to_file
1198 + quoteName(dviname);
1201 lyxrc.print_spool_command + ' ';
1202 if (target_name != "default") {
1203 command2 += lyxrc.print_spool_printerprefix
1207 command2 += quoteName(psname);
1209 // If successful, then spool command
1210 res = one.startscript(
1215 res = one.startscript(
1216 Systemcall::DontWait,
1219 // case 2: print directly to a printer
1220 if (target_name != "default")
1221 command += ' ' + lyxrc.print_to_printer + target_name + ' ';
1222 res = one.startscript(
1223 Systemcall::DontWait,
1224 command + quoteName(dviname));
1228 // case 1: print to a file
1229 FileName const filename(makeAbsPath(target_name,
1230 lyx_view_->buffer()->filePath()));
1231 FileName const dvifile(makeAbsPath(dviname, path));
1232 if (filename.exists()) {
1233 docstring text = bformat(
1234 _("The file %1$s already exists.\n\n"
1235 "Do you want to overwrite that file?"),
1236 makeDisplayPath(filename.absFilename()));
1237 if (Alert::prompt(_("Overwrite file?"),
1238 text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
1241 command += ' ' + lyxrc.print_to_file
1242 + quoteName(filename.toFilesystemEncoding())
1244 + quoteName(dvifile.toFilesystemEncoding());
1245 res = one.startscript(Systemcall::DontWait,
1250 showPrintError(buffer->absFileName());
1254 case LFUN_BUFFER_IMPORT:
1259 // quitting is triggered by the gui code
1260 // (leaving the event loop).
1261 lyx_view_->message(from_utf8(N_("Exiting.")));
1262 if (theBufferList().quitWriteAll())
1263 theApp()->gui().closeAllViews();
1266 case LFUN_BUFFER_AUTO_SAVE:
1267 lyx_view_->buffer()->autoSave();
1270 case LFUN_RECONFIGURE:
1271 BOOST_ASSERT(lyx_view_);
1272 // argument is any additional parameter to the configure.py command
1273 reconfigure(*lyx_view_, argument);
1276 case LFUN_HELP_OPEN: {
1277 BOOST_ASSERT(lyx_view_);
1278 string const arg = argument;
1280 setErrorMessage(from_ascii(N_("Missing argument")));
1283 FileName const fname = i18nLibFileSearch("doc", arg, "lyx");
1284 if (fname.empty()) {
1285 lyxerr << "LyX: unable to find documentation file `"
1286 << arg << "'. Bad installation?" << endl;
1289 lyx_view_->message(bformat(_("Opening help file %1$s..."),
1290 makeDisplayPath(fname.absFilename())));
1291 Buffer * buf = lyx_view_->loadLyXFile(fname, false);
1294 lyx_view_->setBuffer(buf);
1295 lyx_view_->showErrorList("Parse");
1297 updateFlags = Update::None;
1301 // --- version control -------------------------------
1302 case LFUN_VC_REGISTER:
1303 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1304 if (!ensureBufferClean(view()))
1306 if (!lyx_view_->buffer()->lyxvc().inUse()) {
1307 lyx_view_->buffer()->lyxvc().registrer();
1310 updateFlags = Update::Force;
1313 case LFUN_VC_CHECK_IN:
1314 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1315 if (!ensureBufferClean(view()))
1317 if (lyx_view_->buffer()->lyxvc().inUse()
1318 && !lyx_view_->buffer()->isReadonly()) {
1319 lyx_view_->buffer()->lyxvc().checkIn();
1324 case LFUN_VC_CHECK_OUT:
1325 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1326 if (!ensureBufferClean(view()))
1328 if (lyx_view_->buffer()->lyxvc().inUse()
1329 && lyx_view_->buffer()->isReadonly()) {
1330 lyx_view_->buffer()->lyxvc().checkOut();
1335 case LFUN_VC_REVERT:
1336 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1337 lyx_view_->buffer()->lyxvc().revert();
1341 case LFUN_VC_UNDO_LAST:
1342 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1343 lyx_view_->buffer()->lyxvc().undoLast();
1347 // --- buffers ----------------------------------------
1348 case LFUN_BUFFER_SWITCH:
1349 BOOST_ASSERT(lyx_view_);
1350 lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1351 updateFlags = Update::None;
1354 case LFUN_BUFFER_NEXT:
1355 BOOST_ASSERT(lyx_view_);
1356 lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer()));
1357 updateFlags = Update::None;
1360 case LFUN_BUFFER_PREVIOUS:
1361 BOOST_ASSERT(lyx_view_);
1362 lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer()));
1363 updateFlags = Update::None;
1366 case LFUN_FILE_NEW: {
1367 BOOST_ASSERT(lyx_view_);
1369 string tmpname = split(argument, name, ':'); // Split filename
1370 Buffer * const b = newFile(name, tmpname);
1372 lyx_view_->setBuffer(b);
1373 updateFlags = Update::None;
1377 case LFUN_FILE_OPEN:
1378 BOOST_ASSERT(lyx_view_);
1380 updateFlags = Update::None;
1383 case LFUN_DROP_LAYOUTS_CHOICE:
1384 BOOST_ASSERT(lyx_view_);
1385 lyx_view_->openLayoutList();
1388 case LFUN_MENU_OPEN:
1389 BOOST_ASSERT(lyx_view_);
1390 lyx_view_->openMenu(from_utf8(argument));
1393 // --- lyxserver commands ----------------------------
1394 case LFUN_SERVER_GET_NAME:
1395 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1396 setMessage(from_utf8(lyx_view_->buffer()->absFileName()));
1397 LYXERR(Debug::INFO) << "FNAME["
1398 << lyx_view_->buffer()->absFileName()
1402 case LFUN_SERVER_NOTIFY:
1403 dispatch_buffer = keyseq.print(KeySequence::Portable);
1404 theServer().notifyClient(to_utf8(dispatch_buffer));
1407 case LFUN_SERVER_GOTO_FILE_ROW: {
1408 BOOST_ASSERT(lyx_view_);
1411 istringstream is(argument);
1412 is >> file_name >> row;
1414 bool loaded = false;
1415 if (prefixIs(file_name, package().temp_dir().absFilename()))
1416 // Needed by inverse dvi search. If it is a file
1417 // in tmpdir, call the apropriated function
1418 buf = theBufferList().getBufferFromTmp(file_name);
1420 // Must replace extension of the file to be .lyx
1421 // and get full path
1422 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1423 // Either change buffer or load the file
1424 if (theBufferList().exists(s.absFilename()))
1425 buf = theBufferList().getBuffer(s.absFilename());
1427 buf = lyx_view_->loadLyXFile(s);
1433 updateFlags = Update::None;
1438 lyx_view_->setBuffer(buf);
1439 view()->setCursorFromRow(row);
1441 lyx_view_->showErrorList("Parse");
1442 updateFlags = Update::FitCursor;
1446 case LFUN_DIALOG_SHOW: {
1447 BOOST_ASSERT(lyx_view_);
1448 string const name = cmd.getArg(0);
1449 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1451 if (name == "character") {
1452 data = freefont2string();
1454 lyx_view_->getDialogs().show("character", data);
1455 } else if (name == "latexlog") {
1456 Buffer::LogType type;
1457 string const logfile = lyx_view_->buffer()->logName(&type);
1459 case Buffer::latexlog:
1462 case Buffer::buildlog:
1466 data += Lexer::quoteString(logfile);
1467 lyx_view_->getDialogs().show("log", data);
1468 } else if (name == "vclog") {
1469 string const data = "vc " +
1470 Lexer::quoteString(lyx_view_->buffer()->lyxvc().getLogFile());
1471 lyx_view_->getDialogs().show("log", data);
1473 lyx_view_->getDialogs().show(name, data);
1477 case LFUN_DIALOG_SHOW_NEW_INSET: {
1478 BOOST_ASSERT(lyx_view_);
1479 string const name = cmd.getArg(0);
1480 InsetCode code = insetCode(name);
1481 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1482 bool insetCodeOK = true;
1491 case HYPERLINK_CODE: {
1492 InsetCommandParams p(code);
1493 data = InsetCommandMailer::params2string(name, p);
1496 case INCLUDE_CODE: {
1497 // data is the include type: one of "include",
1498 // "input", "verbatiminput" or "verbatiminput*"
1500 // default type is requested
1502 InsetCommandParams p(INCLUDE_CODE, data);
1503 data = InsetCommandMailer::params2string("include", p);
1507 // \c data == "Boxed" || "Frameless" etc
1508 InsetBoxParams p(data);
1509 data = InsetBoxMailer::params2string(p);
1513 InsetBranchParams p;
1514 data = InsetBranchMailer::params2string(p);
1518 InsetCommandParams p(CITE_CODE);
1519 data = InsetCommandMailer::params2string(name, p);
1523 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1526 case EXTERNAL_CODE: {
1527 InsetExternalParams p;
1528 Buffer const & buffer = *lyx_view_->buffer();
1529 data = InsetExternalMailer::params2string(p, buffer);
1534 data = InsetFloatMailer::params2string(p);
1537 case LISTINGS_CODE: {
1538 InsetListingsParams p;
1539 data = InsetListingsMailer::params2string(p);
1542 case GRAPHICS_CODE: {
1543 InsetGraphicsParams p;
1544 Buffer const & buffer = *lyx_view_->buffer();
1545 data = InsetGraphicsMailer::params2string(p, buffer);
1550 data = InsetNoteMailer::params2string(p);
1555 data = InsetVSpaceMailer::params2string(space);
1560 data = InsetWrapMailer::params2string(p);
1564 lyxerr << "Inset type '" << name <<
1565 "' not recognized in LFUN_DIALOG_SHOW_NEW_INSET" << std:: endl;
1566 insetCodeOK = false;
1568 } // end switch(code)
1570 lyx_view_->getDialogs().show(name, data, 0);
1574 case LFUN_DIALOG_UPDATE: {
1575 BOOST_ASSERT(lyx_view_);
1576 string const & name = argument;
1577 // Can only update a dialog connected to an existing inset
1578 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1580 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1581 inset->dispatch(view()->cursor(), fr);
1582 } else if (name == "paragraph") {
1583 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1584 } else if (name == "prefs") {
1585 lyx_view_->getDialogs().update(name, string());
1590 case LFUN_DIALOG_HIDE:
1591 LyX::cref().hideDialogs(argument, 0);
1594 case LFUN_DIALOG_TOGGLE: {
1595 BOOST_ASSERT(lyx_view_);
1596 if (lyx_view_->getDialogs().visible(cmd.getArg(0)))
1597 dispatch(FuncRequest(LFUN_DIALOG_HIDE, argument));
1599 dispatch(FuncRequest(LFUN_DIALOG_SHOW, argument));
1603 case LFUN_DIALOG_DISCONNECT_INSET:
1604 BOOST_ASSERT(lyx_view_);
1605 lyx_view_->getDialogs().disconnect(argument);
1609 case LFUN_CITATION_INSERT: {
1610 BOOST_ASSERT(lyx_view_);
1611 if (!argument.empty()) {
1612 // we can have one optional argument, delimited by '|'
1613 // citation-insert <key>|<text_before>
1614 // this should be enhanced to also support text_after
1615 // and citation style
1616 string arg = argument;
1618 if (contains(argument, "|")) {
1619 arg = token(argument, '|', 0);
1620 opt1 = token(argument, '|', 1);
1622 InsetCommandParams icp(CITE_CODE);
1623 icp["key"] = from_utf8(arg);
1625 icp["before"] = from_utf8(opt1);
1626 string icstr = InsetCommandMailer::params2string("citation", icp);
1627 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1630 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1634 case LFUN_BUFFER_CHILD_OPEN: {
1635 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1636 Buffer * parent = lyx_view_->buffer();
1637 FileName filename = makeAbsPath(argument, parent->filePath());
1638 view()->saveBookmark(false);
1640 bool parsed = false;
1641 if (theBufferList().exists(filename.absFilename())) {
1642 child = theBufferList().getBuffer(filename.absFilename());
1644 setMessage(bformat(_("Opening child document %1$s..."),
1645 makeDisplayPath(filename.absFilename())));
1646 child = lyx_view_->loadLyXFile(filename, true);
1650 // Set the parent name of the child document.
1651 // This makes insertion of citations and references in the child work,
1652 // when the target is in the parent or another child document.
1653 child->setParentName(parent->absFileName());
1654 updateLabels(*child->masterBuffer());
1655 lyx_view_->setBuffer(child);
1657 lyx_view_->showErrorList("Parse");
1660 // If a screen update is required (in case where auto_open is false),
1661 // setBuffer() would have taken care of it already. Otherwise we shall
1662 // reset the update flag because it can cause a circular problem.
1664 updateFlags = Update::None;
1668 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1669 BOOST_ASSERT(lyx_view_);
1670 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1673 case LFUN_KEYMAP_OFF:
1674 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1675 lyx_view_->view()->getIntl().keyMapOn(false);
1678 case LFUN_KEYMAP_PRIMARY:
1679 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1680 lyx_view_->view()->getIntl().keyMapPrim();
1683 case LFUN_KEYMAP_SECONDARY:
1684 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1685 lyx_view_->view()->getIntl().keyMapSec();
1688 case LFUN_KEYMAP_TOGGLE:
1689 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1690 lyx_view_->view()->getIntl().toggleKeyMap();
1696 string rest = split(argument, countstr, ' ');
1697 istringstream is(countstr);
1700 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1701 for (int i = 0; i < count; ++i)
1702 dispatch(lyxaction.lookupFunc(rest));
1706 case LFUN_COMMAND_SEQUENCE: {
1707 // argument contains ';'-terminated commands
1708 string arg = argument;
1709 while (!arg.empty()) {
1711 arg = split(arg, first, ';');
1712 FuncRequest func(lyxaction.lookupFunc(first));
1713 func.origin = cmd.origin;
1721 if (LyX::ref().topLevelCmdDef().lock(argument, func)) {
1722 func.origin = cmd.origin;
1724 LyX::ref().topLevelCmdDef().release(argument);
1726 if (func.action == LFUN_UNKNOWN_ACTION) {
1727 // unknown command definition
1728 lyxerr << "Warning: unknown command definition `"
1732 // recursion detected
1733 lyxerr << "Warning: Recursion in the command definition `"
1734 << argument << "' detected"
1741 case LFUN_PREFERENCES_SAVE: {
1742 lyxrc.write(makeAbsPath("preferences",
1743 package().user_support().absFilename()),
1748 case LFUN_SCREEN_FONT_UPDATE:
1749 BOOST_ASSERT(lyx_view_);
1750 // handle the screen font changes.
1751 theFontLoader().update();
1752 /// FIXME: only the current view will be updated. the Gui
1753 /// class is able to furnish the list of views.
1754 updateFlags = Update::Force;
1757 case LFUN_SET_COLOR: {
1759 string const x11_name = split(argument, lyx_name, ' ');
1760 if (lyx_name.empty() || x11_name.empty()) {
1761 setErrorMessage(from_ascii(N_(
1762 "Syntax: set-color <lyx_name>"
1767 bool const graphicsbg_changed =
1768 (lyx_name == lcolor.getLyXName(Color_graphicsbg) &&
1769 x11_name != lcolor.getX11Name(Color_graphicsbg));
1771 if (!lcolor.setColor(lyx_name, x11_name)) {
1773 bformat(_("Set-color \"%1$s\" failed "
1774 "- color is undefined or "
1775 "may not be redefined"),
1776 from_utf8(lyx_name)));
1780 theApp()->updateColor(lcolor.getFromLyXName(lyx_name));
1782 if (graphicsbg_changed) {
1783 // FIXME: The graphics cache no longer has a changeDisplay method.
1785 graphics::GCache::get().changeDisplay(true);
1792 BOOST_ASSERT(lyx_view_);
1793 lyx_view_->message(from_utf8(argument));
1796 case LFUN_EXTERNAL_EDIT: {
1797 BOOST_ASSERT(lyx_view_);
1798 FuncRequest fr(action, argument);
1799 InsetExternal().dispatch(view()->cursor(), fr);
1803 case LFUN_GRAPHICS_EDIT: {
1804 FuncRequest fr(action, argument);
1805 InsetGraphics().dispatch(view()->cursor(), fr);
1809 case LFUN_INSET_APPLY: {
1810 BOOST_ASSERT(lyx_view_);
1811 string const name = cmd.getArg(0);
1812 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1814 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1815 inset->dispatch(view()->cursor(), fr);
1817 FuncRequest fr(LFUN_INSET_INSERT, argument);
1820 // ideally, the update flag should be set by the insets,
1821 // but this is not possible currently
1822 updateFlags = Update::Force | Update::FitCursor;
1826 case LFUN_ALL_INSETS_TOGGLE: {
1827 BOOST_ASSERT(lyx_view_);
1829 string const name = split(argument, action, ' ');
1830 InsetCode const inset_code = insetCode(name);
1832 Cursor & cur = view()->cursor();
1833 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1835 Inset & inset = lyx_view_->buffer()->inset();
1836 InsetIterator it = inset_iterator_begin(inset);
1837 InsetIterator const end = inset_iterator_end(inset);
1838 for (; it != end; ++it) {
1839 if (!it->asInsetMath()
1840 && (inset_code == NO_CODE
1841 || inset_code == it->lyxCode())) {
1842 Cursor tmpcur = cur;
1843 tmpcur.pushBackward(*it);
1844 it->dispatch(tmpcur, fr);
1847 updateFlags = Update::Force | Update::FitCursor;
1851 case LFUN_BUFFER_LANGUAGE: {
1852 BOOST_ASSERT(lyx_view_);
1853 Buffer & buffer = *lyx_view_->buffer();
1854 Language const * oldL = buffer.params().language;
1855 Language const * newL = languages.getLanguage(argument);
1856 if (!newL || oldL == newL)
1859 if (oldL->rightToLeft() == newL->rightToLeft()
1860 && !buffer.isMultiLingual())
1861 buffer.changeLanguage(oldL, newL);
1865 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1866 string const fname =
1867 addName(addPath(package().user_support().absFilename(), "templates/"),
1869 Buffer defaults(fname);
1871 istringstream ss(argument);
1874 int const unknown_tokens = defaults.readHeader(lex);
1876 if (unknown_tokens != 0) {
1877 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1878 << unknown_tokens << " unknown token"
1879 << (unknown_tokens == 1 ? "" : "s")
1883 if (defaults.writeFile(FileName(defaults.absFileName())))
1884 setMessage(bformat(_("Document defaults saved in %1$s"),
1885 makeDisplayPath(fname)));
1887 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1891 case LFUN_BUFFER_PARAMS_APPLY: {
1892 BOOST_ASSERT(lyx_view_);
1893 biblio::CiteEngine const oldEngine =
1894 lyx_view_->buffer()->params().getEngine();
1896 Buffer * buffer = lyx_view_->buffer();
1898 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1900 Cursor & cur = view()->cursor();
1901 cur.recordUndoFullDocument();
1903 istringstream ss(argument);
1906 int const unknown_tokens = buffer->readHeader(lex);
1908 if (unknown_tokens != 0) {
1909 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1910 << unknown_tokens << " unknown token"
1911 << (unknown_tokens == 1 ? "" : "s")
1915 updateLayout(oldClass, buffer);
1917 biblio::CiteEngine const newEngine =
1918 lyx_view_->buffer()->params().getEngine();
1920 if (oldEngine != newEngine) {
1921 FuncRequest fr(LFUN_INSET_REFRESH);
1923 Inset & inset = lyx_view_->buffer()->inset();
1924 InsetIterator it = inset_iterator_begin(inset);
1925 InsetIterator const end = inset_iterator_end(inset);
1926 for (; it != end; ++it)
1927 if (it->lyxCode() == CITE_CODE)
1928 it->dispatch(cur, fr);
1931 updateFlags = Update::Force | Update::FitCursor;
1935 case LFUN_LAYOUT_MODULES_CLEAR: {
1936 BOOST_ASSERT(lyx_view_);
1937 Buffer * buffer = lyx_view_->buffer();
1938 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1939 view()->cursor().recordUndoFullDocument();
1940 buffer->params().clearLayoutModules();
1941 updateLayout(oldClass, buffer);
1942 updateFlags = Update::Force | Update::FitCursor;
1946 case LFUN_LAYOUT_MODULE_ADD: {
1947 BOOST_ASSERT(lyx_view_);
1948 Buffer * buffer = lyx_view_->buffer();
1949 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1950 view()->cursor().recordUndoFullDocument();
1951 buffer->params().addLayoutModule(argument);
1952 updateLayout(oldClass, buffer);
1953 updateFlags = Update::Force | Update::FitCursor;
1957 case LFUN_TEXTCLASS_APPLY: {
1958 BOOST_ASSERT(lyx_view_);
1959 Buffer * buffer = lyx_view_->buffer();
1961 loadTextClass(argument);
1963 std::pair<bool, textclass_type> const tc_pair =
1964 textclasslist.numberOfClass(argument);
1969 textclass_type const old_class = buffer->params().getBaseClass();
1970 textclass_type const new_class = tc_pair.second;
1972 if (old_class == new_class)
1976 //Save the old, possibly modular, layout for use in conversion.
1977 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1978 view()->cursor().recordUndoFullDocument();
1979 buffer->params().setBaseClass(new_class);
1980 updateLayout(oldClass, buffer);
1981 updateFlags = Update::Force | Update::FitCursor;
1985 case LFUN_LAYOUT_RELOAD: {
1986 BOOST_ASSERT(lyx_view_);
1987 Buffer * buffer = lyx_view_->buffer();
1988 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1989 textclass_type const tc = buffer->params().getBaseClass();
1990 textclasslist.reset(tc);
1991 buffer->params().setBaseClass(tc);
1992 updateLayout(oldClass, buffer);
1993 updateFlags = Update::Force | Update::FitCursor;
1997 case LFUN_TEXTCLASS_LOAD:
1998 loadTextClass(argument);
2001 case LFUN_LYXRC_APPLY: {
2002 LyXRC const lyxrc_orig = lyxrc;
2004 istringstream ss(argument);
2005 bool const success = lyxrc.read(ss) == 0;
2008 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
2009 << "Unable to read lyxrc data"
2014 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
2016 if (lyx_view_ && lyx_view_->buffer())
2017 lyx_view_->updateLayoutChoice(true);
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(false);
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_DEFFILE:
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_PIXMAP_CACHE:
2592 case LyXRC::RC_USE_SPELL_LIB:
2593 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2594 case LyXRC::RC_SORT_LAYOUTS:
2595 case LyXRC::RC_VIEWER:
2596 case LyXRC::RC_LAST: