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