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