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