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.
24 #include "LayoutFile.h"
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"
36 #include "DispatchResult.h"
38 #include "ErrorList.h"
40 #include "FuncRequest.h"
41 #include "FuncStatus.h"
42 #include "InsetIterator.h"
47 #include "LyXAction.h"
52 #include "Paragraph.h"
53 #include "ParagraphParameters.h"
54 #include "ParIterator.h"
58 #include "SpellChecker.h"
60 #include "insets/InsetBox.h"
61 #include "insets/InsetBranch.h"
62 #include "insets/InsetCommand.h"
63 #include "insets/InsetERT.h"
64 #include "insets/InsetExternal.h"
65 #include "insets/InsetFloat.h"
66 #include "insets/InsetGraphics.h"
67 #include "insets/InsetInclude.h"
68 #include "insets/InsetListings.h"
69 #include "insets/InsetNote.h"
70 #include "insets/InsetPhantom.h"
71 #include "insets/InsetSpace.h"
72 #include "insets/InsetTabular.h"
73 #include "insets/InsetVSpace.h"
74 #include "insets/InsetWrap.h"
76 #include "frontends/alert.h"
77 #include "frontends/Application.h"
78 #include "frontends/KeySymbol.h"
79 #include "frontends/LyXView.h"
80 #include "frontends/Selection.h"
82 #include "support/debug.h"
83 #include "support/environment.h"
84 #include "support/FileName.h"
85 #include "support/filetools.h"
86 #include "support/gettext.h"
87 #include "support/lstrings.h"
88 #include "support/Path.h"
89 #include "support/Package.h"
90 #include "support/Systemcall.h"
91 #include "support/convert.h"
92 #include "support/os.h"
98 using namespace lyx::support;
102 using frontend::LyXView;
104 namespace Alert = frontend::Alert;
109 // This function runs "configure" and then rereads lyx.defaults to
110 // reconfigure the automatic settings.
111 void reconfigure(LyXView * lv, string const & option)
113 // emit message signal.
115 lv->message(_("Running configure..."));
117 // Run configure in user lyx directory
118 PathChanger p(package().user_support());
119 string configure_command = package().configure_command();
120 configure_command += option;
122 int ret = one.startscript(Systemcall::Wait, configure_command);
124 // emit message signal.
126 lv->message(_("Reloading configuration..."));
127 lyxrc.read(libFileSearch(string(), "lyxrc.defaults"));
128 // Re-read packages.lst
129 LaTeXFeatures::getAvailable();
132 Alert::information(_("System reconfiguration failed"),
133 _("The system reconfiguration has failed.\n"
134 "Default textclass is used but LyX may "
135 "not be able to work properly.\n"
136 "Please reconfigure again if needed."));
139 Alert::information(_("System reconfigured"),
140 _("The system has been reconfigured.\n"
141 "You need to restart LyX to make use of any\n"
142 "updated document class specifications."));
146 bool getLocalStatus(Cursor cursor, FuncRequest const & cmd, FuncStatus & status)
148 // Try to fix cursor in case it is broken.
149 cursor.fixIfBroken();
151 // This is, of course, a mess. Better create a new doc iterator and use
152 // this in Inset::getStatus. This might require an additional
153 // BufferView * arg, though (which should be avoided)
154 //Cursor safe = *this;
156 for ( ; cursor.depth(); cursor.pop()) {
157 //lyxerr << "\nCursor::getStatus: cmd: " << cmd << endl << *this << endl;
158 LASSERT(cursor.idx() <= cursor.lastidx(), /**/);
159 LASSERT(cursor.pit() <= cursor.lastpit(), /**/);
160 LASSERT(cursor.pos() <= cursor.lastpos(), /**/);
162 // The inset's getStatus() will return 'true' if it made
163 // a definitive decision on whether it want to handle the
164 // request or not. The result of this decision is put into
165 // the 'status' parameter.
166 if (cursor.inset().getStatus(cursor, cmd, status)) {
175 /** Return the change status at cursor position, taking in account the
176 * status at each level of the document iterator (a table in a deleted
177 * footnote is deleted).
178 * When \param outer is true, the top slice is not looked at.
180 Change::Type lookupChangeType(DocIterator const & dit, bool outer = false)
182 size_t const depth = dit.depth() - (outer ? 1 : 0);
184 for (size_t i = 0 ; i < depth ; ++i) {
185 CursorSlice const & slice = dit[i];
186 if (!slice.inset().inMathed()
187 && slice.pos() < slice.paragraph().size()) {
188 Change::Type const ch = slice.paragraph().lookupChange(slice.pos()).type;
189 if (ch != Change::UNCHANGED)
193 return Change::UNCHANGED;
200 : lyx_view_(0), encoded_last_key(0), meta_fake_bit(NoModifier)
205 void LyXFunc::initKeySequences(KeyMap * kb)
207 keyseq = KeySequence(kb, kb);
208 cancel_meta_seq = KeySequence(kb, kb);
212 void LyXFunc::setLyXView(LyXView * lv)
214 if (lyx_view_ && lyx_view_->currentBufferView() && lyx_view_ != lv)
215 // save current selection to the selection buffer to allow
216 // middle-button paste in another window
217 cap::saveSelection(lyx_view_->currentBufferView()->cursor());
222 void LyXFunc::handleKeyFunc(FuncCode action)
224 char_type c = encoded_last_key;
229 LASSERT(lyx_view_ && lyx_view_->currentBufferView(), /**/);
230 BufferView * bv = lyx_view_->currentBufferView();
231 bv->getIntl().getTransManager().deadkey(
232 c, get_accent(action).accent, bv->cursor().innerText(),
234 // Need to clear, in case the minibuffer calls these
237 // copied verbatim from do_accent_char
238 bv->cursor().resetAnchor();
239 bv->processUpdateFlags(Update::FitCursor);
242 //FIXME: bookmark handling is a frontend issue. This code should be transferred
243 // to GuiView and be GuiView and be window dependent.
244 void LyXFunc::gotoBookmark(unsigned int idx, bool openFile, bool switchToBuffer)
246 LASSERT(lyx_view_, /**/);
247 if (!theSession().bookmarks().isValid(idx))
249 BookmarksSection::Bookmark const & bm = theSession().bookmarks().bookmark(idx);
250 LASSERT(!bm.filename.empty(), /**/);
251 string const file = bm.filename.absFilename();
252 // if the file is not opened, open it.
253 if (!theBufferList().exists(bm.filename)) {
255 dispatch(FuncRequest(LFUN_FILE_OPEN, file));
259 // open may fail, so we need to test it again
260 if (!theBufferList().exists(bm.filename))
263 // bm can be changed when saving
264 BookmarksSection::Bookmark tmp = bm;
266 // Special case idx == 0 used for back-from-back jump navigation
268 dispatch(FuncRequest(LFUN_BOOKMARK_SAVE, "0"));
270 // if the current buffer is not that one, switch to it.
271 if (!lyx_view_->documentBufferView()
272 || lyx_view_->documentBufferView()->buffer().fileName() != tmp.filename) {
275 dispatch(FuncRequest(LFUN_BUFFER_SWITCH, file));
278 // moveToPosition try paragraph id first and then paragraph (pit, pos).
279 if (!lyx_view_->documentBufferView()->moveToPosition(
280 tmp.bottom_pit, tmp.bottom_pos, tmp.top_id, tmp.top_pos))
287 // Cursor jump succeeded!
288 Cursor const & cur = lyx_view_->documentBufferView()->cursor();
289 pit_type new_pit = cur.pit();
290 pos_type new_pos = cur.pos();
291 int new_id = cur.paragraph().id();
293 // if bottom_pit, bottom_pos or top_id has been changed, update bookmark
294 // see http://bugzilla.lyx.org/show_bug.cgi?id=3092
295 if (bm.bottom_pit != new_pit || bm.bottom_pos != new_pos
296 || bm.top_id != new_id) {
297 const_cast<BookmarksSection::Bookmark &>(bm).updatePos(
298 new_pit, new_pos, new_id);
303 void LyXFunc::processKeySym(KeySymbol const & keysym, KeyModifier state)
305 LYXERR(Debug::KEY, "KeySym is " << keysym.getSymbolName());
307 // Do nothing if we have nothing (JMarc)
308 if (!keysym.isOK()) {
309 LYXERR(Debug::KEY, "Empty kbd action (probably composing)");
310 lyx_view_->restartCursor();
314 if (keysym.isModifier()) {
315 LYXERR(Debug::KEY, "isModifier true");
317 lyx_view_->restartCursor();
321 //Encoding const * encoding = lyx_view_->documentBufferView()->cursor().getEncoding();
322 //encoded_last_key = keysym.getISOEncoded(encoding ? encoding->name() : "");
323 // FIXME: encoded_last_key shadows the member variable of the same
324 // name. Is that intended?
325 char_type encoded_last_key = keysym.getUCSEncoded();
327 // Do a one-deep top-level lookup for
328 // cancel and meta-fake keys. RVDK_PATCH_5
329 cancel_meta_seq.reset();
331 FuncRequest func = cancel_meta_seq.addkey(keysym, state);
332 LYXERR(Debug::KEY, "action first set to [" << func.action << ']');
334 // When not cancel or meta-fake, do the normal lookup.
335 // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
336 // Mostly, meta_fake_bit = NoModifier. RVDK_PATCH_5.
337 if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_PREFIX)) {
338 // remove Caps Lock and Mod2 as a modifiers
339 func = keyseq.addkey(keysym, (state | meta_fake_bit));
340 LYXERR(Debug::KEY, "action now set to [" << func.action << ']');
343 // Dont remove this unless you know what you are doing.
344 meta_fake_bit = NoModifier;
346 // Can this happen now ?
347 if (func.action == LFUN_NOACTION)
348 func = FuncRequest(LFUN_COMMAND_PREFIX);
350 LYXERR(Debug::KEY, " Key [action=" << func.action << "]["
351 << keyseq.print(KeySequence::Portable) << ']');
353 // already here we know if it any point in going further
354 // why not return already here if action == -1 and
355 // num_bytes == 0? (Lgb)
357 if (keyseq.length() > 1)
358 lyx_view_->message(keyseq.print(KeySequence::ForGui));
361 // Maybe user can only reach the key via holding down shift.
362 // Let's see. But only if shift is the only modifier
363 if (func.action == LFUN_UNKNOWN_ACTION && state == ShiftModifier) {
364 LYXERR(Debug::KEY, "Trying without shift");
365 func = keyseq.addkey(keysym, NoModifier);
366 LYXERR(Debug::KEY, "Action now " << func.action);
369 if (func.action == LFUN_UNKNOWN_ACTION) {
370 // Hmm, we didn't match any of the keysequences. See
371 // if it's normal insertable text not already covered
373 if (keysym.isText() && keyseq.length() == 1) {
374 LYXERR(Debug::KEY, "isText() is true, inserting.");
375 func = FuncRequest(LFUN_SELF_INSERT,
376 FuncRequest::KEYBOARD);
378 LYXERR(Debug::KEY, "Unknown, !isText() - giving up");
379 lyx_view_->message(_("Unknown function."));
380 lyx_view_->restartCursor();
385 if (func.action == LFUN_SELF_INSERT) {
386 if (encoded_last_key != 0) {
387 docstring const arg(1, encoded_last_key);
388 dispatch(FuncRequest(LFUN_SELF_INSERT, arg,
389 FuncRequest::KEYBOARD));
390 LYXERR(Debug::KEY, "SelfInsert arg[`" << to_utf8(arg) << "']");
400 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
402 //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
405 /* In LyX/Mac, when a dialog is open, the menus of the
406 application can still be accessed without giving focus to
407 the main window. In this case, we want to disable the menu
408 entries that are buffer or view-related.
410 If this code is moved somewhere else (like in
411 GuiView::getStatus), then several functions will not be
414 frontend::LyXView * lv = 0;
417 && (cmd.origin != FuncRequest::MENU || lyx_view_->hasFocus())) {
419 if (lyx_view_->documentBufferView())
420 buf = &lyx_view_->documentBufferView()->buffer();
423 if (cmd.action == LFUN_NOACTION) {
424 flag.message(from_utf8(N_("Nothing to do")));
425 flag.setEnabled(false);
429 switch (cmd.action) {
430 case LFUN_UNKNOWN_ACTION:
432 flag.setEnabled(false);
439 if (flag.unknown()) {
440 flag.message(from_utf8(N_("Unknown action")));
444 if (!flag.enabled()) {
445 if (flag.message().empty())
446 flag.message(from_utf8(N_("Command disabled")));
450 // Check whether we need a buffer
451 if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
453 flag.message(from_utf8(N_("Command not allowed with"
454 "out any document open")));
455 flag.setEnabled(false);
459 // I would really like to avoid having this switch and rather try to
460 // encode this in the function itself.
461 // -- And I'd rather let an inset decide which LFUNs it is willing
462 // to handle (Andre')
464 switch (cmd.action) {
466 case LFUN_BUFFER_CHKTEX:
467 enable = buf->isLatex() && !lyxrc.chktex_command.empty();
470 case LFUN_BUILD_PROGRAM:
471 enable = buf->isExportable("program");
474 case LFUN_CITATION_INSERT: {
475 FuncRequest fr(LFUN_INSET_INSERT, "citation");
476 enable = getStatus(fr).enabled();
480 // This could be used for the no-GUI version. The GUI version is handled in
481 // LyXView::getStatus(). See above.
483 case LFUN_BUFFER_WRITE:
484 case LFUN_BUFFER_WRITE_AS: {
485 Buffer * b = theBufferList().getBuffer(FileName(cmd.getArg(0)));
486 enable = b && (b->isUnnamed() || !b->isClean());
491 case LFUN_BUFFER_WRITE_ALL: {
492 // We enable the command only if there are some modified buffers
493 Buffer * first = theBufferList().first();
498 // We cannot use a for loop as the buffer list is a cycle.
504 b = theBufferList().next(b);
505 } while (b != first);
509 case LFUN_BOOKMARK_GOTO: {
510 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
511 enable = theSession().bookmarks().isValid(num);
515 case LFUN_BOOKMARK_CLEAR:
516 enable = theSession().bookmarks().hasValid();
519 // this one is difficult to get right. As a half-baked
520 // solution, we consider only the first action of the sequence
521 case LFUN_COMMAND_SEQUENCE: {
522 // argument contains ';'-terminated commands
523 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
524 FuncRequest func(lyxaction.lookupFunc(firstcmd));
525 func.origin = cmd.origin;
526 flag = getStatus(func);
530 // we want to check if at least one of these is enabled
531 case LFUN_COMMAND_ALTERNATIVES: {
532 // argument contains ';'-terminated commands
533 string arg = to_utf8(cmd.argument());
534 while (!arg.empty()) {
536 arg = split(arg, first, ';');
537 FuncRequest func(lyxaction.lookupFunc(first));
538 func.origin = cmd.origin;
539 flag = getStatus(func);
540 // if this one is enabled, the whole thing is
549 string name = to_utf8(cmd.argument());
550 if (theTopLevelCmdDef().lock(name, func)) {
551 func.origin = cmd.origin;
552 flag = getStatus(func);
553 theTopLevelCmdDef().release(name);
555 // catch recursion or unknown command
556 // definition. all operations until the
557 // recursion or unknown command definition
558 // occurs are performed, so set the state to
565 case LFUN_MASTER_BUFFER_UPDATE:
566 case LFUN_MASTER_BUFFER_VIEW:
567 if (!buf->parent()) {
571 case LFUN_BUFFER_UPDATE:
572 case LFUN_BUFFER_VIEW: {
573 string format = to_utf8(cmd.argument());
574 if (cmd.argument().empty())
575 format = buf->getDefaultOutputFormat();
576 typedef vector<Format const *> Formats;
578 formats = buf->exportableFormats(true);
579 Formats::const_iterator fit = formats.begin();
580 Formats::const_iterator end = formats.end();
582 for (; fit != end ; ++fit) {
583 if ((*fit)->name() == format)
589 case LFUN_COMMAND_PREFIX:
591 case LFUN_META_PREFIX:
592 case LFUN_BUFFER_CLOSE:
593 case LFUN_BUFFER_IMPORT:
594 case LFUN_BUFFER_AUTO_SAVE:
595 case LFUN_RECONFIGURE:
597 case LFUN_DROP_LAYOUTS_CHOICE:
598 case LFUN_SERVER_GET_FILENAME:
599 case LFUN_SERVER_NOTIFY:
600 case LFUN_SERVER_GOTO_FILE_ROW:
601 case LFUN_BUFFER_CHILD_OPEN:
602 case LFUN_CURSOR_FOLLOWS_SCROLLBAR_TOGGLE:
603 case LFUN_KEYMAP_OFF:
604 case LFUN_KEYMAP_PRIMARY:
605 case LFUN_KEYMAP_SECONDARY:
606 case LFUN_KEYMAP_TOGGLE:
608 case LFUN_BUFFER_EXPORT_CUSTOM:
609 case LFUN_PREFERENCES_SAVE:
610 case LFUN_INSET_EDIT:
611 case LFUN_BUFFER_LANGUAGE:
612 case LFUN_TEXTCLASS_APPLY:
613 case LFUN_TEXTCLASS_LOAD:
614 case LFUN_BUFFER_SAVE_AS_DEFAULT:
615 case LFUN_BUFFER_PARAMS_APPLY:
616 case LFUN_LAYOUT_MODULES_CLEAR:
617 case LFUN_LAYOUT_MODULE_ADD:
618 case LFUN_LAYOUT_RELOAD:
619 case LFUN_LYXRC_APPLY:
620 // these are handled in our dispatch()
628 if (theApp()->getStatus(cmd, flag))
631 // Does the view know something?
636 if (lv->getStatus(cmd, flag))
639 BufferView * bv = lv->currentBufferView();
640 // If we do not have a BufferView, then other functions are disabled
645 // Is this a function that acts on inset at point?
646 Inset * inset = bv->cursor().nextInset();
647 if (lyxaction.funcHasFlag(cmd.action, LyXAction::AtPoint)
648 && inset && inset->getStatus(bv->cursor(), cmd, flag))
651 bool decided = getLocalStatus(bv->cursor(), cmd, flag);
653 // try the BufferView
654 decided = bv->getStatus(cmd, flag);
657 bv->buffer().getStatus(cmd, flag);
661 flag.setEnabled(false);
663 // Can we use a readonly buffer?
664 if (buf && buf->isReadonly()
665 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
666 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
667 flag.message(from_utf8(N_("Document is read-only")));
668 flag.setEnabled(false);
671 // Are we in a DELETED change-tracking region?
672 if (lyx_view_ && lyx_view_->documentBufferView()
673 && (lookupChangeType(lyx_view_->documentBufferView()->cursor(), true)
675 && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
676 && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
677 flag.message(from_utf8(N_("This portion of the document is deleted.")));
678 flag.setEnabled(false);
681 // the default error message if we disable the command
682 if (!flag.enabled() && flag.message().empty())
683 flag.message(from_utf8(N_("Command disabled")));
691 bool loadLayoutFile(string const & name, string const & buf_path)
693 if (!LayoutFileList::get().haveClass(name)) {
694 lyxerr << "Document class \"" << name
695 << "\" does not exist."
700 LayoutFile & tc = LayoutFileList::get()[name];
701 if (!tc.load(buf_path)) {
702 docstring s = bformat(_("The document class %1$s "
703 "could not be loaded."), from_utf8(name));
704 Alert::error(_("Could not load class"), s);
711 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
716 void LyXFunc::dispatch(FuncRequest const & cmd)
718 string const argument = to_utf8(cmd.argument());
719 FuncCode const action = cmd.action;
721 LYXERR(Debug::ACTION, "\nLyXFunc::dispatch: cmd: " << cmd);
722 //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
724 // we have not done anything wrong yet.
726 dispatch_buffer.erase();
728 // redraw the screen at the end (first of the two drawing steps).
729 //This is done unless explicitely requested otherwise
730 Update::flags updateFlags = Update::FitCursor;
732 FuncStatus const flag = getStatus(cmd);
733 if (!flag.enabled()) {
734 // We cannot use this function here
735 LYXERR(Debug::ACTION, "LyXFunc::dispatch: "
736 << lyxaction.getActionName(action)
737 << " [" << action << "] is disabled at this location");
738 setErrorMessage(flag.message());
740 lyx_view_->restartCursor();
743 if (lyx_view_ && lyx_view_->currentBufferView())
744 buffer = &lyx_view_->currentBufferView()->buffer();
747 case LFUN_COMMAND_PREFIX:
748 LASSERT(lyx_view_, /**/);
749 lyx_view_->message(keyseq.printOptions(true));
753 LASSERT(lyx_view_ && lyx_view_->currentBufferView(), /**/);
755 meta_fake_bit = NoModifier;
757 // cancel any selection
758 dispatch(FuncRequest(LFUN_MARK_OFF));
759 setMessage(from_ascii(N_("Cancel")));
762 case LFUN_META_PREFIX:
763 meta_fake_bit = AltModifier;
764 setMessage(keyseq.print(KeySequence::ForGui));
767 // --- Menus -----------------------------------------------
768 case LFUN_BUFFER_CLOSE:
769 lyx_view_->closeBuffer();
771 updateFlags = Update::None;
774 case LFUN_BUFFER_CLOSE_ALL:
775 lyx_view_->closeBufferAll();
777 updateFlags = Update::None;
780 case LFUN_BUFFER_UPDATE: {
781 LASSERT(lyx_view_ && lyx_view_->documentBufferView(), /**/);
782 Buffer & doc_buffer = lyx_view_->documentBufferView()->buffer();
783 string format = argument;
784 if (argument.empty())
785 format = doc_buffer.getDefaultOutputFormat();
786 doc_buffer.doExport(format, true);
790 case LFUN_BUFFER_VIEW: {
791 LASSERT(lyx_view_ && lyx_view_->documentBufferView(), /**/);
792 Buffer & doc_buffer = lyx_view_->documentBufferView()->buffer();
793 string format = argument;
794 if (argument.empty())
795 format = doc_buffer.getDefaultOutputFormat();
796 doc_buffer.preview(format);
800 case LFUN_MASTER_BUFFER_UPDATE: {
801 LASSERT(lyx_view_ && lyx_view_->documentBufferView(), /**/);
802 Buffer & doc_buffer = lyx_view_->documentBufferView()->buffer();
803 string format = argument;
804 if (argument.empty())
805 format = doc_buffer.masterBuffer()->getDefaultOutputFormat();
806 doc_buffer.masterBuffer()->doExport(format, true);
810 case LFUN_MASTER_BUFFER_VIEW: {
811 LASSERT(lyx_view_ && lyx_view_->documentBufferView(), /**/);
812 Buffer & doc_buffer = lyx_view_->documentBufferView()->buffer();
813 string format = argument;
814 if (argument.empty())
815 format = doc_buffer.masterBuffer()->getDefaultOutputFormat();
816 doc_buffer.masterBuffer()->preview(format);
820 case LFUN_BUILD_PROGRAM:
821 LASSERT(lyx_view_ && buffer, /**/);
822 buffer->doExport("program", true);
825 case LFUN_BUFFER_CHKTEX:
826 LASSERT(lyx_view_ && buffer, /**/);
830 case LFUN_BUFFER_EXPORT:
831 LASSERT(lyx_view_ && buffer, /**/);
832 if (argument == "custom")
833 dispatch(FuncRequest(LFUN_DIALOG_SHOW, "sendto"));
835 buffer->doExport(argument, false);
838 case LFUN_BUFFER_EXPORT_CUSTOM: {
839 LASSERT(lyx_view_ && buffer, /**/);
841 string command = split(argument, format_name, ' ');
842 Format const * format = formats.getFormat(format_name);
844 lyxerr << "Format \"" << format_name
845 << "\" not recognized!"
850 // The name of the file created by the conversion process
853 // Output to filename
854 if (format->name() == "lyx") {
855 string const latexname = buffer->latexName(false);
856 filename = changeExtension(latexname,
857 format->extension());
858 filename = addName(buffer->temppath(), filename);
860 if (!buffer->writeFile(FileName(filename)))
864 buffer->doExport(format_name, true, filename);
867 // Substitute $$FName for filename
868 if (!contains(command, "$$FName"))
869 command = "( " + command + " ) < $$FName";
870 command = subst(command, "$$FName", filename);
872 // Execute the command in the background
874 call.startscript(Systemcall::DontWait, command);
878 // FIXME: There is need for a command-line import.
880 case LFUN_BUFFER_IMPORT:
885 case LFUN_BUFFER_AUTO_SAVE:
889 case LFUN_RECONFIGURE:
890 // argument is any additional parameter to the configure.py command
891 reconfigure(lyx_view_, argument);
894 case LFUN_HELP_OPEN: {
896 theApp()->dispatch(FuncRequest(LFUN_WINDOW_NEW));
897 string const arg = argument;
899 setErrorMessage(from_utf8(N_("Missing argument")));
902 FileName fname = i18nLibFileSearch("doc", arg, "lyx");
904 fname = i18nLibFileSearch("examples", arg, "lyx");
907 lyxerr << "LyX: unable to find documentation file `"
908 << arg << "'. Bad installation?" << endl;
911 lyx_view_->message(bformat(_("Opening help file %1$s..."),
912 makeDisplayPath(fname.absFilename())));
913 Buffer * buf = lyx_view_->loadDocument(fname, false);
916 lyx_view_->setBuffer(buf);
917 buf->errors("Parse");
919 updateFlags = Update::None;
923 // --- lyxserver commands ----------------------------
924 case LFUN_SERVER_GET_FILENAME:
925 LASSERT(lyx_view_ && buffer, /**/);
926 setMessage(from_utf8(buffer->absFileName()));
927 LYXERR(Debug::INFO, "FNAME["
928 << buffer->absFileName() << ']');
931 case LFUN_SERVER_NOTIFY:
932 dispatch_buffer = keyseq.print(KeySequence::Portable);
933 theServer().notifyClient(to_utf8(dispatch_buffer));
936 case LFUN_SERVER_GOTO_FILE_ROW: {
937 LASSERT(lyx_view_, /**/);
940 istringstream is(argument);
941 is >> file_name >> row;
942 file_name = os::internal_path(file_name);
945 string const abstmp = package().temp_dir().absFilename();
946 string const realtmp = package().temp_dir().realPath();
947 // We have to use os::path_prefix_is() here, instead of
948 // simply prefixIs(), because the file name comes from
949 // an external application and may need case adjustment.
950 if (os::path_prefix_is(file_name, abstmp, os::CASE_ADJUSTED)
951 || os::path_prefix_is(file_name, realtmp, os::CASE_ADJUSTED)) {
952 // Needed by inverse dvi search. If it is a file
953 // in tmpdir, call the apropriated function.
954 // If tmpdir is a symlink, we may have the real
955 // path passed back, so we correct for that.
956 if (!prefixIs(file_name, abstmp))
957 file_name = subst(file_name, realtmp, abstmp);
958 buf = theBufferList().getBufferFromTmp(file_name);
960 // Must replace extension of the file to be .lyx
962 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
963 // Either change buffer or load the file
964 if (theBufferList().exists(s))
965 buf = theBufferList().getBuffer(s);
966 else if (s.exists()) {
967 buf = lyx_view_->loadDocument(s);
970 lyx_view_->message(bformat(
971 _("File does not exist: %1$s"),
972 makeDisplayPath(file_name)));
976 updateFlags = Update::None;
981 lyx_view_->setBuffer(buf);
982 lyx_view_->documentBufferView()->setCursorFromRow(row);
984 buf->errors("Parse");
985 updateFlags = Update::FitCursor;
990 case LFUN_DIALOG_SHOW_NEW_INSET: {
991 LASSERT(lyx_view_, /**/);
992 string const name = cmd.getArg(0);
993 InsetCode code = insetCode(name);
994 string data = trim(to_utf8(cmd.argument()).substr(name.size()));
995 bool insetCodeOK = true;
1002 case NOMENCL_PRINT_CODE:
1005 case HYPERLINK_CODE: {
1006 InsetCommandParams p(code);
1007 data = InsetCommand::params2string(name, p);
1010 case INCLUDE_CODE: {
1011 // data is the include type: one of "include",
1012 // "input", "verbatiminput" or "verbatiminput*"
1014 // default type is requested
1016 InsetCommandParams p(INCLUDE_CODE, data);
1017 data = InsetCommand::params2string("include", p);
1021 // \c data == "Boxed" || "Frameless" etc
1022 InsetBoxParams p(data);
1023 data = InsetBox::params2string(p);
1027 InsetBranchParams p;
1028 data = InsetBranch::params2string(p);
1032 InsetCommandParams p(CITE_CODE);
1033 data = InsetCommand::params2string(name, p);
1037 data = InsetERT::params2string(InsetCollapsable::Open);
1040 case EXTERNAL_CODE: {
1041 InsetExternalParams p;
1042 data = InsetExternal::params2string(p, *buffer);
1047 data = InsetFloat::params2string(p);
1050 case LISTINGS_CODE: {
1051 InsetListingsParams p;
1052 data = InsetListings::params2string(p);
1055 case GRAPHICS_CODE: {
1056 InsetGraphicsParams p;
1057 data = InsetGraphics::params2string(p, *buffer);
1062 data = InsetNote::params2string(p);
1065 case PHANTOM_CODE: {
1066 InsetPhantomParams p;
1067 data = InsetPhantom::params2string(p);
1072 data = InsetSpace::params2string(p);
1077 data = InsetVSpace::params2string(space);
1082 data = InsetWrap::params2string(p);
1086 lyxerr << "Inset type '" << name <<
1087 "' not recognized in LFUN_DIALOG_SHOW_NEW_INSET" << endl;
1088 insetCodeOK = false;
1090 } // end switch(code)
1092 dispatch(FuncRequest(LFUN_DIALOG_SHOW, name + " " + data));
1096 case LFUN_CITATION_INSERT: {
1097 LASSERT(lyx_view_, /**/);
1098 if (!argument.empty()) {
1099 // we can have one optional argument, delimited by '|'
1100 // citation-insert <key>|<text_before>
1101 // this should be enhanced to also support text_after
1102 // and citation style
1103 string arg = argument;
1105 if (contains(argument, "|")) {
1106 arg = token(argument, '|', 0);
1107 opt1 = token(argument, '|', 1);
1109 InsetCommandParams icp(CITE_CODE);
1110 icp["key"] = from_utf8(arg);
1112 icp["before"] = from_utf8(opt1);
1113 string icstr = InsetCommand::params2string("citation", icp);
1114 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1117 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1121 case LFUN_BUFFER_CHILD_OPEN: {
1122 LASSERT(lyx_view_ && buffer, /**/);
1123 FileName filename = makeAbsPath(argument, buffer->filePath());
1124 lyx_view_->documentBufferView()->saveBookmark(false);
1126 bool parsed = false;
1127 if (theBufferList().exists(filename)) {
1128 child = theBufferList().getBuffer(filename);
1130 setMessage(bformat(_("Opening child document %1$s..."),
1131 makeDisplayPath(filename.absFilename())));
1132 child = lyx_view_->loadDocument(filename, false);
1136 // Set the parent name of the child document.
1137 // This makes insertion of citations and references in the child work,
1138 // when the target is in the parent or another child document.
1139 child->setParent(buffer);
1140 child->masterBuffer()->updateLabels();
1141 lyx_view_->setBuffer(child);
1143 child->errors("Parse");
1146 // If a screen update is required (in case where auto_open is false),
1147 // setBuffer() would have taken care of it already. Otherwise we shall
1148 // reset the update flag because it can cause a circular problem.
1150 updateFlags = Update::None;
1154 case LFUN_CURSOR_FOLLOWS_SCROLLBAR_TOGGLE:
1155 LASSERT(lyx_view_, /**/);
1156 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1159 case LFUN_KEYMAP_OFF:
1160 LASSERT(lyx_view_ && lyx_view_->currentBufferView(), /**/);
1161 lyx_view_->currentBufferView()->getIntl().keyMapOn(false);
1164 case LFUN_KEYMAP_PRIMARY:
1165 LASSERT(lyx_view_ && lyx_view_->currentBufferView(), /**/);
1166 lyx_view_->currentBufferView()->getIntl().keyMapPrim();
1169 case LFUN_KEYMAP_SECONDARY:
1170 LASSERT(lyx_view_ && lyx_view_->currentBufferView(), /**/);
1171 lyx_view_->currentBufferView()->getIntl().keyMapSec();
1174 case LFUN_KEYMAP_TOGGLE:
1175 LASSERT(lyx_view_ && lyx_view_->currentBufferView(), /**/);
1176 lyx_view_->currentBufferView()->getIntl().toggleKeyMap();
1182 string rest = split(argument, countstr, ' ');
1183 istringstream is(countstr);
1186 //lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1187 for (int i = 0; i < count; ++i)
1188 dispatch(lyxaction.lookupFunc(rest));
1192 case LFUN_COMMAND_SEQUENCE: {
1193 // argument contains ';'-terminated commands
1194 string arg = argument;
1195 if (theBufferList().isLoaded(buffer))
1196 buffer->undo().beginUndoGroup();
1197 while (!arg.empty()) {
1199 arg = split(arg, first, ';');
1200 FuncRequest func(lyxaction.lookupFunc(first));
1201 func.origin = cmd.origin;
1204 if (theBufferList().isLoaded(buffer))
1205 buffer->undo().endUndoGroup();
1209 case LFUN_COMMAND_ALTERNATIVES: {
1210 // argument contains ';'-terminated commands
1211 string arg = argument;
1212 while (!arg.empty()) {
1214 arg = split(arg, first, ';');
1215 FuncRequest func(lyxaction.lookupFunc(first));
1216 func.origin = cmd.origin;
1217 FuncStatus stat = getStatus(func);
1218 if (stat.enabled()) {
1228 if (theTopLevelCmdDef().lock(argument, func)) {
1229 func.origin = cmd.origin;
1231 theTopLevelCmdDef().release(argument);
1233 if (func.action == LFUN_UNKNOWN_ACTION) {
1234 // unknown command definition
1235 lyxerr << "Warning: unknown command definition `"
1239 // recursion detected
1240 lyxerr << "Warning: Recursion in the command definition `"
1241 << argument << "' detected"
1248 case LFUN_PREFERENCES_SAVE: {
1249 lyxrc.write(makeAbsPath("preferences",
1250 package().user_support().absFilename()),
1255 case LFUN_BUFFER_LANGUAGE: {
1256 LASSERT(lyx_view_, /**/);
1257 Language const * oldL = buffer->params().language;
1258 Language const * newL = languages.getLanguage(argument);
1259 if (!newL || oldL == newL)
1262 if (oldL->rightToLeft() == newL->rightToLeft()
1263 && !buffer->isMultiLingual())
1264 buffer->changeLanguage(oldL, newL);
1268 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1269 string const fname =
1270 addName(addPath(package().user_support().absFilename(), "templates/"),
1272 Buffer defaults(fname);
1274 istringstream ss(argument);
1277 int const unknown_tokens = defaults.readHeader(lex);
1279 if (unknown_tokens != 0) {
1280 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1281 << unknown_tokens << " unknown token"
1282 << (unknown_tokens == 1 ? "" : "s")
1286 if (defaults.writeFile(FileName(defaults.absFileName())))
1287 setMessage(bformat(_("Document defaults saved in %1$s"),
1288 makeDisplayPath(fname)));
1290 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1294 case LFUN_BUFFER_PARAMS_APPLY: {
1295 LASSERT(lyx_view_, /**/);
1297 DocumentClass const * const oldClass = buffer->params().documentClassPtr();
1298 Cursor & cur = lyx_view_->documentBufferView()->cursor();
1299 cur.recordUndoFullDocument();
1301 istringstream ss(argument);
1304 int const unknown_tokens = buffer->readHeader(lex);
1306 if (unknown_tokens != 0) {
1307 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1308 << unknown_tokens << " unknown token"
1309 << (unknown_tokens == 1 ? "" : "s")
1313 updateLayout(oldClass, buffer);
1315 updateFlags = Update::Force | Update::FitCursor;
1316 // We are most certainly here because of a change in the document
1317 // It is then better to make sure that all dialogs are in sync with
1318 // current document settings. LyXView::restartCursor() achieve this.
1319 lyx_view_->restartCursor();
1323 case LFUN_LAYOUT_MODULES_CLEAR: {
1324 LASSERT(lyx_view_ && lyx_view_->documentBufferView(), /**/);
1325 DocumentClass const * const oldClass = buffer->params().documentClassPtr();
1326 lyx_view_->documentBufferView()->cursor().recordUndoFullDocument();
1327 buffer->params().clearLayoutModules();
1328 buffer->params().makeDocumentClass();
1329 updateLayout(oldClass, buffer);
1330 updateFlags = Update::Force | Update::FitCursor;
1334 case LFUN_LAYOUT_MODULE_ADD: {
1335 LASSERT(lyx_view_ && lyx_view_->documentBufferView(), /**/);
1336 BufferParams const & params = buffer->params();
1337 if (!params.moduleCanBeAdded(argument)) {
1338 LYXERR0("Module `" << argument <<
1339 "' cannot be added due to failed requirements or "
1340 "conflicts with installed modules.");
1343 DocumentClass const * const oldClass = params.documentClassPtr();
1344 lyx_view_->documentBufferView()->cursor().recordUndoFullDocument();
1345 buffer->params().addLayoutModule(argument);
1346 buffer->params().makeDocumentClass();
1347 updateLayout(oldClass, buffer);
1348 updateFlags = Update::Force | Update::FitCursor;
1352 case LFUN_TEXTCLASS_APPLY: {
1353 LASSERT(lyx_view_ && lyx_view_->documentBufferView(), /**/);
1355 if (!loadLayoutFile(argument, buffer->temppath()) &&
1356 !loadLayoutFile(argument, buffer->filePath()))
1359 LayoutFile const * old_layout = buffer->params().baseClass();
1360 LayoutFile const * new_layout = &(LayoutFileList::get()[argument]);
1362 if (old_layout == new_layout)
1366 //Save the old, possibly modular, layout for use in conversion.
1367 DocumentClass const * const oldDocClass =
1368 buffer->params().documentClassPtr();
1369 lyx_view_->documentBufferView()->cursor().recordUndoFullDocument();
1370 buffer->params().setBaseClass(argument);
1371 buffer->params().makeDocumentClass();
1372 updateLayout(oldDocClass, buffer);
1373 updateFlags = Update::Force | Update::FitCursor;
1377 case LFUN_LAYOUT_RELOAD: {
1378 LASSERT(lyx_view_, /**/);
1379 DocumentClass const * const oldClass = buffer->params().documentClassPtr();
1380 LayoutFileIndex bc = buffer->params().baseClassID();
1381 LayoutFileList::get().reset(bc);
1382 buffer->params().setBaseClass(bc);
1383 buffer->params().makeDocumentClass();
1384 updateLayout(oldClass, buffer);
1385 updateFlags = Update::Force | Update::FitCursor;
1389 case LFUN_TEXTCLASS_LOAD:
1390 loadLayoutFile(argument, buffer->temppath()) ||
1391 loadLayoutFile(argument, buffer->filePath());
1394 case LFUN_LYXRC_APPLY: {
1395 // reset active key sequences, since the bindings
1396 // are updated (bug 6064)
1398 LyXRC const lyxrc_orig = lyxrc;
1400 istringstream ss(argument);
1401 bool const success = lyxrc.read(ss) == 0;
1404 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1405 << "Unable to read lyxrc data"
1410 actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1414 theApp()->resetGui();
1416 /// We force the redraw in any case because there might be
1417 /// some screen font changes.
1418 /// FIXME: only the current view will be updated. the Gui
1419 /// class is able to furnish the list of views.
1420 updateFlags = Update::Force;
1424 case LFUN_BOOKMARK_GOTO:
1425 // go to bookmark, open unopened file and switch to buffer if necessary
1426 gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
1427 updateFlags = Update::FitCursor;
1430 case LFUN_BOOKMARK_CLEAR:
1431 theSession().bookmarks().clear();
1435 LASSERT(theApp(), /**/);
1436 // Let the frontend dispatch its own actions.
1437 if (theApp()->dispatch(cmd))
1438 // Nothing more to do.
1441 // Everything below is only for active lyx_view_
1445 // Start an undo group. This may be needed for
1446 // some stuff like inset-apply on labels.
1447 if (theBufferList().isLoaded(buffer))
1448 buffer->undo().beginUndoGroup();
1450 // Let the current LyXView dispatch its own actions.
1451 if (lyx_view_->dispatch(cmd)) {
1452 if (lyx_view_->currentBufferView()) {
1453 updateFlags = lyx_view_->currentBufferView()->cursor().result().update();
1454 if (theBufferList().isLoaded(buffer))
1455 buffer->undo().endUndoGroup();
1460 LASSERT(lyx_view_->currentBufferView(), /**/);
1462 // Let the current BufferView dispatch its own actions.
1463 if (lyx_view_->currentBufferView()->dispatch(cmd)) {
1464 // The BufferView took care of its own updates if needed.
1465 updateFlags = Update::None;
1466 if (theBufferList().isLoaded(buffer))
1467 buffer->undo().endUndoGroup();
1471 // OK, so try the Buffer itself
1473 BufferView * bv = lyx_view_->currentBufferView();
1474 bv->buffer().dispatch(cmd, dr);
1475 if (dr.dispatched()) {
1476 updateFlags = dr.update();
1480 // Is this a function that acts on inset at point?
1481 Inset * inset = bv->cursor().nextInset();
1482 if (lyxaction.funcHasFlag(action, LyXAction::AtPoint)
1484 bv->cursor().result().dispatched(true);
1485 bv->cursor().result().update(Update::FitCursor | Update::Force);
1486 FuncRequest tmpcmd = cmd;
1487 inset->dispatch(bv->cursor(), tmpcmd);
1488 if (bv->cursor().result().dispatched()) {
1489 updateFlags = bv->cursor().result().update();
1494 // Let the current Cursor dispatch its own actions.
1495 Cursor old = bv->cursor();
1496 bv->cursor().getPos(cursorPosBeforeDispatchX_,
1497 cursorPosBeforeDispatchY_);
1498 bv->cursor().dispatch(cmd);
1500 // notify insets we just left
1501 if (bv->cursor() != old) {
1503 bool badcursor = notifyCursorLeavesOrEnters(old, bv->cursor());
1505 bv->cursor().fixIfBroken();
1508 if (theBufferList().isLoaded(buffer))
1509 buffer->undo().endUndoGroup();
1511 // update completion. We do it here and not in
1512 // processKeySym to avoid another redraw just for a
1513 // changed inline completion
1514 if (cmd.origin == FuncRequest::KEYBOARD) {
1515 if (cmd.action == LFUN_SELF_INSERT
1516 || (cmd.action == LFUN_ERT_INSERT && bv->cursor().inMathed()))
1517 lyx_view_->updateCompletion(bv->cursor(), true, true);
1518 else if (cmd.action == LFUN_CHAR_DELETE_BACKWARD)
1519 lyx_view_->updateCompletion(bv->cursor(), false, true);
1521 lyx_view_->updateCompletion(bv->cursor(), false, false);
1524 updateFlags = bv->cursor().result().update();
1527 // if we executed a mutating lfun, mark the buffer as dirty
1528 if (theBufferList().isLoaded(buffer) && flag.enabled()
1529 && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
1530 && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
1531 buffer->markDirty();
1533 if (lyx_view_ && lyx_view_->currentBufferView()) {
1534 // BufferView::update() updates the ViewMetricsInfo and
1535 // also initializes the position cache for all insets in
1536 // (at least partially) visible top-level paragraphs.
1537 // We will redraw the screen only if needed.
1538 lyx_view_->currentBufferView()->processUpdateFlags(updateFlags);
1540 // Do we have a selection?
1541 theSelection().haveSelection(
1542 lyx_view_->currentBufferView()->cursor().selection());
1545 lyx_view_->restartCursor();
1549 // Some messages may already be translated, so we cannot use _()
1550 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
1555 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
1557 const bool verbose = (cmd.origin == FuncRequest::MENU
1558 || cmd.origin == FuncRequest::TOOLBAR
1559 || cmd.origin == FuncRequest::COMMANDBUFFER);
1561 if (cmd.action == LFUN_SELF_INSERT || !verbose) {
1562 LYXERR(Debug::ACTION, "dispatch msg is " << to_utf8(msg));
1564 lyx_view_->message(msg);
1568 docstring dispatch_msg = msg;
1569 if (!dispatch_msg.empty())
1570 dispatch_msg += ' ';
1572 docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
1574 bool argsadded = false;
1576 if (!cmd.argument().empty()) {
1577 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1578 comname += ' ' + cmd.argument();
1583 docstring const shortcuts = theTopLevelKeymap().printBindings(cmd, KeySequence::ForGui);
1585 if (!shortcuts.empty())
1586 comname += ": " + shortcuts;
1587 else if (!argsadded && !cmd.argument().empty())
1588 comname += ' ' + cmd.argument();
1590 if (!comname.empty()) {
1591 comname = rtrim(comname);
1592 dispatch_msg += '(' + rtrim(comname) + ')';
1595 LYXERR(Debug::ACTION, "verbose dispatch msg " << to_utf8(dispatch_msg));
1596 if (!dispatch_msg.empty())
1597 lyx_view_->message(dispatch_msg);
1601 // Each "lyx_view_" should have it's own message method. lyxview and
1602 // the minibuffer would use the minibuffer, but lyxserver would
1603 // send an ERROR signal to its client. Alejandro 970603
1604 // This function is bit problematic when it comes to NLS, to make the
1605 // lyx servers client be language indepenent we must not translate
1606 // strings sent to this func.
1607 void LyXFunc::setErrorMessage(docstring const & m) const
1609 dispatch_buffer = m;
1614 void LyXFunc::setMessage(docstring const & m) const
1616 dispatch_buffer = m;
1620 docstring LyXFunc::viewStatusMessage()
1622 // When meta-fake key is pressed, show the key sequence so far + "M-".
1624 return keyseq.print(KeySequence::ForGui) + "M-";
1626 // Else, when a non-complete key sequence is pressed,
1627 // show the available options.
1628 if (keyseq.length() > 0 && !keyseq.deleted())
1629 return keyseq.printOptions(true);
1631 LASSERT(lyx_view_, /**/);
1632 if (!lyx_view_->currentBufferView())
1633 return _("Welcome to LyX!");
1635 return lyx_view_->currentBufferView()->cursor().currentState();
1639 bool LyXFunc::wasMetaKey() const
1641 return (meta_fake_bit != NoModifier);
1645 void LyXFunc::updateLayout(DocumentClass const * const oldlayout, Buffer * buf)
1647 lyx_view_->message(_("Converting document to new document class..."));
1649 StableDocIterator backcur(lyx_view_->currentBufferView()->cursor());
1650 ErrorList & el = buf->errorList("Class Switch");
1651 cap::switchBetweenClasses(
1652 oldlayout, buf->params().documentClassPtr(),
1653 static_cast<InsetText &>(buf->inset()), el);
1655 lyx_view_->currentBufferView()->setCursor(backcur.asDocIterator(buf));
1657 buf->errors("Class Switch");
1658 buf->updateLabels();
1664 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
1666 // Why the switch you might ask. It is a trick to ensure that all
1667 // the elements in the LyXRCTags enum is handled. As you can see
1668 // there are no breaks at all. So it is just a huge fall-through.
1669 // The nice thing is that we will get a warning from the compiler
1670 // if we forget an element.
1671 LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
1673 case LyXRC::RC_ACCEPT_COMPOUND:
1674 case LyXRC::RC_ALT_LANG:
1675 case LyXRC::RC_PLAINTEXT_LINELEN:
1676 case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
1677 case LyXRC::RC_AUTOCORRECTION_MATH:
1678 case LyXRC::RC_AUTOREGIONDELETE:
1679 case LyXRC::RC_AUTORESET_OPTIONS:
1680 case LyXRC::RC_AUTOSAVE:
1681 case LyXRC::RC_AUTO_NUMBER:
1682 case LyXRC::RC_BACKUPDIR_PATH:
1683 case LyXRC::RC_BIBTEX_ALTERNATIVES:
1684 case LyXRC::RC_BIBTEX_COMMAND:
1685 case LyXRC::RC_BINDFILE:
1686 case LyXRC::RC_CHECKLASTFILES:
1687 case LyXRC::RC_COMPLETION_CURSOR_TEXT:
1688 case LyXRC::RC_COMPLETION_INLINE_DELAY:
1689 case LyXRC::RC_COMPLETION_INLINE_DOTS:
1690 case LyXRC::RC_COMPLETION_INLINE_MATH:
1691 case LyXRC::RC_COMPLETION_INLINE_TEXT:
1692 case LyXRC::RC_COMPLETION_POPUP_AFTER_COMPLETE:
1693 case LyXRC::RC_COMPLETION_POPUP_DELAY:
1694 case LyXRC::RC_COMPLETION_POPUP_MATH:
1695 case LyXRC::RC_COMPLETION_POPUP_TEXT:
1696 case LyXRC::RC_USELASTFILEPOS:
1697 case LyXRC::RC_LOADSESSION:
1698 case LyXRC::RC_CHKTEX_COMMAND:
1699 case LyXRC::RC_CONVERTER:
1700 case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
1701 case LyXRC::RC_COPIER:
1702 case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
1703 case LyXRC::RC_SCROLL_BELOW_DOCUMENT:
1704 case LyXRC::RC_DATE_INSERT_FORMAT:
1705 case LyXRC::RC_DEFAULT_LANGUAGE:
1706 case LyXRC::RC_GUI_LANGUAGE:
1707 case LyXRC::RC_DEFAULT_PAPERSIZE:
1708 case LyXRC::RC_DEFAULT_VIEW_FORMAT:
1709 case LyXRC::RC_DEFFILE:
1710 case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
1711 case LyXRC::RC_DISPLAY_GRAPHICS:
1712 case LyXRC::RC_DOCUMENTPATH:
1713 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
1714 FileName path(lyxrc_new.document_path);
1715 if (path.exists() && path.isDirectory())
1716 package().document_dir() = FileName(lyxrc.document_path);
1718 case LyXRC::RC_EDITOR_ALTERNATIVES:
1719 case LyXRC::RC_ESC_CHARS:
1720 case LyXRC::RC_EXAMPLEPATH:
1721 case LyXRC::RC_FONT_ENCODING:
1722 case LyXRC::RC_FORMAT:
1723 case LyXRC::RC_GROUP_LAYOUTS:
1724 case LyXRC::RC_HUNSPELLDIR_PATH:
1725 case LyXRC::RC_INDEX_ALTERNATIVES:
1726 case LyXRC::RC_INDEX_COMMAND:
1727 case LyXRC::RC_JBIBTEX_COMMAND:
1728 case LyXRC::RC_JINDEX_COMMAND:
1729 case LyXRC::RC_NOMENCL_COMMAND:
1730 case LyXRC::RC_INPUT:
1731 case LyXRC::RC_KBMAP:
1732 case LyXRC::RC_KBMAP_PRIMARY:
1733 case LyXRC::RC_KBMAP_SECONDARY:
1734 case LyXRC::RC_LABEL_INIT_LENGTH:
1735 case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
1736 case LyXRC::RC_LANGUAGE_AUTO_END:
1737 case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
1738 case LyXRC::RC_LANGUAGE_COMMAND_END:
1739 case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
1740 case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
1741 case LyXRC::RC_LANGUAGE_PACKAGE:
1742 case LyXRC::RC_LANGUAGE_USE_BABEL:
1743 case LyXRC::RC_MAC_LIKE_WORD_MOVEMENT:
1744 case LyXRC::RC_MACRO_EDIT_STYLE:
1745 case LyXRC::RC_MAKE_BACKUP:
1746 case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
1747 case LyXRC::RC_MOUSE_WHEEL_SPEED:
1748 case LyXRC::RC_NUMLASTFILES:
1749 case LyXRC::RC_PARAGRAPH_MARKERS:
1750 case LyXRC::RC_PATH_PREFIX:
1751 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
1752 prependEnvPath("PATH", lyxrc.path_prefix);
1754 case LyXRC::RC_PERS_DICT:
1755 case LyXRC::RC_PREVIEW:
1756 case LyXRC::RC_PREVIEW_HASHED_LABELS:
1757 case LyXRC::RC_PREVIEW_SCALE_FACTOR:
1758 case LyXRC::RC_PRINTCOLLCOPIESFLAG:
1759 case LyXRC::RC_PRINTCOPIESFLAG:
1760 case LyXRC::RC_PRINTER:
1761 case LyXRC::RC_PRINTEVENPAGEFLAG:
1762 case LyXRC::RC_PRINTEXSTRAOPTIONS:
1763 case LyXRC::RC_PRINTFILEEXTENSION:
1764 case LyXRC::RC_PRINTLANDSCAPEFLAG:
1765 case LyXRC::RC_PRINTODDPAGEFLAG:
1766 case LyXRC::RC_PRINTPAGERANGEFLAG:
1767 case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
1768 case LyXRC::RC_PRINTPAPERFLAG:
1769 case LyXRC::RC_PRINTREVERSEFLAG:
1770 case LyXRC::RC_PRINTSPOOL_COMMAND:
1771 case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
1772 case LyXRC::RC_PRINTTOFILE:
1773 case LyXRC::RC_PRINTTOPRINTER:
1774 case LyXRC::RC_PRINT_ADAPTOUTPUT:
1775 case LyXRC::RC_PRINT_COMMAND:
1776 case LyXRC::RC_RTL_SUPPORT:
1777 case LyXRC::RC_SCREEN_DPI:
1778 case LyXRC::RC_SCREEN_FONT_ROMAN:
1779 case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
1780 case LyXRC::RC_SCREEN_FONT_SANS:
1781 case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
1782 case LyXRC::RC_SCREEN_FONT_SCALABLE:
1783 case LyXRC::RC_SCREEN_FONT_SIZES:
1784 case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
1785 case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
1786 case LyXRC::RC_GEOMETRY_SESSION:
1787 case LyXRC::RC_SCREEN_ZOOM:
1788 case LyXRC::RC_SERVERPIPE:
1789 case LyXRC::RC_SET_COLOR:
1790 case LyXRC::RC_SHOW_BANNER:
1791 case LyXRC::RC_OPEN_BUFFERS_IN_TABS:
1792 case LyXRC::RC_SPELL_COMMAND:
1793 case LyXRC::RC_SPELLCHECKER:
1794 case LyXRC::RC_SPELLCHECK_CONTINUOUSLY:
1795 case LyXRC::RC_SPLITINDEX_COMMAND:
1796 case LyXRC::RC_TEMPDIRPATH:
1797 case LyXRC::RC_TEMPLATEPATH:
1798 case LyXRC::RC_TEX_ALLOWS_SPACES:
1799 case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
1800 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
1801 os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
1803 case LyXRC::RC_THESAURUSDIRPATH:
1804 case LyXRC::RC_UIFILE:
1805 case LyXRC::RC_USER_EMAIL:
1806 case LyXRC::RC_USER_NAME:
1807 case LyXRC::RC_USETEMPDIR:
1808 case LyXRC::RC_USE_ALT_LANG:
1809 case LyXRC::RC_USE_CONVERTER_CACHE:
1810 case LyXRC::RC_USE_ESC_CHARS:
1811 case LyXRC::RC_USE_INP_ENC:
1812 case LyXRC::RC_USE_PERS_DICT:
1813 case LyXRC::RC_USE_TOOLTIP:
1814 case LyXRC::RC_USE_PIXMAP_CACHE:
1815 case LyXRC::RC_USE_SPELL_LIB:
1816 case LyXRC::RC_VIEWDVI_PAPEROPTION:
1817 case LyXRC::RC_SORT_LAYOUTS:
1818 case LyXRC::RC_FULL_SCREEN_LIMIT:
1819 case LyXRC::RC_FULL_SCREEN_SCROLLBAR:
1820 case LyXRC::RC_FULL_SCREEN_MENUBAR:
1821 case LyXRC::RC_FULL_SCREEN_TABBAR:
1822 case LyXRC::RC_FULL_SCREEN_TOOLBARS:
1823 case LyXRC::RC_FULL_SCREEN_WIDTH:
1824 case LyXRC::RC_VISUAL_CURSOR:
1825 case LyXRC::RC_VIEWER:
1826 case LyXRC::RC_VIEWER_ALTERNATIVES:
1827 case LyXRC::RC_LAST: