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