]> git.lyx.org Git - lyx.git/blob - src/LyXFunc.cpp
Move LFUN_BUFFER_RELOAD and LFUN_VC_* to GuiView. Try to use the document 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_TOGGLE_READ_ONLY:
467                 flag.setOnOff(buf->isReadonly());
468                 break;
469
470         case LFUN_BUFFER_CHKTEX:
471                 enable = buf->isLatex() && !lyxrc.chktex_command.empty();
472                 break;
473
474         case LFUN_BUILD_PROGRAM:
475                 enable = buf->isExportable("program");
476                 break;
477
478         case LFUN_CITATION_INSERT: {
479                 FuncRequest fr(LFUN_INSET_INSERT, "citation");
480                 enable = getStatus(fr).enabled();
481                 break;
482         }
483         
484         // This could be used for the no-GUI version. The GUI version is handled in
485         // LyXView::getStatus(). See above.
486         /*
487         case LFUN_BUFFER_WRITE:
488         case LFUN_BUFFER_WRITE_AS: {
489                 Buffer * b = theBufferList().getBuffer(FileName(cmd.getArg(0)));
490                 enable = b && (b->isUnnamed() || !b->isClean());
491                 break;
492         }
493         */
494
495         case LFUN_BUFFER_WRITE_ALL: {
496                 // We enable the command only if there are some modified buffers
497                 Buffer * first = theBufferList().first();
498                 enable = false;
499                 if (!first)
500                         break;
501                 Buffer * b = first;
502                 // We cannot use a for loop as the buffer list is a cycle.
503                 do {
504                         if (!b->isClean()) {
505                                 enable = true;
506                                 break;
507                         }
508                         b = theBufferList().next(b);
509                 } while (b != first); 
510                 break;
511         }
512
513         case LFUN_BOOKMARK_GOTO: {
514                 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
515                 enable = theSession().bookmarks().isValid(num);
516                 break;
517         }
518
519         case LFUN_BOOKMARK_CLEAR:
520                 enable = theSession().bookmarks().hasValid();
521                 break;
522
523         // this one is difficult to get right. As a half-baked
524         // solution, we consider only the first action of the sequence
525         case LFUN_COMMAND_SEQUENCE: {
526                 // argument contains ';'-terminated commands
527                 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
528                 FuncRequest func(lyxaction.lookupFunc(firstcmd));
529                 func.origin = cmd.origin;
530                 flag = getStatus(func);
531                 break;
532         }
533
534         // we want to check if at least one of these is enabled
535         case LFUN_COMMAND_ALTERNATIVES: {
536                 // argument contains ';'-terminated commands
537                 string arg = to_utf8(cmd.argument());
538                 while (!arg.empty()) {
539                         string first;
540                         arg = split(arg, first, ';');
541                         FuncRequest func(lyxaction.lookupFunc(first));
542                         func.origin = cmd.origin;
543                         flag = getStatus(func);
544                         // if this one is enabled, the whole thing is
545                         if (flag.enabled())
546                                 break;
547                 }
548                 break;
549         }
550
551         case LFUN_CALL: {
552                 FuncRequest func;
553                 string name = to_utf8(cmd.argument());
554                 if (theTopLevelCmdDef().lock(name, func)) {
555                         func.origin = cmd.origin;
556                         flag = getStatus(func);
557                         theTopLevelCmdDef().release(name);
558                 } else {
559                         // catch recursion or unknown command
560                         // definition. all operations until the
561                         // recursion or unknown command definition
562                         // occurs are performed, so set the state to
563                         // enabled
564                         enable = true;
565                 }
566                 break;
567         }
568
569         case LFUN_MASTER_BUFFER_UPDATE:
570         case LFUN_MASTER_BUFFER_VIEW: 
571                 if (!buf->parent()) {
572                         enable = false;
573                         break;
574                 }
575         case LFUN_BUFFER_UPDATE:
576         case LFUN_BUFFER_VIEW: {
577                 string format = to_utf8(cmd.argument());
578                 if (cmd.argument().empty())
579                         format = buf->getDefaultOutputFormat();
580                 typedef vector<Format const *> Formats;
581                 Formats formats;
582                 formats = buf->exportableFormats(true);
583                 Formats::const_iterator fit = formats.begin();
584                 Formats::const_iterator end = formats.end();
585                 enable = false;
586                 for (; fit != end ; ++fit) {
587                         if ((*fit)->name() == format)
588                                 enable = true;
589                 }
590                 break;
591         }
592
593         case LFUN_WORD_FINDADV:
594         case LFUN_COMMAND_PREFIX:
595         case LFUN_COMMAND_EXECUTE:
596         case LFUN_CANCEL:
597         case LFUN_META_PREFIX:
598         case LFUN_BUFFER_CLOSE:
599         case LFUN_BUFFER_IMPORT:
600         case LFUN_BUFFER_AUTO_SAVE:
601         case LFUN_RECONFIGURE:
602         case LFUN_HELP_OPEN:
603         case LFUN_DROP_LAYOUTS_CHOICE:
604         case LFUN_MENU_OPEN:
605         case LFUN_SERVER_GET_FILENAME:
606         case LFUN_SERVER_NOTIFY:
607         case LFUN_SERVER_GOTO_FILE_ROW:
608         case LFUN_DIALOG_HIDE:
609         case LFUN_DIALOG_DISCONNECT_INSET:
610         case LFUN_BUFFER_CHILD_OPEN:
611         case LFUN_CURSOR_FOLLOWS_SCROLLBAR_TOGGLE:
612         case LFUN_KEYMAP_OFF:
613         case LFUN_KEYMAP_PRIMARY:
614         case LFUN_KEYMAP_SECONDARY:
615         case LFUN_KEYMAP_TOGGLE:
616         case LFUN_REPEAT:
617         case LFUN_BUFFER_EXPORT_CUSTOM:
618         case LFUN_PREFERENCES_SAVE:
619         case LFUN_MESSAGE:
620         case LFUN_INSET_EDIT:
621         case LFUN_BUFFER_LANGUAGE:
622         case LFUN_TEXTCLASS_APPLY:
623         case LFUN_TEXTCLASS_LOAD:
624         case LFUN_BUFFER_SAVE_AS_DEFAULT:
625         case LFUN_BUFFER_PARAMS_APPLY:
626         case LFUN_LAYOUT_MODULES_CLEAR:
627         case LFUN_LAYOUT_MODULE_ADD:
628         case LFUN_LAYOUT_RELOAD:
629         case LFUN_LYXRC_APPLY:
630         case LFUN_BUFFER_NEXT:
631         case LFUN_BUFFER_PREVIOUS:
632                 // these are handled in our dispatch()
633                 break;
634
635         default:
636                 if (!theApp()) {
637                         enable = false;
638                         break;
639                 }
640                 if (theApp()->getStatus(cmd, flag))
641                         break;
642
643                 // Does the view know something?
644                 if (!lv) {
645                         enable = false;
646                         break;
647                 }
648                 if (lv->getStatus(cmd, flag))
649                         break;
650
651                 BufferView * bv = lv->currentBufferView();
652                 // If we do not have a BufferView, then other functions are disabled
653                 if (!bv) {
654                         enable = false;
655                         break;
656                 }
657                 // Is this a function that acts on inset at point?
658                 Inset * inset = bv->cursor().nextInset();
659                 if (lyxaction.funcHasFlag(cmd.action, LyXAction::AtPoint)
660                     && inset && inset->getStatus(bv->cursor(), cmd, flag))
661                         break;
662
663                 bool decided = getLocalStatus(bv->cursor(), cmd, flag);
664                 if (!decided)
665                         // try the BufferView
666                         decided = bv->getStatus(cmd, flag);
667                 if (!decided)
668                         // try the Buffer
669                         bv->buffer().getStatus(cmd, flag);
670         }
671
672         if (!enable)
673                 flag.setEnabled(false);
674
675         // Can we use a readonly buffer?
676         if (buf && buf->isReadonly()
677             && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
678             && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
679                 flag.message(from_utf8(N_("Document is read-only")));
680                 flag.setEnabled(false);
681         }
682
683         // Are we in a DELETED change-tracking region?
684         if (lyx_view_ && lyx_view_->documentBufferView()
685                 && (lookupChangeType(lyx_view_->documentBufferView()->cursor(), true)
686                     == Change::DELETED)
687             && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
688             && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
689                 flag.message(from_utf8(N_("This portion of the document is deleted.")));
690                 flag.setEnabled(false);
691         }
692
693         // the default error message if we disable the command
694         if (!flag.enabled() && flag.message().empty())
695                 flag.message(from_utf8(N_("Command disabled")));
696
697         return flag;
698 }
699
700
701 namespace {
702
703 bool loadLayoutFile(string const & name, string const & buf_path)
704 {
705         if (!LayoutFileList::get().haveClass(name)) {
706                 lyxerr << "Document class \"" << name
707                        << "\" does not exist."
708                        << endl;
709                 return false;
710         }
711
712         LayoutFile & tc = LayoutFileList::get()[name];
713         if (!tc.load(buf_path)) {
714                 docstring s = bformat(_("The document class %1$s "
715                                    "could not be loaded."), from_utf8(name));
716                 Alert::error(_("Could not load class"), s);
717                 return false;
718         }
719         return true;
720 }
721
722
723 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
724
725 } //namespace anon
726
727
728 void LyXFunc::dispatch(FuncRequest const & cmd)
729 {
730         string const argument = to_utf8(cmd.argument());
731         FuncCode const action = cmd.action;
732
733         LYXERR(Debug::ACTION, "\nLyXFunc::dispatch: cmd: " << cmd);
734         //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
735
736         // we have not done anything wrong yet.
737         errorstat = false;
738         dispatch_buffer.erase();
739
740         // redraw the screen at the end (first of the two drawing steps).
741         //This is done unless explicitely requested otherwise
742         Update::flags updateFlags = Update::FitCursor;
743
744         FuncStatus const flag = getStatus(cmd);
745         if (!flag.enabled()) {
746                 // We cannot use this function here
747                 LYXERR(Debug::ACTION, "LyXFunc::dispatch: "
748                        << lyxaction.getActionName(action)
749                        << " [" << action << "] is disabled at this location");
750                 setErrorMessage(flag.message());
751                 if (lyx_view_)
752                         lyx_view_->restartCursor();
753         } else {
754                 Buffer * buffer = 0;
755                 if (lyx_view_ && lyx_view_->currentBufferView())
756                         buffer = &lyx_view_->currentBufferView()->buffer();
757                 switch (action) {
758
759                 case LFUN_COMMAND_PREFIX:
760                         LASSERT(lyx_view_, /**/);
761                         lyx_view_->message(keyseq.printOptions(true));
762                         break;
763
764                 case LFUN_CANCEL:
765                         LASSERT(lyx_view_ && lyx_view_->currentBufferView(), /**/);
766                         keyseq.reset();
767                         meta_fake_bit = NoModifier;
768                         if (buffer)
769                                 // cancel any selection
770                                 dispatch(FuncRequest(LFUN_MARK_OFF));
771                         setMessage(from_ascii(N_("Cancel")));
772                         break;
773
774                 case LFUN_META_PREFIX:
775                         meta_fake_bit = AltModifier;
776                         setMessage(keyseq.print(KeySequence::ForGui));
777                         break;
778
779                 case LFUN_BUFFER_TOGGLE_READ_ONLY: {
780                         LASSERT(lyx_view_ && lyx_view_->currentBufferView() && buffer, /**/);
781                         if (buffer->lyxvc().inUse())
782                                 buffer->lyxvc().toggleReadOnly();
783                         else
784                                 buffer->setReadonly(!buffer->isReadonly());
785                         break;
786                 }
787
788                 // --- Menus -----------------------------------------------
789                 case LFUN_BUFFER_CLOSE:
790                         lyx_view_->closeBuffer();
791                         buffer = 0;
792                         updateFlags = Update::None;
793                         break;
794
795                 case LFUN_BUFFER_CLOSE_ALL:
796                         lyx_view_->closeBufferAll();
797                         buffer = 0;
798                         updateFlags = Update::None;
799                         break;
800
801                 case LFUN_BUFFER_UPDATE: {
802                         LASSERT(lyx_view_ && lyx_view_->documentBufferView(), /**/);
803                         Buffer & doc_buffer = lyx_view_->documentBufferView()->buffer();
804                         string format = argument;
805                         if (argument.empty())
806                                 format = doc_buffer.getDefaultOutputFormat();
807                         doc_buffer.doExport(format, true);
808                         break;
809                 }
810
811                 case LFUN_BUFFER_VIEW: {
812                         LASSERT(lyx_view_ && lyx_view_->documentBufferView(), /**/);
813                         Buffer & doc_buffer = lyx_view_->documentBufferView()->buffer();
814                         string format = argument;
815                         if (argument.empty())
816                                 format = doc_buffer.getDefaultOutputFormat();
817                         doc_buffer.preview(format);
818                         break;
819                 }
820
821                 case LFUN_MASTER_BUFFER_UPDATE: {
822                         LASSERT(lyx_view_ && lyx_view_->documentBufferView(), /**/);
823                         Buffer & doc_buffer = lyx_view_->documentBufferView()->buffer();
824                         string format = argument;
825                         if (argument.empty())
826                                 format = doc_buffer.masterBuffer()->getDefaultOutputFormat();
827                         doc_buffer.masterBuffer()->doExport(format, true);
828                         break;
829                 }
830
831                 case LFUN_MASTER_BUFFER_VIEW: {
832                         LASSERT(lyx_view_ && lyx_view_->documentBufferView(), /**/);
833                         Buffer & doc_buffer = lyx_view_->documentBufferView()->buffer();
834                         string format = argument;
835                         if (argument.empty())
836                                 format = doc_buffer.masterBuffer()->getDefaultOutputFormat();
837                         doc_buffer.masterBuffer()->preview(format);
838                         break;
839                 }
840
841                 case LFUN_BUILD_PROGRAM:
842                         LASSERT(lyx_view_ && buffer, /**/);
843                         buffer->doExport("program", true);
844                         break;
845
846                 case LFUN_BUFFER_CHKTEX:
847                         LASSERT(lyx_view_ && buffer, /**/);
848                         buffer->runChktex();
849                         break;
850
851                 case LFUN_BUFFER_EXPORT:
852                         LASSERT(lyx_view_ && buffer, /**/);
853                         if (argument == "custom")
854                                 dispatch(FuncRequest(LFUN_DIALOG_SHOW, "sendto"));
855                         else
856                                 buffer->doExport(argument, false);
857                         break;
858
859                 case LFUN_BUFFER_EXPORT_CUSTOM: {
860                         LASSERT(lyx_view_ && buffer, /**/);
861                         string format_name;
862                         string command = split(argument, format_name, ' ');
863                         Format const * format = formats.getFormat(format_name);
864                         if (!format) {
865                                 lyxerr << "Format \"" << format_name
866                                        << "\" not recognized!"
867                                        << endl;
868                                 break;
869                         }
870
871                         // The name of the file created by the conversion process
872                         string filename;
873
874                         // Output to filename
875                         if (format->name() == "lyx") {
876                                 string const latexname = buffer->latexName(false);
877                                 filename = changeExtension(latexname,
878                                                            format->extension());
879                                 filename = addName(buffer->temppath(), filename);
880
881                                 if (!buffer->writeFile(FileName(filename)))
882                                         break;
883
884                         } else {
885                                 buffer->doExport(format_name, true, filename);
886                         }
887
888                         // Substitute $$FName for filename
889                         if (!contains(command, "$$FName"))
890                                 command = "( " + command + " ) < $$FName";
891                         command = subst(command, "$$FName", filename);
892
893                         // Execute the command in the background
894                         Systemcall call;
895                         call.startscript(Systemcall::DontWait, command);
896                         break;
897                 }
898
899                 // FIXME: There is need for a command-line import.
900                 /*
901                 case LFUN_BUFFER_IMPORT:
902                         doImport(argument);
903                         break;
904                 */
905
906                 case LFUN_BUFFER_AUTO_SAVE:
907                         buffer->autoSave();
908                         break;
909
910                 case LFUN_RECONFIGURE:
911                         // argument is any additional parameter to the configure.py command
912                         reconfigure(lyx_view_, argument);
913                         break;
914
915                 case LFUN_HELP_OPEN: {
916                         if (lyx_view_ == 0)
917                                 theApp()->dispatch(FuncRequest(LFUN_WINDOW_NEW));
918                         string const arg = argument;
919                         if (arg.empty()) {
920                                 setErrorMessage(from_utf8(N_("Missing argument")));
921                                 break;
922                         }
923                         FileName fname = i18nLibFileSearch("doc", arg, "lyx");
924                         if (fname.empty()) 
925                                 fname = i18nLibFileSearch("examples", arg, "lyx");
926
927                         if (fname.empty()) {
928                                 lyxerr << "LyX: unable to find documentation file `"
929                                                          << arg << "'. Bad installation?" << endl;
930                                 break;
931                         }
932                         lyx_view_->message(bformat(_("Opening help file %1$s..."),
933                                 makeDisplayPath(fname.absFilename())));
934                         Buffer * buf = lyx_view_->loadDocument(fname, false);
935                         if (buf) {
936                                 buf->updateLabels();
937                                 lyx_view_->setBuffer(buf);
938                                 buf->errors("Parse");
939                         }
940                         updateFlags = Update::None;
941                         break;
942                 }
943
944                 // --- lyxserver commands ----------------------------
945                 case LFUN_SERVER_GET_FILENAME:
946                         LASSERT(lyx_view_ && buffer, /**/);
947                         setMessage(from_utf8(buffer->absFileName()));
948                         LYXERR(Debug::INFO, "FNAME["
949                                 << buffer->absFileName() << ']');
950                         break;
951
952                 case LFUN_SERVER_NOTIFY:
953                         dispatch_buffer = keyseq.print(KeySequence::Portable);
954                         theServer().notifyClient(to_utf8(dispatch_buffer));
955                         break;
956
957                 case LFUN_SERVER_GOTO_FILE_ROW: {
958                         LASSERT(lyx_view_, /**/);
959                         string file_name;
960                         int row;
961                         istringstream is(argument);
962                         is >> file_name >> row;
963                         file_name = os::internal_path(file_name);
964                         Buffer * buf = 0;
965                         bool loaded = false;
966                         string const abstmp = package().temp_dir().absFilename();
967                         string const realtmp = package().temp_dir().realPath();
968                         // We have to use os::path_prefix_is() here, instead of
969                         // simply prefixIs(), because the file name comes from
970                         // an external application and may need case adjustment.
971                         if (os::path_prefix_is(file_name, abstmp, os::CASE_ADJUSTED)
972                             || os::path_prefix_is(file_name, realtmp, os::CASE_ADJUSTED)) {
973                                 // Needed by inverse dvi search. If it is a file
974                                 // in tmpdir, call the apropriated function.
975                                 // If tmpdir is a symlink, we may have the real
976                                 // path passed back, so we correct for that.
977                                 if (!prefixIs(file_name, abstmp))
978                                         file_name = subst(file_name, realtmp, abstmp);
979                                 buf = theBufferList().getBufferFromTmp(file_name);
980                         } else {
981                                 // Must replace extension of the file to be .lyx
982                                 // and get full path
983                                 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
984                                 // Either change buffer or load the file
985                                 if (theBufferList().exists(s))
986                                         buf = theBufferList().getBuffer(s);
987                                 else if (s.exists()) {
988                                         buf = lyx_view_->loadDocument(s);
989                                         loaded = true;
990                                 } else
991                                         lyx_view_->message(bformat(
992                                                 _("File does not exist: %1$s"),
993                                                 makeDisplayPath(file_name)));
994                         }
995
996                         if (!buf) {
997                                 updateFlags = Update::None;
998                                 break;
999                         }
1000
1001                         buf->updateLabels();
1002                         lyx_view_->setBuffer(buf);
1003                         lyx_view_->documentBufferView()->setCursorFromRow(row);
1004                         if (loaded)
1005                                 buf->errors("Parse");
1006                         updateFlags = Update::FitCursor;
1007                         break;
1008                 }
1009
1010
1011                 case LFUN_DIALOG_SHOW_NEW_INSET: {
1012                         LASSERT(lyx_view_, /**/);
1013                         string const name = cmd.getArg(0);
1014                         InsetCode code = insetCode(name);
1015                         string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1016                         bool insetCodeOK = true;
1017                         switch (code) {
1018                         case BIBITEM_CODE:
1019                         case BIBTEX_CODE:
1020                         case INDEX_CODE:
1021                         case LABEL_CODE:
1022                         case NOMENCL_CODE:
1023                         case NOMENCL_PRINT_CODE:
1024                         case REF_CODE:
1025                         case TOC_CODE:
1026                         case HYPERLINK_CODE: {
1027                                 InsetCommandParams p(code);
1028                                 data = InsetCommand::params2string(name, p);
1029                                 break;
1030                         }
1031                         case INCLUDE_CODE: {
1032                                 // data is the include type: one of "include",
1033                                 // "input", "verbatiminput" or "verbatiminput*"
1034                                 if (data.empty())
1035                                         // default type is requested
1036                                         data = "include";
1037                                 InsetCommandParams p(INCLUDE_CODE, data);
1038                                 data = InsetCommand::params2string("include", p);
1039                                 break;
1040                         }
1041                         case BOX_CODE: {
1042                                 // \c data == "Boxed" || "Frameless" etc
1043                                 InsetBoxParams p(data);
1044                                 data = InsetBox::params2string(p);
1045                                 break;
1046                         }
1047                         case BRANCH_CODE: {
1048                                 InsetBranchParams p;
1049                                 data = InsetBranch::params2string(p);
1050                                 break;
1051                         }
1052                         case CITE_CODE: {
1053                                 InsetCommandParams p(CITE_CODE);
1054                                 data = InsetCommand::params2string(name, p);
1055                                 break;
1056                         }
1057                         case ERT_CODE: {
1058                                 data = InsetERT::params2string(InsetCollapsable::Open);
1059                                 break;
1060                         }
1061                         case EXTERNAL_CODE: {
1062                                 InsetExternalParams p;
1063                                 data = InsetExternal::params2string(p, *buffer);
1064                                 break;
1065                         }
1066                         case FLOAT_CODE:  {
1067                                 InsetFloatParams p;
1068                                 data = InsetFloat::params2string(p);
1069                                 break;
1070                         }
1071                         case LISTINGS_CODE: {
1072                                 InsetListingsParams p;
1073                                 data = InsetListings::params2string(p);
1074                                 break;
1075                         }
1076                         case GRAPHICS_CODE: {
1077                                 InsetGraphicsParams p;
1078                                 data = InsetGraphics::params2string(p, *buffer);
1079                                 break;
1080                         }
1081                         case NOTE_CODE: {
1082                                 InsetNoteParams p;
1083                                 data = InsetNote::params2string(p);
1084                                 break;
1085                         }
1086                         case PHANTOM_CODE: {
1087                                 InsetPhantomParams p;
1088                                 data = InsetPhantom::params2string(p);
1089                                 break;
1090                         }
1091                         case SPACE_CODE: {
1092                                 InsetSpaceParams p;
1093                                 data = InsetSpace::params2string(p);
1094                                 break;
1095                         }
1096                         case VSPACE_CODE: {
1097                                 VSpace space;
1098                                 data = InsetVSpace::params2string(space);
1099                                 break;
1100                         }
1101                         case WRAP_CODE: {
1102                                 InsetWrapParams p;
1103                                 data = InsetWrap::params2string(p);
1104                                 break;
1105                         }
1106                         default:
1107                                 lyxerr << "Inset type '" << name << 
1108                                         "' not recognized in LFUN_DIALOG_SHOW_NEW_INSET" <<  endl;
1109                                 insetCodeOK = false;
1110                                 break;
1111                         } // end switch(code)
1112                         if (insetCodeOK)
1113                                 dispatch(FuncRequest(LFUN_DIALOG_SHOW, name + " " + data));
1114                         break;
1115                 }
1116
1117                 case LFUN_CITATION_INSERT: {
1118                         LASSERT(lyx_view_, /**/);
1119                         if (!argument.empty()) {
1120                                 // we can have one optional argument, delimited by '|'
1121                                 // citation-insert <key>|<text_before>
1122                                 // this should be enhanced to also support text_after
1123                                 // and citation style
1124                                 string arg = argument;
1125                                 string opt1;
1126                                 if (contains(argument, "|")) {
1127                                         arg = token(argument, '|', 0);
1128                                         opt1 = token(argument, '|', 1);
1129                                 }
1130                                 InsetCommandParams icp(CITE_CODE);
1131                                 icp["key"] = from_utf8(arg);
1132                                 if (!opt1.empty())
1133                                         icp["before"] = from_utf8(opt1);
1134                                 string icstr = InsetCommand::params2string("citation", icp);
1135                                 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1136                                 dispatch(fr);
1137                         } else
1138                                 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1139                         break;
1140                 }
1141
1142                 case LFUN_BUFFER_CHILD_OPEN: {
1143                         LASSERT(lyx_view_ && buffer, /**/);
1144                         FileName filename = makeAbsPath(argument, buffer->filePath());
1145                         lyx_view_->documentBufferView()->saveBookmark(false);
1146                         Buffer * child = 0;
1147                         bool parsed = false;
1148                         if (theBufferList().exists(filename)) {
1149                                 child = theBufferList().getBuffer(filename);
1150                         } else {
1151                                 setMessage(bformat(_("Opening child document %1$s..."),
1152                                         makeDisplayPath(filename.absFilename())));
1153                                 child = lyx_view_->loadDocument(filename, false);
1154                                 parsed = true;
1155                         }
1156                         if (child) {
1157                                 // Set the parent name of the child document.
1158                                 // This makes insertion of citations and references in the child work,
1159                                 // when the target is in the parent or another child document.
1160                                 child->setParent(buffer);
1161                                 child->masterBuffer()->updateLabels();
1162                                 lyx_view_->setBuffer(child);
1163                                 if (parsed)
1164                                         child->errors("Parse");
1165                         }
1166
1167                         // If a screen update is required (in case where auto_open is false), 
1168                         // setBuffer() would have taken care of it already. Otherwise we shall 
1169                         // reset the update flag because it can cause a circular problem.
1170                         // See bug 3970.
1171                         updateFlags = Update::None;
1172                         break;
1173                 }
1174
1175                 case LFUN_CURSOR_FOLLOWS_SCROLLBAR_TOGGLE:
1176                         LASSERT(lyx_view_, /**/);
1177                         lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1178                         break;
1179
1180                 case LFUN_KEYMAP_OFF:
1181                         LASSERT(lyx_view_ && lyx_view_->currentBufferView(), /**/);
1182                         lyx_view_->currentBufferView()->getIntl().keyMapOn(false);
1183                         break;
1184
1185                 case LFUN_KEYMAP_PRIMARY:
1186                         LASSERT(lyx_view_ && lyx_view_->currentBufferView(), /**/);
1187                         lyx_view_->currentBufferView()->getIntl().keyMapPrim();
1188                         break;
1189
1190                 case LFUN_KEYMAP_SECONDARY:
1191                         LASSERT(lyx_view_ && lyx_view_->currentBufferView(), /**/);
1192                         lyx_view_->currentBufferView()->getIntl().keyMapSec();
1193                         break;
1194
1195                 case LFUN_KEYMAP_TOGGLE:
1196                         LASSERT(lyx_view_ && lyx_view_->currentBufferView(), /**/);
1197                         lyx_view_->currentBufferView()->getIntl().toggleKeyMap();
1198                         break;
1199
1200                 case LFUN_REPEAT: {
1201                         // repeat command
1202                         string countstr;
1203                         string rest = split(argument, countstr, ' ');
1204                         istringstream is(countstr);
1205                         int count = 0;
1206                         is >> count;
1207                         //lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1208                         for (int i = 0; i < count; ++i)
1209                                 dispatch(lyxaction.lookupFunc(rest));
1210                         break;
1211                 }
1212
1213                 case LFUN_COMMAND_SEQUENCE: {
1214                         // argument contains ';'-terminated commands
1215                         string arg = argument;
1216                         if (theBufferList().isLoaded(buffer))
1217                                 buffer->undo().beginUndoGroup();
1218                         while (!arg.empty()) {
1219                                 string first;
1220                                 arg = split(arg, first, ';');
1221                                 FuncRequest func(lyxaction.lookupFunc(first));
1222                                 func.origin = cmd.origin;
1223                                 dispatch(func);
1224                         }
1225                         if (theBufferList().isLoaded(buffer))
1226                                 buffer->undo().endUndoGroup();
1227                         break;
1228                 }
1229
1230                 case LFUN_COMMAND_ALTERNATIVES: {
1231                         // argument contains ';'-terminated commands
1232                         string arg = argument;
1233                         while (!arg.empty()) {
1234                                 string first;
1235                                 arg = split(arg, first, ';');
1236                                 FuncRequest func(lyxaction.lookupFunc(first));
1237                                 func.origin = cmd.origin;
1238                                 FuncStatus stat = getStatus(func);
1239                                 if (stat.enabled()) {
1240                                         dispatch(func);
1241                                         break;
1242                                 }
1243                         }
1244                         break;
1245                 }
1246
1247                 case LFUN_CALL: {
1248                         FuncRequest func;
1249                         if (theTopLevelCmdDef().lock(argument, func)) {
1250                                 func.origin = cmd.origin;
1251                                 dispatch(func);
1252                                 theTopLevelCmdDef().release(argument);
1253                         } else {
1254                                 if (func.action == LFUN_UNKNOWN_ACTION) {
1255                                         // unknown command definition
1256                                         lyxerr << "Warning: unknown command definition `"
1257                                                    << argument << "'"
1258                                                    << endl;
1259                                 } else {
1260                                         // recursion detected
1261                                         lyxerr << "Warning: Recursion in the command definition `"
1262                                                    << argument << "' detected"
1263                                                    << endl;
1264                                 }
1265                         }
1266                         break;
1267                 }
1268
1269                 case LFUN_PREFERENCES_SAVE: {
1270                         lyxrc.write(makeAbsPath("preferences",
1271                                                 package().user_support().absFilename()),
1272                                     false);
1273                         break;
1274                 }
1275
1276                 case LFUN_MESSAGE:
1277                         LASSERT(lyx_view_, /**/);
1278                         lyx_view_->message(from_utf8(argument));
1279                         break;
1280
1281                 case LFUN_BUFFER_LANGUAGE: {
1282                         LASSERT(lyx_view_, /**/);
1283                         Language const * oldL = buffer->params().language;
1284                         Language const * newL = languages.getLanguage(argument);
1285                         if (!newL || oldL == newL)
1286                                 break;
1287
1288                         if (oldL->rightToLeft() == newL->rightToLeft()
1289                             && !buffer->isMultiLingual())
1290                                 buffer->changeLanguage(oldL, newL);
1291                         break;
1292                 }
1293
1294                 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1295                         string const fname =
1296                                 addName(addPath(package().user_support().absFilename(), "templates/"),
1297                                         "defaults.lyx");
1298                         Buffer defaults(fname);
1299
1300                         istringstream ss(argument);
1301                         Lexer lex;
1302                         lex.setStream(ss);
1303                         int const unknown_tokens = defaults.readHeader(lex);
1304
1305                         if (unknown_tokens != 0) {
1306                                 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1307                                        << unknown_tokens << " unknown token"
1308                                        << (unknown_tokens == 1 ? "" : "s")
1309                                        << endl;
1310                         }
1311
1312                         if (defaults.writeFile(FileName(defaults.absFileName())))
1313                                 setMessage(bformat(_("Document defaults saved in %1$s"),
1314                                                    makeDisplayPath(fname)));
1315                         else
1316                                 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1317                         break;
1318                 }
1319
1320                 case LFUN_BUFFER_PARAMS_APPLY: {
1321                         LASSERT(lyx_view_, /**/);
1322                         
1323                         DocumentClass const * const oldClass = buffer->params().documentClassPtr();
1324                         Cursor & cur = lyx_view_->documentBufferView()->cursor();
1325                         cur.recordUndoFullDocument();
1326                         
1327                         istringstream ss(argument);
1328                         Lexer lex;
1329                         lex.setStream(ss);
1330                         int const unknown_tokens = buffer->readHeader(lex);
1331
1332                         if (unknown_tokens != 0) {
1333                                 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1334                                                 << unknown_tokens << " unknown token"
1335                                                 << (unknown_tokens == 1 ? "" : "s")
1336                                                 << endl;
1337                         }
1338                         
1339                         updateLayout(oldClass, buffer);
1340                         
1341                         updateFlags = Update::Force | Update::FitCursor;
1342                         // We are most certainly here because of a change in the document
1343                         // It is then better to make sure that all dialogs are in sync with
1344                         // current document settings. LyXView::restartCursor() achieve this.
1345                         lyx_view_->restartCursor();
1346                         break;
1347                 }
1348                 
1349                 case LFUN_LAYOUT_MODULES_CLEAR: {
1350                         LASSERT(lyx_view_ && lyx_view_->documentBufferView(), /**/);
1351                         DocumentClass const * const oldClass = buffer->params().documentClassPtr();
1352                         lyx_view_->documentBufferView()->cursor().recordUndoFullDocument();
1353                         buffer->params().clearLayoutModules();
1354                         buffer->params().makeDocumentClass();
1355                         updateLayout(oldClass, buffer);
1356                         updateFlags = Update::Force | Update::FitCursor;
1357                         break;
1358                 }
1359                 
1360                 case LFUN_LAYOUT_MODULE_ADD: {
1361                         LASSERT(lyx_view_ && lyx_view_->documentBufferView(), /**/);
1362                         BufferParams const & params = buffer->params();
1363                         if (!params.moduleCanBeAdded(argument)) {
1364                                 LYXERR0("Module `" << argument << 
1365                                                 "' cannot be added due to failed requirements or "
1366                                                 "conflicts with installed modules.");
1367                                 break;
1368                         }
1369                         DocumentClass const * const oldClass = params.documentClassPtr();
1370                         lyx_view_->documentBufferView()->cursor().recordUndoFullDocument();
1371                         buffer->params().addLayoutModule(argument);
1372                         buffer->params().makeDocumentClass();
1373                         updateLayout(oldClass, buffer);
1374                         updateFlags = Update::Force | Update::FitCursor;
1375                         break;
1376                 }
1377
1378                 case LFUN_TEXTCLASS_APPLY: {
1379                         LASSERT(lyx_view_ && lyx_view_->documentBufferView(), /**/);
1380
1381                         if (!loadLayoutFile(argument, buffer->temppath()) &&
1382                                 !loadLayoutFile(argument, buffer->filePath()))
1383                                 break;
1384
1385                         LayoutFile const * old_layout = buffer->params().baseClass();
1386                         LayoutFile const * new_layout = &(LayoutFileList::get()[argument]);
1387
1388                         if (old_layout == new_layout)
1389                                 // nothing to do
1390                                 break;
1391
1392                         //Save the old, possibly modular, layout for use in conversion.
1393                         DocumentClass const * const oldDocClass =
1394                                 buffer->params().documentClassPtr();
1395                         lyx_view_->documentBufferView()->cursor().recordUndoFullDocument();
1396                         buffer->params().setBaseClass(argument);
1397                         buffer->params().makeDocumentClass();
1398                         updateLayout(oldDocClass, buffer);
1399                         updateFlags = Update::Force | Update::FitCursor;
1400                         break;
1401                 }
1402                 
1403                 case LFUN_LAYOUT_RELOAD: {
1404                         LASSERT(lyx_view_, /**/);
1405                         DocumentClass const * const oldClass = buffer->params().documentClassPtr();
1406                         LayoutFileIndex bc = buffer->params().baseClassID();
1407                         LayoutFileList::get().reset(bc);
1408                         buffer->params().setBaseClass(bc);
1409                         buffer->params().makeDocumentClass();
1410                         updateLayout(oldClass, buffer);
1411                         updateFlags = Update::Force | Update::FitCursor;
1412                         break;
1413                 }
1414
1415                 case LFUN_TEXTCLASS_LOAD:
1416                         loadLayoutFile(argument, buffer->temppath()) ||
1417                         loadLayoutFile(argument, buffer->filePath());
1418                         break;
1419
1420                 case LFUN_LYXRC_APPLY: {
1421                         // reset active key sequences, since the bindings
1422                         // are updated (bug 6064)
1423                         keyseq.reset();
1424                         LyXRC const lyxrc_orig = lyxrc;
1425
1426                         istringstream ss(argument);
1427                         bool const success = lyxrc.read(ss) == 0;
1428
1429                         if (!success) {
1430                                 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1431                                        << "Unable to read lyxrc data"
1432                                        << endl;
1433                                 break;
1434                         }
1435
1436                         actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1437
1438                         setSpellChecker();
1439
1440                         theApp()->resetGui();
1441
1442                         /// We force the redraw in any case because there might be
1443                         /// some screen font changes.
1444                         /// FIXME: only the current view will be updated. the Gui
1445                         /// class is able to furnish the list of views.
1446                         updateFlags = Update::Force;
1447                         break;
1448                 }
1449
1450                 case LFUN_BOOKMARK_GOTO:
1451                         // go to bookmark, open unopened file and switch to buffer if necessary
1452                         gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
1453                         updateFlags = Update::FitCursor;
1454                         break;
1455
1456                 case LFUN_BOOKMARK_CLEAR:
1457                         theSession().bookmarks().clear();
1458                         break;
1459
1460                 default:
1461                         LASSERT(theApp(), /**/);
1462                         // Let the frontend dispatch its own actions.
1463                         if (theApp()->dispatch(cmd))
1464                                 // Nothing more to do.
1465                                 return;
1466
1467                         // Everything below is only for active lyx_view_
1468                         if (lyx_view_ == 0)
1469                                 break;
1470
1471                         // Start an undo group. This may be needed for
1472                         // some stuff like inset-apply on labels.
1473                         if (theBufferList().isLoaded(buffer))
1474                                 buffer->undo().beginUndoGroup();
1475                                 
1476                         // Let the current LyXView dispatch its own actions.
1477                         if (lyx_view_->dispatch(cmd)) {
1478                                 if (lyx_view_->currentBufferView()) {
1479                                         updateFlags = lyx_view_->currentBufferView()->cursor().result().update();
1480                                         if (theBufferList().isLoaded(buffer))
1481                                                 buffer->undo().endUndoGroup();
1482                                 }
1483                                 break;
1484                         }
1485
1486                         LASSERT(lyx_view_->currentBufferView(), /**/);
1487
1488                         // Let the current BufferView dispatch its own actions.
1489                         if (lyx_view_->currentBufferView()->dispatch(cmd)) {
1490                                 // The BufferView took care of its own updates if needed.
1491                                 updateFlags = Update::None;
1492                                 if (theBufferList().isLoaded(buffer))
1493                                         buffer->undo().endUndoGroup();
1494                                 break;
1495                         }
1496
1497                         // OK, so try the Buffer itself
1498                         DispatchResult dr;
1499                         BufferView * bv = lyx_view_->currentBufferView();
1500                         bv->buffer().dispatch(cmd, dr);
1501                         if (dr.dispatched()) {
1502                                 updateFlags = dr.update();
1503                                 break;
1504                         }
1505
1506                         // Is this a function that acts on inset at point?
1507                         Inset * inset = bv->cursor().nextInset();
1508                         if (lyxaction.funcHasFlag(action, LyXAction::AtPoint)
1509                             && inset) {
1510                                 bv->cursor().result().dispatched(true);
1511                                 bv->cursor().result().update(Update::FitCursor | Update::Force);
1512                                 FuncRequest tmpcmd = cmd;
1513                                 inset->dispatch(bv->cursor(), tmpcmd);
1514                                 if (bv->cursor().result().dispatched()) {
1515                                         updateFlags = bv->cursor().result().update();
1516                                         break;
1517                                 }
1518                         }
1519
1520                         // Let the current Cursor dispatch its own actions.
1521                         Cursor old = bv->cursor();
1522                         bv->cursor().getPos(cursorPosBeforeDispatchX_,
1523                                                 cursorPosBeforeDispatchY_);
1524                         bv->cursor().dispatch(cmd);
1525
1526                         // notify insets we just left
1527                         if (bv->cursor() != old) {
1528                                 old.fixIfBroken();
1529                                 bool badcursor = notifyCursorLeavesOrEnters(old, bv->cursor());
1530                                 if (badcursor)
1531                                         bv->cursor().fixIfBroken();
1532                         }
1533
1534                         if (theBufferList().isLoaded(buffer))
1535                                 buffer->undo().endUndoGroup();
1536
1537                         // update completion. We do it here and not in
1538                         // processKeySym to avoid another redraw just for a
1539                         // changed inline completion
1540                         if (cmd.origin == FuncRequest::KEYBOARD) {
1541                                 if (cmd.action == LFUN_SELF_INSERT
1542                                     || (cmd.action == LFUN_ERT_INSERT && bv->cursor().inMathed()))
1543                                         lyx_view_->updateCompletion(bv->cursor(), true, true);
1544                                 else if (cmd.action == LFUN_CHAR_DELETE_BACKWARD)
1545                                         lyx_view_->updateCompletion(bv->cursor(), false, true);
1546                                 else
1547                                         lyx_view_->updateCompletion(bv->cursor(), false, false);
1548                         }
1549
1550                         updateFlags = bv->cursor().result().update();
1551                 }
1552
1553                 // if we executed a mutating lfun, mark the buffer as dirty
1554                 if (theBufferList().isLoaded(buffer) && flag.enabled()
1555                     && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
1556                     && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
1557                         buffer->markDirty();                    
1558
1559                 if (lyx_view_ && lyx_view_->currentBufferView()) {
1560                         // BufferView::update() updates the ViewMetricsInfo and
1561                         // also initializes the position cache for all insets in
1562                         // (at least partially) visible top-level paragraphs.
1563                         // We will redraw the screen only if needed.
1564                         lyx_view_->currentBufferView()->processUpdateFlags(updateFlags);
1565
1566                         // Do we have a selection?
1567                         theSelection().haveSelection(
1568                                 lyx_view_->currentBufferView()->cursor().selection());
1569                         
1570                         // update gui
1571                         lyx_view_->restartCursor();
1572                 }
1573         }
1574         if (lyx_view_) {
1575                 // Some messages may already be translated, so we cannot use _()
1576                 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
1577         }
1578 }
1579
1580
1581 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
1582 {
1583         const bool verbose = (cmd.origin == FuncRequest::MENU
1584                               || cmd.origin == FuncRequest::TOOLBAR
1585                               || cmd.origin == FuncRequest::COMMANDBUFFER);
1586
1587         if (cmd.action == LFUN_SELF_INSERT || !verbose) {
1588                 LYXERR(Debug::ACTION, "dispatch msg is " << to_utf8(msg));
1589                 if (!msg.empty())
1590                         lyx_view_->message(msg);
1591                 return;
1592         }
1593
1594         docstring dispatch_msg = msg;
1595         if (!dispatch_msg.empty())
1596                 dispatch_msg += ' ';
1597
1598         docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
1599
1600         bool argsadded = false;
1601
1602         if (!cmd.argument().empty()) {
1603                 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1604                         comname += ' ' + cmd.argument();
1605                         argsadded = true;
1606                 }
1607         }
1608
1609         docstring const shortcuts = theTopLevelKeymap().printBindings(cmd, KeySequence::ForGui);
1610
1611         if (!shortcuts.empty())
1612                 comname += ": " + shortcuts;
1613         else if (!argsadded && !cmd.argument().empty())
1614                 comname += ' ' + cmd.argument();
1615
1616         if (!comname.empty()) {
1617                 comname = rtrim(comname);
1618                 dispatch_msg += '(' + rtrim(comname) + ')';
1619         }
1620
1621         LYXERR(Debug::ACTION, "verbose dispatch msg " << to_utf8(dispatch_msg));
1622         if (!dispatch_msg.empty())
1623                 lyx_view_->message(dispatch_msg);
1624 }
1625
1626
1627 // Each "lyx_view_" should have it's own message method. lyxview and
1628 // the minibuffer would use the minibuffer, but lyxserver would
1629 // send an ERROR signal to its client.  Alejandro 970603
1630 // This function is bit problematic when it comes to NLS, to make the
1631 // lyx servers client be language indepenent we must not translate
1632 // strings sent to this func.
1633 void LyXFunc::setErrorMessage(docstring const & m) const
1634 {
1635         dispatch_buffer = m;
1636         errorstat = true;
1637 }
1638
1639
1640 void LyXFunc::setMessage(docstring const & m) const
1641 {
1642         dispatch_buffer = m;
1643 }
1644
1645
1646 docstring LyXFunc::viewStatusMessage()
1647 {
1648         // When meta-fake key is pressed, show the key sequence so far + "M-".
1649         if (wasMetaKey())
1650                 return keyseq.print(KeySequence::ForGui) + "M-";
1651
1652         // Else, when a non-complete key sequence is pressed,
1653         // show the available options.
1654         if (keyseq.length() > 0 && !keyseq.deleted())
1655                 return keyseq.printOptions(true);
1656
1657         LASSERT(lyx_view_, /**/);
1658         if (!lyx_view_->currentBufferView())
1659                 return _("Welcome to LyX!");
1660
1661         return lyx_view_->currentBufferView()->cursor().currentState();
1662 }
1663
1664
1665 bool LyXFunc::wasMetaKey() const
1666 {
1667         return (meta_fake_bit != NoModifier);
1668 }
1669
1670
1671 void LyXFunc::updateLayout(DocumentClass const * const oldlayout, Buffer * buf)
1672 {
1673         lyx_view_->message(_("Converting document to new document class..."));
1674         
1675         StableDocIterator backcur(lyx_view_->currentBufferView()->cursor());
1676         ErrorList & el = buf->errorList("Class Switch");
1677         cap::switchBetweenClasses(
1678                         oldlayout, buf->params().documentClassPtr(),
1679                         static_cast<InsetText &>(buf->inset()), el);
1680
1681         lyx_view_->currentBufferView()->setCursor(backcur.asDocIterator(buf));
1682
1683         buf->errors("Class Switch");
1684         buf->updateLabels();
1685 }
1686
1687
1688 namespace {
1689
1690 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
1691 {
1692         // Why the switch you might ask. It is a trick to ensure that all
1693         // the elements in the LyXRCTags enum is handled. As you can see
1694         // there are no breaks at all. So it is just a huge fall-through.
1695         // The nice thing is that we will get a warning from the compiler
1696         // if we forget an element.
1697         LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
1698         switch (tag) {
1699         case LyXRC::RC_ACCEPT_COMPOUND:
1700         case LyXRC::RC_ALT_LANG:
1701         case LyXRC::RC_PLAINTEXT_LINELEN:
1702         case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
1703         case LyXRC::RC_AUTOCORRECTION_MATH:
1704         case LyXRC::RC_AUTOREGIONDELETE:
1705         case LyXRC::RC_AUTORESET_OPTIONS:
1706         case LyXRC::RC_AUTOSAVE:
1707         case LyXRC::RC_AUTO_NUMBER:
1708         case LyXRC::RC_BACKUPDIR_PATH:
1709         case LyXRC::RC_BIBTEX_ALTERNATIVES:
1710         case LyXRC::RC_BIBTEX_COMMAND:
1711         case LyXRC::RC_BINDFILE:
1712         case LyXRC::RC_CHECKLASTFILES:
1713         case LyXRC::RC_COMPLETION_CURSOR_TEXT:
1714         case LyXRC::RC_COMPLETION_INLINE_DELAY:
1715         case LyXRC::RC_COMPLETION_INLINE_DOTS:
1716         case LyXRC::RC_COMPLETION_INLINE_MATH:
1717         case LyXRC::RC_COMPLETION_INLINE_TEXT:
1718         case LyXRC::RC_COMPLETION_POPUP_AFTER_COMPLETE:
1719         case LyXRC::RC_COMPLETION_POPUP_DELAY:
1720         case LyXRC::RC_COMPLETION_POPUP_MATH:
1721         case LyXRC::RC_COMPLETION_POPUP_TEXT:
1722         case LyXRC::RC_USELASTFILEPOS:
1723         case LyXRC::RC_LOADSESSION:
1724         case LyXRC::RC_CHKTEX_COMMAND:
1725         case LyXRC::RC_CONVERTER:
1726         case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
1727         case LyXRC::RC_COPIER:
1728         case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
1729         case LyXRC::RC_SCROLL_BELOW_DOCUMENT:
1730         case LyXRC::RC_DATE_INSERT_FORMAT:
1731         case LyXRC::RC_DEFAULT_LANGUAGE:
1732         case LyXRC::RC_GUI_LANGUAGE:
1733         case LyXRC::RC_DEFAULT_PAPERSIZE:
1734         case LyXRC::RC_DEFAULT_VIEW_FORMAT:
1735         case LyXRC::RC_DEFFILE:
1736         case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
1737         case LyXRC::RC_DISPLAY_GRAPHICS:
1738         case LyXRC::RC_DOCUMENTPATH:
1739                 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
1740                         FileName path(lyxrc_new.document_path);
1741                         if (path.exists() && path.isDirectory())
1742                                 package().document_dir() = FileName(lyxrc.document_path);
1743                 }
1744         case LyXRC::RC_EDITOR_ALTERNATIVES:
1745         case LyXRC::RC_ESC_CHARS:
1746         case LyXRC::RC_EXAMPLEPATH:
1747         case LyXRC::RC_FONT_ENCODING:
1748         case LyXRC::RC_FORMAT:
1749         case LyXRC::RC_GROUP_LAYOUTS:
1750         case LyXRC::RC_HUNSPELLDIR_PATH:
1751         case LyXRC::RC_INDEX_ALTERNATIVES:
1752         case LyXRC::RC_INDEX_COMMAND:
1753         case LyXRC::RC_JBIBTEX_COMMAND:
1754         case LyXRC::RC_JINDEX_COMMAND:
1755         case LyXRC::RC_NOMENCL_COMMAND:
1756         case LyXRC::RC_INPUT:
1757         case LyXRC::RC_KBMAP:
1758         case LyXRC::RC_KBMAP_PRIMARY:
1759         case LyXRC::RC_KBMAP_SECONDARY:
1760         case LyXRC::RC_LABEL_INIT_LENGTH:
1761         case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
1762         case LyXRC::RC_LANGUAGE_AUTO_END:
1763         case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
1764         case LyXRC::RC_LANGUAGE_COMMAND_END:
1765         case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
1766         case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
1767         case LyXRC::RC_LANGUAGE_PACKAGE:
1768         case LyXRC::RC_LANGUAGE_USE_BABEL:
1769         case LyXRC::RC_MAC_LIKE_WORD_MOVEMENT:
1770         case LyXRC::RC_MACRO_EDIT_STYLE:
1771         case LyXRC::RC_MAKE_BACKUP:
1772         case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
1773         case LyXRC::RC_MOUSE_WHEEL_SPEED:
1774         case LyXRC::RC_NUMLASTFILES:
1775         case LyXRC::RC_PARAGRAPH_MARKERS:
1776         case LyXRC::RC_PATH_PREFIX:
1777                 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
1778                         prependEnvPath("PATH", lyxrc.path_prefix);
1779                 }
1780         case LyXRC::RC_PERS_DICT:
1781         case LyXRC::RC_PREVIEW:
1782         case LyXRC::RC_PREVIEW_HASHED_LABELS:
1783         case LyXRC::RC_PREVIEW_SCALE_FACTOR:
1784         case LyXRC::RC_PRINTCOLLCOPIESFLAG:
1785         case LyXRC::RC_PRINTCOPIESFLAG:
1786         case LyXRC::RC_PRINTER:
1787         case LyXRC::RC_PRINTEVENPAGEFLAG:
1788         case LyXRC::RC_PRINTEXSTRAOPTIONS:
1789         case LyXRC::RC_PRINTFILEEXTENSION:
1790         case LyXRC::RC_PRINTLANDSCAPEFLAG:
1791         case LyXRC::RC_PRINTODDPAGEFLAG:
1792         case LyXRC::RC_PRINTPAGERANGEFLAG:
1793         case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
1794         case LyXRC::RC_PRINTPAPERFLAG:
1795         case LyXRC::RC_PRINTREVERSEFLAG:
1796         case LyXRC::RC_PRINTSPOOL_COMMAND:
1797         case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
1798         case LyXRC::RC_PRINTTOFILE:
1799         case LyXRC::RC_PRINTTOPRINTER:
1800         case LyXRC::RC_PRINT_ADAPTOUTPUT:
1801         case LyXRC::RC_PRINT_COMMAND:
1802         case LyXRC::RC_RTL_SUPPORT:
1803         case LyXRC::RC_SCREEN_DPI:
1804         case LyXRC::RC_SCREEN_FONT_ROMAN:
1805         case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
1806         case LyXRC::RC_SCREEN_FONT_SANS:
1807         case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
1808         case LyXRC::RC_SCREEN_FONT_SCALABLE:
1809         case LyXRC::RC_SCREEN_FONT_SIZES:
1810         case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
1811         case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
1812         case LyXRC::RC_GEOMETRY_SESSION:
1813         case LyXRC::RC_SCREEN_ZOOM:
1814         case LyXRC::RC_SERVERPIPE:
1815         case LyXRC::RC_SET_COLOR:
1816         case LyXRC::RC_SHOW_BANNER:
1817         case LyXRC::RC_OPEN_BUFFERS_IN_TABS:
1818         case LyXRC::RC_SPELL_COMMAND:
1819         case LyXRC::RC_SPELLCHECKER:
1820         case LyXRC::RC_SPELLCHECK_CONTINUOUSLY:
1821         case LyXRC::RC_SPLITINDEX_COMMAND:
1822         case LyXRC::RC_TEMPDIRPATH:
1823         case LyXRC::RC_TEMPLATEPATH:
1824         case LyXRC::RC_TEX_ALLOWS_SPACES:
1825         case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
1826                 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
1827                         os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
1828                 }
1829         case LyXRC::RC_THESAURUSDIRPATH:
1830         case LyXRC::RC_UIFILE:
1831         case LyXRC::RC_USER_EMAIL:
1832         case LyXRC::RC_USER_NAME:
1833         case LyXRC::RC_USETEMPDIR:
1834         case LyXRC::RC_USE_ALT_LANG:
1835         case LyXRC::RC_USE_CONVERTER_CACHE:
1836         case LyXRC::RC_USE_ESC_CHARS:
1837         case LyXRC::RC_USE_INP_ENC:
1838         case LyXRC::RC_USE_PERS_DICT:
1839         case LyXRC::RC_USE_TOOLTIP:
1840         case LyXRC::RC_USE_PIXMAP_CACHE:
1841         case LyXRC::RC_USE_SPELL_LIB:
1842         case LyXRC::RC_VIEWDVI_PAPEROPTION:
1843         case LyXRC::RC_SORT_LAYOUTS:
1844         case LyXRC::RC_FULL_SCREEN_LIMIT:
1845         case LyXRC::RC_FULL_SCREEN_SCROLLBAR:
1846         case LyXRC::RC_FULL_SCREEN_MENUBAR:
1847         case LyXRC::RC_FULL_SCREEN_TABBAR:
1848         case LyXRC::RC_FULL_SCREEN_TOOLBARS:
1849         case LyXRC::RC_FULL_SCREEN_WIDTH:
1850         case LyXRC::RC_VISUAL_CURSOR:
1851         case LyXRC::RC_VIEWER:
1852         case LyXRC::RC_VIEWER_ALTERNATIVES:
1853         case LyXRC::RC_LAST:
1854                 break;
1855         }
1856 }
1857
1858 } // namespace anon
1859 } // namespace lyx