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