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