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