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