3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Alfredo Braunstein
7 * \author Lars Gullik Bjønnes
8 * \author Jean-Marc Lasgouttes
9 * \author Angus Leeming
11 * \author André Pönitz
14 * \author Martin Vermeer
15 * \author Jürgen Vigna
17 * Full author contact details are available in file CREDITS.
25 #include "BranchList.h"
26 #include "buffer_funcs.h"
28 #include "BufferList.h"
29 #include "BufferParams.h"
30 #include "BufferView.h"
33 #include "Converter.h"
35 #include "CutAndPaste.h"
37 #include "DispatchResult.h"
39 #include "ErrorList.h"
41 #include "FuncRequest.h"
42 #include "FuncStatus.h"
44 #include "InsetIterator.h"
49 #include "LyXAction.h"
54 #include "Paragraph.h"
55 #include "ParagraphParameters.h"
56 #include "ParIterator.h"
60 #include "TextClassList.h"
61 #include "ToolbarBackend.h"
63 #include "insets/InsetBox.h"
64 #include "insets/InsetBranch.h"
65 #include "insets/InsetCommand.h"
66 #include "insets/InsetERT.h"
67 #include "insets/InsetExternal.h"
68 #include "insets/InsetFloat.h"
69 #include "insets/InsetListings.h"
70 #include "insets/InsetGraphics.h"
71 #include "insets/InsetInclude.h"
72 #include "insets/InsetNote.h"
73 #include "insets/InsetTabular.h"
74 #include "insets/InsetVSpace.h"
75 #include "insets/InsetWrap.h"
77 #include "frontends/Application.h"
78 #include "frontends/alert.h"
79 #include "frontends/Dialogs.h"
80 #include "frontends/FileDialog.h"
81 #include "frontends/FontLoader.h"
82 #include "frontends/Gui.h"
83 #include "frontends/KeySymbol.h"
84 #include "frontends/LyXView.h"
85 #include "frontends/Selection.h"
86 #include "frontends/WorkArea.h"
88 #include "support/environment.h"
89 #include "support/FileFilterList.h"
90 #include "support/filetools.h"
91 #include "support/fs_extras.h"
92 #include "support/lstrings.h"
93 #include "support/Path.h"
94 #include "support/Package.h"
95 #include "support/Systemcall.h"
96 #include "support/convert.h"
97 #include "support/os.h"
99 #include <boost/current_function.hpp>
104 using std::make_pair;
107 using std::istringstream;
108 using std::ostringstream;
114 using frontend::LyXView;
116 using support::absolutePath;
117 using support::addName;
118 using support::addPath;
119 using support::bformat;
120 using support::changeExtension;
121 using support::contains;
122 using support::FileFilterList;
123 using support::FileName;
124 using support::fileSearch;
125 using support::i18nLibFileSearch;
126 using support::makeDisplayPath;
127 using support::makeAbsPath;
128 using support::package;
129 using support::quoteName;
130 using support::rtrim;
131 using support::split;
132 using support::subst;
133 using support::Systemcall;
134 using support::token;
136 using support::prefixIs;
139 namespace Alert = frontend::Alert;
141 extern bool quitting;
146 bool import(LyXView * lv, FileName const & filename,
147 string const & format, ErrorList & errorList)
149 docstring const displaypath = makeDisplayPath(filename.absFilename());
150 lv->message(bformat(_("Importing %1$s..."), displaypath));
152 FileName const lyxfile(changeExtension(filename.absFilename(), ".lyx"));
154 string loader_format;
155 vector<string> loaders = theConverters().loaders();
156 if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
157 for (vector<string>::const_iterator it = loaders.begin();
158 it != loaders.end(); ++it) {
159 if (theConverters().isReachable(format, *it)) {
160 string const tofile =
161 changeExtension(filename.absFilename(),
162 formats.extension(*it));
163 if (!theConverters().convert(0, filename, FileName(tofile),
164 filename, format, *it, errorList))
170 if (loader_format.empty()) {
171 frontend::Alert::error(_("Couldn't import file"),
172 bformat(_("No information for importing the format %1$s."),
173 formats.prettyName(format)));
177 loader_format = format;
181 if (loader_format == "lyx") {
182 Buffer * buf = lv->loadLyXFile(lyxfile);
185 lv->message(_("file not imported!"));
190 lv->showErrorList("Parse");
192 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
197 bool as_paragraphs = loader_format == "textparagraph";
198 string filename2 = (loader_format == format) ? filename.absFilename()
199 : changeExtension(filename.absFilename(),
200 formats.extension(loader_format));
201 lv->view()->insertPlaintextFile(filename2, as_paragraphs);
202 lv->dispatch(FuncRequest(LFUN_MARK_OFF));
206 lv->message(_("imported."));
212 // This function runs "configure" and then rereads lyx.defaults to
213 // reconfigure the automatic settings.
214 void reconfigure(LyXView & lv, string const & option)
216 // emit message signal.
217 lv.message(_("Running configure..."));
219 // Run configure in user lyx directory
220 support::Path p(package().user_support());
221 string configure_command = package().configure_command();
222 configure_command += option;
224 int ret = one.startscript(Systemcall::Wait, configure_command);
226 // emit message signal.
227 lv.message(_("Reloading configuration..."));
228 lyxrc.read(support::libFileSearch(string(), "lyxrc.defaults"));
229 // Re-read packages.lst
230 LaTeXFeatures::getAvailable();
233 Alert::information(_("System reconfiguration failed"),
234 _("The system reconfiguration has failed.\n"
235 "Default textclass is used but LyX may "
236 "not be able to work properly.\n"
237 "Please reconfigure again if needed."));
240 Alert::information(_("System reconfigured"),
241 _("The system has been reconfigured.\n"
242 "You need to restart LyX to make use of any\n"
243 "updated document class specifications."));
247 bool getLocalStatus(Cursor cursor, FuncRequest const & cmd, FuncStatus & status)
249 // Try to fix cursor in case it is broken.
250 cursor.fixIfBroken();
252 // This is, of course, a mess. Better create a new doc iterator and use
253 // this in Inset::getStatus. This might require an additional
254 // BufferView * arg, though (which should be avoided)
255 //Cursor safe = *this;
257 for ( ; cursor.depth(); cursor.pop()) {
258 //lyxerr << "\nCursor::getStatus: cmd: " << cmd << endl << *this << endl;
259 BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
260 BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
261 BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
263 // The inset's getStatus() will return 'true' if it made
264 // a definitive decision on whether it want to handle the
265 // request or not. The result of this decision is put into
266 // the 'status' parameter.
267 if (cursor.inset().getStatus(cursor, cmd, status)) {
276 /** Return the change status at cursor position, taking in account the
277 * status at each level of the document iterator (a table in a deleted
278 * footnote is deleted).
279 * When \param outer is true, the top slice is not looked at.
281 Change::Type lookupChangeType(DocIterator const & dit, bool outer = false)
283 size_t const depth = dit.depth() - (outer ? 1 : 0);
285 for (size_t i = 0 ; i < depth ; ++i) {
286 CursorSlice const & slice = dit[i];
287 if (!slice.inset().inMathed()
288 && slice.pos() < slice.paragraph().size()) {
289 Change::Type const ch = slice.paragraph().lookupChange(slice.pos()).type;
290 if (ch != Change::UNCHANGED)
294 return Change::UNCHANGED;
301 : lyx_view_(0), encoded_last_key(0), meta_fake_bit(NoModifier)
306 void LyXFunc::initKeySequences(KeyMap * kb)
308 keyseq = KeySequence(kb, kb);
309 cancel_meta_seq = KeySequence(kb, kb);
313 void LyXFunc::setLyXView(LyXView * lv)
315 if (!quitting && lyx_view_ && lyx_view_->view() && lyx_view_ != lv)
316 // save current selection to the selection buffer to allow
317 // middle-button paste in another window
318 cap::saveSelection(lyx_view_->view()->cursor());
323 void LyXFunc::handleKeyFunc(kb_action action)
325 char_type c = encoded_last_key;
330 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
331 lyx_view_->view()->getIntl().getTransManager().deadkey(
332 c, get_accent(action).accent, view()->cursor().innerText(), view()->cursor());
333 // Need to clear, in case the minibuffer calls these
336 // copied verbatim from do_accent_char
337 view()->cursor().resetAnchor();
338 view()->processUpdateFlags(Update::FitCursor);
342 void LyXFunc::gotoBookmark(unsigned int idx, bool openFile, bool switchToBuffer)
344 BOOST_ASSERT(lyx_view_);
345 if (!LyX::ref().session().bookmarks().isValid(idx))
347 BookmarksSection::Bookmark const & bm = LyX::ref().session().bookmarks().bookmark(idx);
348 BOOST_ASSERT(!bm.filename.empty());
349 string const file = bm.filename.absFilename();
350 // if the file is not opened, open it.
351 if (!theBufferList().exists(file)) {
353 dispatch(FuncRequest(LFUN_FILE_OPEN, file));
357 // open may fail, so we need to test it again
358 if (!theBufferList().exists(file))
361 // if the current buffer is not that one, switch to it.
362 if (lyx_view_->buffer()->absFileName() != file) {
365 dispatch(FuncRequest(LFUN_BUFFER_SWITCH, file));
367 // moveToPosition try paragraph id first and then paragraph (pit, pos).
368 if (!view()->moveToPosition(bm.bottom_pit, bm.bottom_pos,
369 bm.top_id, bm.top_pos))
372 // Cursor jump succeeded!
373 Cursor const & cur = view()->cursor();
374 pit_type new_pit = cur.pit();
375 pos_type new_pos = cur.pos();
376 int new_id = cur.paragraph().id();
378 // if bottom_pit, bottom_pos or top_id has been changed, update bookmark
379 // see http://bugzilla.lyx.org/show_bug.cgi?id=3092
380 if (bm.bottom_pit != new_pit || bm.bottom_pos != new_pos
381 || bm.top_id != new_id) {
382 const_cast<BookmarksSection::Bookmark &>(bm).updatePos(
383 new_pit, new_pos, new_id);
389 void restartCursor(LyXView * lv)
391 /* When we move around, or type, it's nice to be able to see
392 * the cursor immediately after the keypress.
394 if (lv && lv->currentWorkArea())
395 lv->currentWorkArea()->startBlinkingCursor();
399 void LyXFunc::processKeySym(KeySymbol const & keysym, KeyModifier state)
401 LYXERR(Debug::KEY) << "KeySym is " << keysym.getSymbolName() << endl;
403 // Do nothing if we have nothing (JMarc)
404 if (!keysym.isOK()) {
405 LYXERR(Debug::KEY) << "Empty kbd action (probably composing)"
407 restartCursor(lyx_view_);
411 if (keysym.isModifier()) {
412 LYXERR(Debug::KEY) << "isModifier true" << endl;
413 restartCursor(lyx_view_);
417 //Encoding const * encoding = view()->cursor().getEncoding();
418 //encoded_last_key = keysym.getISOEncoded(encoding ? encoding->name() : "");
419 // FIXME: encoded_last_key shadows the member variable of the same
420 // name. Is that intended?
421 char_type encoded_last_key = keysym.getUCSEncoded();
423 // Do a one-deep top-level lookup for
424 // cancel and meta-fake keys. RVDK_PATCH_5
425 cancel_meta_seq.reset();
427 FuncRequest func = cancel_meta_seq.addkey(keysym, state);
428 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
429 << " action first set to [" << func.action << ']'
432 // When not cancel or meta-fake, do the normal lookup.
433 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
434 // Mostly, meta_fake_bit = NoModifier. RVDK_PATCH_5.
435 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_PREFIX)) {
436 // remove Caps Lock and Mod2 as a modifiers
437 func = keyseq.addkey(keysym, (state | meta_fake_bit));
438 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
439 << "action now set to ["
440 << func.action << ']' << endl;
443 // Dont remove this unless you know what you are doing.
444 meta_fake_bit = NoModifier;
446 // Can this happen now ?
447 if (func.action == LFUN_NOACTION)
448 func = FuncRequest(LFUN_COMMAND_PREFIX);
450 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
452 << func.action << "]["
453 << to_utf8(keyseq.print(KeySequence::Portable)) << ']'
456 // already here we know if it any point in going further
457 // why not return already here if action == -1 and
458 // num_bytes == 0? (Lgb)
460 if (keyseq.length() > 1)
461 lyx_view_->message(keyseq.print(KeySequence::ForGui));
464 // Maybe user can only reach the key via holding down shift.
465 // Let's see. But only if shift is the only modifier
466 if (func.action == LFUN_UNKNOWN_ACTION && state == ShiftModifier) {
467 LYXERR(Debug::KEY) << "Trying without shift" << endl;
468 func = keyseq.addkey(keysym, NoModifier);
469 LYXERR(Debug::KEY) << "Action now " << func.action << endl;
472 if (func.action == LFUN_UNKNOWN_ACTION) {
473 // Hmm, we didn't match any of the keysequences. See
474 // if it's normal insertable text not already covered
476 if (keysym.isText() && keyseq.length() == 1) {
477 LYXERR(Debug::KEY) << "isText() is true, inserting." << endl;
478 func = FuncRequest(LFUN_SELF_INSERT,
479 FuncRequest::KEYBOARD);
481 LYXERR(Debug::KEY) << "Unknown, !isText() - giving up" << endl;
482 lyx_view_->message(_("Unknown function."));
483 restartCursor(lyx_view_);
488 if (func.action == LFUN_SELF_INSERT) {
489 if (encoded_last_key != 0) {
490 docstring const arg(1, encoded_last_key);
491 dispatch(FuncRequest(LFUN_SELF_INSERT, arg,
492 FuncRequest::KEYBOARD));
494 << "SelfInsert arg[`" << to_utf8(arg) << "']" << endl;
500 restartCursor(lyx_view_);
504 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
506 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
509 /* In LyX/Mac, when a dialog is open, the menus of the
510 application can still be accessed without giving focus to
511 the main window. In this case, we want to disable the menu
512 entries that are buffer-related.
514 Note that this code is not perfect, as bug 1941 attests:
515 http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
517 Buffer * buf = lyx_view_? lyx_view_->buffer() : 0;
518 if (lyx_view_ && cmd.origin == FuncRequest::MENU && !lyx_view_->hasFocus())
521 if (cmd.action == LFUN_NOACTION) {
522 flag.message(from_utf8(N_("Nothing to do")));
527 switch (cmd.action) {
528 case LFUN_UNKNOWN_ACTION:
529 #ifndef HAVE_LIBAIKSAURUS
530 case LFUN_THESAURUS_ENTRY:
540 if (flag.unknown()) {
541 flag.message(from_utf8(N_("Unknown action")));
545 if (!flag.enabled()) {
546 if (flag.message().empty())
547 flag.message(from_utf8(N_("Command disabled")));
551 // Check whether we need a buffer
552 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
554 flag.message(from_utf8(N_("Command not allowed with"
555 "out any document open")));
560 // I would really like to avoid having this switch and rather try to
561 // encode this in the function itself.
562 // -- And I'd rather let an inset decide which LFUNs it is willing
563 // to handle (Andre')
565 switch (cmd.action) {
566 case LFUN_BUFFER_TOGGLE_READ_ONLY:
567 flag.setOnOff(buf->isReadonly());
570 case LFUN_BUFFER_SWITCH:
571 // toggle on the current buffer, but do not toggle off
572 // the other ones (is that a good idea?)
573 if (buf && to_utf8(cmd.argument()) == buf->absFileName())
577 case LFUN_BUFFER_EXPORT:
578 enable = cmd.argument() == "custom"
579 || buf->isExportable(to_utf8(cmd.argument()));
582 case LFUN_BUFFER_CHKTEX:
583 enable = buf->isLatex() && !lyxrc.chktex_command.empty();
586 case LFUN_BUILD_PROGRAM:
587 enable = buf->isExportable("program");
590 case LFUN_VC_REGISTER:
591 enable = !buf->lyxvc().inUse();
593 case LFUN_VC_CHECK_IN:
594 enable = buf->lyxvc().inUse() && !buf->isReadonly();
596 case LFUN_VC_CHECK_OUT:
597 enable = buf->lyxvc().inUse() && buf->isReadonly();
600 case LFUN_VC_UNDO_LAST:
601 enable = buf->lyxvc().inUse();
603 case LFUN_BUFFER_RELOAD:
604 enable = !buf->isUnnamed() && buf->fileName().exists()
605 && (!buf->isClean() || buf->isExternallyModified(Buffer::timestamp_method));
608 case LFUN_INSET_APPLY: {
613 string const name = cmd.getArg(0);
614 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
616 FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
618 if (!inset->getStatus(view()->cursor(), fr, fs)) {
619 // Every inset is supposed to handle this
624 FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
625 flag |= getStatus(fr);
627 enable = flag.enabled();
631 case LFUN_DIALOG_TOGGLE:
632 flag.setOnOff(lyx_view_->getDialogs().visible(cmd.getArg(0)));
633 // fall through to set "enable"
634 case LFUN_DIALOG_SHOW: {
635 string const name = cmd.getArg(0);
637 enable = name == "aboutlyx"
638 || name == "file" //FIXME: should be removed.
640 || name == "texinfo";
641 else if (name == "print")
642 enable = buf->isExportable("dvi")
643 && lyxrc.print_command != "none";
644 else if (name == "character") {
648 InsetCode ic = view()->cursor().inset().lyxCode();
649 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
652 else if (name == "latexlog")
653 enable = FileName(buf->logName()).isFileReadable();
654 else if (name == "spellchecker")
655 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
656 enable = !buf->isReadonly();
660 else if (name == "vclog")
661 enable = buf->lyxvc().inUse();
665 case LFUN_DIALOG_UPDATE: {
666 string const name = cmd.getArg(0);
668 enable = name == "prefs";
672 case LFUN_CITATION_INSERT: {
673 FuncRequest fr(LFUN_INSET_INSERT, "citation");
674 enable = getStatus(fr).enabled();
678 case LFUN_BUFFER_WRITE: {
679 enable = lyx_view_->buffer()->isUnnamed()
680 || !lyx_view_->buffer()->isClean();
685 case LFUN_BUFFER_WRITE_ALL: {
686 // We enable the command only if there are some modified buffers
687 Buffer * first = theBufferList().first();
688 bool modified = false;
692 // We cannot use a for loop as the buffer list is a cycle.
698 b = theBufferList().next(b);
699 } while (b != first);
707 case LFUN_BOOKMARK_GOTO: {
708 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
709 enable = LyX::ref().session().bookmarks().isValid(num);
713 case LFUN_BOOKMARK_CLEAR:
714 enable = LyX::ref().session().bookmarks().size() > 0;
717 case LFUN_TOOLBAR_TOGGLE: {
718 bool const current = lyx_view_->isToolbarVisible(cmd.getArg(0));
719 flag.setOnOff(current);
722 case LFUN_WINDOW_CLOSE: {
723 enable = (theApp()->gui().viewIds().size() > 1);
727 // this one is difficult to get right. As a half-baked
728 // solution, we consider only the first action of the sequence
729 case LFUN_COMMAND_SEQUENCE: {
730 // argument contains ';'-terminated commands
731 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
732 FuncRequest func(lyxaction.lookupFunc(firstcmd));
733 func.origin = cmd.origin;
734 flag = getStatus(func);
740 std::string name(to_utf8(cmd.argument()));
741 if (LyX::ref().topLevelCmdDef().lock(name, func)) {
742 func.origin = cmd.origin;
743 flag = getStatus(func);
744 LyX::ref().topLevelCmdDef().release(name);
746 // catch recursion or unknown command definiton
747 // all operations until the recursion or unknown command
748 // definiton occures are performed, so set the state to enabled
754 case LFUN_BUFFER_NEW:
755 case LFUN_BUFFER_NEW_TEMPLATE:
756 case LFUN_WORD_FIND_FORWARD:
757 case LFUN_WORD_FIND_BACKWARD:
758 case LFUN_COMMAND_PREFIX:
759 case LFUN_COMMAND_EXECUTE:
761 case LFUN_META_PREFIX:
762 case LFUN_BUFFER_CLOSE:
763 case LFUN_BUFFER_WRITE_AS:
764 case LFUN_BUFFER_UPDATE:
765 case LFUN_BUFFER_VIEW:
766 case LFUN_MASTER_BUFFER_UPDATE:
767 case LFUN_MASTER_BUFFER_VIEW:
768 case LFUN_BUFFER_IMPORT:
769 case LFUN_BUFFER_AUTO_SAVE:
770 case LFUN_RECONFIGURE:
774 case LFUN_DROP_LAYOUTS_CHOICE:
776 case LFUN_SERVER_GET_NAME:
777 case LFUN_SERVER_NOTIFY:
778 case LFUN_SERVER_GOTO_FILE_ROW:
779 case LFUN_DIALOG_HIDE:
780 case LFUN_DIALOG_DISCONNECT_INSET:
781 case LFUN_BUFFER_CHILD_OPEN:
782 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
783 case LFUN_KEYMAP_OFF:
784 case LFUN_KEYMAP_PRIMARY:
785 case LFUN_KEYMAP_SECONDARY:
786 case LFUN_KEYMAP_TOGGLE:
788 case LFUN_BUFFER_EXPORT_CUSTOM:
789 case LFUN_BUFFER_PRINT:
790 case LFUN_PREFERENCES_SAVE:
791 case LFUN_SCREEN_FONT_UPDATE:
794 case LFUN_EXTERNAL_EDIT:
795 case LFUN_GRAPHICS_EDIT:
796 case LFUN_ALL_INSETS_TOGGLE:
797 case LFUN_BUFFER_LANGUAGE:
798 case LFUN_TEXTCLASS_APPLY:
799 case LFUN_TEXTCLASS_LOAD:
800 case LFUN_BUFFER_SAVE_AS_DEFAULT:
801 case LFUN_BUFFER_PARAMS_APPLY:
802 case LFUN_LAYOUT_MODULES_CLEAR:
803 case LFUN_LAYOUT_MODULE_ADD:
804 case LFUN_LAYOUT_RELOAD:
805 case LFUN_LYXRC_APPLY:
806 case LFUN_BUFFER_NEXT:
807 case LFUN_BUFFER_PREVIOUS:
808 case LFUN_WINDOW_NEW:
810 // these are handled in our dispatch()
818 if (!getLocalStatus(view()->cursor(), cmd, flag))
819 flag = view()->getStatus(cmd);
825 // Can we use a readonly buffer?
826 if (buf && buf->isReadonly()
827 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
828 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
829 flag.message(from_utf8(N_("Document is read-only")));
833 // Are we in a DELETED change-tracking region?
835 && lookupChangeType(view()->cursor(), true) == Change::DELETED
836 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
837 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
838 flag.message(from_utf8(N_("This portion of the document is deleted.")));
842 // the default error message if we disable the command
843 if (!flag.enabled() && flag.message().empty())
844 flag.message(from_utf8(N_("Command disabled")));
850 bool LyXFunc::ensureBufferClean(BufferView * bv)
852 Buffer & buf = bv->buffer();
856 docstring const file = buf.fileName().displayName(30);
857 docstring text = bformat(_("The document %1$s has unsaved "
858 "changes.\n\nDo you want to save "
859 "the document?"), file);
860 int const ret = Alert::prompt(_("Save changed document?"),
861 text, 0, 1, _("&Save"),
865 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
867 return buf.isClean();
873 void showPrintError(string const & name)
875 docstring str = bformat(_("Could not print the document %1$s.\n"
876 "Check that your printer is set up correctly."),
877 makeDisplayPath(name, 50));
878 Alert::error(_("Print document failed"), str);
882 void loadTextClass(string const & name)
884 std::pair<bool, textclass_type> const tc_pair =
885 textclasslist.numberOfClass(name);
887 if (!tc_pair.first) {
888 lyxerr << "Document class \"" << name
889 << "\" does not exist."
894 textclass_type const tc = tc_pair.second;
896 if (!textclasslist[tc].load()) {
897 docstring s = bformat(_("The document class %1$s."
898 "could not be loaded."),
899 from_utf8(textclasslist[tc].name()));
900 Alert::error(_("Could not load class"), s);
905 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
910 void LyXFunc::dispatch(FuncRequest const & cmd)
912 string const argument = to_utf8(cmd.argument());
913 kb_action const action = cmd.action;
915 LYXERR(Debug::ACTION) << endl << "LyXFunc::dispatch: cmd: " << cmd << endl;
916 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
918 // we have not done anything wrong yet.
920 dispatch_buffer.erase();
922 // redraw the screen at the end (first of the two drawing steps).
923 //This is done unless explicitely requested otherwise
924 Update::flags updateFlags = Update::FitCursor;
926 FuncStatus const flag = getStatus(cmd);
927 if (!flag.enabled()) {
928 // We cannot use this function here
929 LYXERR(Debug::ACTION) << "LyXFunc::dispatch: "
930 << lyxaction.getActionName(action)
931 << " [" << action << "] is disabled at this location"
933 setErrorMessage(flag.message());
937 case LFUN_WORD_FIND_FORWARD:
938 case LFUN_WORD_FIND_BACKWARD: {
939 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
940 static docstring last_search;
941 docstring searched_string;
943 if (!cmd.argument().empty()) {
944 last_search = cmd.argument();
945 searched_string = cmd.argument();
947 searched_string = last_search;
950 if (searched_string.empty())
953 bool const fw = action == LFUN_WORD_FIND_FORWARD;
954 docstring const data =
955 find2string(searched_string, true, false, fw);
956 find(view(), FuncRequest(LFUN_WORD_FIND, data));
960 case LFUN_COMMAND_PREFIX:
961 BOOST_ASSERT(lyx_view_);
962 lyx_view_->message(keyseq.printOptions(true));
965 case LFUN_COMMAND_EXECUTE:
966 BOOST_ASSERT(lyx_view_);
967 lyx_view_->showMiniBuffer(true);
971 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
973 meta_fake_bit = NoModifier;
974 if (lyx_view_->buffer())
975 // cancel any selection
976 dispatch(FuncRequest(LFUN_MARK_OFF));
977 setMessage(from_ascii(N_("Cancel")));
980 case LFUN_META_PREFIX:
981 meta_fake_bit = AltModifier;
982 setMessage(keyseq.print(KeySequence::ForGui));
985 case LFUN_BUFFER_TOGGLE_READ_ONLY: {
986 BOOST_ASSERT(lyx_view_ && lyx_view_->view() && lyx_view_->buffer());
987 Buffer * buf = lyx_view_->buffer();
988 if (buf->lyxvc().inUse())
989 buf->lyxvc().toggleReadOnly();
991 buf->setReadonly(!lyx_view_->buffer()->isReadonly());
995 // --- Menus -----------------------------------------------
996 case LFUN_BUFFER_NEW:
997 menuNew(argument, false);
998 updateFlags = Update::None;
1001 case LFUN_BUFFER_NEW_TEMPLATE:
1002 menuNew(argument, true);
1003 updateFlags = Update::None;
1006 case LFUN_BUFFER_CLOSE:
1008 updateFlags = Update::None;
1011 case LFUN_BUFFER_WRITE:
1012 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1013 if (!lyx_view_->buffer()->isUnnamed()) {
1014 docstring const str = bformat(_("Saving document %1$s..."),
1015 makeDisplayPath(lyx_view_->buffer()->absFileName()));
1016 lyx_view_->message(str);
1017 lyx_view_->buffer()->menuWrite();
1018 lyx_view_->message(str + _(" done."));
1020 lyx_view_->buffer()->writeAs();
1022 updateFlags = Update::None;
1025 case LFUN_BUFFER_WRITE_AS:
1026 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1027 lyx_view_->buffer()->writeAs(argument);
1028 updateFlags = Update::None;
1031 case LFUN_BUFFER_WRITE_ALL: {
1032 Buffer * first = theBufferList().first();
1035 lyx_view_->message(_("Saving all documents..."));
1037 // We cannot use a for loop as the buffer list cycles.
1039 if (!b->isClean()) {
1040 if (!b->isUnnamed()) {
1042 lyxerr[Debug::ACTION] << "Saved " << b->absFileName() << endl;
1046 b = theBufferList().next(b);
1047 } while (b != first);
1048 lyx_view_->message(_("All documents saved."));
1051 updateFlags = Update::None;
1055 case LFUN_BUFFER_RELOAD: {
1056 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1057 docstring const file = makeDisplayPath(lyx_view_->buffer()->absFileName(), 20);
1058 docstring text = bformat(_("Any changes will be lost. Are you sure "
1059 "you want to revert to the saved version of the document %1$s?"), file);
1060 int const ret = Alert::prompt(_("Revert to saved document?"),
1061 text, 1, 1, _("&Revert"), _("&Cancel"));
1068 case LFUN_BUFFER_UPDATE:
1069 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1070 lyx_view_->buffer()->doExport(argument, true);
1073 case LFUN_BUFFER_VIEW:
1074 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1075 lyx_view_->buffer()->preview(argument);
1078 case LFUN_MASTER_BUFFER_UPDATE:
1079 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->masterBuffer());
1080 lyx_view_->buffer()->masterBuffer()->doExport(argument, true);
1083 case LFUN_MASTER_BUFFER_VIEW:
1084 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->masterBuffer());
1085 lyx_view_->buffer()->masterBuffer()->preview(argument);
1088 case LFUN_BUILD_PROGRAM:
1089 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1090 lyx_view_->buffer()->doExport("program", true);
1093 case LFUN_BUFFER_CHKTEX:
1094 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1095 lyx_view_->buffer()->runChktex();
1098 case LFUN_BUFFER_EXPORT:
1099 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1100 if (argument == "custom")
1101 lyx_view_->getDialogs().show("sendto");
1103 lyx_view_->buffer()->doExport(argument, false);
1106 case LFUN_BUFFER_EXPORT_CUSTOM: {
1107 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1109 string command = split(argument, format_name, ' ');
1110 Format const * format = formats.getFormat(format_name);
1112 lyxerr << "Format \"" << format_name
1113 << "\" not recognized!"
1118 Buffer * buffer = lyx_view_->buffer();
1120 // The name of the file created by the conversion process
1123 // Output to filename
1124 if (format->name() == "lyx") {
1125 string const latexname = buffer->latexName(false);
1126 filename = changeExtension(latexname,
1127 format->extension());
1128 filename = addName(buffer->temppath(), filename);
1130 if (!buffer->writeFile(FileName(filename)))
1134 buffer->doExport(format_name, true, filename);
1137 // Substitute $$FName for filename
1138 if (!contains(command, "$$FName"))
1139 command = "( " + command + " ) < $$FName";
1140 command = subst(command, "$$FName", filename);
1142 // Execute the command in the background
1144 call.startscript(Systemcall::DontWait, command);
1148 case LFUN_BUFFER_PRINT: {
1149 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1150 // FIXME: cmd.getArg() might fail if one of the arguments
1151 // contains double quotes
1152 string target = cmd.getArg(0);
1153 string target_name = cmd.getArg(1);
1154 string command = cmd.getArg(2);
1157 || target_name.empty()
1158 || command.empty()) {
1159 lyxerr << "Unable to parse \""
1160 << argument << '"' << endl;
1163 if (target != "printer" && target != "file") {
1164 lyxerr << "Unrecognized target \""
1165 << target << '"' << endl;
1169 Buffer * buffer = lyx_view_->buffer();
1171 if (!buffer->doExport("dvi", true)) {
1172 showPrintError(buffer->absFileName());
1176 // Push directory path.
1177 string const path = buffer->temppath();
1178 // Prevent the compiler from optimizing away p
1180 support::Path p(pp);
1182 // there are three cases here:
1183 // 1. we print to a file
1184 // 2. we print directly to a printer
1185 // 3. we print using a spool command (print to file first)
1188 string const dviname =
1189 changeExtension(buffer->latexName(true), "dvi");
1191 if (target == "printer") {
1192 if (!lyxrc.print_spool_command.empty()) {
1193 // case 3: print using a spool
1194 string const psname =
1195 changeExtension(dviname,".ps");
1196 command += ' ' + lyxrc.print_to_file
1199 + quoteName(dviname);
1202 lyxrc.print_spool_command + ' ';
1203 if (target_name != "default") {
1204 command2 += lyxrc.print_spool_printerprefix
1208 command2 += quoteName(psname);
1210 // If successful, then spool command
1211 res = one.startscript(
1216 res = one.startscript(
1217 Systemcall::DontWait,
1220 // case 2: print directly to a printer
1221 if (target_name != "default")
1222 command += ' ' + lyxrc.print_to_printer + target_name + ' ';
1223 res = one.startscript(
1224 Systemcall::DontWait,
1225 command + quoteName(dviname));
1229 // case 1: print to a file
1230 FileName const filename(makeAbsPath(target_name,
1231 lyx_view_->buffer()->filePath()));
1232 FileName const dvifile(makeAbsPath(dviname, path));
1233 if (filename.exists()) {
1234 docstring text = bformat(
1235 _("The file %1$s already exists.\n\n"
1236 "Do you want to overwrite that file?"),
1237 makeDisplayPath(filename.absFilename()));
1238 if (Alert::prompt(_("Overwrite file?"),
1239 text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
1242 command += ' ' + lyxrc.print_to_file
1243 + quoteName(filename.toFilesystemEncoding())
1245 + quoteName(dvifile.toFilesystemEncoding());
1246 res = one.startscript(Systemcall::DontWait,
1251 showPrintError(buffer->absFileName());
1255 case LFUN_BUFFER_IMPORT:
1260 // quitting is triggered by the gui code
1261 // (leaving the event loop).
1262 lyx_view_->message(from_utf8(N_("Exiting.")));
1263 if (theBufferList().quitWriteAll())
1264 theApp()->gui().closeAllViews();
1267 case LFUN_BUFFER_AUTO_SAVE:
1268 lyx_view_->buffer()->autoSave();
1271 case LFUN_RECONFIGURE:
1272 BOOST_ASSERT(lyx_view_);
1273 // argument is any additional parameter to the configure.py command
1274 reconfigure(*lyx_view_, argument);
1277 case LFUN_HELP_OPEN: {
1278 BOOST_ASSERT(lyx_view_);
1279 string const arg = argument;
1281 setErrorMessage(from_ascii(N_("Missing argument")));
1284 FileName const fname = i18nLibFileSearch("doc", arg, "lyx");
1285 if (fname.empty()) {
1286 lyxerr << "LyX: unable to find documentation file `"
1287 << arg << "'. Bad installation?" << endl;
1290 lyx_view_->message(bformat(_("Opening help file %1$s..."),
1291 makeDisplayPath(fname.absFilename())));
1292 Buffer * buf = lyx_view_->loadLyXFile(fname, false);
1295 lyx_view_->setBuffer(buf);
1296 lyx_view_->showErrorList("Parse");
1298 updateFlags = Update::None;
1302 // --- version control -------------------------------
1303 case LFUN_VC_REGISTER:
1304 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1305 if (!ensureBufferClean(view()))
1307 if (!lyx_view_->buffer()->lyxvc().inUse()) {
1308 lyx_view_->buffer()->lyxvc().registrer();
1311 updateFlags = Update::Force;
1314 case LFUN_VC_CHECK_IN:
1315 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1316 if (!ensureBufferClean(view()))
1318 if (lyx_view_->buffer()->lyxvc().inUse()
1319 && !lyx_view_->buffer()->isReadonly()) {
1320 lyx_view_->buffer()->lyxvc().checkIn();
1325 case LFUN_VC_CHECK_OUT:
1326 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1327 if (!ensureBufferClean(view()))
1329 if (lyx_view_->buffer()->lyxvc().inUse()
1330 && lyx_view_->buffer()->isReadonly()) {
1331 lyx_view_->buffer()->lyxvc().checkOut();
1336 case LFUN_VC_REVERT:
1337 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1338 lyx_view_->buffer()->lyxvc().revert();
1342 case LFUN_VC_UNDO_LAST:
1343 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1344 lyx_view_->buffer()->lyxvc().undoLast();
1348 // --- buffers ----------------------------------------
1349 case LFUN_BUFFER_SWITCH:
1350 BOOST_ASSERT(lyx_view_);
1351 lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1352 updateFlags = Update::None;
1355 case LFUN_BUFFER_NEXT:
1356 BOOST_ASSERT(lyx_view_);
1357 lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer()));
1358 updateFlags = Update::None;
1361 case LFUN_BUFFER_PREVIOUS:
1362 BOOST_ASSERT(lyx_view_);
1363 lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer()));
1364 updateFlags = Update::None;
1367 case LFUN_FILE_NEW: {
1368 BOOST_ASSERT(lyx_view_);
1370 string tmpname = split(argument, name, ':'); // Split filename
1371 Buffer * const b = newFile(name, tmpname);
1373 lyx_view_->setBuffer(b);
1374 updateFlags = Update::None;
1378 case LFUN_FILE_OPEN:
1379 BOOST_ASSERT(lyx_view_);
1381 updateFlags = Update::None;
1384 case LFUN_DROP_LAYOUTS_CHOICE:
1385 BOOST_ASSERT(lyx_view_);
1386 lyx_view_->openLayoutList();
1389 case LFUN_MENU_OPEN:
1390 BOOST_ASSERT(lyx_view_);
1391 lyx_view_->openMenu(from_utf8(argument));
1394 // --- lyxserver commands ----------------------------
1395 case LFUN_SERVER_GET_NAME:
1396 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1397 setMessage(from_utf8(lyx_view_->buffer()->absFileName()));
1398 LYXERR(Debug::INFO) << "FNAME["
1399 << lyx_view_->buffer()->absFileName()
1403 case LFUN_SERVER_NOTIFY:
1404 dispatch_buffer = keyseq.print(KeySequence::Portable);
1405 theServer().notifyClient(to_utf8(dispatch_buffer));
1408 case LFUN_SERVER_GOTO_FILE_ROW: {
1409 BOOST_ASSERT(lyx_view_);
1412 istringstream is(argument);
1413 is >> file_name >> row;
1415 bool loaded = false;
1416 if (prefixIs(file_name, package().temp_dir().absFilename()))
1417 // Needed by inverse dvi search. If it is a file
1418 // in tmpdir, call the apropriated function
1419 buf = theBufferList().getBufferFromTmp(file_name);
1421 // Must replace extension of the file to be .lyx
1422 // and get full path
1423 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1424 // Either change buffer or load the file
1425 if (theBufferList().exists(s.absFilename()))
1426 buf = theBufferList().getBuffer(s.absFilename());
1428 buf = lyx_view_->loadLyXFile(s);
1434 updateFlags = Update::None;
1439 lyx_view_->setBuffer(buf);
1440 view()->setCursorFromRow(row);
1442 lyx_view_->showErrorList("Parse");
1443 updateFlags = Update::FitCursor;
1447 case LFUN_DIALOG_SHOW: {
1448 BOOST_ASSERT(lyx_view_);
1449 string const name = cmd.getArg(0);
1450 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1452 if (name == "character") {
1453 data = freefont2string();
1455 lyx_view_->getDialogs().show("character", data);
1456 } else if (name == "latexlog") {
1457 Buffer::LogType type;
1458 string const logfile = lyx_view_->buffer()->logName(&type);
1460 case Buffer::latexlog:
1463 case Buffer::buildlog:
1467 data += Lexer::quoteString(logfile);
1468 lyx_view_->getDialogs().show("log", data);
1469 } else if (name == "vclog") {
1470 string const data = "vc " +
1471 Lexer::quoteString(lyx_view_->buffer()->lyxvc().getLogFile());
1472 lyx_view_->getDialogs().show("log", data);
1474 lyx_view_->getDialogs().show(name, data);
1478 case LFUN_DIALOG_SHOW_NEW_INSET: {
1479 BOOST_ASSERT(lyx_view_);
1480 string const name = cmd.getArg(0);
1481 InsetCode code = insetCode(name);
1482 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1483 bool insetCodeOK = true;
1492 case HYPERLINK_CODE: {
1493 InsetCommandParams p(code);
1494 data = InsetCommandMailer::params2string(name, p);
1497 case INCLUDE_CODE: {
1498 // data is the include type: one of "include",
1499 // "input", "verbatiminput" or "verbatiminput*"
1501 // default type is requested
1503 InsetCommandParams p(INCLUDE_CODE, data);
1504 data = InsetCommandMailer::params2string("include", p);
1508 // \c data == "Boxed" || "Frameless" etc
1509 InsetBoxParams p(data);
1510 data = InsetBoxMailer::params2string(p);
1514 InsetBranchParams p;
1515 data = InsetBranchMailer::params2string(p);
1519 InsetCommandParams p(CITE_CODE);
1520 data = InsetCommandMailer::params2string(name, p);
1524 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1527 case EXTERNAL_CODE: {
1528 InsetExternalParams p;
1529 Buffer const & buffer = *lyx_view_->buffer();
1530 data = InsetExternalMailer::params2string(p, buffer);
1535 data = InsetFloatMailer::params2string(p);
1538 case LISTINGS_CODE: {
1539 InsetListingsParams p;
1540 data = InsetListingsMailer::params2string(p);
1543 case GRAPHICS_CODE: {
1544 InsetGraphicsParams p;
1545 Buffer const & buffer = *lyx_view_->buffer();
1546 data = InsetGraphicsMailer::params2string(p, buffer);
1551 data = InsetNoteMailer::params2string(p);
1556 data = InsetVSpaceMailer::params2string(space);
1561 data = InsetWrapMailer::params2string(p);
1565 lyxerr << "Inset type '" << name <<
1566 "' not recognized in LFUN_DIALOG_SHOW_NEW_INSET" << std:: endl;
1567 insetCodeOK = false;
1569 } // end switch(code)
1571 lyx_view_->getDialogs().show(name, data, 0);
1575 case LFUN_DIALOG_UPDATE: {
1576 BOOST_ASSERT(lyx_view_);
1577 string const & name = argument;
1578 // Can only update a dialog connected to an existing inset
1579 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1581 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1582 inset->dispatch(view()->cursor(), fr);
1583 } else if (name == "paragraph") {
1584 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1585 } else if (name == "prefs") {
1586 lyx_view_->getDialogs().update(name, string());
1591 case LFUN_DIALOG_HIDE:
1592 LyX::cref().hideDialogs(argument, 0);
1595 case LFUN_DIALOG_TOGGLE: {
1596 BOOST_ASSERT(lyx_view_);
1597 if (lyx_view_->getDialogs().visible(cmd.getArg(0)))
1598 dispatch(FuncRequest(LFUN_DIALOG_HIDE, argument));
1600 dispatch(FuncRequest(LFUN_DIALOG_SHOW, argument));
1604 case LFUN_DIALOG_DISCONNECT_INSET:
1605 BOOST_ASSERT(lyx_view_);
1606 lyx_view_->getDialogs().disconnect(argument);
1610 case LFUN_CITATION_INSERT: {
1611 BOOST_ASSERT(lyx_view_);
1612 if (!argument.empty()) {
1613 // we can have one optional argument, delimited by '|'
1614 // citation-insert <key>|<text_before>
1615 // this should be enhanced to also support text_after
1616 // and citation style
1617 string arg = argument;
1619 if (contains(argument, "|")) {
1620 arg = token(argument, '|', 0);
1621 opt1 = token(argument, '|', 1);
1623 InsetCommandParams icp(CITE_CODE);
1624 icp["key"] = from_utf8(arg);
1626 icp["before"] = from_utf8(opt1);
1627 string icstr = InsetCommandMailer::params2string("citation", icp);
1628 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1631 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1635 case LFUN_BUFFER_CHILD_OPEN: {
1636 BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1637 Buffer * parent = lyx_view_->buffer();
1638 FileName filename = makeAbsPath(argument, parent->filePath());
1639 view()->saveBookmark(false);
1641 bool parsed = false;
1642 if (theBufferList().exists(filename.absFilename())) {
1643 child = theBufferList().getBuffer(filename.absFilename());
1645 setMessage(bformat(_("Opening child document %1$s..."),
1646 makeDisplayPath(filename.absFilename())));
1647 child = lyx_view_->loadLyXFile(filename, true);
1651 // Set the parent name of the child document.
1652 // This makes insertion of citations and references in the child work,
1653 // when the target is in the parent or another child document.
1654 child->setParentName(parent->absFileName());
1655 updateLabels(*child->masterBuffer());
1656 lyx_view_->setBuffer(child);
1658 lyx_view_->showErrorList("Parse");
1661 // If a screen update is required (in case where auto_open is false),
1662 // setBuffer() would have taken care of it already. Otherwise we shall
1663 // reset the update flag because it can cause a circular problem.
1665 updateFlags = Update::None;
1669 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1670 BOOST_ASSERT(lyx_view_);
1671 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1674 case LFUN_KEYMAP_OFF:
1675 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1676 lyx_view_->view()->getIntl().keyMapOn(false);
1679 case LFUN_KEYMAP_PRIMARY:
1680 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1681 lyx_view_->view()->getIntl().keyMapPrim();
1684 case LFUN_KEYMAP_SECONDARY:
1685 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1686 lyx_view_->view()->getIntl().keyMapSec();
1689 case LFUN_KEYMAP_TOGGLE:
1690 BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1691 lyx_view_->view()->getIntl().toggleKeyMap();
1697 string rest = split(argument, countstr, ' ');
1698 istringstream is(countstr);
1701 lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1702 for (int i = 0; i < count; ++i)
1703 dispatch(lyxaction.lookupFunc(rest));
1707 case LFUN_COMMAND_SEQUENCE: {
1708 // argument contains ';'-terminated commands
1709 string arg = argument;
1710 while (!arg.empty()) {
1712 arg = split(arg, first, ';');
1713 FuncRequest func(lyxaction.lookupFunc(first));
1714 func.origin = cmd.origin;
1722 if (LyX::ref().topLevelCmdDef().lock(argument, func)) {
1723 func.origin = cmd.origin;
1725 LyX::ref().topLevelCmdDef().release(argument);
1727 if (func.action == LFUN_UNKNOWN_ACTION) {
1728 // unknown command definition
1729 lyxerr << "Warning: unknown command definition `"
1733 // recursion detected
1734 lyxerr << "Warning: Recursion in the command definition `"
1735 << argument << "' detected"
1742 case LFUN_PREFERENCES_SAVE: {
1743 lyxrc.write(makeAbsPath("preferences",
1744 package().user_support().absFilename()),
1749 case LFUN_SCREEN_FONT_UPDATE:
1750 BOOST_ASSERT(lyx_view_);
1751 // handle the screen font changes.
1752 theFontLoader().update();
1753 /// FIXME: only the current view will be updated. the Gui
1754 /// class is able to furnish the list of views.
1755 updateFlags = Update::Force;
1758 case LFUN_SET_COLOR: {
1760 string const x11_name = split(argument, lyx_name, ' ');
1761 if (lyx_name.empty() || x11_name.empty()) {
1762 setErrorMessage(from_ascii(N_(
1763 "Syntax: set-color <lyx_name>"
1768 bool const graphicsbg_changed =
1769 (lyx_name == lcolor.getLyXName(Color_graphicsbg) &&
1770 x11_name != lcolor.getX11Name(Color_graphicsbg));
1772 if (!lcolor.setColor(lyx_name, x11_name)) {
1774 bformat(_("Set-color \"%1$s\" failed "
1775 "- color is undefined or "
1776 "may not be redefined"),
1777 from_utf8(lyx_name)));
1781 theApp()->updateColor(lcolor.getFromLyXName(lyx_name));
1783 if (graphicsbg_changed) {
1784 // FIXME: The graphics cache no longer has a changeDisplay method.
1786 graphics::GCache::get().changeDisplay(true);
1793 BOOST_ASSERT(lyx_view_);
1794 lyx_view_->message(from_utf8(argument));
1797 case LFUN_EXTERNAL_EDIT: {
1798 BOOST_ASSERT(lyx_view_);
1799 FuncRequest fr(action, argument);
1800 InsetExternal().dispatch(view()->cursor(), fr);
1804 case LFUN_GRAPHICS_EDIT: {
1805 FuncRequest fr(action, argument);
1806 InsetGraphics().dispatch(view()->cursor(), fr);
1810 case LFUN_INSET_APPLY: {
1811 BOOST_ASSERT(lyx_view_);
1812 string const name = cmd.getArg(0);
1813 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1815 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1816 inset->dispatch(view()->cursor(), fr);
1818 FuncRequest fr(LFUN_INSET_INSERT, argument);
1821 // ideally, the update flag should be set by the insets,
1822 // but this is not possible currently
1823 updateFlags = Update::Force | Update::FitCursor;
1827 case LFUN_ALL_INSETS_TOGGLE: {
1828 BOOST_ASSERT(lyx_view_);
1830 string const name = split(argument, action, ' ');
1831 InsetCode const inset_code = insetCode(name);
1833 Cursor & cur = view()->cursor();
1834 FuncRequest fr(LFUN_INSET_TOGGLE, action);
1836 Inset & inset = lyx_view_->buffer()->inset();
1837 InsetIterator it = inset_iterator_begin(inset);
1838 InsetIterator const end = inset_iterator_end(inset);
1839 for (; it != end; ++it) {
1840 if (!it->asInsetMath()
1841 && (inset_code == NO_CODE
1842 || inset_code == it->lyxCode())) {
1843 Cursor tmpcur = cur;
1844 tmpcur.pushLeft(*it);
1845 it->dispatch(tmpcur, fr);
1848 updateFlags = Update::Force | Update::FitCursor;
1852 case LFUN_BUFFER_LANGUAGE: {
1853 BOOST_ASSERT(lyx_view_);
1854 Buffer & buffer = *lyx_view_->buffer();
1855 Language const * oldL = buffer.params().language;
1856 Language const * newL = languages.getLanguage(argument);
1857 if (!newL || oldL == newL)
1860 if (oldL->rightToLeft() == newL->rightToLeft()
1861 && !buffer.isMultiLingual())
1862 buffer.changeLanguage(oldL, newL);
1866 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1867 string const fname =
1868 addName(addPath(package().user_support().absFilename(), "templates/"),
1870 Buffer defaults(fname);
1872 istringstream ss(argument);
1875 int const unknown_tokens = defaults.readHeader(lex);
1877 if (unknown_tokens != 0) {
1878 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1879 << unknown_tokens << " unknown token"
1880 << (unknown_tokens == 1 ? "" : "s")
1884 if (defaults.writeFile(FileName(defaults.absFileName())))
1885 setMessage(bformat(_("Document defaults saved in %1$s"),
1886 makeDisplayPath(fname)));
1888 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1892 case LFUN_BUFFER_PARAMS_APPLY: {
1893 BOOST_ASSERT(lyx_view_);
1894 biblio::CiteEngine const oldEngine =
1895 lyx_view_->buffer()->params().getEngine();
1897 Buffer * buffer = lyx_view_->buffer();
1899 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1901 Cursor & cur = view()->cursor();
1902 cur.recordUndoFullDocument();
1904 istringstream ss(argument);
1907 int const unknown_tokens = buffer->readHeader(lex);
1909 if (unknown_tokens != 0) {
1910 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1911 << unknown_tokens << " unknown token"
1912 << (unknown_tokens == 1 ? "" : "s")
1916 updateLayout(oldClass, buffer);
1918 biblio::CiteEngine const newEngine =
1919 lyx_view_->buffer()->params().getEngine();
1921 if (oldEngine != newEngine) {
1922 FuncRequest fr(LFUN_INSET_REFRESH);
1924 Inset & inset = lyx_view_->buffer()->inset();
1925 InsetIterator it = inset_iterator_begin(inset);
1926 InsetIterator const end = inset_iterator_end(inset);
1927 for (; it != end; ++it)
1928 if (it->lyxCode() == CITE_CODE)
1929 it->dispatch(cur, fr);
1932 updateFlags = Update::Force | Update::FitCursor;
1936 case LFUN_LAYOUT_MODULES_CLEAR: {
1937 BOOST_ASSERT(lyx_view_);
1938 Buffer * buffer = lyx_view_->buffer();
1939 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1940 view()->cursor().recordUndoFullDocument();
1941 buffer->params().clearLayoutModules();
1942 updateLayout(oldClass, buffer);
1943 updateFlags = Update::Force | Update::FitCursor;
1947 case LFUN_LAYOUT_MODULE_ADD: {
1948 BOOST_ASSERT(lyx_view_);
1949 Buffer * buffer = lyx_view_->buffer();
1950 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1951 view()->cursor().recordUndoFullDocument();
1952 buffer->params().addLayoutModule(argument);
1953 updateLayout(oldClass, buffer);
1954 updateFlags = Update::Force | Update::FitCursor;
1958 case LFUN_TEXTCLASS_APPLY: {
1959 BOOST_ASSERT(lyx_view_);
1960 Buffer * buffer = lyx_view_->buffer();
1962 loadTextClass(argument);
1964 std::pair<bool, textclass_type> const tc_pair =
1965 textclasslist.numberOfClass(argument);
1970 textclass_type const old_class = buffer->params().getBaseClass();
1971 textclass_type const new_class = tc_pair.second;
1973 if (old_class == new_class)
1977 //Save the old, possibly modular, layout for use in conversion.
1978 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1979 view()->cursor().recordUndoFullDocument();
1980 buffer->params().setBaseClass(new_class);
1981 updateLayout(oldClass, buffer);
1982 updateFlags = Update::Force | Update::FitCursor;
1986 case LFUN_LAYOUT_RELOAD: {
1987 BOOST_ASSERT(lyx_view_);
1988 Buffer * buffer = lyx_view_->buffer();
1989 TextClassPtr oldClass = buffer->params().getTextClassPtr();
1990 textclass_type const tc = buffer->params().getBaseClass();
1991 textclasslist.reset(tc);
1992 buffer->params().setBaseClass(tc);
1993 updateLayout(oldClass, buffer);
1994 updateFlags = Update::Force | Update::FitCursor;
1998 case LFUN_TEXTCLASS_LOAD:
1999 loadTextClass(argument);
2002 case LFUN_LYXRC_APPLY: {
2003 LyXRC const lyxrc_orig = lyxrc;
2005 istringstream ss(argument);
2006 bool const success = lyxrc.read(ss) == 0;
2009 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
2010 << "Unable to read lyxrc data"
2015 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
2017 /// We force the redraw in any case because there might be
2018 /// some screen font changes.
2019 /// FIXME: only the current view will be updated. the Gui
2020 /// class is able to furnish the list of views.
2021 updateFlags = Update::Force;
2025 case LFUN_WINDOW_NEW:
2026 LyX::ref().newLyXView();
2029 case LFUN_WINDOW_CLOSE:
2030 BOOST_ASSERT(lyx_view_);
2031 BOOST_ASSERT(theApp());
2032 // update bookmark pit of the current buffer before window close
2033 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2034 gotoBookmark(i+1, false, false);
2035 // ask the user for saving changes or cancel quit
2036 if (!theBufferList().quitWriteAll())
2041 case LFUN_BOOKMARK_GOTO:
2042 // go to bookmark, open unopened file and switch to buffer if necessary
2043 gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
2046 case LFUN_BOOKMARK_CLEAR:
2047 LyX::ref().session().bookmarks().clear();
2050 case LFUN_TOOLBAR_TOGGLE: {
2051 BOOST_ASSERT(lyx_view_);
2052 string const name = cmd.getArg(0);
2053 bool const allowauto = cmd.getArg(1) == "allowauto";
2054 lyx_view_->toggleToolbarState(name, allowauto);
2055 ToolbarInfo * tbi = lyx_view_->getToolbarInfo(name);
2057 setMessage(bformat(_("Unknown toolbar \"%1$s\""),
2062 if (tbi->flags & ToolbarInfo::ON)
2064 else if (tbi->flags & ToolbarInfo::OFF)
2066 else if (tbi->flags & ToolbarInfo::AUTO)
2069 setMessage(bformat(_("Toolbar \"%1$s\" state set to %2$s"),
2070 _(tbi->gui_name), state));
2075 BOOST_ASSERT(lyx_view_);
2076 view()->cursor().dispatch(cmd);
2077 updateFlags = view()->cursor().result().update();
2078 if (!view()->cursor().result().dispatched())
2079 updateFlags = view()->dispatch(cmd);
2084 if (lyx_view_ && lyx_view_->buffer()) {
2085 // BufferView::update() updates the ViewMetricsInfo and
2086 // also initializes the position cache for all insets in
2087 // (at least partially) visible top-level paragraphs.
2088 // We will redraw the screen only if needed.
2089 view()->processUpdateFlags(updateFlags);
2090 lyx_view_->updateStatusBar();
2092 // if we executed a mutating lfun, mark the buffer as dirty
2094 && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
2095 && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
2096 lyx_view_->buffer()->markDirty();
2098 //Do we have a selection?
2099 theSelection().haveSelection(view()->cursor().selection());
2101 if (view()->cursor().inTexted()) {
2102 lyx_view_->updateLayoutChoice();
2106 if (!quitting && lyx_view_) {
2107 lyx_view_->updateToolbars();
2108 // Some messages may already be translated, so we cannot use _()
2109 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
2114 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
2116 const bool verbose = (cmd.origin == FuncRequest::MENU
2117 || cmd.origin == FuncRequest::TOOLBAR
2118 || cmd.origin == FuncRequest::COMMANDBUFFER);
2120 if (cmd.action == LFUN_SELF_INSERT || !verbose) {
2121 LYXERR(Debug::ACTION) << "dispatch msg is " << to_utf8(msg) << endl;
2123 lyx_view_->message(msg);
2127 docstring dispatch_msg = msg;
2128 if (!dispatch_msg.empty())
2129 dispatch_msg += ' ';
2131 docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
2133 bool argsadded = false;
2135 if (!cmd.argument().empty()) {
2136 if (cmd.action != LFUN_UNKNOWN_ACTION) {
2137 comname += ' ' + cmd.argument();
2142 docstring const shortcuts = theTopLevelKeymap().printBindings(cmd);
2144 if (!shortcuts.empty())
2145 comname += ": " + shortcuts;
2146 else if (!argsadded && !cmd.argument().empty())
2147 comname += ' ' + cmd.argument();
2149 if (!comname.empty()) {
2150 comname = rtrim(comname);
2151 dispatch_msg += '(' + rtrim(comname) + ')';
2154 LYXERR(Debug::ACTION) << "verbose dispatch msg "
2155 << to_utf8(dispatch_msg) << endl;
2156 if (!dispatch_msg.empty())
2157 lyx_view_->message(dispatch_msg);
2161 void LyXFunc::menuNew(string const & name, bool fromTemplate)
2163 // FIXME: initpath is not used. What to do?
2164 string initpath = lyxrc.document_path;
2165 string filename(name);
2167 if (lyx_view_->buffer()) {
2168 string const trypath = lyx_view_->buffer()->filePath();
2169 // If directory is writeable, use this as default.
2170 if (FileName(trypath).isDirWritable())
2174 static int newfile_number;
2176 if (filename.empty()) {
2177 filename = addName(lyxrc.document_path,
2178 "newfile" + convert<string>(++newfile_number) + ".lyx");
2179 while (theBufferList().exists(filename) ||
2180 FileName(filename).isReadable()) {
2182 filename = addName(lyxrc.document_path,
2183 "newfile" + convert<string>(newfile_number) +
2188 // The template stuff
2191 FileDialog dlg(_("Select template file"));
2192 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
2193 dlg.setButton1(_("Templates|#T#t"), from_utf8(lyxrc.template_path));
2195 FileDialog::Result result =
2196 dlg.open(from_utf8(lyxrc.template_path),
2197 FileFilterList(_("LyX Documents (*.lyx)")),
2200 if (result.first == FileDialog::Later)
2202 if (result.second.empty())
2204 templname = to_utf8(result.second);
2207 Buffer * const b = newFile(filename, templname, !name.empty());
2209 lyx_view_->setBuffer(b);
2213 void LyXFunc::open(string const & fname)
2215 string initpath = lyxrc.document_path;
2217 if (lyx_view_->buffer()) {
2218 string const trypath = lyx_view_->buffer()->filePath();
2219 // If directory is writeable, use this as default.
2220 if (FileName(trypath).isDirWritable())
2226 if (fname.empty()) {
2227 FileDialog dlg(_("Select document to open"), LFUN_FILE_OPEN);
2228 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
2229 dlg.setButton2(_("Examples|#E#e"),
2230 from_utf8(addPath(package().system_support().absFilename(), "examples")));
2232 FileDialog::Result result =
2233 dlg.open(from_utf8(initpath),
2234 FileFilterList(_("LyX Documents (*.lyx)")),
2237 if (result.first == FileDialog::Later)
2240 filename = to_utf8(result.second);
2242 // check selected filename
2243 if (filename.empty()) {
2244 lyx_view_->message(_("Canceled."));
2250 // get absolute path of file and add ".lyx" to the filename if
2252 FileName const fullname = fileSearch(string(), filename, "lyx");
2253 if (!fullname.empty())
2254 filename = fullname.absFilename();
2256 // if the file doesn't exist, let the user create one
2257 if (!fullname.exists()) {
2258 // the user specifically chose this name. Believe him.
2259 Buffer * const b = newFile(filename, string(), true);
2261 lyx_view_->setBuffer(b);
2265 docstring const disp_fn = makeDisplayPath(filename);
2266 lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
2269 Buffer * buf = lyx_view_->loadLyXFile(fullname);
2272 lyx_view_->setBuffer(buf);
2273 lyx_view_->showErrorList("Parse");
2274 str2 = bformat(_("Document %1$s opened."), disp_fn);
2276 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2278 lyx_view_->message(str2);
2282 void LyXFunc::doImport(string const & argument)
2285 string filename = split(argument, format, ' ');
2287 LYXERR(Debug::INFO) << "LyXFunc::doImport: " << format
2288 << " file: " << filename << endl;
2290 // need user interaction
2291 if (filename.empty()) {
2292 string initpath = lyxrc.document_path;
2294 if (lyx_view_->buffer()) {
2295 string const trypath = lyx_view_->buffer()->filePath();
2296 // If directory is writeable, use this as default.
2297 if (FileName(trypath).isDirWritable())
2301 docstring const text = bformat(_("Select %1$s file to import"),
2302 formats.prettyName(format));
2304 FileDialog dlg(text, LFUN_BUFFER_IMPORT);
2305 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
2306 dlg.setButton2(_("Examples|#E#e"),
2307 from_utf8(addPath(package().system_support().absFilename(), "examples")));
2309 docstring filter = formats.prettyName(format);
2312 filter += from_utf8(formats.extension(format));
2315 FileDialog::Result result =
2316 dlg.open(from_utf8(initpath),
2317 FileFilterList(filter),
2320 if (result.first == FileDialog::Later)
2323 filename = to_utf8(result.second);
2325 // check selected filename
2326 if (filename.empty())
2327 lyx_view_->message(_("Canceled."));
2330 if (filename.empty())
2333 // get absolute path of file
2334 FileName const fullname(makeAbsPath(filename));
2336 FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
2338 // Check if the document already is open
2339 if (use_gui && theBufferList().exists(lyxfile.absFilename())) {
2340 if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) {
2341 lyx_view_->message(_("Canceled."));
2346 // if the file exists already, and we didn't do
2347 // -i lyx thefile.lyx, warn
2348 if (lyxfile.exists() && fullname != lyxfile) {
2349 docstring const file = makeDisplayPath(lyxfile.absFilename(), 30);
2351 docstring text = bformat(_("The document %1$s already exists.\n\n"
2352 "Do you want to overwrite that document?"), file);
2353 int const ret = Alert::prompt(_("Overwrite document?"),
2354 text, 0, 1, _("&Overwrite"), _("&Cancel"));
2357 lyx_view_->message(_("Canceled."));
2362 ErrorList errorList;
2363 import(lyx_view_, fullname, format, errorList);
2364 // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2368 void LyXFunc::closeBuffer()
2370 // goto bookmark to update bookmark pit.
2371 for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2372 gotoBookmark(i+1, false, false);
2374 theBufferList().close(lyx_view_->buffer(), true);
2378 void LyXFunc::reloadBuffer()
2380 FileName filename(lyx_view_->buffer()->absFileName());
2381 docstring const disp_fn = makeDisplayPath(filename.absFilename());
2384 Buffer * buf = lyx_view_->loadLyXFile(filename);
2387 lyx_view_->setBuffer(buf);
2388 lyx_view_->showErrorList("Parse");
2389 str = bformat(_("Document %1$s reloaded."), disp_fn);
2391 str = bformat(_("Could not reload document %1$s"), disp_fn);
2393 lyx_view_->message(str);
2396 // Each "lyx_view_" should have it's own message method. lyxview and
2397 // the minibuffer would use the minibuffer, but lyxserver would
2398 // send an ERROR signal to its client. Alejandro 970603
2399 // This function is bit problematic when it comes to NLS, to make the
2400 // lyx servers client be language indepenent we must not translate
2401 // strings sent to this func.
2402 void LyXFunc::setErrorMessage(docstring const & m) const
2404 dispatch_buffer = m;
2409 void LyXFunc::setMessage(docstring const & m) const
2411 dispatch_buffer = m;
2415 docstring const LyXFunc::viewStatusMessage()
2417 // When meta-fake key is pressed, show the key sequence so far + "M-".
2419 return keyseq.print(KeySequence::ForGui) + "M-";
2421 // Else, when a non-complete key sequence is pressed,
2422 // show the available options.
2423 if (keyseq.length() > 0 && !keyseq.deleted())
2424 return keyseq.printOptions(true);
2426 BOOST_ASSERT(lyx_view_);
2427 if (!lyx_view_->buffer())
2428 return _("Welcome to LyX!");
2430 return view()->cursor().currentState();
2434 BufferView * LyXFunc::view() const
2436 BOOST_ASSERT(lyx_view_);
2437 return lyx_view_->view();
2441 bool LyXFunc::wasMetaKey() const
2443 return (meta_fake_bit != NoModifier);
2447 void LyXFunc::updateLayout(TextClassPtr const & oldlayout,
2450 lyx_view_->message(_("Converting document to new document class..."));
2452 StableDocIterator backcur(view()->cursor());
2453 ErrorList & el = buffer->errorList("Class Switch");
2454 cap::switchBetweenClasses(
2455 oldlayout, buffer->params().getTextClassPtr(),
2456 static_cast<InsetText &>(buffer->inset()), el);
2458 view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
2460 buffer->errors("Class Switch");
2461 updateLabels(*buffer);
2467 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2469 // Why the switch you might ask. It is a trick to ensure that all
2470 // the elements in the LyXRCTags enum is handled. As you can see
2471 // there are no breaks at all. So it is just a huge fall-through.
2472 // The nice thing is that we will get a warning from the compiler
2473 // if we forget an element.
2474 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2476 case LyXRC::RC_ACCEPT_COMPOUND:
2477 case LyXRC::RC_ALT_LANG:
2478 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
2479 case LyXRC::RC_PLAINTEXT_LINELEN:
2480 case LyXRC::RC_AUTOREGIONDELETE:
2481 case LyXRC::RC_AUTORESET_OPTIONS:
2482 case LyXRC::RC_AUTOSAVE:
2483 case LyXRC::RC_AUTO_NUMBER:
2484 case LyXRC::RC_BACKUPDIR_PATH:
2485 case LyXRC::RC_BIBTEX_COMMAND:
2486 case LyXRC::RC_BINDFILE:
2487 case LyXRC::RC_CHECKLASTFILES:
2488 case LyXRC::RC_USELASTFILEPOS:
2489 case LyXRC::RC_LOADSESSION:
2490 case LyXRC::RC_CHKTEX_COMMAND:
2491 case LyXRC::RC_CONVERTER:
2492 case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
2493 case LyXRC::RC_COPIER:
2494 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2495 case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2496 case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2497 case LyXRC::RC_DATE_INSERT_FORMAT:
2498 case LyXRC::RC_DEFAULT_LANGUAGE:
2499 case LyXRC::RC_DEFAULT_PAPERSIZE:
2500 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2501 case LyXRC::RC_DISPLAY_GRAPHICS:
2502 case LyXRC::RC_DOCUMENTPATH:
2503 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2504 FileName path(lyxrc_new.document_path);
2505 if (path.exists() && path.isDirectory())
2506 support::package().document_dir() = FileName(lyxrc.document_path);
2508 case LyXRC::RC_ESC_CHARS:
2509 case LyXRC::RC_FONT_ENCODING:
2510 case LyXRC::RC_FORMAT:
2511 case LyXRC::RC_INDEX_COMMAND:
2512 case LyXRC::RC_INPUT:
2513 case LyXRC::RC_KBMAP:
2514 case LyXRC::RC_KBMAP_PRIMARY:
2515 case LyXRC::RC_KBMAP_SECONDARY:
2516 case LyXRC::RC_LABEL_INIT_LENGTH:
2517 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2518 case LyXRC::RC_LANGUAGE_AUTO_END:
2519 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2520 case LyXRC::RC_LANGUAGE_COMMAND_END:
2521 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2522 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2523 case LyXRC::RC_LANGUAGE_PACKAGE:
2524 case LyXRC::RC_LANGUAGE_USE_BABEL:
2525 case LyXRC::RC_MAKE_BACKUP:
2526 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2527 case LyXRC::RC_NUMLASTFILES:
2528 case LyXRC::RC_PATH_PREFIX:
2529 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2530 support::prependEnvPath("PATH", lyxrc.path_prefix);
2532 case LyXRC::RC_PERS_DICT:
2533 case LyXRC::RC_PREVIEW:
2534 case LyXRC::RC_PREVIEW_HASHED_LABELS:
2535 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2536 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2537 case LyXRC::RC_PRINTCOPIESFLAG:
2538 case LyXRC::RC_PRINTER:
2539 case LyXRC::RC_PRINTEVENPAGEFLAG:
2540 case LyXRC::RC_PRINTEXSTRAOPTIONS:
2541 case LyXRC::RC_PRINTFILEEXTENSION:
2542 case LyXRC::RC_PRINTLANDSCAPEFLAG:
2543 case LyXRC::RC_PRINTODDPAGEFLAG:
2544 case LyXRC::RC_PRINTPAGERANGEFLAG:
2545 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2546 case LyXRC::RC_PRINTPAPERFLAG:
2547 case LyXRC::RC_PRINTREVERSEFLAG:
2548 case LyXRC::RC_PRINTSPOOL_COMMAND:
2549 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2550 case LyXRC::RC_PRINTTOFILE:
2551 case LyXRC::RC_PRINTTOPRINTER:
2552 case LyXRC::RC_PRINT_ADAPTOUTPUT:
2553 case LyXRC::RC_PRINT_COMMAND:
2554 case LyXRC::RC_RTL_SUPPORT:
2555 case LyXRC::RC_SCREEN_DPI:
2556 case LyXRC::RC_SCREEN_FONT_ROMAN:
2557 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2558 case LyXRC::RC_SCREEN_FONT_SANS:
2559 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2560 case LyXRC::RC_SCREEN_FONT_SCALABLE:
2561 case LyXRC::RC_SCREEN_FONT_SIZES:
2562 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2563 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2564 case LyXRC::RC_SCREEN_GEOMETRY_HEIGHT:
2565 case LyXRC::RC_SCREEN_GEOMETRY_WIDTH:
2566 case LyXRC::RC_SCREEN_GEOMETRY_XYSAVED:
2567 case LyXRC::RC_SCREEN_ZOOM:
2568 case LyXRC::RC_SERVERPIPE:
2569 case LyXRC::RC_SET_COLOR:
2570 case LyXRC::RC_SHOW_BANNER:
2571 case LyXRC::RC_SPELL_COMMAND:
2572 case LyXRC::RC_TEMPDIRPATH:
2573 case LyXRC::RC_TEMPLATEPATH:
2574 case LyXRC::RC_TEX_ALLOWS_SPACES:
2575 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2576 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2577 support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2579 case LyXRC::RC_UIFILE:
2580 case LyXRC::RC_USER_EMAIL:
2581 case LyXRC::RC_USER_NAME:
2582 case LyXRC::RC_USETEMPDIR:
2583 case LyXRC::RC_USE_ALT_LANG:
2584 case LyXRC::RC_USE_CONVERTER_CACHE:
2585 case LyXRC::RC_USE_ESC_CHARS:
2586 case LyXRC::RC_USE_INP_ENC:
2587 case LyXRC::RC_USE_PERS_DICT:
2588 case LyXRC::RC_USE_SPELL_LIB:
2589 case LyXRC::RC_VIEWDVI_PAPEROPTION:
2590 case LyXRC::RC_VIEWER:
2591 case LyXRC::RC_LAST: