]> git.lyx.org Git - lyx.git/blob - src/LyXFunc.cpp
Transfer LFUN_BUFFER_TOGGLE_READ_ONLY to Buffer.
[lyx.git] / src / LyXFunc.cpp
1 /**
2  * \file LyXFunc.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Alfredo Braunstein
7  * \author Lars Gullik Bjønnes
8  * \author Jean-Marc Lasgouttes
9  * \author Angus Leeming
10  * \author John Levon
11  * \author André Pönitz
12  * \author Allan Rae
13  * \author Dekel Tsur
14  * \author Martin Vermeer
15  * \author Jürgen Vigna
16  *
17  * Full author contact details are available in file CREDITS.
18  */
19
20 #include <config.h>
21
22 #include "LyXFunc.h"
23
24 #include "LayoutFile.h"
25 #include "BranchList.h"
26 #include "buffer_funcs.h"
27 #include "Buffer.h"
28 #include "BufferList.h"
29 #include "BufferParams.h"
30 #include "BufferView.h"
31 #include "CmdDef.h"
32 #include "Color.h"
33 #include "Converter.h"
34 #include "Cursor.h"
35 #include "CutAndPaste.h"
36 #include "DispatchResult.h"
37 #include "Encoding.h"
38 #include "ErrorList.h"
39 #include "Format.h"
40 #include "FuncRequest.h"
41 #include "FuncStatus.h"
42 #include "InsetIterator.h"
43 #include "Intl.h"
44 #include "KeyMap.h"
45 #include "Language.h"
46 #include "Lexer.h"
47 #include "LyXAction.h"
48 #include "lyxfind.h"
49 #include "LyX.h"
50 #include "LyXRC.h"
51 #include "LyXVC.h"
52 #include "Paragraph.h"
53 #include "ParagraphParameters.h"
54 #include "ParIterator.h"
55 #include "Row.h"
56 #include "Server.h"
57 #include "Session.h"
58 #include "SpellChecker.h"
59
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"
75
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"
81
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"
93
94 #include <sstream>
95 #include <vector>
96
97 using namespace std;
98 using namespace lyx::support;
99
100 namespace lyx {
101
102 using frontend::LyXView;
103
104 namespace Alert = frontend::Alert;
105
106 namespace {
107
108
109 // This function runs "configure" and then rereads lyx.defaults to
110 // reconfigure the automatic settings.
111 void reconfigure(LyXView * lv, string const & option)
112 {
113         // emit message signal.
114         if (lv)
115                 lv->message(_("Running configure..."));
116
117         // Run configure in user lyx directory
118         PathChanger p(package().user_support());
119         string configure_command = package().configure_command();
120         configure_command += option;
121         Systemcall one;
122         int ret = one.startscript(Systemcall::Wait, configure_command);
123         p.pop();
124         // emit message signal.
125         if (lv)
126                 lv->message(_("Reloading configuration..."));
127         lyxrc.read(libFileSearch(string(), "lyxrc.defaults"));
128         // Re-read packages.lst
129         LaTeXFeatures::getAvailable();
130
131         if (ret)
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."));
137         else
138
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."));
143 }
144
145
146 bool getLocalStatus(Cursor cursor, FuncRequest const & cmd, FuncStatus & status)
147 {
148         // Try to fix cursor in case it is broken.
149         cursor.fixIfBroken();
150
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;
155         bool res = false;
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(), /**/);
161
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)) {
167                         res = true;
168                         break;
169                 }
170         }
171         return res;
172 }
173
174
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.
179  */
180 Change::Type lookupChangeType(DocIterator const & dit, bool outer = false)
181 {
182         size_t const depth = dit.depth() - (outer ? 1 : 0);
183
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)
190                                 return ch;
191                 }
192         }
193         return Change::UNCHANGED;
194 }
195
196 }
197
198
199 LyXFunc::LyXFunc()
200         : lyx_view_(0), encoded_last_key(0), meta_fake_bit(NoModifier)
201 {
202 }
203
204
205 void LyXFunc::initKeySequences(KeyMap * kb)
206 {
207         keyseq = KeySequence(kb, kb);
208         cancel_meta_seq = KeySequence(kb, kb);
209 }
210
211
212 void LyXFunc::setLyXView(LyXView * lv)
213 {
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());
218         lyx_view_ = lv;
219 }
220
221
222 void LyXFunc::handleKeyFunc(FuncCode action)
223 {
224         char_type c = encoded_last_key;
225
226         if (keyseq.length())
227                 c = 0;
228
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(),
233                 bv->cursor());
234         // Need to clear, in case the minibuffer calls these
235         // actions
236         keyseq.clear();
237         // copied verbatim from do_accent_char
238         bv->cursor().resetAnchor();
239         bv->processUpdateFlags(Update::FitCursor);
240 }
241
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)
245 {
246         LASSERT(lyx_view_, /**/);
247         if (!theSession().bookmarks().isValid(idx))
248                 return;
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)) {
254                 if (openFile)
255                         dispatch(FuncRequest(LFUN_FILE_OPEN, file));
256                 else
257                         return;
258         }
259         // open may fail, so we need to test it again
260         if (!theBufferList().exists(bm.filename))
261                 return;
262
263         // bm can be changed when saving
264         BookmarksSection::Bookmark tmp = bm;
265
266         // Special case idx == 0 used for back-from-back jump navigation
267         if (idx == 0)
268                 dispatch(FuncRequest(LFUN_BOOKMARK_SAVE, "0"));
269
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) {
273                 if (!switchToBuffer)
274                         return;
275                 dispatch(FuncRequest(LFUN_BUFFER_SWITCH, file));
276         }
277
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))
281                 return;
282
283         // bm changed
284         if (idx == 0)
285                 return;
286
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();
292
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);
299         }
300 }
301
302
303 void LyXFunc::processKeySym(KeySymbol const & keysym, KeyModifier state)
304 {
305         LYXERR(Debug::KEY, "KeySym is " << keysym.getSymbolName());
306
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();
311                 return;
312         }
313
314         if (keysym.isModifier()) {
315                 LYXERR(Debug::KEY, "isModifier true");
316                 if (lyx_view_)
317                         lyx_view_->restartCursor();
318                 return;
319         }
320
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();
326
327         // Do a one-deep top-level lookup for
328         // cancel and meta-fake keys. RVDK_PATCH_5
329         cancel_meta_seq.reset();
330
331         FuncRequest func = cancel_meta_seq.addkey(keysym, state);
332         LYXERR(Debug::KEY, "action first set to [" << func.action << ']');
333
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 << ']');
341         }
342
343         // Dont remove this unless you know what you are doing.
344         meta_fake_bit = NoModifier;
345
346         // Can this happen now ?
347         if (func.action == LFUN_NOACTION)
348                 func = FuncRequest(LFUN_COMMAND_PREFIX);
349
350         LYXERR(Debug::KEY, " Key [action=" << func.action << "]["
351                 << keyseq.print(KeySequence::Portable) << ']');
352
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)
356
357         if (keyseq.length() > 1)
358                 lyx_view_->message(keyseq.print(KeySequence::ForGui));
359
360
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);
367         }
368
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
372                 // by a binding
373                 if (keysym.isText() && keyseq.length() == 1) {
374                         LYXERR(Debug::KEY, "isText() is true, inserting.");
375                         func = FuncRequest(LFUN_SELF_INSERT,
376                                            FuncRequest::KEYBOARD);
377                 } else {
378                         LYXERR(Debug::KEY, "Unknown, !isText() - giving up");
379                         lyx_view_->message(_("Unknown function."));
380                         lyx_view_->restartCursor();
381                         return;
382                 }
383         }
384
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) << "']");
391                 }
392         } else {
393                 dispatch(func);
394                 if (!lyx_view_)
395                         return;
396         }
397 }
398
399
400 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
401 {
402         //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
403         FuncStatus flag;
404
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.
409
410            If this code is moved somewhere else (like in
411            GuiView::getStatus), then several functions will not be
412            handled correctly.
413         */
414         frontend::LyXView * lv = 0;
415         Buffer * buf = 0;
416         if (lyx_view_ 
417             && (cmd.origin != FuncRequest::MENU || lyx_view_->hasFocus())) {
418                 lv = lyx_view_;
419                 if (lyx_view_->documentBufferView())
420                         buf = &lyx_view_->documentBufferView()->buffer();
421         }
422
423         if (cmd.action == LFUN_NOACTION) {
424                 flag.message(from_utf8(N_("Nothing to do")));
425                 flag.setEnabled(false);
426                 return flag;
427         }
428
429         switch (cmd.action) {
430         case LFUN_UNKNOWN_ACTION:
431                 flag.unknown(true);
432                 flag.setEnabled(false);
433                 break;
434
435         default:
436                 break;
437         }
438
439         if (flag.unknown()) {
440                 flag.message(from_utf8(N_("Unknown action")));
441                 return flag;
442         }
443
444         if (!flag.enabled()) {
445                 if (flag.message().empty())
446                         flag.message(from_utf8(N_("Command disabled")));
447                 return flag;
448         }
449
450         // Check whether we need a buffer
451         if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
452                 // no, exit directly
453                 flag.message(from_utf8(N_("Command not allowed with"
454                                     "out any document open")));
455                 flag.setEnabled(false);
456                 return flag;
457         }
458
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')
463         bool enable = true;
464         switch (cmd.action) {
465
466         case LFUN_BUFFER_CHKTEX:
467                 enable = buf->isLatex() && !lyxrc.chktex_command.empty();
468                 break;
469
470         case LFUN_BUILD_PROGRAM:
471                 enable = buf->isExportable("program");
472                 break;
473
474         case LFUN_CITATION_INSERT: {
475                 FuncRequest fr(LFUN_INSET_INSERT, "citation");
476                 enable = getStatus(fr).enabled();
477                 break;
478         }
479         
480         // This could be used for the no-GUI version. The GUI version is handled in
481         // LyXView::getStatus(). See above.
482         /*
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());
487                 break;
488         }
489         */
490
491         case LFUN_BUFFER_WRITE_ALL: {
492                 // We enable the command only if there are some modified buffers
493                 Buffer * first = theBufferList().first();
494                 enable = false;
495                 if (!first)
496                         break;
497                 Buffer * b = first;
498                 // We cannot use a for loop as the buffer list is a cycle.
499                 do {
500                         if (!b->isClean()) {
501                                 enable = true;
502                                 break;
503                         }
504                         b = theBufferList().next(b);
505                 } while (b != first); 
506                 break;
507         }
508
509         case LFUN_BOOKMARK_GOTO: {
510                 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
511                 enable = theSession().bookmarks().isValid(num);
512                 break;
513         }
514
515         case LFUN_BOOKMARK_CLEAR:
516                 enable = theSession().bookmarks().hasValid();
517                 break;
518
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);
527                 break;
528         }
529
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()) {
535                         string first;
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
541                         if (flag.enabled())
542                                 break;
543                 }
544                 break;
545         }
546
547         case LFUN_CALL: {
548                 FuncRequest func;
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);
554                 } else {
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
559                         // enabled
560                         enable = true;
561                 }
562                 break;
563         }
564
565         case LFUN_MASTER_BUFFER_UPDATE:
566         case LFUN_MASTER_BUFFER_VIEW: 
567                 if (!buf->parent()) {
568                         enable = false;
569                         break;
570                 }
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;
577                 Formats formats;
578                 formats = buf->exportableFormats(true);
579                 Formats::const_iterator fit = formats.begin();
580                 Formats::const_iterator end = formats.end();
581                 enable = false;
582                 for (; fit != end ; ++fit) {
583                         if ((*fit)->name() == format)
584                                 enable = true;
585                 }
586                 break;
587         }
588
589         case LFUN_COMMAND_PREFIX:
590         case LFUN_CANCEL:
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:
596         case LFUN_HELP_OPEN:
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:
607         case LFUN_REPEAT:
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()
621                 break;
622
623         default:
624                 if (!theApp()) {
625                         enable = false;
626                         break;
627                 }
628                 if (theApp()->getStatus(cmd, flag))
629                         break;
630
631                 // Does the view know something?
632                 if (!lv) {
633                         enable = false;
634                         break;
635                 }
636                 if (lv->getStatus(cmd, flag))
637                         break;
638
639                 BufferView * bv = lv->currentBufferView();
640                 // If we do not have a BufferView, then other functions are disabled
641                 if (!bv) {
642                         enable = false;
643                         break;
644                 }
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))
649                         break;
650
651                 bool decided = getLocalStatus(bv->cursor(), cmd, flag);
652                 if (!decided)
653                         // try the BufferView
654                         decided = bv->getStatus(cmd, flag);
655                 if (!decided)
656                         // try the Buffer
657                         bv->buffer().getStatus(cmd, flag);
658         }
659
660         if (!enable)
661                 flag.setEnabled(false);
662
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);
669         }
670
671         // Are we in a DELETED change-tracking region?
672         if (lyx_view_ && lyx_view_->documentBufferView()
673                 && (lookupChangeType(lyx_view_->documentBufferView()->cursor(), true)
674                     == Change::DELETED)
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);
679         }
680
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")));
684
685         return flag;
686 }
687
688
689 namespace {
690
691 bool loadLayoutFile(string const & name, string const & buf_path)
692 {
693         if (!LayoutFileList::get().haveClass(name)) {
694                 lyxerr << "Document class \"" << name
695                        << "\" does not exist."
696                        << endl;
697                 return false;
698         }
699
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);
705                 return false;
706         }
707         return true;
708 }
709
710
711 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
712
713 } //namespace anon
714
715
716 void LyXFunc::dispatch(FuncRequest const & cmd)
717 {
718         string const argument = to_utf8(cmd.argument());
719         FuncCode const action = cmd.action;
720
721         LYXERR(Debug::ACTION, "\nLyXFunc::dispatch: cmd: " << cmd);
722         //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
723
724         // we have not done anything wrong yet.
725         errorstat = false;
726         dispatch_buffer.erase();
727
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;
731
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());
739                 if (lyx_view_)
740                         lyx_view_->restartCursor();
741         } else {
742                 Buffer * buffer = 0;
743                 if (lyx_view_ && lyx_view_->currentBufferView())
744                         buffer = &lyx_view_->currentBufferView()->buffer();
745                 switch (action) {
746
747                 case LFUN_COMMAND_PREFIX:
748                         LASSERT(lyx_view_, /**/);
749                         lyx_view_->message(keyseq.printOptions(true));
750                         break;
751
752                 case LFUN_CANCEL:
753                         LASSERT(lyx_view_ && lyx_view_->currentBufferView(), /**/);
754                         keyseq.reset();
755                         meta_fake_bit = NoModifier;
756                         if (buffer)
757                                 // cancel any selection
758                                 dispatch(FuncRequest(LFUN_MARK_OFF));
759                         setMessage(from_ascii(N_("Cancel")));
760                         break;
761
762                 case LFUN_META_PREFIX:
763                         meta_fake_bit = AltModifier;
764                         setMessage(keyseq.print(KeySequence::ForGui));
765                         break;
766
767                 // --- Menus -----------------------------------------------
768                 case LFUN_BUFFER_CLOSE:
769                         lyx_view_->closeBuffer();
770                         buffer = 0;
771                         updateFlags = Update::None;
772                         break;
773
774                 case LFUN_BUFFER_CLOSE_ALL:
775                         lyx_view_->closeBufferAll();
776                         buffer = 0;
777                         updateFlags = Update::None;
778                         break;
779
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);
787                         break;
788                 }
789
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);
797                         break;
798                 }
799
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);
807                         break;
808                 }
809
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);
817                         break;
818                 }
819
820                 case LFUN_BUILD_PROGRAM:
821                         LASSERT(lyx_view_ && buffer, /**/);
822                         buffer->doExport("program", true);
823                         break;
824
825                 case LFUN_BUFFER_CHKTEX:
826                         LASSERT(lyx_view_ && buffer, /**/);
827                         buffer->runChktex();
828                         break;
829
830                 case LFUN_BUFFER_EXPORT:
831                         LASSERT(lyx_view_ && buffer, /**/);
832                         if (argument == "custom")
833                                 dispatch(FuncRequest(LFUN_DIALOG_SHOW, "sendto"));
834                         else
835                                 buffer->doExport(argument, false);
836                         break;
837
838                 case LFUN_BUFFER_EXPORT_CUSTOM: {
839                         LASSERT(lyx_view_ && buffer, /**/);
840                         string format_name;
841                         string command = split(argument, format_name, ' ');
842                         Format const * format = formats.getFormat(format_name);
843                         if (!format) {
844                                 lyxerr << "Format \"" << format_name
845                                        << "\" not recognized!"
846                                        << endl;
847                                 break;
848                         }
849
850                         // The name of the file created by the conversion process
851                         string filename;
852
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);
859
860                                 if (!buffer->writeFile(FileName(filename)))
861                                         break;
862
863                         } else {
864                                 buffer->doExport(format_name, true, filename);
865                         }
866
867                         // Substitute $$FName for filename
868                         if (!contains(command, "$$FName"))
869                                 command = "( " + command + " ) < $$FName";
870                         command = subst(command, "$$FName", filename);
871
872                         // Execute the command in the background
873                         Systemcall call;
874                         call.startscript(Systemcall::DontWait, command);
875                         break;
876                 }
877
878                 // FIXME: There is need for a command-line import.
879                 /*
880                 case LFUN_BUFFER_IMPORT:
881                         doImport(argument);
882                         break;
883                 */
884
885                 case LFUN_BUFFER_AUTO_SAVE:
886                         buffer->autoSave();
887                         break;
888
889                 case LFUN_RECONFIGURE:
890                         // argument is any additional parameter to the configure.py command
891                         reconfigure(lyx_view_, argument);
892                         break;
893
894                 case LFUN_HELP_OPEN: {
895                         if (lyx_view_ == 0)
896                                 theApp()->dispatch(FuncRequest(LFUN_WINDOW_NEW));
897                         string const arg = argument;
898                         if (arg.empty()) {
899                                 setErrorMessage(from_utf8(N_("Missing argument")));
900                                 break;
901                         }
902                         FileName fname = i18nLibFileSearch("doc", arg, "lyx");
903                         if (fname.empty()) 
904                                 fname = i18nLibFileSearch("examples", arg, "lyx");
905
906                         if (fname.empty()) {
907                                 lyxerr << "LyX: unable to find documentation file `"
908                                                          << arg << "'. Bad installation?" << endl;
909                                 break;
910                         }
911                         lyx_view_->message(bformat(_("Opening help file %1$s..."),
912                                 makeDisplayPath(fname.absFilename())));
913                         Buffer * buf = lyx_view_->loadDocument(fname, false);
914                         if (buf) {
915                                 buf->updateLabels();
916                                 lyx_view_->setBuffer(buf);
917                                 buf->errors("Parse");
918                         }
919                         updateFlags = Update::None;
920                         break;
921                 }
922
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() << ']');
929                         break;
930
931                 case LFUN_SERVER_NOTIFY:
932                         dispatch_buffer = keyseq.print(KeySequence::Portable);
933                         theServer().notifyClient(to_utf8(dispatch_buffer));
934                         break;
935
936                 case LFUN_SERVER_GOTO_FILE_ROW: {
937                         LASSERT(lyx_view_, /**/);
938                         string file_name;
939                         int row;
940                         istringstream is(argument);
941                         is >> file_name >> row;
942                         file_name = os::internal_path(file_name);
943                         Buffer * buf = 0;
944                         bool loaded = false;
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);
959                         } else {
960                                 // Must replace extension of the file to be .lyx
961                                 // and get full path
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);
968                                         loaded = true;
969                                 } else
970                                         lyx_view_->message(bformat(
971                                                 _("File does not exist: %1$s"),
972                                                 makeDisplayPath(file_name)));
973                         }
974
975                         if (!buf) {
976                                 updateFlags = Update::None;
977                                 break;
978                         }
979
980                         buf->updateLabels();
981                         lyx_view_->setBuffer(buf);
982                         lyx_view_->documentBufferView()->setCursorFromRow(row);
983                         if (loaded)
984                                 buf->errors("Parse");
985                         updateFlags = Update::FitCursor;
986                         break;
987                 }
988
989
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;
996                         switch (code) {
997                         case BIBITEM_CODE:
998                         case BIBTEX_CODE:
999                         case INDEX_CODE:
1000                         case LABEL_CODE:
1001                         case NOMENCL_CODE:
1002                         case NOMENCL_PRINT_CODE:
1003                         case REF_CODE:
1004                         case TOC_CODE:
1005                         case HYPERLINK_CODE: {
1006                                 InsetCommandParams p(code);
1007                                 data = InsetCommand::params2string(name, p);
1008                                 break;
1009                         }
1010                         case INCLUDE_CODE: {
1011                                 // data is the include type: one of "include",
1012                                 // "input", "verbatiminput" or "verbatiminput*"
1013                                 if (data.empty())
1014                                         // default type is requested
1015                                         data = "include";
1016                                 InsetCommandParams p(INCLUDE_CODE, data);
1017                                 data = InsetCommand::params2string("include", p);
1018                                 break;
1019                         }
1020                         case BOX_CODE: {
1021                                 // \c data == "Boxed" || "Frameless" etc
1022                                 InsetBoxParams p(data);
1023                                 data = InsetBox::params2string(p);
1024                                 break;
1025                         }
1026                         case BRANCH_CODE: {
1027                                 InsetBranchParams p;
1028                                 data = InsetBranch::params2string(p);
1029                                 break;
1030                         }
1031                         case CITE_CODE: {
1032                                 InsetCommandParams p(CITE_CODE);
1033                                 data = InsetCommand::params2string(name, p);
1034                                 break;
1035                         }
1036                         case ERT_CODE: {
1037                                 data = InsetERT::params2string(InsetCollapsable::Open);
1038                                 break;
1039                         }
1040                         case EXTERNAL_CODE: {
1041                                 InsetExternalParams p;
1042                                 data = InsetExternal::params2string(p, *buffer);
1043                                 break;
1044                         }
1045                         case FLOAT_CODE:  {
1046                                 InsetFloatParams p;
1047                                 data = InsetFloat::params2string(p);
1048                                 break;
1049                         }
1050                         case LISTINGS_CODE: {
1051                                 InsetListingsParams p;
1052                                 data = InsetListings::params2string(p);
1053                                 break;
1054                         }
1055                         case GRAPHICS_CODE: {
1056                                 InsetGraphicsParams p;
1057                                 data = InsetGraphics::params2string(p, *buffer);
1058                                 break;
1059                         }
1060                         case NOTE_CODE: {
1061                                 InsetNoteParams p;
1062                                 data = InsetNote::params2string(p);
1063                                 break;
1064                         }
1065                         case PHANTOM_CODE: {
1066                                 InsetPhantomParams p;
1067                                 data = InsetPhantom::params2string(p);
1068                                 break;
1069                         }
1070                         case SPACE_CODE: {
1071                                 InsetSpaceParams p;
1072                                 data = InsetSpace::params2string(p);
1073                                 break;
1074                         }
1075                         case VSPACE_CODE: {
1076                                 VSpace space;
1077                                 data = InsetVSpace::params2string(space);
1078                                 break;
1079                         }
1080                         case WRAP_CODE: {
1081                                 InsetWrapParams p;
1082                                 data = InsetWrap::params2string(p);
1083                                 break;
1084                         }
1085                         default:
1086                                 lyxerr << "Inset type '" << name << 
1087                                         "' not recognized in LFUN_DIALOG_SHOW_NEW_INSET" <<  endl;
1088                                 insetCodeOK = false;
1089                                 break;
1090                         } // end switch(code)
1091                         if (insetCodeOK)
1092                                 dispatch(FuncRequest(LFUN_DIALOG_SHOW, name + " " + data));
1093                         break;
1094                 }
1095
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;
1104                                 string opt1;
1105                                 if (contains(argument, "|")) {
1106                                         arg = token(argument, '|', 0);
1107                                         opt1 = token(argument, '|', 1);
1108                                 }
1109                                 InsetCommandParams icp(CITE_CODE);
1110                                 icp["key"] = from_utf8(arg);
1111                                 if (!opt1.empty())
1112                                         icp["before"] = from_utf8(opt1);
1113                                 string icstr = InsetCommand::params2string("citation", icp);
1114                                 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1115                                 dispatch(fr);
1116                         } else
1117                                 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1118                         break;
1119                 }
1120
1121                 case LFUN_BUFFER_CHILD_OPEN: {
1122                         LASSERT(lyx_view_ && buffer, /**/);
1123                         FileName filename = makeAbsPath(argument, buffer->filePath());
1124                         lyx_view_->documentBufferView()->saveBookmark(false);
1125                         Buffer * child = 0;
1126                         bool parsed = false;
1127                         if (theBufferList().exists(filename)) {
1128                                 child = theBufferList().getBuffer(filename);
1129                         } else {
1130                                 setMessage(bformat(_("Opening child document %1$s..."),
1131                                         makeDisplayPath(filename.absFilename())));
1132                                 child = lyx_view_->loadDocument(filename, false);
1133                                 parsed = true;
1134                         }
1135                         if (child) {
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);
1142                                 if (parsed)
1143                                         child->errors("Parse");
1144                         }
1145
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.
1149                         // See bug 3970.
1150                         updateFlags = Update::None;
1151                         break;
1152                 }
1153
1154                 case LFUN_CURSOR_FOLLOWS_SCROLLBAR_TOGGLE:
1155                         LASSERT(lyx_view_, /**/);
1156                         lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1157                         break;
1158
1159                 case LFUN_KEYMAP_OFF:
1160                         LASSERT(lyx_view_ && lyx_view_->currentBufferView(), /**/);
1161                         lyx_view_->currentBufferView()->getIntl().keyMapOn(false);
1162                         break;
1163
1164                 case LFUN_KEYMAP_PRIMARY:
1165                         LASSERT(lyx_view_ && lyx_view_->currentBufferView(), /**/);
1166                         lyx_view_->currentBufferView()->getIntl().keyMapPrim();
1167                         break;
1168
1169                 case LFUN_KEYMAP_SECONDARY:
1170                         LASSERT(lyx_view_ && lyx_view_->currentBufferView(), /**/);
1171                         lyx_view_->currentBufferView()->getIntl().keyMapSec();
1172                         break;
1173
1174                 case LFUN_KEYMAP_TOGGLE:
1175                         LASSERT(lyx_view_ && lyx_view_->currentBufferView(), /**/);
1176                         lyx_view_->currentBufferView()->getIntl().toggleKeyMap();
1177                         break;
1178
1179                 case LFUN_REPEAT: {
1180                         // repeat command
1181                         string countstr;
1182                         string rest = split(argument, countstr, ' ');
1183                         istringstream is(countstr);
1184                         int count = 0;
1185                         is >> count;
1186                         //lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1187                         for (int i = 0; i < count; ++i)
1188                                 dispatch(lyxaction.lookupFunc(rest));
1189                         break;
1190                 }
1191
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()) {
1198                                 string first;
1199                                 arg = split(arg, first, ';');
1200                                 FuncRequest func(lyxaction.lookupFunc(first));
1201                                 func.origin = cmd.origin;
1202                                 dispatch(func);
1203                         }
1204                         if (theBufferList().isLoaded(buffer))
1205                                 buffer->undo().endUndoGroup();
1206                         break;
1207                 }
1208
1209                 case LFUN_COMMAND_ALTERNATIVES: {
1210                         // argument contains ';'-terminated commands
1211                         string arg = argument;
1212                         while (!arg.empty()) {
1213                                 string first;
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()) {
1219                                         dispatch(func);
1220                                         break;
1221                                 }
1222                         }
1223                         break;
1224                 }
1225
1226                 case LFUN_CALL: {
1227                         FuncRequest func;
1228                         if (theTopLevelCmdDef().lock(argument, func)) {
1229                                 func.origin = cmd.origin;
1230                                 dispatch(func);
1231                                 theTopLevelCmdDef().release(argument);
1232                         } else {
1233                                 if (func.action == LFUN_UNKNOWN_ACTION) {
1234                                         // unknown command definition
1235                                         lyxerr << "Warning: unknown command definition `"
1236                                                    << argument << "'"
1237                                                    << endl;
1238                                 } else {
1239                                         // recursion detected
1240                                         lyxerr << "Warning: Recursion in the command definition `"
1241                                                    << argument << "' detected"
1242                                                    << endl;
1243                                 }
1244                         }
1245                         break;
1246                 }
1247
1248                 case LFUN_PREFERENCES_SAVE: {
1249                         lyxrc.write(makeAbsPath("preferences",
1250                                                 package().user_support().absFilename()),
1251                                     false);
1252                         break;
1253                 }
1254
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)
1260                                 break;
1261
1262                         if (oldL->rightToLeft() == newL->rightToLeft()
1263                             && !buffer->isMultiLingual())
1264                                 buffer->changeLanguage(oldL, newL);
1265                         break;
1266                 }
1267
1268                 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1269                         string const fname =
1270                                 addName(addPath(package().user_support().absFilename(), "templates/"),
1271                                         "defaults.lyx");
1272                         Buffer defaults(fname);
1273
1274                         istringstream ss(argument);
1275                         Lexer lex;
1276                         lex.setStream(ss);
1277                         int const unknown_tokens = defaults.readHeader(lex);
1278
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")
1283                                        << endl;
1284                         }
1285
1286                         if (defaults.writeFile(FileName(defaults.absFileName())))
1287                                 setMessage(bformat(_("Document defaults saved in %1$s"),
1288                                                    makeDisplayPath(fname)));
1289                         else
1290                                 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1291                         break;
1292                 }
1293
1294                 case LFUN_BUFFER_PARAMS_APPLY: {
1295                         LASSERT(lyx_view_, /**/);
1296                         
1297                         DocumentClass const * const oldClass = buffer->params().documentClassPtr();
1298                         Cursor & cur = lyx_view_->documentBufferView()->cursor();
1299                         cur.recordUndoFullDocument();
1300                         
1301                         istringstream ss(argument);
1302                         Lexer lex;
1303                         lex.setStream(ss);
1304                         int const unknown_tokens = buffer->readHeader(lex);
1305
1306                         if (unknown_tokens != 0) {
1307                                 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1308                                                 << unknown_tokens << " unknown token"
1309                                                 << (unknown_tokens == 1 ? "" : "s")
1310                                                 << endl;
1311                         }
1312                         
1313                         updateLayout(oldClass, buffer);
1314                         
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();
1320                         break;
1321                 }
1322                 
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;
1331                         break;
1332                 }
1333                 
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.");
1341                                 break;
1342                         }
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;
1349                         break;
1350                 }
1351
1352                 case LFUN_TEXTCLASS_APPLY: {
1353                         LASSERT(lyx_view_ && lyx_view_->documentBufferView(), /**/);
1354
1355                         if (!loadLayoutFile(argument, buffer->temppath()) &&
1356                                 !loadLayoutFile(argument, buffer->filePath()))
1357                                 break;
1358
1359                         LayoutFile const * old_layout = buffer->params().baseClass();
1360                         LayoutFile const * new_layout = &(LayoutFileList::get()[argument]);
1361
1362                         if (old_layout == new_layout)
1363                                 // nothing to do
1364                                 break;
1365
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;
1374                         break;
1375                 }
1376                 
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;
1386                         break;
1387                 }
1388
1389                 case LFUN_TEXTCLASS_LOAD:
1390                         loadLayoutFile(argument, buffer->temppath()) ||
1391                         loadLayoutFile(argument, buffer->filePath());
1392                         break;
1393
1394                 case LFUN_LYXRC_APPLY: {
1395                         // reset active key sequences, since the bindings
1396                         // are updated (bug 6064)
1397                         keyseq.reset();
1398                         LyXRC const lyxrc_orig = lyxrc;
1399
1400                         istringstream ss(argument);
1401                         bool const success = lyxrc.read(ss) == 0;
1402
1403                         if (!success) {
1404                                 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1405                                        << "Unable to read lyxrc data"
1406                                        << endl;
1407                                 break;
1408                         }
1409
1410                         actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1411
1412                         setSpellChecker();
1413
1414                         theApp()->resetGui();
1415
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;
1421                         break;
1422                 }
1423
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;
1428                         break;
1429
1430                 case LFUN_BOOKMARK_CLEAR:
1431                         theSession().bookmarks().clear();
1432                         break;
1433
1434                 default:
1435                         LASSERT(theApp(), /**/);
1436                         // Let the frontend dispatch its own actions.
1437                         if (theApp()->dispatch(cmd))
1438                                 // Nothing more to do.
1439                                 return;
1440
1441                         // Everything below is only for active lyx_view_
1442                         if (lyx_view_ == 0)
1443                                 break;
1444
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();
1449                                 
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();
1456                                 }
1457                                 break;
1458                         }
1459
1460                         LASSERT(lyx_view_->currentBufferView(), /**/);
1461
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();
1468                                 break;
1469                         }
1470
1471                         // OK, so try the Buffer itself
1472                         DispatchResult dr;
1473                         BufferView * bv = lyx_view_->currentBufferView();
1474                         bv->buffer().dispatch(cmd, dr);
1475                         if (dr.dispatched()) {
1476                                 updateFlags = dr.update();
1477                                 break;
1478                         }
1479
1480                         // Is this a function that acts on inset at point?
1481                         Inset * inset = bv->cursor().nextInset();
1482                         if (lyxaction.funcHasFlag(action, LyXAction::AtPoint)
1483                             && inset) {
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();
1490                                         break;
1491                                 }
1492                         }
1493
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);
1499
1500                         // notify insets we just left
1501                         if (bv->cursor() != old) {
1502                                 old.fixIfBroken();
1503                                 bool badcursor = notifyCursorLeavesOrEnters(old, bv->cursor());
1504                                 if (badcursor)
1505                                         bv->cursor().fixIfBroken();
1506                         }
1507
1508                         if (theBufferList().isLoaded(buffer))
1509                                 buffer->undo().endUndoGroup();
1510
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);
1520                                 else
1521                                         lyx_view_->updateCompletion(bv->cursor(), false, false);
1522                         }
1523
1524                         updateFlags = bv->cursor().result().update();
1525                 }
1526
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();                    
1532
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);
1539
1540                         // Do we have a selection?
1541                         theSelection().haveSelection(
1542                                 lyx_view_->currentBufferView()->cursor().selection());
1543                         
1544                         // update gui
1545                         lyx_view_->restartCursor();
1546                 }
1547         }
1548         if (lyx_view_) {
1549                 // Some messages may already be translated, so we cannot use _()
1550                 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
1551         }
1552 }
1553
1554
1555 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
1556 {
1557         const bool verbose = (cmd.origin == FuncRequest::MENU
1558                               || cmd.origin == FuncRequest::TOOLBAR
1559                               || cmd.origin == FuncRequest::COMMANDBUFFER);
1560
1561         if (cmd.action == LFUN_SELF_INSERT || !verbose) {
1562                 LYXERR(Debug::ACTION, "dispatch msg is " << to_utf8(msg));
1563                 if (!msg.empty())
1564                         lyx_view_->message(msg);
1565                 return;
1566         }
1567
1568         docstring dispatch_msg = msg;
1569         if (!dispatch_msg.empty())
1570                 dispatch_msg += ' ';
1571
1572         docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
1573
1574         bool argsadded = false;
1575
1576         if (!cmd.argument().empty()) {
1577                 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1578                         comname += ' ' + cmd.argument();
1579                         argsadded = true;
1580                 }
1581         }
1582
1583         docstring const shortcuts = theTopLevelKeymap().printBindings(cmd, KeySequence::ForGui);
1584
1585         if (!shortcuts.empty())
1586                 comname += ": " + shortcuts;
1587         else if (!argsadded && !cmd.argument().empty())
1588                 comname += ' ' + cmd.argument();
1589
1590         if (!comname.empty()) {
1591                 comname = rtrim(comname);
1592                 dispatch_msg += '(' + rtrim(comname) + ')';
1593         }
1594
1595         LYXERR(Debug::ACTION, "verbose dispatch msg " << to_utf8(dispatch_msg));
1596         if (!dispatch_msg.empty())
1597                 lyx_view_->message(dispatch_msg);
1598 }
1599
1600
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
1608 {
1609         dispatch_buffer = m;
1610         errorstat = true;
1611 }
1612
1613
1614 void LyXFunc::setMessage(docstring const & m) const
1615 {
1616         dispatch_buffer = m;
1617 }
1618
1619
1620 docstring LyXFunc::viewStatusMessage()
1621 {
1622         // When meta-fake key is pressed, show the key sequence so far + "M-".
1623         if (wasMetaKey())
1624                 return keyseq.print(KeySequence::ForGui) + "M-";
1625
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);
1630
1631         LASSERT(lyx_view_, /**/);
1632         if (!lyx_view_->currentBufferView())
1633                 return _("Welcome to LyX!");
1634
1635         return lyx_view_->currentBufferView()->cursor().currentState();
1636 }
1637
1638
1639 bool LyXFunc::wasMetaKey() const
1640 {
1641         return (meta_fake_bit != NoModifier);
1642 }
1643
1644
1645 void LyXFunc::updateLayout(DocumentClass const * const oldlayout, Buffer * buf)
1646 {
1647         lyx_view_->message(_("Converting document to new document class..."));
1648         
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);
1654
1655         lyx_view_->currentBufferView()->setCursor(backcur.asDocIterator(buf));
1656
1657         buf->errors("Class Switch");
1658         buf->updateLabels();
1659 }
1660
1661
1662 namespace {
1663
1664 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
1665 {
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;
1672         switch (tag) {
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);
1717                 }
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);
1753                 }
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);
1802                 }
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:
1828                 break;
1829         }
1830 }
1831
1832 } // namespace anon
1833 } // namespace lyx