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