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