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