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