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