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