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