]> git.lyx.org Git - lyx.git/blob - src/lyxfunc.C
update display after LFUN_ALL_INSETS_TOGGLE
[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                         update = true;
1412                         break;
1413                 }
1414
1415                 case LFUN_LANGUAGE_BUFFER: {
1416                         Buffer & buffer = *owner->buffer();
1417                         Language const * oldL = buffer.params().language;
1418                         Language const * newL = languages.getLanguage(argument);
1419                         if (!newL || oldL == newL)
1420                                 break;
1421
1422                         if (oldL->RightToLeft() == newL->RightToLeft()
1423                             && !buffer.isMultiLingual())
1424                                 buffer.changeLanguage(oldL, newL);
1425                         else
1426                                 buffer.updateDocLang(newL);
1427                         break;
1428                 }
1429
1430                 case LFUN_SAVE_AS_DEFAULT: {
1431                         string const fname =
1432                                 AddName(AddPath(package().user_support(), "templates/"),
1433                                         "defaults.lyx");
1434                         Buffer defaults(fname);
1435
1436                         istringstream ss(argument);
1437                         LyXLex lex(0,0);
1438                         lex.setStream(ss);
1439                         int const unknown_tokens = defaults.readHeader(lex);
1440
1441                         if (unknown_tokens != 0) {
1442                                 lyxerr << "Warning in LFUN_SAVE_AS_DEFAULT!\n"
1443                                        << unknown_tokens << " unknown token"
1444                                        << (unknown_tokens == 1 ? "" : "s")
1445                                        << endl;
1446                         }
1447
1448                         if (defaults.writeFile(defaults.fileName()))
1449                                 setMessage(_("Document defaults saved in ")
1450                                            + MakeDisplayPath(fname));
1451                         else
1452                                 setErrorMessage(_("Unable to save document defaults"));
1453                         break;
1454                 }
1455
1456                 case LFUN_BUFFERPARAMS_APPLY: {
1457                         biblio::CiteEngine const engine =
1458                                 owner->buffer()->params().cite_engine;
1459
1460                         istringstream ss(argument);
1461                         LyXLex lex(0,0);
1462                         lex.setStream(ss);
1463                         int const unknown_tokens =
1464                                 owner->buffer()->readHeader(lex);
1465
1466                         if (unknown_tokens != 0) {
1467                                 lyxerr << "Warning in LFUN_BUFFERPARAMS_APPLY!\n"
1468                                        << unknown_tokens << " unknown token"
1469                                        << (unknown_tokens == 1 ? "" : "s")
1470                                        << endl;
1471                         }
1472                         if (engine == owner->buffer()->params().cite_engine)
1473                                 break;
1474
1475                         LCursor & cur = view()->cursor();
1476                         FuncRequest fr(LFUN_INSET_REFRESH);
1477
1478                         InsetBase & inset = owner->buffer()->inset();
1479                         InsetIterator it  = inset_iterator_begin(inset);
1480                         InsetIterator const end = inset_iterator_end(inset);
1481                         for (; it != end; ++it)
1482                                 if (it->lyxCode() == InsetBase::CITE_CODE)
1483                                         it->dispatch(cur, fr);
1484                         break;
1485                 }
1486
1487                 case LFUN_TEXTCLASS_APPLY: {
1488                         recordUndoFullDocument(view());
1489                         Buffer * buffer = owner->buffer();
1490
1491                         lyx::textclass_type const old_class =
1492                                 buffer->params().textclass;
1493
1494                         loadTextclass(argument);
1495
1496                         std::pair<bool, lyx::textclass_type> const tc_pair =
1497                                 textclasslist.NumberOfClass(argument);
1498
1499                         if (!tc_pair.first)
1500                                 break;
1501
1502                         lyx::textclass_type const new_class = tc_pair.second;
1503                         if (old_class == new_class)
1504                                 // nothing to do
1505                                 break;
1506
1507                         owner->message(_("Converting document to new document class..."));
1508                         StableDocIterator backcur(view()->cursor());
1509                         ErrorList el;
1510                         lyx::cap::SwitchBetweenClasses(
1511                                 old_class, new_class,
1512                                 buffer->paragraphs(), el);
1513
1514                         view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
1515                         bufferErrors(*buffer, el);
1516                         view()->showErrorList(_("Class switch"));
1517                         updateCounters(*buffer);
1518                         update = true;
1519                         break;
1520                 }
1521
1522                 case LFUN_TEXTCLASS_LOAD:
1523                         loadTextclass(argument);
1524                         break;
1525
1526                 case LFUN_LYXRC_APPLY: {
1527                         LyXRC const lyxrc_orig = lyxrc;
1528
1529                         istringstream ss(argument);
1530                         bool const success = lyxrc.read(ss) == 0;
1531
1532                         if (!success) {
1533                                 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1534                                        << "Unable to read lyxrc data"
1535                                        << endl;
1536                                 break;
1537                         }
1538
1539                         actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1540                         break;
1541                 }
1542
1543                 default: {
1544                         view()->cursor().dispatch(cmd);
1545                         update |= view()->cursor().result().update();
1546                         if (!view()->cursor().result().dispatched())
1547                                 update |= view()->dispatch(cmd);
1548                         break;
1549                 }
1550                 }
1551
1552                 if (view()->available()) {
1553                         // Redraw screen unless explicitly told otherwise.
1554                         // This also initializes the position cache for all insets
1555                         // in (at least partially) visible top-level paragraphs.
1556                         if (update)
1557                                 view()->update(Update::FitCursor | Update::Force);
1558                         else
1559                                 view()->update(Update::FitCursor);
1560
1561                         // if we executed a mutating lfun, mark the buffer as dirty
1562                         // FIXME: Why not use flag.enabled() but call getStatus again?
1563                         if (getStatus(cmd).enabled()
1564                                         && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)
1565                                         && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly))
1566                                 view()->buffer()->markDirty();
1567                 }
1568
1569                 if (view()->cursor().inTexted()) {
1570                         view()->owner()->updateLayoutChoice();
1571                 }
1572         }
1573         sendDispatchMessage(_(getMessage()), cmd);
1574 }
1575
1576
1577 void LyXFunc::sendDispatchMessage(string const & msg, FuncRequest const & cmd)
1578 {
1579         owner->updateMenubar();
1580         owner->updateToolbars();
1581
1582         const bool verbose = (cmd.origin == FuncRequest::UI
1583                               || cmd.origin == FuncRequest::COMMANDBUFFER);
1584
1585         if (cmd.action == LFUN_SELFINSERT || !verbose) {
1586                 lyxerr[Debug::ACTION] << "dispatch msg is " << msg << endl;
1587                 if (!msg.empty())
1588                         owner->message(msg);
1589                 return;
1590         }
1591
1592         string dispatch_msg = msg;
1593         if (!dispatch_msg.empty())
1594                 dispatch_msg += ' ';
1595
1596         string comname = lyxaction.getActionName(cmd.action);
1597
1598         bool argsadded = false;
1599
1600         if (!cmd.argument.empty()) {
1601                 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1602                         comname += ' ' + cmd.argument;
1603                         argsadded = true;
1604                 }
1605         }
1606
1607         string const shortcuts = toplevel_keymap->printbindings(cmd);
1608
1609         if (!shortcuts.empty())
1610                 comname += ": " + shortcuts;
1611         else if (!argsadded && !cmd.argument.empty())
1612                 comname += ' ' + cmd.argument;
1613
1614         if (!comname.empty()) {
1615                 comname = rtrim(comname);
1616                 dispatch_msg += '(' + rtrim(comname) + ')';
1617         }
1618
1619         lyxerr[Debug::ACTION] << "verbose dispatch msg " << dispatch_msg << endl;
1620         if (!dispatch_msg.empty())
1621                 owner->message(dispatch_msg);
1622 }
1623
1624
1625 void LyXFunc::setupLocalKeymap()
1626 {
1627         keyseq.stdmap = toplevel_keymap.get();
1628         keyseq.curmap = toplevel_keymap.get();
1629         cancel_meta_seq.stdmap = toplevel_keymap.get();
1630         cancel_meta_seq.curmap = toplevel_keymap.get();
1631 }
1632
1633
1634 void LyXFunc::menuNew(string const & name, bool fromTemplate)
1635 {
1636         string initpath = lyxrc.document_path;
1637         string filename(name);
1638
1639         if (view()->available()) {
1640                 string const trypath = owner->buffer()->filePath();
1641                 // If directory is writeable, use this as default.
1642                 if (IsDirWriteable(trypath))
1643                         initpath = trypath;
1644         }
1645
1646         static int newfile_number;
1647
1648         if (filename.empty()) {
1649                 filename = AddName(lyxrc.document_path,
1650                             "newfile" + convert<string>(++newfile_number) + ".lyx");
1651                 while (bufferlist.exists(filename) || fs::is_readable(filename)) {
1652                         ++newfile_number;
1653                         filename = AddName(lyxrc.document_path,
1654                                            "newfile" +  convert<string>(newfile_number) +
1655                                     ".lyx");
1656                 }
1657         }
1658
1659         // The template stuff
1660         string templname;
1661         if (fromTemplate) {
1662                 FileDialog fileDlg(_("Select template file"),
1663                         LFUN_SELECT_FILE_SYNC,
1664                         make_pair(string(_("Documents|#o#O")),
1665                                   string(lyxrc.document_path)),
1666                         make_pair(string(_("Templates|#T#t")),
1667                                   string(lyxrc.template_path)));
1668
1669                 FileDialog::Result result =
1670                         fileDlg.open(lyxrc.template_path,
1671                                      FileFilterList(_("LyX Documents (*.lyx)")),
1672                                      string());
1673
1674                 if (result.first == FileDialog::Later)
1675                         return;
1676                 if (result.second.empty())
1677                         return;
1678                 templname = result.second;
1679         }
1680
1681         view()->newFile(filename, templname, !name.empty());
1682 }
1683
1684
1685 void LyXFunc::open(string const & fname)
1686 {
1687         string initpath = lyxrc.document_path;
1688
1689         if (view()->available()) {
1690                 string const trypath = owner->buffer()->filePath();
1691                 // If directory is writeable, use this as default.
1692                 if (IsDirWriteable(trypath))
1693                         initpath = trypath;
1694         }
1695
1696         string filename;
1697
1698         if (fname.empty()) {
1699                 FileDialog fileDlg(_("Select document to open"),
1700                         LFUN_FILE_OPEN,
1701                         make_pair(string(_("Documents|#o#O")),
1702                                   string(lyxrc.document_path)),
1703                         make_pair(string(_("Examples|#E#e")),
1704                                   string(AddPath(package().system_support(), "examples"))));
1705
1706                 FileDialog::Result result =
1707                         fileDlg.open(initpath,
1708                                      FileFilterList(_("LyX Documents (*.lyx)")),
1709                                      string());
1710
1711                 if (result.first == FileDialog::Later)
1712                         return;
1713
1714                 filename = result.second;
1715
1716                 // check selected filename
1717                 if (filename.empty()) {
1718                         owner->message(_("Canceled."));
1719                         return;
1720                 }
1721         } else
1722                 filename = fname;
1723
1724         // get absolute path of file and add ".lyx" to the filename if
1725         // necessary
1726         string const fullpath = FileSearch(string(), filename, "lyx");
1727         if (!fullpath.empty()) {
1728                 filename = fullpath;
1729         }
1730
1731         string const disp_fn(MakeDisplayPath(filename));
1732
1733         // if the file doesn't exist, let the user create one
1734         if (!fs::exists(filename)) {
1735                 // the user specifically chose this name. Believe them.
1736                 view()->newFile(filename, "", true);
1737                 return;
1738         }
1739
1740         owner->message(bformat(_("Opening document %1$s..."), disp_fn));
1741
1742         string str2;
1743         if (view()->loadLyXFile(filename)) {
1744                 str2 = bformat(_("Document %1$s opened."), disp_fn);
1745         } else {
1746                 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1747         }
1748         owner->message(str2);
1749 }
1750
1751
1752 void LyXFunc::doImport(string const & argument)
1753 {
1754         string format;
1755         string filename = split(argument, format, ' ');
1756
1757         lyxerr[Debug::INFO] << "LyXFunc::doImport: " << format
1758                             << " file: " << filename << endl;
1759
1760         // need user interaction
1761         if (filename.empty()) {
1762                 string initpath = lyxrc.document_path;
1763
1764                 if (view()->available()) {
1765                         string const trypath = owner->buffer()->filePath();
1766                         // If directory is writeable, use this as default.
1767                         if (IsDirWriteable(trypath))
1768                                 initpath = trypath;
1769                 }
1770
1771                 string const text = bformat(_("Select %1$s file to import"),
1772                         formats.prettyName(format));
1773
1774                 FileDialog fileDlg(text,
1775                         LFUN_IMPORT,
1776                         make_pair(string(_("Documents|#o#O")),
1777                                   string(lyxrc.document_path)),
1778                         make_pair(string(_("Examples|#E#e")),
1779                                   string(AddPath(package().system_support(), "examples"))));
1780
1781                 string const filter = formats.prettyName(format)
1782                         + " (*." + formats.extension(format) + ')';
1783
1784                 FileDialog::Result result =
1785                         fileDlg.open(initpath,
1786                                      FileFilterList(filter),
1787                                      string());
1788
1789                 if (result.first == FileDialog::Later)
1790                         return;
1791
1792                 filename = result.second;
1793
1794                 // check selected filename
1795                 if (filename.empty())
1796                         owner->message(_("Canceled."));
1797         }
1798
1799         if (filename.empty())
1800                 return;
1801
1802         // get absolute path of file
1803         filename = MakeAbsPath(filename);
1804
1805         string const lyxfile = ChangeExtension(filename, ".lyx");
1806
1807         // Check if the document already is open
1808         if (lyx_gui::use_gui && bufferlist.exists(lyxfile)) {
1809                 if (!bufferlist.close(bufferlist.getBuffer(lyxfile), true)) {
1810                         owner->message(_("Canceled."));
1811                         return;
1812                 }
1813         }
1814
1815         // if the file exists already, and we didn't do
1816         // -i lyx thefile.lyx, warn
1817         if (fs::exists(lyxfile) && filename != lyxfile) {
1818                 string const file = MakeDisplayPath(lyxfile, 30);
1819
1820                 string text = bformat(_("The document %1$s already exists.\n\n"
1821                         "Do you want to over-write that document?"), file);
1822                 int const ret = Alert::prompt(_("Over-write document?"),
1823                         text, 0, 1, _("&Over-write"), _("&Cancel"));
1824
1825                 if (ret == 1) {
1826                         owner->message(_("Canceled."));
1827                         return;
1828                 }
1829         }
1830
1831         Importer::Import(owner, filename, format);
1832 }
1833
1834
1835 void LyXFunc::closeBuffer()
1836 {
1837         if (bufferlist.close(owner->buffer(), true) && !quitting) {
1838                 if (bufferlist.empty()) {
1839                         // need this otherwise SEGV may occur while
1840                         // trying to set variables that don't exist
1841                         // since there's no current buffer
1842                         owner->getDialogs().hideBufferDependent();
1843                 } else {
1844                         view()->setBuffer(bufferlist.first());
1845                 }
1846         }
1847 }
1848
1849
1850 // Each "owner" should have it's own message method. lyxview and
1851 // the minibuffer would use the minibuffer, but lyxserver would
1852 // send an ERROR signal to its client.  Alejandro 970603
1853 // This function is bit problematic when it comes to NLS, to make the
1854 // lyx servers client be language indepenent we must not translate
1855 // strings sent to this func.
1856 void LyXFunc::setErrorMessage(string const & m) const
1857 {
1858         dispatch_buffer = m;
1859         errorstat = true;
1860 }
1861
1862
1863 void LyXFunc::setMessage(string const & m) const
1864 {
1865         dispatch_buffer = m;
1866 }
1867
1868
1869 string const LyXFunc::viewStatusMessage()
1870 {
1871         // When meta-fake key is pressed, show the key sequence so far + "M-".
1872         if (wasMetaKey())
1873                 return keyseq.print() + "M-";
1874
1875         // Else, when a non-complete key sequence is pressed,
1876         // show the available options.
1877         if (keyseq.length() > 0 && !keyseq.deleted())
1878                 return keyseq.printOptions();
1879
1880         if (!view()->available())
1881                 return _("Welcome to LyX!");
1882
1883         return view()->cursor().currentState();
1884 }
1885
1886
1887 BufferView * LyXFunc::view() const
1888 {
1889         BOOST_ASSERT(owner);
1890         return owner->view().get();
1891 }
1892
1893
1894 bool LyXFunc::wasMetaKey() const
1895 {
1896         return (meta_fake_bit != key_modifier::none);
1897 }
1898
1899
1900 namespace {
1901
1902 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
1903 {
1904         // Why the switch you might ask. It is a trick to ensure that all
1905         // the elements in the LyXRCTags enum is handled. As you can see
1906         // there are no breaks at all. So it is just a huge fall-through.
1907         // The nice thing is that we will get a warning from the compiler
1908         // if we forget an element.
1909         LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
1910         switch (tag) {
1911         case LyXRC::RC_ACCEPT_COMPOUND:
1912         case LyXRC::RC_ALT_LANG:
1913         case LyXRC::RC_ASCIIROFF_COMMAND:
1914         case LyXRC::RC_ASCII_LINELEN:
1915         case LyXRC::RC_AUTOREGIONDELETE:
1916         case LyXRC::RC_AUTORESET_OPTIONS:
1917         case LyXRC::RC_AUTOSAVE:
1918         case LyXRC::RC_AUTO_NUMBER:
1919         case LyXRC::RC_BACKUPDIR_PATH:
1920         case LyXRC::RC_BIBTEX_COMMAND:
1921         case LyXRC::RC_BINDFILE:
1922         case LyXRC::RC_CHECKLASTFILES:
1923         case LyXRC::RC_CHKTEX_COMMAND:
1924         case LyXRC::RC_CONVERTER:
1925         case LyXRC::RC_COPIER:
1926         case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
1927         case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
1928         case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
1929         case LyXRC::RC_CYGWIN_PATH_FIX:
1930                 if (lyxrc_orig.cygwin_path_fix != lyxrc_new.cygwin_path_fix) {
1931                         namespace os = lyx::support::os;
1932                         os::cygwin_path_fix(lyxrc_new.cygwin_path_fix);
1933                 }
1934         case LyXRC::RC_DATE_INSERT_FORMAT:
1935         case LyXRC::RC_DEFAULT_LANGUAGE:
1936         case LyXRC::RC_DEFAULT_PAPERSIZE:
1937         case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
1938         case LyXRC::RC_DISPLAY_GRAPHICS:
1939         case LyXRC::RC_DOCUMENTPATH:
1940                 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
1941                         if (fs::exists(lyxrc_new.document_path) &&
1942                             fs::is_directory(lyxrc_new.document_path)) {
1943                                 using lyx::support::package;
1944                                 package().document_dir() = lyxrc.document_path;
1945                         }
1946                 }
1947         case LyXRC::RC_ESC_CHARS:
1948         case LyXRC::RC_FONT_ENCODING:
1949         case LyXRC::RC_FORMAT:
1950         case LyXRC::RC_INDEX_COMMAND:
1951         case LyXRC::RC_INPUT:
1952         case LyXRC::RC_KBMAP:
1953         case LyXRC::RC_KBMAP_PRIMARY:
1954         case LyXRC::RC_KBMAP_SECONDARY:
1955         case LyXRC::RC_LABEL_INIT_LENGTH:
1956         case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
1957         case LyXRC::RC_LANGUAGE_AUTO_END:
1958         case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
1959         case LyXRC::RC_LANGUAGE_COMMAND_END:
1960         case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
1961         case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
1962         case LyXRC::RC_LANGUAGE_PACKAGE:
1963         case LyXRC::RC_LANGUAGE_USE_BABEL:
1964         case LyXRC::RC_LASTFILES:
1965         case LyXRC::RC_MAKE_BACKUP:
1966         case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
1967         case LyXRC::RC_NUMLASTFILES:
1968         case LyXRC::RC_PATH_PREFIX:
1969                 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
1970                         using lyx::support::prependEnvPath;
1971                         prependEnvPath("PATH", lyxrc.path_prefix);
1972                 }
1973         case LyXRC::RC_PERS_DICT:
1974         case LyXRC::RC_POPUP_BOLD_FONT:
1975         case LyXRC::RC_POPUP_FONT_ENCODING:
1976         case LyXRC::RC_POPUP_NORMAL_FONT:
1977         case LyXRC::RC_PREVIEW:
1978         case LyXRC::RC_PREVIEW_HASHED_LABELS:
1979         case LyXRC::RC_PREVIEW_SCALE_FACTOR:
1980         case LyXRC::RC_PRINTCOLLCOPIESFLAG:
1981         case LyXRC::RC_PRINTCOPIESFLAG:
1982         case LyXRC::RC_PRINTER:
1983         case LyXRC::RC_PRINTEVENPAGEFLAG:
1984         case LyXRC::RC_PRINTEXSTRAOPTIONS:
1985         case LyXRC::RC_PRINTFILEEXTENSION:
1986         case LyXRC::RC_PRINTLANDSCAPEFLAG:
1987         case LyXRC::RC_PRINTODDPAGEFLAG:
1988         case LyXRC::RC_PRINTPAGERANGEFLAG:
1989         case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
1990         case LyXRC::RC_PRINTPAPERFLAG:
1991         case LyXRC::RC_PRINTREVERSEFLAG:
1992         case LyXRC::RC_PRINTSPOOL_COMMAND:
1993         case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
1994         case LyXRC::RC_PRINTTOFILE:
1995         case LyXRC::RC_PRINTTOPRINTER:
1996         case LyXRC::RC_PRINT_ADAPTOUTPUT:
1997         case LyXRC::RC_PRINT_COMMAND:
1998         case LyXRC::RC_RTL_SUPPORT:
1999         case LyXRC::RC_SCREEN_DPI:
2000         case LyXRC::RC_SCREEN_FONT_ENCODING:
2001         case LyXRC::RC_SCREEN_FONT_ROMAN:
2002         case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2003         case LyXRC::RC_SCREEN_FONT_SANS:
2004         case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2005         case LyXRC::RC_SCREEN_FONT_SCALABLE:
2006         case LyXRC::RC_SCREEN_FONT_SIZES:
2007         case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2008         case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2009         case LyXRC::RC_SCREEN_ZOOM:
2010         case LyXRC::RC_SERVERPIPE:
2011         case LyXRC::RC_SET_COLOR:
2012         case LyXRC::RC_SHOW_BANNER:
2013         case LyXRC::RC_SPELL_COMMAND:
2014         case LyXRC::RC_TEMPDIRPATH:
2015         case LyXRC::RC_TEMPLATEPATH:
2016         case LyXRC::RC_TEX_ALLOWS_SPACES:
2017         case LyXRC::RC_UIFILE:
2018         case LyXRC::RC_USER_EMAIL:
2019         case LyXRC::RC_USER_NAME:
2020         case LyXRC::RC_USETEMPDIR:
2021         case LyXRC::RC_USE_ALT_LANG:
2022         case LyXRC::RC_USE_ESC_CHARS:
2023         case LyXRC::RC_USE_INP_ENC:
2024         case LyXRC::RC_USE_PERS_DICT:
2025         case LyXRC::RC_USE_SPELL_LIB:
2026         case LyXRC::RC_VIEWDVI_PAPEROPTION:
2027         case LyXRC::RC_VIEWER:
2028         case LyXRC::RC_WHEEL_JUMP:
2029         case LyXRC::RC_LAST:
2030                 break;
2031         }
2032 }
2033
2034 } // namespace anon