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