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