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