]> git.lyx.org Git - lyx.git/blob - src/lyxfunc.C
0964eba16541267a52d1e5f22a66d5659d4d8dc6
[lyx.git] / src / lyxfunc.C
1 /**
2  * \file lyxfunc.C
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 "BranchList.h"
25 #include "buffer.h"
26 #include "buffer_funcs.h"
27 #include "bufferlist.h"
28 #include "bufferparams.h"
29 #include "BufferView.h"
30 #include "cursor.h"
31 #include "CutAndPaste.h"
32 #include "debug.h"
33 #include "dispatchresult.h"
34 #include "encoding.h"
35 #include "errorlist.h"
36 #include "exporter.h"
37 #include "format.h"
38 #include "funcrequest.h"
39 #include "gettext.h"
40 #include "importer.h"
41 #include "insetiterator.h"
42 #include "intl.h"
43 #include "kbmap.h"
44 #include "language.h"
45 #include "LColor.h"
46 #include "lyx_cb.h"
47 #include "LyXAction.h"
48 #include "lyxfind.h"
49 #include "lyxlex.h"
50 #include "lyxrc.h"
51 #include "lyxrow.h"
52 #include "lyxserver.h"
53 #include "lyxtextclasslist.h"
54 #include "lyxvc.h"
55 #include "paragraph.h"
56 #include "pariterator.h"
57 #include "ParagraphParameters.h"
58 #include "undo.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/insetnote.h"
69 #include "insets/insettabular.h"
70 #include "insets/insetvspace.h"
71 #include "insets/insetwrap.h"
72
73 #include "frontends/Alert.h"
74 #include "frontends/Dialogs.h"
75 #include "frontends/FileDialog.h"
76 #include "frontends/lyx_gui.h"
77 #include "frontends/LyXKeySym.h"
78 #include "frontends/LyXView.h"
79 #include "frontends/Menubar.h"
80 #include "frontends/Toolbars.h"
81
82 #include "support/environment.h"
83 #include "support/filefilterlist.h"
84 #include "support/filetools.h"
85 #include "support/forkedcontr.h"
86 #include "support/fs_extras.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 <boost/current_function.hpp>
95 #include <boost/filesystem/operations.hpp>
96
97 #include <sstream>
98
99 using bv_funcs::freefont2string;
100
101 using lyx::support::AbsolutePath;
102 using lyx::support::AddName;
103 using lyx::support::AddPath;
104 using lyx::support::bformat;
105 using lyx::support::ChangeExtension;
106 using lyx::support::contains;
107 using lyx::support::FileFilterList;
108 using lyx::support::FileSearch;
109 using lyx::support::ForkedcallsController;
110 using lyx::support::i18nLibFileSearch;
111 using lyx::support::IsDirWriteable;
112 using lyx::support::IsFileReadable;
113 using lyx::support::isStrInt;
114 using lyx::support::MakeAbsPath;
115 using lyx::support::MakeDisplayPath;
116 using lyx::support::package;
117 using lyx::support::Path;
118 using lyx::support::QuoteName;
119 using lyx::support::rtrim;
120 using lyx::support::split;
121 using lyx::support::subst;
122 using lyx::support::Systemcall;
123 using lyx::support::token;
124 using lyx::support::trim;
125 using lyx::support::prefixIs;
126
127 using std::endl;
128 using std::make_pair;
129 using std::pair;
130 using std::string;
131 using std::istringstream;
132
133 namespace biblio = lyx::biblio;
134 namespace fs = boost::filesystem;
135
136
137 extern BufferList bufferlist;
138 extern LyXServer * lyxserver;
139
140 extern boost::scoped_ptr<kb_keymap> toplevel_keymap;
141
142 // (alkis)
143 extern tex_accent_struct get_accent(kb_action action);
144
145
146 namespace {
147
148 bool getStatus(LCursor cursor,
149                FuncRequest const & cmd, FuncStatus & status)
150 {
151         // Try to fix cursor in case it is broken.
152         cursor.fixIfBroken();
153
154         // This is, of course, a mess. Better create a new doc iterator and use
155         // this in Inset::getStatus. This might require an additional
156         // BufferView * arg, though (which should be avoided)
157         //LCursor safe = *this;
158         bool res = false;
159         for ( ; cursor.depth(); cursor.pop()) {
160                 //lyxerr << "\nLCursor::getStatus: cmd: " << cmd << endl << *this << endl;
161                 BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
162                 BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
163                 BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
164
165                 // The inset's getStatus() will return 'true' if it made
166                 // a definitive decision on whether it want to handle the
167                 // request or not. The result of this decision is put into
168                 // the 'status' parameter.
169                 if (cursor.inset().getStatus(cursor, cmd, status)) {
170                         res = true;
171                         break;
172                 }
173         }
174         return res;
175 }
176
177
178 /** Return the change status at cursor position, taking in account the
179  * status at each level of the document iterator (a table in a deleted
180  * footnote is deleted).
181  * When \param outer is true, the top slice is not looked at.
182  */
183 Change::Type lookupChange(DocIterator const & dit, bool outer = false)
184 {
185         size_t const depth = dit.depth() - (outer ? 1 : 0);
186
187         for (size_t i = 0 ; i < depth ; ++i) {
188                 CursorSlice const & slice = dit[i];
189                 if (!slice.inset().inMathed() 
190                     && slice.pos() < slice.paragraph().size()) {
191                         Change::Type const ch = slice.paragraph().lookupChange(slice.pos());
192                         if (ch != Change::UNCHANGED)
193                                 return ch;
194                 }
195         }
196         return Change::UNCHANGED;
197 }
198
199 }
200
201 LyXFunc::LyXFunc(LyXView * lv)
202         : owner(lv),
203         encoded_last_key(0),
204         keyseq(toplevel_keymap.get(), toplevel_keymap.get()),
205         cancel_meta_seq(toplevel_keymap.get(), toplevel_keymap.get()),
206         meta_fake_bit(key_modifier::none)
207 {
208 }
209
210
211 void LyXFunc::handleKeyFunc(kb_action action)
212 {
213         char c = encoded_last_key;
214
215         if (keyseq.length()) {
216                 c = 0;
217         }
218
219         owner->getIntl().getTransManager()
220                 .deadkey(c, get_accent(action).accent, view()->getLyXText());
221         // Need to clear, in case the minibuffer calls these
222         // actions
223         keyseq.clear();
224         // copied verbatim from do_accent_char
225         view()->cursor().resetAnchor();
226         view()->update();
227 }
228
229
230 void LyXFunc::processKeySym(LyXKeySymPtr keysym, key_modifier::state state)
231 {
232         lyxerr[Debug::KEY] << "KeySym is " << keysym->getSymbolName() << endl;
233
234         // Do nothing if we have nothing (JMarc)
235         if (!keysym->isOK()) {
236                 lyxerr[Debug::KEY] << "Empty kbd action (probably composing)"
237                                    << endl;
238                 return;
239         }
240
241         if (keysym->isModifier()) {
242                 lyxerr[Debug::KEY] << "isModifier true" << endl;
243                 return;
244         }
245
246         Encoding const * encoding = view()->cursor().getEncoding();
247
248         encoded_last_key = keysym->getISOEncoded(encoding ? encoding->Name() : "");
249
250         // Do a one-deep top-level lookup for
251         // cancel and meta-fake keys. RVDK_PATCH_5
252         cancel_meta_seq.reset();
253
254         FuncRequest func = cancel_meta_seq.addkey(keysym, state);
255         lyxerr[Debug::KEY] << BOOST_CURRENT_FUNCTION
256                            << " action first set to [" << func.action << ']'
257                            << endl;
258
259         // When not cancel or meta-fake, do the normal lookup.
260         // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
261         // Mostly, meta_fake_bit = key_modifier::none. RVDK_PATCH_5.
262         if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_FAKE)) {
263                 // remove Caps Lock and Mod2 as a modifiers
264                 func = keyseq.addkey(keysym, (state | meta_fake_bit));
265                 lyxerr[Debug::KEY] << BOOST_CURRENT_FUNCTION
266                                    << "action now set to ["
267                                    << func.action << ']' << endl;
268         }
269
270         // Dont remove this unless you know what you are doing.
271         meta_fake_bit = key_modifier::none;
272
273         // Can this happen now ?
274         if (func.action == LFUN_NOACTION) {
275                 func = FuncRequest(LFUN_PREFIX);
276         }
277
278         if (lyxerr.debugging(Debug::KEY)) {
279                 lyxerr << BOOST_CURRENT_FUNCTION
280                        << " Key [action="
281                        << func.action << "]["
282                        << keyseq.print() << ']'
283                        << endl;
284         }
285
286         // already here we know if it any point in going further
287         // why not return already here if action == -1 and
288         // num_bytes == 0? (Lgb)
289
290         if (keyseq.length() > 1) {
291                 owner->message(keyseq.print());
292         }
293
294
295         // Maybe user can only reach the key via holding down shift.
296         // Let's see. But only if shift is the only modifier
297         if (func.action == LFUN_UNKNOWN_ACTION &&
298             state == key_modifier::shift) {
299                 lyxerr[Debug::KEY] << "Trying without shift" << endl;
300                 func = keyseq.addkey(keysym, key_modifier::none);
301                 lyxerr[Debug::KEY] << "Action now " << func.action << endl;
302         }
303
304         if (func.action == LFUN_UNKNOWN_ACTION) {
305                 // Hmm, we didn't match any of the keysequences. See
306                 // if it's normal insertable text not already covered
307                 // by a binding
308                 if (keysym->isText() && keyseq.length() == 1) {
309                         lyxerr[Debug::KEY] << "isText() is true, inserting." << endl;
310                         func = FuncRequest(LFUN_SELFINSERT);
311                 } else {
312                         lyxerr[Debug::KEY] << "Unknown, !isText() - giving up" << endl;
313                         owner->message(_("Unknown function."));
314                         return;
315                 }
316         }
317
318         if (func.action == LFUN_SELFINSERT) {
319                 if (encoded_last_key != 0) {
320                         string const arg(1, encoded_last_key);
321                         dispatch(FuncRequest(LFUN_SELFINSERT, arg));
322                         lyxerr[Debug::KEY]
323                                 << "SelfInsert arg[`" << arg << "']" << endl;
324                 }
325         } else {
326                 dispatch(func);
327         }
328 }
329
330
331 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
332 {
333         //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
334         FuncStatus flag;
335         LCursor & cur = view()->cursor();
336
337         /* In LyX/Mac, when a dialog is open, the menus of the
338            application can still be accessed without giving focus to
339            the main window. In this case, we want to disable the menu
340            entries that are buffer-related.
341         */
342         Buffer * buf;
343         if (cmd.origin == FuncRequest::UI && !owner->hasFocus())
344                 buf = 0;
345         else
346                 buf = owner->buffer();
347
348         if (cmd.action == LFUN_NOACTION) {
349                 flag.message(N_("Nothing to do"));
350                 flag.enabled(false);
351                 return flag;
352         }
353
354         switch (cmd.action) {
355         case LFUN_UNKNOWN_ACTION:
356 #ifndef HAVE_LIBAIKSAURUS
357         case LFUN_THESAURUS_ENTRY:
358 #endif
359                 flag.unknown(true);
360                 flag.enabled(false);
361                 break;
362         default:
363                 flag |= lyx_gui::getStatus(cmd);
364         }
365
366         if (flag.unknown()) {
367                 flag.message(N_("Unknown action"));
368                 return flag;
369         }
370
371         if (!flag.enabled()) {
372                 if (flag.message().empty())
373                         flag.message(N_("Command disabled"));
374                 return flag;
375         }
376
377         // Check whether we need a buffer
378         if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
379                 // no, exit directly
380                 flag.message(N_("Command not allowed with"
381                                     "out any document open"));
382                 flag.enabled(false);
383                 return flag;
384         }
385
386         // I would really like to avoid having this switch and rather try to
387         // encode this in the function itself.
388         // -- And I'd rather let an inset decide which LFUNs it is willing
389         // to handle (Andre')
390         bool enable = true;
391         switch (cmd.action) {
392         case LFUN_TOOLTIPS_TOGGLE:
393                 flag.setOnOff(owner->getDialogs().tooltipsEnabled());
394                 break;
395
396         case LFUN_READ_ONLY_TOGGLE:
397                 flag.setOnOff(buf->isReadonly());
398                 break;
399
400         case LFUN_SWITCHBUFFER:
401                 // toggle on the current buffer, but do not toggle off
402                 // the other ones (is that a good idea?)
403                 if (cmd.argument == buf->fileName())
404                         flag.setOnOff(true);
405                 break;
406
407         case LFUN_EXPORT:
408                 enable = cmd.argument == "custom"
409                         || Exporter::IsExportable(*buf, cmd.argument);
410                 break;
411         case LFUN_CUT:
412         case LFUN_COPY:
413                 enable = cur.selection();
414                 break;
415
416         case LFUN_RUNCHKTEX:
417                 enable = buf->isLatex() && lyxrc.chktex_command != "none";
418                 break;
419
420         case LFUN_BUILDPROG:
421                 enable = Exporter::IsExportable(*buf, "program");
422                 break;
423
424         case LFUN_LAYOUT_TABULAR:
425                 enable = cur.innerInsetOfType(InsetBase::TABULAR_CODE);
426                 break;
427
428         case LFUN_LAYOUT:
429         case LFUN_LAYOUT_PARAGRAPH:
430                 enable = !cur.inset().forceDefaultParagraphs(&cur.inset());
431                 break;
432
433         case LFUN_VC_REGISTER:
434                 enable = !buf->lyxvc().inUse();
435                 break;
436         case LFUN_VC_CHECKIN:
437                 enable = buf->lyxvc().inUse() && !buf->isReadonly();
438                 break;
439         case LFUN_VC_CHECKOUT:
440                 enable = buf->lyxvc().inUse() && buf->isReadonly();
441                 break;
442         case LFUN_VC_REVERT:
443         case LFUN_VC_UNDO:
444                 enable = buf->lyxvc().inUse();
445                 break;
446         case LFUN_MENURELOAD:
447                 enable = !buf->isUnnamed() && !buf->isClean();
448                 break;
449
450         case LFUN_INSET_SETTINGS: {
451                 enable = false;
452                 if (!cur)
453                         break;
454                 InsetBase::Code code = cur.inset().lyxCode();
455                 switch (code) {
456                         case InsetBase::TABULAR_CODE:
457                                 enable = cmd.argument == "tabular";
458                                 break;
459                         case InsetBase::ERT_CODE:
460                                 enable = cmd.argument == "ert";
461                                 break;
462                         case InsetBase::FLOAT_CODE:
463                                 enable = cmd.argument == "float";
464                                 break;
465                         case InsetBase::WRAP_CODE:
466                                 enable = cmd.argument == "wrap";
467                                 break;
468                         case InsetBase::NOTE_CODE:
469                                 enable = cmd.argument == "note";
470                                 break;
471                         case InsetBase::BRANCH_CODE:
472                                 enable = cmd.argument == "branch";
473                                 break;
474                         case InsetBase::BOX_CODE:
475                                 enable = cmd.argument == "box";
476                                 break;
477                         default:
478                                 break;
479                 }
480                 break;
481         }
482
483         case LFUN_INSET_APPLY: {
484                 string const name = cmd.getArg(0);
485                 InsetBase * inset = owner->getDialogs().getOpenInset(name);
486                 if (inset) {
487                         FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument);
488                         FuncStatus fs;
489                         bool const success = inset->getStatus(cur, fr, fs);
490                         // Every inset is supposed to handle this
491                         BOOST_ASSERT(success);
492                         flag |= fs;
493                 } else {
494                         FuncRequest fr(LFUN_INSET_INSERT, cmd.argument);
495                         flag |= getStatus(fr);
496                 }
497                 enable = flag.enabled();
498                 break;
499         }
500
501         case LFUN_DIALOG_SHOW: {
502                 string const name = cmd.getArg(0);
503                 if (!buf)
504                         enable = name == "aboutlyx"
505                                 || name == "file"
506                                 || name == "forks"
507                                 || name == "prefs"
508                                 || name == "texinfo";
509                 else if (name == "print")
510                         enable = Exporter::IsExportable(*buf, "dvi")
511                                 && lyxrc.print_command != "none";
512                 else if (name == "character" || name == "mathpanel")
513                         enable = cur.inset().lyxCode() != InsetBase::ERT_CODE;
514                 else if (name == "latexlog")
515                         enable = IsFileReadable(buf->getLogName().second);
516 #if !defined (USE_ASPELL) && !defined (USE_ISPELL) && !defined (USE_PSPELL)
517                 else if (name == "spellchecker")
518                         enable = false;
519 #endif
520                 else if (name == "vclog")
521                         enable = buf->lyxvc().inUse();
522                 break;
523         }
524
525         case LFUN_DIALOG_SHOW_NEW_INSET:
526                 enable = cur.inset().lyxCode() != InsetBase::ERT_CODE;
527                 break;
528
529         case LFUN_DIALOG_UPDATE: {
530                 string const name = cmd.getArg(0);
531                 if (!buf)
532                         enable = name == "prefs";
533                 break;
534         }
535
536         // this one is difficult to get right. As a half-baked
537         // solution, we consider only the first action of the sequence
538         case LFUN_SEQUENCE: {
539                 // argument contains ';'-terminated commands
540                 string const firstcmd = token(cmd.argument, ';', 0);
541                 FuncRequest func(lyxaction.lookupFunc(firstcmd));
542                 func.origin = cmd.origin;
543                 flag = getStatus(func);
544         }
545
546         case LFUN_MENUNEW:
547         case LFUN_MENUNEWTMPLT:
548         case LFUN_WORDFINDFORWARD:
549         case LFUN_WORDFINDBACKWARD:
550         case LFUN_PREFIX:
551         case LFUN_EXEC_COMMAND:
552         case LFUN_CANCEL:
553         case LFUN_META_FAKE:
554         case LFUN_CLOSEBUFFER:
555         case LFUN_MENUWRITE:
556         case LFUN_WRITEAS:
557         case LFUN_UPDATE:
558         case LFUN_PREVIEW:
559         case LFUN_IMPORT:
560         case LFUN_QUIT:
561         case LFUN_TOCVIEW:
562         case LFUN_AUTOSAVE:
563         case LFUN_RECONFIGURE:
564         case LFUN_HELP_OPEN:
565         case LFUN_FILE_NEW:
566         case LFUN_FILE_OPEN:
567         case LFUN_DROP_LAYOUTS_CHOICE:
568         case LFUN_MENU_OPEN_BY_NAME:
569         case LFUN_GETNAME:
570         case LFUN_NOTIFY:
571         case LFUN_GOTOFILEROW:
572         case LFUN_DIALOG_SHOW_NEXT_INSET:
573         case LFUN_DIALOG_HIDE:
574         case LFUN_DIALOG_DISCONNECT_INSET:
575         case LFUN_CHILDOPEN:
576         case LFUN_TOGGLECURSORFOLLOW:
577         case LFUN_KMAP_OFF:
578         case LFUN_KMAP_PRIM:
579         case LFUN_KMAP_SEC:
580         case LFUN_KMAP_TOGGLE:
581         case LFUN_REPEAT:
582         case LFUN_EXPORT_CUSTOM:
583         case LFUN_PRINT:
584         case LFUN_SAVEPREFERENCES:
585         case LFUN_SCREEN_FONT_UPDATE:
586         case LFUN_SET_COLOR:
587         case LFUN_MESSAGE:
588         case LFUN_EXTERNAL_EDIT:
589         case LFUN_GRAPHICS_EDIT:
590         case LFUN_ALL_INSETS_TOGGLE:
591         case LFUN_LANGUAGE_BUFFER:
592         case LFUN_TEXTCLASS_APPLY:
593         case LFUN_TEXTCLASS_LOAD:
594         case LFUN_SAVE_AS_DEFAULT:
595         case LFUN_BUFFERPARAMS_APPLY:
596         case LFUN_LYXRC_APPLY:
597         case LFUN_NEXTBUFFER:
598         case LFUN_PREVIOUSBUFFER:
599                 // these are handled in our dispatch()
600                 break;
601
602         default:
603
604                 if (!::getStatus(cur, cmd, flag))
605                         flag = view()->getStatus(cmd);
606         }
607
608         if (!enable)
609                 flag.enabled(false);
610
611         // Can we use a readonly buffer?
612         if (buf && buf->isReadonly()
613             && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
614             && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
615                 flag.message(N_("Document is read-only"));
616                 flag.enabled(false);
617         }
618
619         // Are we in a DELETED change-tracking region?
620         if (buf && buf->params().tracking_changes
621             && lookupChange(cur, true) == Change::DELETED
622             && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
623             && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
624                 flag.message(N_("This portion of the document is deleted."));
625                 flag.enabled(false);
626         }
627
628         // the default error message if we disable the command
629         if (!flag.enabled() && flag.message().empty())
630                 flag.message(N_("Command disabled"));
631
632         return flag;
633 }
634
635
636 namespace {
637
638 bool ensureBufferClean(BufferView * bv)
639 {
640         Buffer & buf = *bv->buffer();
641         if (buf.isClean())
642                 return true;
643
644         string const file = MakeDisplayPath(buf.fileName(), 30);
645         string text = bformat(_("The document %1$s has unsaved "
646                                 "changes.\n\nDo you want to save "
647                                 "the document?"), file);
648         int const ret = Alert::prompt(_("Save changed document?"),
649                                       text, 0, 1, _("&Save"),
650                                       _("&Cancel"));
651
652         if (ret == 0)
653                 bv->owner()->dispatch(FuncRequest(LFUN_MENUWRITE));
654
655         return buf.isClean();
656 }
657
658
659 void showPrintError(string const & name)
660 {
661         string str = bformat(_("Could not print the document %1$s.\n"
662                                "Check that your printer is set up correctly."),
663                              MakeDisplayPath(name, 50));
664         Alert::error(_("Print document failed"), str);
665 }
666
667
668 void loadTextclass(string const & name)
669 {
670         std::pair<bool, lyx::textclass_type> const tc_pair =
671                 textclasslist.NumberOfClass(name);
672
673         if (!tc_pair.first) {
674                 lyxerr << "Document class \"" << name
675                        << "\" does not exist."
676                        << std::endl;
677                 return;
678         }
679
680         lyx::textclass_type const tc = tc_pair.second;
681
682         if (!textclasslist[tc].load()) {
683                 string s = bformat(_("The document could not be converted\n"
684                                      "into the document class %1$s."),
685                                    textclasslist[tc].name());
686                 Alert::error(_("Could not change class"), s);
687         }
688 }
689
690
691 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
692
693 } //namespace anon
694
695
696 void LyXFunc::dispatch(FuncRequest const & cmd)
697 {
698         BOOST_ASSERT(view());
699         string const argument = cmd.argument;
700         kb_action const action = cmd.action;
701
702         lyxerr[Debug::ACTION] << "LyXFunc::dispatch: cmd: " << cmd << endl;
703         //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
704
705         // we have not done anything wrong yet.
706         errorstat = false;
707         dispatch_buffer.erase();
708
709         bool update = false;
710
711         FuncStatus const flag = getStatus(cmd);
712         if (!flag.enabled()) {
713                 // We cannot use this function here
714                 lyxerr[Debug::ACTION] << "LyXFunc::dispatch: "
715                        << lyxaction.getActionName(action)
716                        << " [" << action << "] is disabled at this location"
717                        << endl;
718                 setErrorMessage(flag.message());
719         } else {
720
721                 if (view()->available())
722                         view()->hideCursor();
723
724                 switch (action) {
725
726                 case LFUN_WORDFINDFORWARD:
727                 case LFUN_WORDFINDBACKWARD: {
728                         static string last_search;
729                         string searched_string;
730
731                         if (!argument.empty()) {
732                                 last_search = argument;
733                                 searched_string = argument;
734                         } else {
735                                 searched_string = last_search;
736                         }
737
738                         if (searched_string.empty())
739                                 break;
740
741                         bool const fw = action == LFUN_WORDFINDFORWARD;
742                         string const data =
743                                 lyx::find::find2string(searched_string, true, false, fw);
744                         lyx::find::find(view(), FuncRequest(LFUN_WORD_FIND, data));
745                         break;
746                 }
747
748                 case LFUN_PREFIX:
749                         owner->message(keyseq.printOptions());
750                         break;
751
752                 case LFUN_EXEC_COMMAND:
753                         owner->getToolbars().display("minibuffer", true);
754                         owner->focus_command_buffer();
755                         break;
756
757                 case LFUN_CANCEL:
758                         keyseq.reset();
759                         meta_fake_bit = key_modifier::none;
760                         if (view()->available())
761                                 // cancel any selection
762                                 dispatch(FuncRequest(LFUN_MARK_OFF));
763                         setMessage(N_("Cancel"));
764                         break;
765
766                 case LFUN_META_FAKE:
767                         meta_fake_bit = key_modifier::alt;
768                         setMessage(keyseq.print());
769                         break;
770
771                 case LFUN_READ_ONLY_TOGGLE:
772                         if (owner->buffer()->lyxvc().inUse())
773                                 owner->buffer()->lyxvc().toggleReadOnly();
774                         else
775                                 owner->buffer()->setReadonly(
776                                         !owner->buffer()->isReadonly());
777                         break;
778
779                 // --- Menus -----------------------------------------------
780                 case LFUN_MENUNEW:
781                         menuNew(argument, false);
782                         break;
783
784                 case LFUN_MENUNEWTMPLT:
785                         menuNew(argument, true);
786                         break;
787
788                 case LFUN_CLOSEBUFFER:
789                         closeBuffer();
790                         break;
791
792                 case LFUN_MENUWRITE:
793                         if (!owner->buffer()->isUnnamed()) {
794                                 string const str = bformat(_("Saving document %1$s..."),
795                                          MakeDisplayPath(owner->buffer()->fileName()));
796                                 owner->message(str);
797                                 MenuWrite(owner->buffer());
798                                 owner->message(str + _(" done."));
799                         } else
800                                 WriteAs(owner->buffer());
801                         break;
802
803                 case LFUN_WRITEAS:
804                         WriteAs(owner->buffer(), argument);
805                         break;
806
807                 case LFUN_MENURELOAD: {
808                         string const file = MakeDisplayPath(view()->buffer()->fileName(), 20);
809                         string text = bformat(_("Any changes will be lost. Are you sure "
810                                 "you want to revert to the saved version of the document %1$s?"), file);
811                         int const ret = Alert::prompt(_("Revert to saved document?"),
812                                 text, 0, 1, _("&Revert"), _("&Cancel"));
813
814                         if (ret == 0)
815                                 view()->reload();
816                         break;
817                 }
818
819                 case LFUN_UPDATE:
820                         Exporter::Export(owner->buffer(), argument, true);
821                         view()->showErrorList(BufferFormat(*owner->buffer()));
822                         break;
823
824                 case LFUN_PREVIEW:
825                         Exporter::Preview(owner->buffer(), argument);
826                         view()->showErrorList(BufferFormat(*owner->buffer()));
827                         break;
828
829                 case LFUN_BUILDPROG:
830                         Exporter::Export(owner->buffer(), "program", true);
831                         view()->showErrorList(_("Build"));
832                         break;
833
834                 case LFUN_RUNCHKTEX:
835                         owner->buffer()->runChktex();
836                         view()->showErrorList(_("ChkTeX"));
837                         break;
838
839                 case LFUN_EXPORT:
840                         if (argument == "custom")
841                                 owner->getDialogs().show("sendto");
842                         else {
843                                 Exporter::Export(owner->buffer(), argument, false);
844                                 view()->showErrorList(BufferFormat(*owner->buffer()));
845                         }
846                         break;
847
848                 case LFUN_EXPORT_CUSTOM: {
849                         string format_name;
850                         string command = split(argument, format_name, ' ');
851                         Format const * format = formats.getFormat(format_name);
852                         if (!format) {
853                                 lyxerr << "Format \"" << format_name
854                                        << "\" not recognized!"
855                                        << std::endl;
856                                 break;
857                         }
858
859                         Buffer * buffer = owner->buffer();
860
861                         // The name of the file created by the conversion process
862                         string filename;
863
864                         // Output to filename
865                         if (format->name() == "lyx") {
866                                 string const latexname =
867                                         buffer->getLatexName(false);
868                                 filename = ChangeExtension(latexname,
869                                                            format->extension());
870                                 filename = AddName(buffer->temppath(), filename);
871
872                                 if (!buffer->writeFile(filename))
873                                         break;
874
875                         } else {
876                                 Exporter::Export(buffer, format_name, true,
877                                                  filename);
878                         }
879
880                         // Substitute $$FName for filename
881                         if (!contains(command, "$$FName"))
882                                 command = "( " + command + " ) < $$FName";
883                         command = subst(command, "$$FName", filename);
884
885                         // Execute the command in the background
886                         Systemcall call;
887                         call.startscript(Systemcall::DontWait, command);
888                         break;
889                 }
890
891                 case LFUN_PRINT: {
892                         string target;
893                         string target_name;
894                         string command = split(split(argument, target, ' '),
895                                                target_name, ' ');
896
897                         if (target.empty()
898                             || target_name.empty()
899                             || command.empty()) {
900                                 lyxerr << "Unable to parse \""
901                                        << argument << '"' << std::endl;
902                                 break;
903                         }
904                         if (target != "printer" && target != "file") {
905                                 lyxerr << "Unrecognized target \""
906                                        << target << '"' << std::endl;
907                                 break;
908                         }
909
910                         Buffer * buffer = owner->buffer();
911
912                         if (!Exporter::Export(buffer, "dvi", true)) {
913                                 showPrintError(buffer->fileName());
914                                 break;
915                         }
916
917                         // Push directory path.
918                         string const path = buffer->temppath();
919                         Path p(path);
920
921                         // there are three cases here:
922                         // 1. we print to a file
923                         // 2. we print directly to a printer
924                         // 3. we print using a spool command (print to file first)
925                         Systemcall one;
926                         int res = 0;
927                         string const dviname =
928                                 ChangeExtension(buffer->getLatexName(true),
929                                                 "dvi");
930
931                         if (target == "printer") {
932                                 if (!lyxrc.print_spool_command.empty()) {
933                                         // case 3: print using a spool
934                                         string const psname =
935                                                 ChangeExtension(dviname,".ps");
936                                         command += lyxrc.print_to_file
937                                                 + QuoteName(psname)
938                                                 + ' '
939                                                 + QuoteName(dviname);
940
941                                         string command2 =
942                                                 lyxrc.print_spool_command +' ';
943                                         if (target_name != "default") {
944                                                 command2 += lyxrc.print_spool_printerprefix
945                                                         + target_name
946                                                         + ' ';
947                                         }
948                                         command2 += QuoteName(psname);
949                                         // First run dvips.
950                                         // If successful, then spool command
951                                         res = one.startscript(
952                                                 Systemcall::Wait,
953                                                 command);
954
955                                         if (res == 0)
956                                                 res = one.startscript(
957                                                         Systemcall::DontWait,
958                                                         command2);
959                                 } else {
960                                         // case 2: print directly to a printer
961                                         res = one.startscript(
962                                                 Systemcall::DontWait,
963                                                 command + QuoteName(dviname));
964                                 }
965
966                         } else {
967                                 // case 1: print to a file
968                                 command += lyxrc.print_to_file
969                                         + QuoteName(MakeAbsPath(target_name,
970                                                                 path))
971                                         + ' '
972                                         + QuoteName(dviname);
973                                 res = one.startscript(Systemcall::DontWait,
974                                                       command);
975                         }
976
977                         if (res != 0)
978                                 showPrintError(buffer->fileName());
979                         break;
980                 }
981
982                 case LFUN_IMPORT:
983                         doImport(argument);
984                         break;
985
986                 case LFUN_QUIT:
987                         QuitLyX(argument == "force");
988                         break;
989
990                 case LFUN_TOCVIEW: {
991                         InsetCommandParams p("tableofcontents");
992                         string const data = InsetCommandMailer::params2string("toc", p);
993                         owner->getDialogs().show("toc", data, 0);
994                         break;
995                 }
996
997                 case LFUN_AUTOSAVE:
998                         AutoSave(view());
999                         break;
1000
1001                 case LFUN_RECONFIGURE:
1002                         Reconfigure(view());
1003                         break;
1004
1005                 case LFUN_HELP_OPEN: {
1006                         string const arg = argument;
1007                         if (arg.empty()) {
1008                                 setErrorMessage(N_("Missing argument"));
1009                                 break;
1010                         }
1011                         string const fname = i18nLibFileSearch("doc", arg, "lyx");
1012                         if (fname.empty()) {
1013                                 lyxerr << "LyX: unable to find documentation file `"
1014                                                          << arg << "'. Bad installation?" << endl;
1015                                 break;
1016                         }
1017                         owner->message(bformat(_("Opening help file %1$s..."),
1018                                 MakeDisplayPath(fname)));
1019                         view()->loadLyXFile(fname, false);
1020                         break;
1021                 }
1022
1023                 // --- version control -------------------------------
1024                 case LFUN_VC_REGISTER:
1025                         if (!ensureBufferClean(view()))
1026                                 break;
1027                         if (!owner->buffer()->lyxvc().inUse()) {
1028                                 owner->buffer()->lyxvc().registrer();
1029                                 view()->reload();
1030                         }
1031                         break;
1032
1033                 case LFUN_VC_CHECKIN:
1034                         if (!ensureBufferClean(view()))
1035                                 break;
1036                         if (owner->buffer()->lyxvc().inUse()
1037                                         && !owner->buffer()->isReadonly()) {
1038                                 owner->buffer()->lyxvc().checkIn();
1039                                 view()->reload();
1040                         }
1041                         break;
1042
1043                 case LFUN_VC_CHECKOUT:
1044                         if (!ensureBufferClean(view()))
1045                                 break;
1046                         if (owner->buffer()->lyxvc().inUse()
1047                                         && owner->buffer()->isReadonly()) {
1048                                 owner->buffer()->lyxvc().checkOut();
1049                                 view()->reload();
1050                         }
1051                         break;
1052
1053                 case LFUN_VC_REVERT:
1054                         owner->buffer()->lyxvc().revert();
1055                         view()->reload();
1056                         break;
1057
1058                 case LFUN_VC_UNDO:
1059                         owner->buffer()->lyxvc().undoLast();
1060                         view()->reload();
1061                         break;
1062
1063                 // --- buffers ----------------------------------------
1064                 case LFUN_SWITCHBUFFER:
1065                         view()->setBuffer(bufferlist.getBuffer(argument));
1066                         break;
1067
1068                 case LFUN_NEXTBUFFER:
1069                         view()->setBuffer(bufferlist.next(view()->buffer()));
1070                         break;
1071
1072                 case LFUN_PREVIOUSBUFFER:
1073                         view()->setBuffer(bufferlist.previous(view()->buffer()));
1074                         break;
1075
1076                 case LFUN_FILE_NEW:
1077                         NewFile(view(), argument);
1078                         break;
1079
1080                 case LFUN_FILE_OPEN:
1081                         open(argument);
1082                         break;
1083
1084                 case LFUN_DROP_LAYOUTS_CHOICE:
1085                         owner->getToolbars().openLayoutList();
1086                         break;
1087
1088                 case LFUN_MENU_OPEN_BY_NAME:
1089                         owner->getMenubar().openByName(argument);
1090                         break;
1091
1092                 // --- lyxserver commands ----------------------------
1093                 case LFUN_GETNAME:
1094                         setMessage(owner->buffer()->fileName());
1095                         lyxerr[Debug::INFO] << "FNAME["
1096                                                          << owner->buffer()->fileName()
1097                                                          << "] " << endl;
1098                         break;
1099
1100                 case LFUN_NOTIFY:
1101                         dispatch_buffer = keyseq.print();
1102                         lyxserver->notifyClient(dispatch_buffer);
1103                         break;
1104
1105                 case LFUN_GOTOFILEROW: {
1106                         string file_name;
1107                         int row;
1108                         istringstream is(argument);
1109                         is >> file_name >> row;
1110                         if (prefixIs(file_name, package().temp_dir())) {
1111                                 // Needed by inverse dvi search. If it is a file
1112                                 // in tmpdir, call the apropriated function
1113                                 view()->setBuffer(bufferlist.getBufferFromTmp(file_name));
1114                         } else {
1115                                 // Must replace extension of the file to be .lyx
1116                                 // and get full path
1117                                 string const s = ChangeExtension(file_name, ".lyx");
1118                                 // Either change buffer or load the file
1119                                 if (bufferlist.exists(s)) {
1120                                         view()->setBuffer(bufferlist.getBuffer(s));
1121                                 } else {
1122                                         view()->loadLyXFile(s);
1123                                 }
1124                         }
1125
1126                         view()->setCursorFromRow(row);
1127
1128                         view()->center();
1129                         // see BufferView_pimpl::center()
1130                         view()->updateScrollbar();
1131                         break;
1132                 }
1133
1134                 case LFUN_DIALOG_SHOW: {
1135                         string const name = cmd.getArg(0);
1136                         string data = trim(cmd.argument.substr(name.size()));
1137
1138                         if (name == "character") {
1139                                 data = freefont2string();
1140                                 if (!data.empty())
1141                                         owner->getDialogs().show("character", data);
1142                         }
1143
1144                         else if (name == "latexlog") {
1145                                 pair<Buffer::LogType, string> const logfile =
1146                                         owner->buffer()->getLogName();
1147                                 switch (logfile.first) {
1148                                 case Buffer::latexlog:
1149                                         data = "latex ";
1150                                         break;
1151                                 case Buffer::buildlog:
1152                                         data = "literate ";
1153                                         break;
1154                                 }
1155                                 data += logfile.second;
1156                                 owner->getDialogs().show("log", data);
1157                         }
1158                         else if (name == "vclog") {
1159                                 string const data = "vc " +
1160                                         owner->buffer()->lyxvc().getLogFile();
1161                                 owner->getDialogs().show("log", data);
1162                         }
1163                         else
1164                                 owner->getDialogs().show(name, data);
1165                         break;
1166                 }
1167
1168                 case LFUN_DIALOG_SHOW_NEW_INSET: {
1169                         string const name = cmd.getArg(0);
1170                         string data = trim(cmd.argument.substr(name.size()));
1171                         if (name == "bibitem" ||
1172                             name == "bibtex" ||
1173                             name == "index" ||
1174                             name == "label" ||
1175                             name == "ref" ||
1176                             name == "toc" ||
1177                             name == "url") {
1178                                 InsetCommandParams p(name);
1179                                 data = InsetCommandMailer::params2string(name, p);
1180                         } else if (name == "include") {
1181                                 InsetCommandParams p(data);
1182                                 data = InsetIncludeMailer::params2string(p);
1183                         } else if (name == "box") {
1184                                 // \c data == "Boxed" || "Frameless" etc
1185                                 InsetBoxParams p(data);
1186                                 data = InsetBoxMailer::params2string(p);
1187                         } else if (name == "branch") {
1188                                 InsetBranchParams p;
1189                                 data = InsetBranchMailer::params2string(p);
1190                         } else if (name == "citation") {
1191                                 InsetCommandParams p("cite");
1192                                 data = InsetCommandMailer::params2string(name, p);
1193                         } else if (name == "ert") {
1194                                 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1195                         } else if (name == "external") {
1196                                 InsetExternalParams p;
1197                                 Buffer const & buffer = *owner->buffer();
1198                                 data = InsetExternalMailer::params2string(p, buffer);
1199                         } else if (name == "float") {
1200                                 InsetFloatParams p;
1201                                 data = InsetFloatMailer::params2string(p);
1202                         } else if (name == "graphics") {
1203                                 InsetGraphicsParams p;
1204                                 Buffer const & buffer = *owner->buffer();
1205                                 data = InsetGraphicsMailer::params2string(p, buffer);
1206                         } else if (name == "note") {
1207                                 InsetNoteParams p;
1208                                 data = InsetNoteMailer::params2string(p);
1209                         } else if (name == "vspace") {
1210                                 VSpace space;
1211                                 data = InsetVSpaceMailer::params2string(space);
1212                         } else if (name == "wrap") {
1213                                 InsetWrapParams p;
1214                                 data = InsetWrapMailer::params2string(p);
1215                         }
1216                         owner->getDialogs().show(name, data, 0);
1217                         break;
1218                 }
1219
1220                 case LFUN_DIALOG_SHOW_NEXT_INSET:
1221                         break;
1222
1223                 case LFUN_DIALOG_UPDATE: {
1224                         string const & name = argument;
1225                         // Can only update a dialog connected to an existing inset
1226                         InsetBase * inset = owner->getDialogs().getOpenInset(name);
1227                         if (inset) {
1228                                 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument);
1229                                 inset->dispatch(view()->cursor(), fr);
1230                         } else if (name == "paragraph") {
1231                                 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1232                         } else if (name == "prefs") {
1233                                 owner->getDialogs().update(name, string());
1234                         }
1235                         break;
1236                 }
1237
1238                 case LFUN_DIALOG_HIDE:
1239                         Dialogs::hide(argument, 0);
1240                         break;
1241
1242                 case LFUN_DIALOG_DISCONNECT_INSET:
1243                         owner->getDialogs().disconnect(argument);
1244                         break;
1245
1246                 case LFUN_CHILDOPEN: {
1247                         string const filename =
1248                                 MakeAbsPath(argument, owner->buffer()->filePath());
1249                         setMessage(N_("Opening child document ") +
1250                                          MakeDisplayPath(filename) + "...");
1251                         view()->savePosition(0);
1252                         string const parentfilename = owner->buffer()->fileName();
1253                         if (bufferlist.exists(filename))
1254                                 view()->setBuffer(bufferlist.getBuffer(filename));
1255                         else
1256                                 view()->loadLyXFile(filename);
1257                         // Set the parent name of the child document.
1258                         // This makes insertion of citations and references in the child work,
1259                         // when the target is in the parent or another child document.
1260                         owner->buffer()->setParentName(parentfilename);
1261                         break;
1262                 }
1263
1264                 case LFUN_TOGGLECURSORFOLLOW:
1265                         lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1266                         break;
1267
1268                 case LFUN_KMAP_OFF:
1269                         owner->getIntl().KeyMapOn(false);
1270                         break;
1271
1272                 case LFUN_KMAP_PRIM:
1273                         owner->getIntl().KeyMapPrim();
1274                         break;
1275
1276                 case LFUN_KMAP_SEC:
1277                         owner->getIntl().KeyMapSec();
1278                         break;
1279
1280                 case LFUN_KMAP_TOGGLE:
1281                         owner->getIntl().ToggleKeyMap();
1282                         break;
1283
1284                 case LFUN_REPEAT: {
1285                         // repeat command
1286                         string countstr;
1287                         string rest = split(argument, countstr, ' ');
1288                         istringstream is(countstr);
1289                         int count = 0;
1290                         is >> count;
1291                         lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1292                         for (int i = 0; i < count; ++i)
1293                                 dispatch(lyxaction.lookupFunc(rest));
1294                         break;
1295                 }
1296
1297                 case LFUN_SEQUENCE: {
1298                         // argument contains ';'-terminated commands
1299                         string arg = argument;
1300                         while (!arg.empty()) {
1301                                 string first;
1302                                 arg = split(arg, first, ';');
1303                                 FuncRequest func(lyxaction.lookupFunc(first));
1304                                 func.origin = cmd.origin;
1305                                 dispatch(func);
1306                         }
1307                         break;
1308                 }
1309
1310                 case LFUN_SAVEPREFERENCES: {
1311                         Path p(package().user_support());
1312                         lyxrc.write("preferences", false);
1313                         break;
1314                 }
1315
1316                 case LFUN_SCREEN_FONT_UPDATE:
1317                         // handle the screen font changes.
1318                         lyxrc.set_font_norm_type();
1319                         lyx_gui::update_fonts();
1320                         // All visible buffers will need resize
1321                         view()->resize();
1322                         break;
1323
1324                 case LFUN_SET_COLOR: {
1325                         string lyx_name;
1326                         string const x11_name = split(argument, lyx_name, ' ');
1327                         if (lyx_name.empty() || x11_name.empty()) {
1328                                 setErrorMessage(N_("Syntax: set-color <lyx_name>"
1329                                                         " <x11_name>"));
1330                                 break;
1331                         }
1332
1333                         bool const graphicsbg_changed =
1334                                 (lyx_name == lcolor.getLyXName(LColor::graphicsbg) &&
1335                                  x11_name != lcolor.getX11Name(LColor::graphicsbg));
1336
1337                         if (!lcolor.setColor(lyx_name, x11_name)) {
1338                                 setErrorMessage(
1339                                         bformat(_("Set-color \"%1$s\" failed "
1340                                                                 "- color is undefined or "
1341                                                                 "may not be redefined"), lyx_name));
1342                                 break;
1343                         }
1344
1345                         lyx_gui::update_color(lcolor.getFromLyXName(lyx_name));
1346
1347                         if (graphicsbg_changed) {
1348 #ifdef WITH_WARNINGS
1349 #warning FIXME!! The graphics cache no longer has a changeDisplay method.
1350 #endif
1351 #if 0
1352                                 lyx::graphics::GCache::get().changeDisplay(true);
1353 #endif
1354                         }
1355                         break;
1356                 }
1357
1358                 case LFUN_MESSAGE:
1359                         owner->message(argument);
1360                         break;
1361
1362                 case LFUN_TOOLTIPS_TOGGLE:
1363                         owner->getDialogs().toggleTooltips();
1364                         break;
1365
1366                 case LFUN_EXTERNAL_EDIT: {
1367                         FuncRequest fr(action, argument);
1368                         InsetExternal().dispatch(view()->cursor(), fr);
1369                         break;
1370                 }
1371
1372                 case LFUN_GRAPHICS_EDIT: {
1373                         FuncRequest fr(action, argument);
1374                         InsetGraphics().dispatch(view()->cursor(), fr);
1375                         break;
1376                 }
1377
1378                 case LFUN_INSET_APPLY: {
1379                         string const name = cmd.getArg(0);
1380                         InsetBase * inset = owner->getDialogs().getOpenInset(name);
1381                         if (inset) {
1382                                 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1383                                 inset->dispatch(view()->cursor(), fr);
1384                         } else {
1385                                 FuncRequest fr(LFUN_INSET_INSERT, argument);
1386                                 dispatch(fr);
1387                         }
1388                         // ideally, the update flag should be set by the insets,
1389                         // but this is not possible currently
1390                         update = true;
1391                         break;
1392                 }
1393
1394                 case LFUN_ALL_INSETS_TOGGLE: {
1395                         string action;
1396                         string const name = split(argument, action, ' ');
1397                         InsetBase::Code const inset_code =
1398                                 InsetBase::translate(name);
1399
1400                         LCursor & cur = view()->cursor();
1401                         FuncRequest fr(LFUN_INSET_TOGGLE, action);
1402
1403                         InsetBase & inset = owner->buffer()->inset();
1404                         InsetIterator it  = inset_iterator_begin(inset);
1405                         InsetIterator const end = inset_iterator_end(inset);
1406                         for (; it != end; ++it) {
1407                                 if (inset_code == InsetBase::NO_CODE
1408                                     || inset_code == it->lyxCode())
1409                                         it->dispatch(cur, fr);
1410                         }
1411                         break;
1412                 }
1413
1414                 case LFUN_LANGUAGE_BUFFER: {
1415                         Buffer & buffer = *owner->buffer();
1416                         Language const * oldL = buffer.params().language;
1417                         Language const * newL = languages.getLanguage(argument);
1418                         if (!newL || oldL == newL)
1419                                 break;
1420
1421                         if (oldL->RightToLeft() == newL->RightToLeft()
1422                             && !buffer.isMultiLingual())
1423                                 buffer.changeLanguage(oldL, newL);
1424                         else
1425                                 buffer.updateDocLang(newL);
1426                         break;
1427                 }
1428
1429                 case LFUN_SAVE_AS_DEFAULT: {
1430                         string const fname =
1431                                 AddName(AddPath(package().user_support(), "templates/"),
1432                                         "defaults.lyx");
1433                         Buffer defaults(fname);
1434
1435                         istringstream ss(argument);
1436                         LyXLex lex(0,0);
1437                         lex.setStream(ss);
1438                         int const unknown_tokens = defaults.readHeader(lex);
1439
1440                         if (unknown_tokens != 0) {
1441                                 lyxerr << "Warning in LFUN_SAVE_AS_DEFAULT!\n"
1442                                        << unknown_tokens << " unknown token"
1443                                        << (unknown_tokens == 1 ? "" : "s")
1444                                        << endl;
1445                         }
1446
1447                         if (defaults.writeFile(defaults.fileName()))
1448                                 setMessage(_("Document defaults saved in ")
1449                                            + MakeDisplayPath(fname));
1450                         else
1451                                 setErrorMessage(_("Unable to save document defaults"));
1452                         break;
1453                 }
1454
1455                 case LFUN_BUFFERPARAMS_APPLY: {
1456                         biblio::CiteEngine const engine =
1457                                 owner->buffer()->params().cite_engine;
1458
1459                         istringstream ss(argument);
1460                         LyXLex lex(0,0);
1461                         lex.setStream(ss);
1462                         int const unknown_tokens =
1463                                 owner->buffer()->readHeader(lex);
1464
1465                         if (unknown_tokens != 0) {
1466                                 lyxerr << "Warning in LFUN_BUFFERPARAMS_APPLY!\n"
1467                                        << unknown_tokens << " unknown token"
1468                                        << (unknown_tokens == 1 ? "" : "s")
1469                                        << endl;
1470                         }
1471                         if (engine == owner->buffer()->params().cite_engine)
1472                                 break;
1473
1474                         LCursor & cur = view()->cursor();
1475                         FuncRequest fr(LFUN_INSET_REFRESH);
1476
1477                         InsetBase & inset = owner->buffer()->inset();
1478                         InsetIterator it  = inset_iterator_begin(inset);
1479                         InsetIterator const end = inset_iterator_end(inset);
1480                         for (; it != end; ++it)
1481                                 if (it->lyxCode() == InsetBase::CITE_CODE)
1482                                         it->dispatch(cur, fr);
1483                         break;
1484                 }
1485
1486                 case LFUN_TEXTCLASS_APPLY: {
1487                         recordUndoFullDocument(view());
1488                         Buffer * buffer = owner->buffer();
1489
1490                         lyx::textclass_type const old_class =
1491                                 buffer->params().textclass;
1492
1493                         loadTextclass(argument);
1494
1495                         std::pair<bool, lyx::textclass_type> const tc_pair =
1496                                 textclasslist.NumberOfClass(argument);
1497
1498                         if (!tc_pair.first)
1499                                 break;
1500
1501                         lyx::textclass_type const new_class = tc_pair.second;
1502                         if (old_class == new_class)
1503                                 // nothing to do
1504                                 break;
1505
1506                         owner->message(_("Converting document to new document class..."));
1507                         StableDocIterator backcur(view()->cursor());
1508                         ErrorList el;
1509                         lyx::cap::SwitchBetweenClasses(
1510                                 old_class, new_class,
1511                                 buffer->paragraphs(), el);
1512
1513                         view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
1514                         bufferErrors(*buffer, el);
1515                         view()->showErrorList(_("Class switch"));
1516                         updateCounters(*buffer);
1517                         update = true;
1518                         break;
1519                 }
1520
1521                 case LFUN_TEXTCLASS_LOAD:
1522                         loadTextclass(argument);
1523                         break;
1524
1525                 case LFUN_LYXRC_APPLY: {
1526                         LyXRC const lyxrc_orig = lyxrc;
1527
1528                         istringstream ss(argument);
1529                         bool const success = lyxrc.read(ss) == 0;
1530
1531                         if (!success) {
1532                                 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1533                                        << "Unable to read lyxrc data"
1534                                        << endl;
1535                                 break;
1536                         }
1537
1538                         actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1539                         break;
1540                 }
1541
1542                 default: {
1543                         view()->cursor().dispatch(cmd);
1544                         update |= view()->cursor().result().update();
1545                         if (!view()->cursor().result().dispatched())
1546                                 update |= view()->dispatch(cmd);
1547                         break;
1548                 }
1549                 }
1550
1551                 if (view()->available()) {
1552                         // Redraw screen unless explicitly told otherwise.
1553                         // This also initializes the position cache for all insets
1554                         // in (at least partially) visible top-level paragraphs.
1555                         if (update)
1556                                 view()->update(Update::FitCursor | Update::Force);
1557                         else
1558                                 view()->update(Update::FitCursor);
1559
1560                         // if we executed a mutating lfun, mark the buffer as dirty
1561                         // FIXME: Why not use flag.enabled() but call getStatus again?
1562                         if (getStatus(cmd).enabled()
1563                                         && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)
1564                                         && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly))
1565                                 view()->buffer()->markDirty();
1566                 }
1567
1568                 if (view()->cursor().inTexted()) {
1569                         view()->owner()->updateLayoutChoice();
1570                 }
1571         }
1572         sendDispatchMessage(_(getMessage()), cmd);
1573 }
1574
1575
1576 void LyXFunc::sendDispatchMessage(string const & msg, FuncRequest const & cmd)
1577 {
1578         owner->updateMenubar();
1579         owner->updateToolbars();
1580
1581         const bool verbose = (cmd.origin == FuncRequest::UI
1582                               || cmd.origin == FuncRequest::COMMANDBUFFER);
1583
1584         if (cmd.action == LFUN_SELFINSERT || !verbose) {
1585                 lyxerr[Debug::ACTION] << "dispatch msg is " << msg << endl;
1586                 if (!msg.empty())
1587                         owner->message(msg);
1588                 return;
1589         }
1590
1591         string dispatch_msg = msg;
1592         if (!dispatch_msg.empty())
1593                 dispatch_msg += ' ';
1594
1595         string comname = lyxaction.getActionName(cmd.action);
1596
1597         bool argsadded = false;
1598
1599         if (!cmd.argument.empty()) {
1600                 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1601                         comname += ' ' + cmd.argument;
1602                         argsadded = true;
1603                 }
1604         }
1605
1606         string const shortcuts = toplevel_keymap->printbindings(cmd);
1607
1608         if (!shortcuts.empty())
1609                 comname += ": " + shortcuts;
1610         else if (!argsadded && !cmd.argument.empty())
1611                 comname += ' ' + cmd.argument;
1612
1613         if (!comname.empty()) {
1614                 comname = rtrim(comname);
1615                 dispatch_msg += '(' + rtrim(comname) + ')';
1616         }
1617
1618         lyxerr[Debug::ACTION] << "verbose dispatch msg " << dispatch_msg << endl;
1619         if (!dispatch_msg.empty())
1620                 owner->message(dispatch_msg);
1621 }
1622
1623
1624 void LyXFunc::setupLocalKeymap()
1625 {
1626         keyseq.stdmap = toplevel_keymap.get();
1627         keyseq.curmap = toplevel_keymap.get();
1628         cancel_meta_seq.stdmap = toplevel_keymap.get();
1629         cancel_meta_seq.curmap = toplevel_keymap.get();
1630 }
1631
1632
1633 void LyXFunc::menuNew(string const & name, bool fromTemplate)
1634 {
1635         string initpath = lyxrc.document_path;
1636         string filename(name);
1637
1638         if (view()->available()) {
1639                 string const trypath = owner->buffer()->filePath();
1640                 // If directory is writeable, use this as default.
1641                 if (IsDirWriteable(trypath))
1642                         initpath = trypath;
1643         }
1644
1645         static int newfile_number;
1646
1647         if (filename.empty()) {
1648                 filename = AddName(lyxrc.document_path,
1649                             "newfile" + convert<string>(++newfile_number) + ".lyx");
1650                 while (bufferlist.exists(filename) || fs::is_readable(filename)) {
1651                         ++newfile_number;
1652                         filename = AddName(lyxrc.document_path,
1653                                            "newfile" +  convert<string>(newfile_number) +
1654                                     ".lyx");
1655                 }
1656         }
1657
1658         // The template stuff
1659         string templname;
1660         if (fromTemplate) {
1661                 FileDialog fileDlg(_("Select template file"),
1662                         LFUN_SELECT_FILE_SYNC,
1663                         make_pair(string(_("Documents|#o#O")),
1664                                   string(lyxrc.document_path)),
1665                         make_pair(string(_("Templates|#T#t")),
1666                                   string(lyxrc.template_path)));
1667
1668                 FileDialog::Result result =
1669                         fileDlg.open(lyxrc.template_path,
1670                                      FileFilterList(_("LyX Documents (*.lyx)")),
1671                                      string());
1672
1673                 if (result.first == FileDialog::Later)
1674                         return;
1675                 if (result.second.empty())
1676                         return;
1677                 templname = result.second;
1678         }
1679
1680         view()->newFile(filename, templname, !name.empty());
1681 }
1682
1683
1684 void LyXFunc::open(string const & fname)
1685 {
1686         string initpath = lyxrc.document_path;
1687
1688         if (view()->available()) {
1689                 string const trypath = owner->buffer()->filePath();
1690                 // If directory is writeable, use this as default.
1691                 if (IsDirWriteable(trypath))
1692                         initpath = trypath;
1693         }
1694
1695         string filename;
1696
1697         if (fname.empty()) {
1698                 FileDialog fileDlg(_("Select document to open"),
1699                         LFUN_FILE_OPEN,
1700                         make_pair(string(_("Documents|#o#O")),
1701                                   string(lyxrc.document_path)),
1702                         make_pair(string(_("Examples|#E#e")),
1703                                   string(AddPath(package().system_support(), "examples"))));
1704
1705                 FileDialog::Result result =
1706                         fileDlg.open(initpath,
1707                                      FileFilterList(_("LyX Documents (*.lyx)")),
1708                                      string());
1709
1710                 if (result.first == FileDialog::Later)
1711                         return;
1712
1713                 filename = result.second;
1714
1715                 // check selected filename
1716                 if (filename.empty()) {
1717                         owner->message(_("Canceled."));
1718                         return;
1719                 }
1720         } else
1721                 filename = fname;
1722
1723         // get absolute path of file and add ".lyx" to the filename if
1724         // necessary
1725         string const fullpath = FileSearch(string(), filename, "lyx");
1726         if (!fullpath.empty()) {
1727                 filename = fullpath;
1728         }
1729
1730         string const disp_fn(MakeDisplayPath(filename));
1731
1732         // if the file doesn't exist, let the user create one
1733         if (!fs::exists(filename)) {
1734                 // the user specifically chose this name. Believe them.
1735                 view()->newFile(filename, "", true);
1736                 return;
1737         }
1738
1739         owner->message(bformat(_("Opening document %1$s..."), disp_fn));
1740
1741         string str2;
1742         if (view()->loadLyXFile(filename)) {
1743                 str2 = bformat(_("Document %1$s opened."), disp_fn);
1744         } else {
1745                 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1746         }
1747         owner->message(str2);
1748 }
1749
1750
1751 void LyXFunc::doImport(string const & argument)
1752 {
1753         string format;
1754         string filename = split(argument, format, ' ');
1755
1756         lyxerr[Debug::INFO] << "LyXFunc::doImport: " << format
1757                             << " file: " << filename << endl;
1758
1759         // need user interaction
1760         if (filename.empty()) {
1761                 string initpath = lyxrc.document_path;
1762
1763                 if (view()->available()) {
1764                         string const trypath = owner->buffer()->filePath();
1765                         // If directory is writeable, use this as default.
1766                         if (IsDirWriteable(trypath))
1767                                 initpath = trypath;
1768                 }
1769
1770                 string const text = bformat(_("Select %1$s file to import"),
1771                         formats.prettyName(format));
1772
1773                 FileDialog fileDlg(text,
1774                         LFUN_IMPORT,
1775                         make_pair(string(_("Documents|#o#O")),
1776                                   string(lyxrc.document_path)),
1777                         make_pair(string(_("Examples|#E#e")),
1778                                   string(AddPath(package().system_support(), "examples"))));
1779
1780                 string const filter = formats.prettyName(format)
1781                         + " (*." + formats.extension(format) + ')';
1782
1783                 FileDialog::Result result =
1784                         fileDlg.open(initpath,
1785                                      FileFilterList(filter),
1786                                      string());
1787
1788                 if (result.first == FileDialog::Later)
1789                         return;
1790
1791                 filename = result.second;
1792
1793                 // check selected filename
1794                 if (filename.empty())
1795                         owner->message(_("Canceled."));
1796         }
1797
1798         if (filename.empty())
1799                 return;
1800
1801         // get absolute path of file
1802         filename = MakeAbsPath(filename);
1803
1804         string const lyxfile = ChangeExtension(filename, ".lyx");
1805
1806         // Check if the document already is open
1807         if (lyx_gui::use_gui && bufferlist.exists(lyxfile)) {
1808                 if (!bufferlist.close(bufferlist.getBuffer(lyxfile), true)) {
1809                         owner->message(_("Canceled."));
1810                         return;
1811                 }
1812         }
1813
1814         // if the file exists already, and we didn't do
1815         // -i lyx thefile.lyx, warn
1816         if (fs::exists(lyxfile) && filename != lyxfile) {
1817                 string const file = MakeDisplayPath(lyxfile, 30);
1818
1819                 string text = bformat(_("The document %1$s already exists.\n\n"
1820                         "Do you want to over-write that document?"), file);
1821                 int const ret = Alert::prompt(_("Over-write document?"),
1822                         text, 0, 1, _("&Over-write"), _("&Cancel"));
1823
1824                 if (ret == 1) {
1825                         owner->message(_("Canceled."));
1826                         return;
1827                 }
1828         }
1829
1830         Importer::Import(owner, filename, format);
1831 }
1832
1833
1834 void LyXFunc::closeBuffer()
1835 {
1836         if (bufferlist.close(owner->buffer(), true) && !quitting) {
1837                 if (bufferlist.empty()) {
1838                         // need this otherwise SEGV may occur while
1839                         // trying to set variables that don't exist
1840                         // since there's no current buffer
1841                         owner->getDialogs().hideBufferDependent();
1842                 } else {
1843                         view()->setBuffer(bufferlist.first());
1844                 }
1845         }
1846 }
1847
1848
1849 // Each "owner" should have it's own message method. lyxview and
1850 // the minibuffer would use the minibuffer, but lyxserver would
1851 // send an ERROR signal to its client.  Alejandro 970603
1852 // This function is bit problematic when it comes to NLS, to make the
1853 // lyx servers client be language indepenent we must not translate
1854 // strings sent to this func.
1855 void LyXFunc::setErrorMessage(string const & m) const
1856 {
1857         dispatch_buffer = m;
1858         errorstat = true;
1859 }
1860
1861
1862 void LyXFunc::setMessage(string const & m) const
1863 {
1864         dispatch_buffer = m;
1865 }
1866
1867
1868 string const LyXFunc::viewStatusMessage()
1869 {
1870         // When meta-fake key is pressed, show the key sequence so far + "M-".
1871         if (wasMetaKey())
1872                 return keyseq.print() + "M-";
1873
1874         // Else, when a non-complete key sequence is pressed,
1875         // show the available options.
1876         if (keyseq.length() > 0 && !keyseq.deleted())
1877                 return keyseq.printOptions();
1878
1879         if (!view()->available())
1880                 return _("Welcome to LyX!");
1881
1882         return view()->cursor().currentState();
1883 }
1884
1885
1886 BufferView * LyXFunc::view() const
1887 {
1888         BOOST_ASSERT(owner);
1889         return owner->view().get();
1890 }
1891
1892
1893 bool LyXFunc::wasMetaKey() const
1894 {
1895         return (meta_fake_bit != key_modifier::none);
1896 }
1897
1898
1899 namespace {
1900
1901 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
1902 {
1903         // Why the switch you might ask. It is a trick to ensure that all
1904         // the elements in the LyXRCTags enum is handled. As you can see
1905         // there are no breaks at all. So it is just a huge fall-through.
1906         // The nice thing is that we will get a warning from the compiler
1907         // if we forget an element.
1908         LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
1909         switch (tag) {
1910         case LyXRC::RC_ACCEPT_COMPOUND:
1911         case LyXRC::RC_ALT_LANG:
1912         case LyXRC::RC_ASCIIROFF_COMMAND:
1913         case LyXRC::RC_ASCII_LINELEN:
1914         case LyXRC::RC_AUTOREGIONDELETE:
1915         case LyXRC::RC_AUTORESET_OPTIONS:
1916         case LyXRC::RC_AUTOSAVE:
1917         case LyXRC::RC_AUTO_NUMBER:
1918         case LyXRC::RC_BACKUPDIR_PATH:
1919         case LyXRC::RC_BIBTEX_COMMAND:
1920         case LyXRC::RC_BINDFILE:
1921         case LyXRC::RC_CHECKLASTFILES:
1922         case LyXRC::RC_CHKTEX_COMMAND:
1923         case LyXRC::RC_CONVERTER:
1924         case LyXRC::RC_COPIER:
1925         case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
1926         case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
1927         case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
1928         case LyXRC::RC_CYGWIN_PATH_FIX:
1929                 if (lyxrc_orig.cygwin_path_fix != lyxrc_new.cygwin_path_fix) {
1930                         namespace os = lyx::support::os;
1931                         os::cygwin_path_fix(lyxrc_new.cygwin_path_fix);
1932                 }
1933         case LyXRC::RC_DATE_INSERT_FORMAT:
1934         case LyXRC::RC_DEFAULT_LANGUAGE:
1935         case LyXRC::RC_DEFAULT_PAPERSIZE:
1936         case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
1937         case LyXRC::RC_DISPLAY_GRAPHICS:
1938         case LyXRC::RC_DOCUMENTPATH:
1939                 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
1940                         if (fs::exists(lyxrc_new.document_path) &&
1941                             fs::is_directory(lyxrc_new.document_path)) {
1942                                 using lyx::support::package;
1943                                 package().document_dir() = lyxrc.document_path;
1944                         }
1945                 }
1946         case LyXRC::RC_ESC_CHARS:
1947         case LyXRC::RC_FONT_ENCODING:
1948         case LyXRC::RC_FORMAT:
1949         case LyXRC::RC_INDEX_COMMAND:
1950         case LyXRC::RC_INPUT:
1951         case LyXRC::RC_KBMAP:
1952         case LyXRC::RC_KBMAP_PRIMARY:
1953         case LyXRC::RC_KBMAP_SECONDARY:
1954         case LyXRC::RC_LABEL_INIT_LENGTH:
1955         case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
1956         case LyXRC::RC_LANGUAGE_AUTO_END:
1957         case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
1958         case LyXRC::RC_LANGUAGE_COMMAND_END:
1959         case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
1960         case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
1961         case LyXRC::RC_LANGUAGE_PACKAGE:
1962         case LyXRC::RC_LANGUAGE_USE_BABEL:
1963         case LyXRC::RC_LASTFILES:
1964         case LyXRC::RC_MAKE_BACKUP:
1965         case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
1966         case LyXRC::RC_NUMLASTFILES:
1967         case LyXRC::RC_PATH_PREFIX:
1968                 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
1969                         using lyx::support::prependEnvPath;
1970                         prependEnvPath("PATH", lyxrc.path_prefix);
1971                 }
1972         case LyXRC::RC_PERS_DICT:
1973         case LyXRC::RC_POPUP_BOLD_FONT:
1974         case LyXRC::RC_POPUP_FONT_ENCODING:
1975         case LyXRC::RC_POPUP_NORMAL_FONT:
1976         case LyXRC::RC_PREVIEW:
1977         case LyXRC::RC_PREVIEW_HASHED_LABELS:
1978         case LyXRC::RC_PREVIEW_SCALE_FACTOR:
1979         case LyXRC::RC_PRINTCOLLCOPIESFLAG:
1980         case LyXRC::RC_PRINTCOPIESFLAG:
1981         case LyXRC::RC_PRINTER:
1982         case LyXRC::RC_PRINTEVENPAGEFLAG:
1983         case LyXRC::RC_PRINTEXSTRAOPTIONS:
1984         case LyXRC::RC_PRINTFILEEXTENSION:
1985         case LyXRC::RC_PRINTLANDSCAPEFLAG:
1986         case LyXRC::RC_PRINTODDPAGEFLAG:
1987         case LyXRC::RC_PRINTPAGERANGEFLAG:
1988         case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
1989         case LyXRC::RC_PRINTPAPERFLAG:
1990         case LyXRC::RC_PRINTREVERSEFLAG:
1991         case LyXRC::RC_PRINTSPOOL_COMMAND:
1992         case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
1993         case LyXRC::RC_PRINTTOFILE:
1994         case LyXRC::RC_PRINTTOPRINTER:
1995         case LyXRC::RC_PRINT_ADAPTOUTPUT:
1996         case LyXRC::RC_PRINT_COMMAND:
1997         case LyXRC::RC_RTL_SUPPORT:
1998         case LyXRC::RC_SCREEN_DPI:
1999         case LyXRC::RC_SCREEN_FONT_ENCODING:
2000         case LyXRC::RC_SCREEN_FONT_ROMAN:
2001         case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2002         case LyXRC::RC_SCREEN_FONT_SANS:
2003         case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2004         case LyXRC::RC_SCREEN_FONT_SCALABLE:
2005         case LyXRC::RC_SCREEN_FONT_SIZES:
2006         case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2007         case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2008         case LyXRC::RC_SCREEN_ZOOM:
2009         case LyXRC::RC_SERVERPIPE:
2010         case LyXRC::RC_SET_COLOR:
2011         case LyXRC::RC_SHOW_BANNER:
2012         case LyXRC::RC_SPELL_COMMAND:
2013         case LyXRC::RC_TEMPDIRPATH:
2014         case LyXRC::RC_TEMPLATEPATH:
2015         case LyXRC::RC_TEX_ALLOWS_SPACES:
2016         case LyXRC::RC_UIFILE:
2017         case LyXRC::RC_USER_EMAIL:
2018         case LyXRC::RC_USER_NAME:
2019         case LyXRC::RC_USETEMPDIR:
2020         case LyXRC::RC_USE_ALT_LANG:
2021         case LyXRC::RC_USE_ESC_CHARS:
2022         case LyXRC::RC_USE_INP_ENC:
2023         case LyXRC::RC_USE_PERS_DICT:
2024         case LyXRC::RC_USE_SPELL_LIB:
2025         case LyXRC::RC_VIEWDVI_PAPEROPTION:
2026         case LyXRC::RC_VIEWER:
2027         case LyXRC::RC_WHEEL_JUMP:
2028         case LyXRC::RC_LAST:
2029                 break;
2030         }
2031 }
2032
2033 } // namespace anon