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