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