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