]> git.lyx.org Git - lyx.git/blob - src/LyXFunc.cpp
* LyXView:
[lyx.git] / src / LyXFunc.cpp
1 /**
2  * \file LyXFunc.cpp
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 "LayoutFile.h"
25 #include "BranchList.h"
26 #include "buffer_funcs.h"
27 #include "Buffer.h"
28 #include "BufferList.h"
29 #include "BufferParams.h"
30 #include "BufferView.h"
31 #include "CmdDef.h"
32 #include "Color.h"
33 #include "Converter.h"
34 #include "Cursor.h"
35 #include "CutAndPaste.h"
36 #include "DispatchResult.h"
37 #include "Encoding.h"
38 #include "ErrorList.h"
39 #include "Format.h"
40 #include "FuncRequest.h"
41 #include "FuncStatus.h"
42 #include "InsetIterator.h"
43 #include "Intl.h"
44 #include "KeyMap.h"
45 #include "Language.h"
46 #include "Lexer.h"
47 #include "LyXAction.h"
48 #include "lyxfind.h"
49 #include "LyX.h"
50 #include "LyXRC.h"
51 #include "LyXVC.h"
52 #include "Paragraph.h"
53 #include "ParagraphParameters.h"
54 #include "ParIterator.h"
55 #include "Row.h"
56 #include "Server.h"
57 #include "Session.h"
58 #include "SpellChecker.h"
59
60 #include "insets/InsetBox.h"
61 #include "insets/InsetBranch.h"
62 #include "insets/InsetCommand.h"
63 #include "insets/InsetERT.h"
64 #include "insets/InsetExternal.h"
65 #include "insets/InsetFloat.h"
66 #include "insets/InsetGraphics.h"
67 #include "insets/InsetInclude.h"
68 #include "insets/InsetListings.h"
69 #include "insets/InsetNote.h"
70 #include "insets/InsetPhantom.h"
71 #include "insets/InsetSpace.h"
72 #include "insets/InsetTabular.h"
73 #include "insets/InsetVSpace.h"
74 #include "insets/InsetWrap.h"
75
76 #include "frontends/alert.h"
77 #include "frontends/Application.h"
78 #include "frontends/KeySymbol.h"
79 #include "frontends/LyXView.h"
80 #include "frontends/Selection.h"
81
82 #include "support/debug.h"
83 #include "support/environment.h"
84 #include "support/FileName.h"
85 #include "support/filetools.h"
86 #include "support/gettext.h"
87 #include "support/lstrings.h"
88 #include "support/Path.h"
89 #include "support/Package.h"
90 #include "support/Systemcall.h"
91 #include "support/convert.h"
92 #include "support/os.h"
93
94 #include <sstream>
95 #include <vector>
96
97 using namespace std;
98 using namespace lyx::support;
99
100 namespace lyx {
101
102 using frontend::LyXView;
103
104 namespace Alert = frontend::Alert;
105
106 namespace {
107
108
109 // This function runs "configure" and then rereads lyx.defaults to
110 // reconfigure the automatic settings.
111 void reconfigure(LyXView * lv, string const & option)
112 {
113         // emit message signal.
114         if (lv)
115                 lv->message(_("Running configure..."));
116
117         // Run configure in user lyx directory
118         PathChanger p(package().user_support());
119         string configure_command = package().configure_command();
120         configure_command += option;
121         Systemcall one;
122         int ret = one.startscript(Systemcall::Wait, configure_command);
123         p.pop();
124         // emit message signal.
125         if (lv)
126                 lv->message(_("Reloading configuration..."));
127         lyxrc.read(libFileSearch(string(), "lyxrc.defaults"));
128         // Re-read packages.lst
129         LaTeXFeatures::getAvailable();
130
131         if (ret)
132                 Alert::information(_("System reconfiguration failed"),
133                            _("The system reconfiguration has failed.\n"
134                                   "Default textclass is used but LyX may "
135                                   "not be able to work properly.\n"
136                                   "Please reconfigure again if needed."));
137         else
138
139                 Alert::information(_("System reconfigured"),
140                            _("The system has been reconfigured.\n"
141                              "You need to restart LyX to make use of any\n"
142                              "updated document class specifications."));
143 }
144
145
146 bool getLocalStatus(Cursor cursor, FuncRequest const & cmd, FuncStatus & status)
147 {
148         // Try to fix cursor in case it is broken.
149         cursor.fixIfBroken();
150
151         // This is, of course, a mess. Better create a new doc iterator and use
152         // this in Inset::getStatus. This might require an additional
153         // BufferView * arg, though (which should be avoided)
154         //Cursor safe = *this;
155         bool res = false;
156         for ( ; cursor.depth(); cursor.pop()) {
157                 //lyxerr << "\nCursor::getStatus: cmd: " << cmd << endl << *this << endl;
158                 LASSERT(cursor.idx() <= cursor.lastidx(), /**/);
159                 LASSERT(cursor.pit() <= cursor.lastpit(), /**/);
160                 LASSERT(cursor.pos() <= cursor.lastpos(), /**/);
161
162                 // The inset's getStatus() will return 'true' if it made
163                 // a definitive decision on whether it want to handle the
164                 // request or not. The result of this decision is put into
165                 // the 'status' parameter.
166                 if (cursor.inset().getStatus(cursor, cmd, status)) {
167                         res = true;
168                         break;
169                 }
170         }
171         return res;
172 }
173
174
175 /** Return the change status at cursor position, taking in account the
176  * status at each level of the document iterator (a table in a deleted
177  * footnote is deleted).
178  * When \param outer is true, the top slice is not looked at.
179  */
180 Change::Type lookupChangeType(DocIterator const & dit, bool outer = false)
181 {
182         size_t const depth = dit.depth() - (outer ? 1 : 0);
183
184         for (size_t i = 0 ; i < depth ; ++i) {
185                 CursorSlice const & slice = dit[i];
186                 if (!slice.inset().inMathed()
187                     && slice.pos() < slice.paragraph().size()) {
188                         Change::Type const ch = slice.paragraph().lookupChange(slice.pos()).type;
189                         if (ch != Change::UNCHANGED)
190                                 return ch;
191                 }
192         }
193         return Change::UNCHANGED;
194 }
195
196 }
197
198
199 LyXFunc::LyXFunc()
200         : lyx_view_(0), encoded_last_key(0), meta_fake_bit(NoModifier)
201 {
202 }
203
204
205 void LyXFunc::initKeySequences(KeyMap * kb)
206 {
207         keyseq = KeySequence(kb, kb);
208         cancel_meta_seq = KeySequence(kb, kb);
209 }
210
211
212 void LyXFunc::setLyXView(LyXView * lv)
213 {
214         if (lyx_view_ && lyx_view_->currentBufferView() && lyx_view_ != lv)
215                 // save current selection to the selection buffer to allow
216                 // middle-button paste in another window
217                 cap::saveSelection(lyx_view_->currentBufferView()->cursor());
218         lyx_view_ = lv;
219 }
220
221
222 void LyXFunc::handleKeyFunc(FuncCode action)
223 {
224         char_type c = encoded_last_key;
225
226         if (keyseq.length())
227                 c = 0;
228
229         LASSERT(lyx_view_ && lyx_view_->currentBufferView(), /**/);
230         lyx_view_->currentBufferView()->getIntl().getTransManager().deadkey(
231                 c, get_accent(action).accent, view()->cursor().innerText(),
232                 currentBufferView()->cursor());
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()->processUpdateFlags(Update::FitCursor);
239 }
240
241 //FIXME: bookmark handling is a frontend issue. This code should be transferred
242 // to GuiView and be GuiView and be window dependent.
243 void LyXFunc::gotoBookmark(unsigned int idx, bool openFile, bool switchToBuffer)
244 {
245         LASSERT(lyx_view_, /**/);
246         if (!theSession().bookmarks().isValid(idx))
247                 return;
248         BookmarksSection::Bookmark const & bm = theSession().bookmarks().bookmark(idx);
249         LASSERT(!bm.filename.empty(), /**/);
250         string const file = bm.filename.absFilename();
251         // if the file is not opened, open it.
252         if (!theBufferList().exists(bm.filename)) {
253                 if (openFile)
254                         dispatch(FuncRequest(LFUN_FILE_OPEN, file));
255                 else
256                         return;
257         }
258         // open may fail, so we need to test it again
259         if (!theBufferList().exists(bm.filename))
260                 return;
261
262         // bm can be changed when saving
263         BookmarksSection::Bookmark tmp = bm;
264
265         // Special case idx == 0 used for back-from-back jump navigation
266         if (idx == 0)
267                 dispatch(FuncRequest(LFUN_BOOKMARK_SAVE, "0"));
268
269         // if the current buffer is not that one, switch to it.
270         if (!lyx_view_->buffer() || lyx_view_->buffer()->fileName() != tmp.filename) {
271                 if (!switchToBuffer)
272                         return;
273                 dispatch(FuncRequest(LFUN_BUFFER_SWITCH, file));
274         }
275
276         // moveToPosition try paragraph id first and then paragraph (pit, pos).
277         if (!view()->moveToPosition(tmp.bottom_pit, tmp.bottom_pos,
278                 tmp.top_id, tmp.top_pos))
279                 return;
280
281         // bm changed
282         if (idx == 0)
283                 return;
284
285         // Cursor jump succeeded!
286         Cursor const & cur = view()->cursor();
287         pit_type new_pit = cur.pit();
288         pos_type new_pos = cur.pos();
289         int new_id = cur.paragraph().id();
290
291         // if bottom_pit, bottom_pos or top_id has been changed, update bookmark
292         // see http://bugzilla.lyx.org/show_bug.cgi?id=3092
293         if (bm.bottom_pit != new_pit || bm.bottom_pos != new_pos 
294                 || bm.top_id != new_id) {
295                 const_cast<BookmarksSection::Bookmark &>(bm).updatePos(
296                         new_pit, new_pos, new_id);
297         }
298 }
299
300
301 void LyXFunc::processKeySym(KeySymbol const & keysym, KeyModifier state)
302 {
303         LYXERR(Debug::KEY, "KeySym is " << keysym.getSymbolName());
304
305         // Do nothing if we have nothing (JMarc)
306         if (!keysym.isOK()) {
307                 LYXERR(Debug::KEY, "Empty kbd action (probably composing)");
308                 lyx_view_->restartCursor();
309                 return;
310         }
311
312         if (keysym.isModifier()) {
313                 LYXERR(Debug::KEY, "isModifier true");
314                 if (lyx_view_)
315                         lyx_view_->restartCursor();
316                 return;
317         }
318
319         //Encoding const * encoding = view()->cursor().getEncoding();
320         //encoded_last_key = keysym.getISOEncoded(encoding ? encoding->name() : "");
321         // FIXME: encoded_last_key shadows the member variable of the same
322         // name. Is that intended?
323         char_type encoded_last_key = keysym.getUCSEncoded();
324
325         // Do a one-deep top-level lookup for
326         // cancel and meta-fake keys. RVDK_PATCH_5
327         cancel_meta_seq.reset();
328
329         FuncRequest func = cancel_meta_seq.addkey(keysym, state);
330         LYXERR(Debug::KEY, "action first set to [" << func.action << ']');
331
332         // When not cancel or meta-fake, do the normal lookup.
333         // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
334         // Mostly, meta_fake_bit = NoModifier. RVDK_PATCH_5.
335         if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_PREFIX)) {
336                 // remove Caps Lock and Mod2 as a modifiers
337                 func = keyseq.addkey(keysym, (state | meta_fake_bit));
338                 LYXERR(Debug::KEY, "action now set to [" << func.action << ']');
339         }
340
341         // Dont remove this unless you know what you are doing.
342         meta_fake_bit = NoModifier;
343
344         // Can this happen now ?
345         if (func.action == LFUN_NOACTION)
346                 func = FuncRequest(LFUN_COMMAND_PREFIX);
347
348         LYXERR(Debug::KEY, " Key [action=" << func.action << "]["
349                 << keyseq.print(KeySequence::Portable) << ']');
350
351         // already here we know if it any point in going further
352         // why not return already here if action == -1 and
353         // num_bytes == 0? (Lgb)
354
355         if (keyseq.length() > 1)
356                 lyx_view_->message(keyseq.print(KeySequence::ForGui));
357
358
359         // Maybe user can only reach the key via holding down shift.
360         // Let's see. But only if shift is the only modifier
361         if (func.action == LFUN_UNKNOWN_ACTION && state == ShiftModifier) {
362                 LYXERR(Debug::KEY, "Trying without shift");
363                 func = keyseq.addkey(keysym, NoModifier);
364                 LYXERR(Debug::KEY, "Action now " << func.action);
365         }
366
367         if (func.action == LFUN_UNKNOWN_ACTION) {
368                 // Hmm, we didn't match any of the keysequences. See
369                 // if it's normal insertable text not already covered
370                 // by a binding
371                 if (keysym.isText() && keyseq.length() == 1) {
372                         LYXERR(Debug::KEY, "isText() is true, inserting.");
373                         func = FuncRequest(LFUN_SELF_INSERT,
374                                            FuncRequest::KEYBOARD);
375                 } else {
376                         LYXERR(Debug::KEY, "Unknown, !isText() - giving up");
377                         lyx_view_->message(_("Unknown function."));
378                         lyx_view_->restartCursor();
379                         return;
380                 }
381         }
382
383         if (func.action == LFUN_SELF_INSERT) {
384                 if (encoded_last_key != 0) {
385                         docstring const arg(1, encoded_last_key);
386                         dispatch(FuncRequest(LFUN_SELF_INSERT, arg,
387                                              FuncRequest::KEYBOARD));
388                         LYXERR(Debug::KEY, "SelfInsert arg[`" << to_utf8(arg) << "']");
389                 }
390         } else {
391                 dispatch(func);
392                 if (!lyx_view_)
393                         return;
394         }
395 }
396
397
398 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
399 {
400         //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
401         FuncStatus flag;
402
403         /* In LyX/Mac, when a dialog is open, the menus of the
404            application can still be accessed without giving focus to
405            the main window. In this case, we want to disable the menu
406            entries that are buffer or view-related.
407
408            If this code is moved somewhere else (like in
409            GuiView::getStatus), then several functions will not be
410            handled correctly.
411         */
412         frontend::LyXView * lv = 0;
413         Buffer * buf = 0;
414         if (lyx_view_ 
415             && (cmd.origin != FuncRequest::MENU || lyx_view_->hasFocus())) {
416                 lv = lyx_view_;
417                 buf = lyx_view_->buffer();
418         }
419
420         if (cmd.action == LFUN_NOACTION) {
421                 flag.message(from_utf8(N_("Nothing to do")));
422                 flag.setEnabled(false);
423                 return flag;
424         }
425
426         switch (cmd.action) {
427         case LFUN_UNKNOWN_ACTION:
428                 flag.unknown(true);
429                 flag.setEnabled(false);
430                 break;
431
432         default:
433                 break;
434         }
435
436         if (flag.unknown()) {
437                 flag.message(from_utf8(N_("Unknown action")));
438                 return flag;
439         }
440
441         if (!flag.enabled()) {
442                 if (flag.message().empty())
443                         flag.message(from_utf8(N_("Command disabled")));
444                 return flag;
445         }
446
447         // Check whether we need a buffer
448         if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
449                 // no, exit directly
450                 flag.message(from_utf8(N_("Command not allowed with"
451                                     "out any document open")));
452                 flag.setEnabled(false);
453                 return flag;
454         }
455
456         // I would really like to avoid having this switch and rather try to
457         // encode this in the function itself.
458         // -- And I'd rather let an inset decide which LFUNs it is willing
459         // to handle (Andre')
460         bool enable = true;
461         switch (cmd.action) {
462
463         case LFUN_BUFFER_TOGGLE_READ_ONLY:
464                 flag.setOnOff(buf->isReadonly());
465                 break;
466
467         case LFUN_BUFFER_SWITCH:
468                 // toggle on the current buffer, but do not toggle off
469                 // the other ones (is that a good idea?)
470                 if (buf && to_utf8(cmd.argument()) == buf->absFileName())
471                         flag.setOnOff(true);
472                 break;
473
474         case LFUN_BUFFER_CHKTEX:
475                 enable = buf->isLatex() && !lyxrc.chktex_command.empty();
476                 break;
477
478         case LFUN_BUILD_PROGRAM:
479                 enable = buf->isExportable("program");
480                 break;
481
482         case LFUN_VC_REGISTER:
483                 enable = !buf->lyxvc().inUse();
484                 break;
485         case LFUN_VC_CHECK_IN:
486                 enable = buf->lyxvc().checkInEnabled();
487                 break;
488         case LFUN_VC_CHECK_OUT:
489                 enable = buf->lyxvc().checkOutEnabled();
490                 break;
491         case LFUN_VC_LOCKING_TOGGLE:
492                 enable = !buf->isReadonly() && buf->lyxvc().lockingToggleEnabled();
493                 flag.setOnOff(enable && !buf->lyxvc().locker().empty());
494                 break;
495         case LFUN_VC_REVERT:
496                 enable = buf->lyxvc().inUse();
497                 break;
498         case LFUN_VC_UNDO_LAST:
499                 enable = buf->lyxvc().undoLastEnabled();
500                 break;
501         case LFUN_BUFFER_RELOAD:
502                 enable = !buf->isUnnamed() && buf->fileName().exists()
503                         && (!buf->isClean() || buf->isExternallyModified(Buffer::timestamp_method));
504                 break;
505
506         case LFUN_CITATION_INSERT: {
507                 FuncRequest fr(LFUN_INSET_INSERT, "citation");
508                 enable = getStatus(fr).enabled();
509                 break;
510         }
511         
512         // This could be used for the no-GUI version. The GUI version is handled in
513         // LyXView::getStatus(). See above.
514         /*
515         case LFUN_BUFFER_WRITE:
516         case LFUN_BUFFER_WRITE_AS: {
517                 Buffer * b = theBufferList().getBuffer(FileName(cmd.getArg(0)));
518                 enable = b && (b->isUnnamed() || !b->isClean());
519                 break;
520         }
521         */
522
523         case LFUN_BUFFER_WRITE_ALL: {
524                 // We enable the command only if there are some modified buffers
525                 Buffer * first = theBufferList().first();
526                 enable = false;
527                 if (!first)
528                         break;
529                 Buffer * b = first;
530                 // We cannot use a for loop as the buffer list is a cycle.
531                 do {
532                         if (!b->isClean()) {
533                                 enable = true;
534                                 break;
535                         }
536                         b = theBufferList().next(b);
537                 } while (b != first); 
538                 break;
539         }
540
541         case LFUN_BOOKMARK_GOTO: {
542                 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
543                 enable = theSession().bookmarks().isValid(num);
544                 break;
545         }
546
547         case LFUN_BOOKMARK_CLEAR:
548                 enable = theSession().bookmarks().hasValid();
549                 break;
550
551         // this one is difficult to get right. As a half-baked
552         // solution, we consider only the first action of the sequence
553         case LFUN_COMMAND_SEQUENCE: {
554                 // argument contains ';'-terminated commands
555                 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
556                 FuncRequest func(lyxaction.lookupFunc(firstcmd));
557                 func.origin = cmd.origin;
558                 flag = getStatus(func);
559                 break;
560         }
561
562         // we want to check if at least one of these is enabled
563         case LFUN_COMMAND_ALTERNATIVES: {
564                 // argument contains ';'-terminated commands
565                 string arg = to_utf8(cmd.argument());
566                 while (!arg.empty()) {
567                         string first;
568                         arg = split(arg, first, ';');
569                         FuncRequest func(lyxaction.lookupFunc(first));
570                         func.origin = cmd.origin;
571                         flag = getStatus(func);
572                         // if this one is enabled, the whole thing is
573                         if (flag.enabled())
574                                 break;
575                 }
576                 break;
577         }
578
579         case LFUN_CALL: {
580                 FuncRequest func;
581                 string name = to_utf8(cmd.argument());
582                 if (theTopLevelCmdDef().lock(name, func)) {
583                         func.origin = cmd.origin;
584                         flag = getStatus(func);
585                         theTopLevelCmdDef().release(name);
586                 } else {
587                         // catch recursion or unknown command
588                         // definition. all operations until the
589                         // recursion or unknown command definition
590                         // occurs are performed, so set the state to
591                         // enabled
592                         enable = true;
593                 }
594                 break;
595         }
596
597         case LFUN_VC_COMMAND: {
598                 if (cmd.argument().empty())
599                         enable = false;
600
601                 if (!buf && contains(cmd.getArg(0), 'D'))
602                         enable = false;
603                 break;
604         }
605
606         case LFUN_MASTER_BUFFER_UPDATE:
607         case LFUN_MASTER_BUFFER_VIEW: 
608                 if (!buf->parent()) {
609                         enable = false;
610                         break;
611                 }
612         case LFUN_BUFFER_UPDATE:
613         case LFUN_BUFFER_VIEW: {
614                 string format = to_utf8(cmd.argument());
615                 if (cmd.argument().empty())
616                         format = buf->getDefaultOutputFormat();
617                 typedef vector<Format const *> Formats;
618                 Formats formats;
619                 formats = buf->exportableFormats(true);
620                 Formats::const_iterator fit = formats.begin();
621                 Formats::const_iterator end = formats.end();
622                 enable = false;
623                 for (; fit != end ; ++fit) {
624                         if ((*fit)->name() == format)
625                                 enable = true;
626                 }
627                 break;
628         }
629
630         case LFUN_WORD_FIND_FORWARD:
631         case LFUN_WORD_FIND_BACKWARD:
632         case LFUN_WORD_FINDADV:
633         case LFUN_COMMAND_PREFIX:
634         case LFUN_COMMAND_EXECUTE:
635         case LFUN_CANCEL:
636         case LFUN_META_PREFIX:
637         case LFUN_BUFFER_CLOSE:
638         case LFUN_BUFFER_IMPORT:
639         case LFUN_BUFFER_AUTO_SAVE:
640         case LFUN_RECONFIGURE:
641         case LFUN_HELP_OPEN:
642         case LFUN_DROP_LAYOUTS_CHOICE:
643         case LFUN_MENU_OPEN:
644         case LFUN_SERVER_GET_FILENAME:
645         case LFUN_SERVER_NOTIFY:
646         case LFUN_SERVER_GOTO_FILE_ROW:
647         case LFUN_DIALOG_HIDE:
648         case LFUN_DIALOG_DISCONNECT_INSET:
649         case LFUN_BUFFER_CHILD_OPEN:
650         case LFUN_CURSOR_FOLLOWS_SCROLLBAR_TOGGLE:
651         case LFUN_KEYMAP_OFF:
652         case LFUN_KEYMAP_PRIMARY:
653         case LFUN_KEYMAP_SECONDARY:
654         case LFUN_KEYMAP_TOGGLE:
655         case LFUN_REPEAT:
656         case LFUN_BUFFER_EXPORT_CUSTOM:
657         case LFUN_PREFERENCES_SAVE:
658         case LFUN_MESSAGE:
659         case LFUN_INSET_EDIT:
660         case LFUN_BUFFER_LANGUAGE:
661         case LFUN_TEXTCLASS_APPLY:
662         case LFUN_TEXTCLASS_LOAD:
663         case LFUN_BUFFER_SAVE_AS_DEFAULT:
664         case LFUN_BUFFER_PARAMS_APPLY:
665         case LFUN_LAYOUT_MODULES_CLEAR:
666         case LFUN_LAYOUT_MODULE_ADD:
667         case LFUN_LAYOUT_RELOAD:
668         case LFUN_LYXRC_APPLY:
669         case LFUN_BUFFER_NEXT:
670         case LFUN_BUFFER_PREVIOUS:
671                 // these are handled in our dispatch()
672                 break;
673
674         default:
675                 if (!theApp()) {
676                         enable = false;
677                         break;
678                 }
679                 if (theApp()->getStatus(cmd, flag))
680                         break;
681
682                 // Does the view know something?
683                 if (!lv) {
684                         enable = false;
685                         break;
686                 }
687                 if (lv->getStatus(cmd, flag))
688                         break;
689
690                 // If we do not have a BufferView, then other functions are disabled
691                 if (!view()) {
692                         enable = false;
693                         break;
694                 }
695
696                 // Is this a function that acts on inset at point?
697                 Inset * inset = view()->cursor().nextInset();
698                 if (lyxaction.funcHasFlag(cmd.action, LyXAction::AtPoint)
699                     && inset && inset->getStatus(view()->cursor(), cmd, flag))
700                         break;
701
702                 bool decided = getLocalStatus(view()->cursor(), cmd, flag);
703                 if (!decided)
704                         // try the BufferView
705                         decided = view()->getStatus(cmd, flag);
706                 if (!decided)
707                         // try the Buffer
708                         view()->buffer().getStatus(cmd, flag);
709         }
710
711         if (!enable)
712                 flag.setEnabled(false);
713
714         // Can we use a readonly buffer?
715         if (buf && buf->isReadonly()
716             && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
717             && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
718                 flag.message(from_utf8(N_("Document is read-only")));
719                 flag.setEnabled(false);
720         }
721
722         // Are we in a DELETED change-tracking region?
723         if (buf && view() 
724                 && lookupChangeType(view()->cursor(), true) == Change::DELETED
725             && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
726             && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
727                 flag.message(from_utf8(N_("This portion of the document is deleted.")));
728                 flag.setEnabled(false);
729         }
730
731         // the default error message if we disable the command
732         if (!flag.enabled() && flag.message().empty())
733                 flag.message(from_utf8(N_("Command disabled")));
734
735         return flag;
736 }
737
738
739 bool LyXFunc::ensureBufferClean(BufferView * bv)
740 {
741         Buffer & buf = bv->buffer();
742         if (buf.isClean() && !buf.isUnnamed())
743                 return true;
744
745         docstring const file = buf.fileName().displayName(30);
746         docstring title;
747         docstring text;
748         if (!buf.isUnnamed()) {
749                 text = bformat(_("The document %1$s has unsaved "
750                                              "changes.\n\nDo you want to save "
751                                              "the document?"), file);
752                 title = _("Save changed document?");
753                 
754         } else {
755                 text = bformat(_("The document %1$s has not been "
756                                              "saved yet.\n\nDo you want to save "
757                                              "the document?"), file);
758                 title = _("Save new document?");
759         }
760         int const ret = Alert::prompt(title, text, 0, 1, _("&Save"), _("&Cancel"));
761
762         if (ret == 0)
763                 lyx_view_->dispatch(FuncRequest(LFUN_BUFFER_WRITE));
764
765         return buf.isClean() && !buf.isUnnamed();
766 }
767
768
769 namespace {
770
771 bool loadLayoutFile(string const & name, string const & buf_path)
772 {
773         if (!LayoutFileList::get().haveClass(name)) {
774                 lyxerr << "Document class \"" << name
775                        << "\" does not exist."
776                        << endl;
777                 return false;
778         }
779
780         LayoutFile & tc = LayoutFileList::get()[name];
781         if (!tc.load(buf_path)) {
782                 docstring s = bformat(_("The document class %1$s "
783                                    "could not be loaded."), from_utf8(name));
784                 Alert::error(_("Could not load class"), s);
785                 return false;
786         }
787         return true;
788 }
789
790
791 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
792
793 } //namespace anon
794
795
796 void LyXFunc::dispatch(FuncRequest const & cmd)
797 {
798         string const argument = to_utf8(cmd.argument());
799         FuncCode const action = cmd.action;
800
801         LYXERR(Debug::ACTION, "\nLyXFunc::dispatch: cmd: " << cmd);
802         //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
803
804         // we have not done anything wrong yet.
805         errorstat = false;
806         dispatch_buffer.erase();
807
808         // redraw the screen at the end (first of the two drawing steps).
809         //This is done unless explicitely requested otherwise
810         Update::flags updateFlags = Update::FitCursor;
811
812         FuncStatus const flag = getStatus(cmd);
813         if (!flag.enabled()) {
814                 // We cannot use this function here
815                 LYXERR(Debug::ACTION, "LyXFunc::dispatch: "
816                        << lyxaction.getActionName(action)
817                        << " [" << action << "] is disabled at this location");
818                 setErrorMessage(flag.message());
819                 if (lyx_view_)
820                         lyx_view_->restartCursor();
821         } else {
822                 Buffer * buffer = lyx_view_ ? lyx_view_->buffer() : 0;
823                 switch (action) {
824
825                 case LFUN_WORD_FIND_FORWARD:
826                 case LFUN_WORD_FIND_BACKWARD: {
827                         LASSERT(lyx_view_ && lyx_view_->currentBufferView(), /**/);
828                         static docstring last_search;
829                         docstring searched_string;
830
831                         if (!cmd.argument().empty()) {
832                                 last_search = cmd.argument();
833                                 searched_string = cmd.argument();
834                         } else {
835                                 searched_string = last_search;
836                         }
837
838                         if (searched_string.empty())
839                                 break;
840
841                         bool const fw = action == LFUN_WORD_FIND_FORWARD;
842                         docstring const data =
843                                 find2string(searched_string, true, false, fw);
844                         find(view(), FuncRequest(LFUN_WORD_FIND, data));
845                         break;
846                 }
847
848                 case LFUN_COMMAND_PREFIX:
849                         LASSERT(lyx_view_, /**/);
850                         lyx_view_->message(keyseq.printOptions(true));
851                         break;
852
853                 case LFUN_CANCEL:
854                         LASSERT(lyx_view_ && lyx_view_->currentBufferView(), /**/);
855                         keyseq.reset();
856                         meta_fake_bit = NoModifier;
857                         if (buffer)
858                                 // cancel any selection
859                                 dispatch(FuncRequest(LFUN_MARK_OFF));
860                         setMessage(from_ascii(N_("Cancel")));
861                         break;
862
863                 case LFUN_META_PREFIX:
864                         meta_fake_bit = AltModifier;
865                         setMessage(keyseq.print(KeySequence::ForGui));
866                         break;
867
868                 case LFUN_BUFFER_TOGGLE_READ_ONLY: {
869                         LASSERT(lyx_view_ && lyx_view_->currentBufferView() && buffer, /**/);
870                         if (buffer->lyxvc().inUse())
871                                 buffer->lyxvc().toggleReadOnly();
872                         else
873                                 buffer->setReadonly(!buffer->isReadonly());
874                         break;
875                 }
876
877                 // --- Menus -----------------------------------------------
878                 case LFUN_BUFFER_CLOSE:
879                         lyx_view_->closeBuffer();
880                         buffer = 0;
881                         updateFlags = Update::None;
882                         break;
883
884                 case LFUN_BUFFER_CLOSE_ALL:
885                         lyx_view_->closeBufferAll();
886                         buffer = 0;
887                         updateFlags = Update::None;
888                         break;
889
890                 case LFUN_BUFFER_RELOAD: {
891                         LASSERT(lyx_view_ && buffer, /**/);
892                         docstring const file = makeDisplayPath(buffer->absFileName(), 20);
893                         docstring text = bformat(_("Any changes will be lost. Are you sure "
894                                                              "you want to revert to the saved version of the document %1$s?"), file);
895                         int const ret = Alert::prompt(_("Revert to saved document?"),
896                                 text, 1, 1, _("&Revert"), _("&Cancel"));
897
898                         if (ret == 0)
899                                 reloadBuffer();
900                         break;
901                 }
902
903                 case LFUN_BUFFER_UPDATE: {
904                         LASSERT(lyx_view_ && lyx_view_->documentBuffer(), /**/);
905                         Buffer * doc_buffer = lyx_view_->documentBuffer();
906                         string format = argument;
907                         if (argument.empty())
908                                 format = doc_buffer->getDefaultOutputFormat();
909                         doc_buffer->doExport(format, true);
910                         break;
911                 }
912
913                 case LFUN_BUFFER_VIEW: {
914                         LASSERT(lyx_view_ && lyx_view_->documentBuffer(), /**/);
915                         Buffer * doc_buffer = lyx_view_->documentBuffer();
916                         string format = argument;
917                         if (argument.empty())
918                                 format = doc_buffer->getDefaultOutputFormat();
919                         doc_buffer->preview(format);
920                         break;
921                 }
922
923                 case LFUN_MASTER_BUFFER_UPDATE: {
924                         LASSERT(lyx_view_ && lyx_view_->documentBuffer() && lyx_view_->documentBuffer()->masterBuffer(), /**/);
925                         Buffer * doc_buffer = lyx_view_->documentBuffer();
926                         string format = argument;
927                         if (argument.empty())
928                                 format = doc_buffer->masterBuffer()->getDefaultOutputFormat();
929                         doc_buffer->masterBuffer()->doExport(format, true);
930                         break;
931                 }
932
933                 case LFUN_MASTER_BUFFER_VIEW: {
934                         LASSERT(lyx_view_ && lyx_view_->documentBuffer() && lyx_view_->documentBuffer()->masterBuffer(), /**/);
935                         Buffer * doc_buffer = lyx_view_->documentBuffer();
936                         string format = argument;
937                         if (argument.empty())
938                                 format = doc_buffer->masterBuffer()->getDefaultOutputFormat();
939                         doc_buffer->masterBuffer()->preview(format);
940                         break;
941                 }
942
943                 case LFUN_BUILD_PROGRAM:
944                         LASSERT(lyx_view_ && buffer, /**/);
945                         buffer->doExport("program", true);
946                         break;
947
948                 case LFUN_BUFFER_CHKTEX:
949                         LASSERT(lyx_view_ && buffer, /**/);
950                         buffer->runChktex();
951                         break;
952
953                 case LFUN_BUFFER_EXPORT:
954                         LASSERT(lyx_view_ && buffer, /**/);
955                         if (argument == "custom")
956                                 dispatch(FuncRequest(LFUN_DIALOG_SHOW, "sendto"));
957                         else
958                                 buffer->doExport(argument, false);
959                         break;
960
961                 case LFUN_BUFFER_EXPORT_CUSTOM: {
962                         LASSERT(lyx_view_ && buffer, /**/);
963                         string format_name;
964                         string command = split(argument, format_name, ' ');
965                         Format const * format = formats.getFormat(format_name);
966                         if (!format) {
967                                 lyxerr << "Format \"" << format_name
968                                        << "\" not recognized!"
969                                        << endl;
970                                 break;
971                         }
972
973                         // The name of the file created by the conversion process
974                         string filename;
975
976                         // Output to filename
977                         if (format->name() == "lyx") {
978                                 string const latexname = buffer->latexName(false);
979                                 filename = changeExtension(latexname,
980                                                            format->extension());
981                                 filename = addName(buffer->temppath(), filename);
982
983                                 if (!buffer->writeFile(FileName(filename)))
984                                         break;
985
986                         } else {
987                                 buffer->doExport(format_name, true, filename);
988                         }
989
990                         // Substitute $$FName for filename
991                         if (!contains(command, "$$FName"))
992                                 command = "( " + command + " ) < $$FName";
993                         command = subst(command, "$$FName", filename);
994
995                         // Execute the command in the background
996                         Systemcall call;
997                         call.startscript(Systemcall::DontWait, command);
998                         break;
999                 }
1000
1001                 // FIXME: There is need for a command-line import.
1002                 /*
1003                 case LFUN_BUFFER_IMPORT:
1004                         doImport(argument);
1005                         break;
1006                 */
1007
1008                 case LFUN_BUFFER_AUTO_SAVE:
1009                         buffer->autoSave();
1010                         break;
1011
1012                 case LFUN_RECONFIGURE:
1013                         // argument is any additional parameter to the configure.py command
1014                         reconfigure(lyx_view_, argument);
1015                         break;
1016
1017                 case LFUN_HELP_OPEN: {
1018                         if (lyx_view_ == 0)
1019                                 theApp()->dispatch(FuncRequest(LFUN_WINDOW_NEW));
1020                         string const arg = argument;
1021                         if (arg.empty()) {
1022                                 setErrorMessage(from_utf8(N_("Missing argument")));
1023                                 break;
1024                         }
1025                         FileName fname = i18nLibFileSearch("doc", arg, "lyx");
1026                         if (fname.empty()) 
1027                                 fname = i18nLibFileSearch("examples", arg, "lyx");
1028
1029                         if (fname.empty()) {
1030                                 lyxerr << "LyX: unable to find documentation file `"
1031                                                          << arg << "'. Bad installation?" << endl;
1032                                 break;
1033                         }
1034                         lyx_view_->message(bformat(_("Opening help file %1$s..."),
1035                                 makeDisplayPath(fname.absFilename())));
1036                         Buffer * buf = lyx_view_->loadDocument(fname, false);
1037                         if (buf) {
1038                                 buf->updateLabels();
1039                                 lyx_view_->setBuffer(buf);
1040                                 buf->errors("Parse");
1041                         }
1042                         updateFlags = Update::None;
1043                         break;
1044                 }
1045
1046                 // --- version control -------------------------------
1047                 case LFUN_VC_REGISTER:
1048                         LASSERT(lyx_view_ && buffer, /**/);
1049                         if (!ensureBufferClean(view()))
1050                                 break;
1051                         if (!buffer->lyxvc().inUse()) {
1052                                 if (buffer->lyxvc().registrer())
1053                                         reloadBuffer();
1054                         }
1055                         updateFlags = Update::Force;
1056                         break;
1057
1058                 case LFUN_VC_CHECK_IN:
1059                         LASSERT(lyx_view_ && buffer, /**/);
1060                         if (!ensureBufferClean(view()))
1061                                 break;
1062                         if (buffer->lyxvc().inUse()
1063                                         && !buffer->isReadonly()) {
1064                                 setMessage(from_utf8(buffer->lyxvc().checkIn()));
1065                                 reloadBuffer();
1066                         }
1067                         break;
1068
1069                 case LFUN_VC_CHECK_OUT:
1070                         LASSERT(lyx_view_ && buffer, /**/);
1071                         if (!ensureBufferClean(view()))
1072                                 break;
1073                         if (buffer->lyxvc().inUse()) {
1074                                 setMessage(from_utf8(buffer->lyxvc().checkOut()));
1075                                 reloadBuffer();
1076                         }
1077                         break;
1078
1079                 case LFUN_VC_LOCKING_TOGGLE:
1080                         LASSERT(lyx_view_ && buffer, /**/);
1081                         if (!ensureBufferClean(view()) || buffer->isReadonly())
1082                                 break;
1083                         if (buffer->lyxvc().inUse()) {
1084                                 string res = buffer->lyxvc().lockingToggle();
1085                                 if (res.empty())
1086                                         frontend::Alert::error(_("Revision control error."),
1087                                                 _("Error when setting the locking property."));
1088                                 else {
1089                                         setMessage(from_utf8(res));
1090                                         reloadBuffer();
1091                                 }
1092                         }
1093                         break;
1094
1095                 case LFUN_VC_REVERT:
1096                         LASSERT(lyx_view_ && buffer, /**/);
1097                         buffer->lyxvc().revert();
1098                         reloadBuffer();
1099                         break;
1100
1101                 case LFUN_VC_UNDO_LAST:
1102                         LASSERT(lyx_view_ && buffer, /**/);
1103                         buffer->lyxvc().undoLast();
1104                         reloadBuffer();
1105                         break;
1106
1107                 // --- lyxserver commands ----------------------------
1108                 case LFUN_SERVER_GET_FILENAME:
1109                         LASSERT(lyx_view_ && buffer, /**/);
1110                         setMessage(from_utf8(buffer->absFileName()));
1111                         LYXERR(Debug::INFO, "FNAME["
1112                                 << buffer->absFileName() << ']');
1113                         break;
1114
1115                 case LFUN_SERVER_NOTIFY:
1116                         dispatch_buffer = keyseq.print(KeySequence::Portable);
1117                         theServer().notifyClient(to_utf8(dispatch_buffer));
1118                         break;
1119
1120                 case LFUN_SERVER_GOTO_FILE_ROW: {
1121                         LASSERT(lyx_view_, /**/);
1122                         string file_name;
1123                         int row;
1124                         istringstream is(argument);
1125                         is >> file_name >> row;
1126                         file_name = os::internal_path(file_name);
1127                         Buffer * buf = 0;
1128                         bool loaded = false;
1129                         string const abstmp = package().temp_dir().absFilename();
1130                         string const realtmp = package().temp_dir().realPath();
1131                         // We have to use os::path_prefix_is() here, instead of
1132                         // simply prefixIs(), because the file name comes from
1133                         // an external application and may need case adjustment.
1134                         if (os::path_prefix_is(file_name, abstmp, os::CASE_ADJUSTED)
1135                             || os::path_prefix_is(file_name, realtmp, os::CASE_ADJUSTED)) {
1136                                 // Needed by inverse dvi search. If it is a file
1137                                 // in tmpdir, call the apropriated function.
1138                                 // If tmpdir is a symlink, we may have the real
1139                                 // path passed back, so we correct for that.
1140                                 if (!prefixIs(file_name, abstmp))
1141                                         file_name = subst(file_name, realtmp, abstmp);
1142                                 buf = theBufferList().getBufferFromTmp(file_name);
1143                         } else {
1144                                 // Must replace extension of the file to be .lyx
1145                                 // and get full path
1146                                 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1147                                 // Either change buffer or load the file
1148                                 if (theBufferList().exists(s))
1149                                         buf = theBufferList().getBuffer(s);
1150                                 else if (s.exists()) {
1151                                         buf = lyx_view_->loadDocument(s);
1152                                         loaded = true;
1153                                 } else
1154                                         lyx_view_->message(bformat(
1155                                                 _("File does not exist: %1$s"),
1156                                                 makeDisplayPath(file_name)));
1157                         }
1158
1159                         if (!buf) {
1160                                 updateFlags = Update::None;
1161                                 break;
1162                         }
1163
1164                         buf->updateLabels();
1165                         lyx_view_->setBuffer(buf);
1166                         view()->setCursorFromRow(row);
1167                         if (loaded)
1168                                 buf->errors("Parse");
1169                         updateFlags = Update::FitCursor;
1170                         break;
1171                 }
1172
1173
1174                 case LFUN_DIALOG_SHOW_NEW_INSET: {
1175                         LASSERT(lyx_view_, /**/);
1176                         string const name = cmd.getArg(0);
1177                         InsetCode code = insetCode(name);
1178                         string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1179                         bool insetCodeOK = true;
1180                         switch (code) {
1181                         case BIBITEM_CODE:
1182                         case BIBTEX_CODE:
1183                         case INDEX_CODE:
1184                         case LABEL_CODE:
1185                         case NOMENCL_CODE:
1186                         case NOMENCL_PRINT_CODE:
1187                         case REF_CODE:
1188                         case TOC_CODE:
1189                         case HYPERLINK_CODE: {
1190                                 InsetCommandParams p(code);
1191                                 data = InsetCommand::params2string(name, p);
1192                                 break;
1193                         }
1194                         case INCLUDE_CODE: {
1195                                 // data is the include type: one of "include",
1196                                 // "input", "verbatiminput" or "verbatiminput*"
1197                                 if (data.empty())
1198                                         // default type is requested
1199                                         data = "include";
1200                                 InsetCommandParams p(INCLUDE_CODE, data);
1201                                 data = InsetCommand::params2string("include", p);
1202                                 break;
1203                         }
1204                         case BOX_CODE: {
1205                                 // \c data == "Boxed" || "Frameless" etc
1206                                 InsetBoxParams p(data);
1207                                 data = InsetBox::params2string(p);
1208                                 break;
1209                         }
1210                         case BRANCH_CODE: {
1211                                 InsetBranchParams p;
1212                                 data = InsetBranch::params2string(p);
1213                                 break;
1214                         }
1215                         case CITE_CODE: {
1216                                 InsetCommandParams p(CITE_CODE);
1217                                 data = InsetCommand::params2string(name, p);
1218                                 break;
1219                         }
1220                         case ERT_CODE: {
1221                                 data = InsetERT::params2string(InsetCollapsable::Open);
1222                                 break;
1223                         }
1224                         case EXTERNAL_CODE: {
1225                                 InsetExternalParams p;
1226                                 data = InsetExternal::params2string(p, *buffer);
1227                                 break;
1228                         }
1229                         case FLOAT_CODE:  {
1230                                 InsetFloatParams p;
1231                                 data = InsetFloat::params2string(p);
1232                                 break;
1233                         }
1234                         case LISTINGS_CODE: {
1235                                 InsetListingsParams p;
1236                                 data = InsetListings::params2string(p);
1237                                 break;
1238                         }
1239                         case GRAPHICS_CODE: {
1240                                 InsetGraphicsParams p;
1241                                 data = InsetGraphics::params2string(p, *buffer);
1242                                 break;
1243                         }
1244                         case NOTE_CODE: {
1245                                 InsetNoteParams p;
1246                                 data = InsetNote::params2string(p);
1247                                 break;
1248                         }
1249                         case PHANTOM_CODE: {
1250                                 InsetPhantomParams p;
1251                                 data = InsetPhantom::params2string(p);
1252                                 break;
1253                         }
1254                         case SPACE_CODE: {
1255                                 InsetSpaceParams p;
1256                                 data = InsetSpace::params2string(p);
1257                                 break;
1258                         }
1259                         case VSPACE_CODE: {
1260                                 VSpace space;
1261                                 data = InsetVSpace::params2string(space);
1262                                 break;
1263                         }
1264                         case WRAP_CODE: {
1265                                 InsetWrapParams p;
1266                                 data = InsetWrap::params2string(p);
1267                                 break;
1268                         }
1269                         default:
1270                                 lyxerr << "Inset type '" << name << 
1271                                         "' not recognized in LFUN_DIALOG_SHOW_NEW_INSET" <<  endl;
1272                                 insetCodeOK = false;
1273                                 break;
1274                         } // end switch(code)
1275                         if (insetCodeOK)
1276                                 dispatch(FuncRequest(LFUN_DIALOG_SHOW, name + " " + data));
1277                         break;
1278                 }
1279
1280                 case LFUN_CITATION_INSERT: {
1281                         LASSERT(lyx_view_, /**/);
1282                         if (!argument.empty()) {
1283                                 // we can have one optional argument, delimited by '|'
1284                                 // citation-insert <key>|<text_before>
1285                                 // this should be enhanced to also support text_after
1286                                 // and citation style
1287                                 string arg = argument;
1288                                 string opt1;
1289                                 if (contains(argument, "|")) {
1290                                         arg = token(argument, '|', 0);
1291                                         opt1 = token(argument, '|', 1);
1292                                 }
1293                                 InsetCommandParams icp(CITE_CODE);
1294                                 icp["key"] = from_utf8(arg);
1295                                 if (!opt1.empty())
1296                                         icp["before"] = from_utf8(opt1);
1297                                 string icstr = InsetCommand::params2string("citation", icp);
1298                                 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1299                                 dispatch(fr);
1300                         } else
1301                                 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1302                         break;
1303                 }
1304
1305                 case LFUN_BUFFER_CHILD_OPEN: {
1306                         LASSERT(lyx_view_ && buffer, /**/);
1307                         FileName filename = makeAbsPath(argument, buffer->filePath());
1308                         view()->saveBookmark(false);
1309                         Buffer * child = 0;
1310                         bool parsed = false;
1311                         if (theBufferList().exists(filename)) {
1312                                 child = theBufferList().getBuffer(filename);
1313                         } else {
1314                                 setMessage(bformat(_("Opening child document %1$s..."),
1315                                         makeDisplayPath(filename.absFilename())));
1316                                 child = lyx_view_->loadDocument(filename, false);
1317                                 parsed = true;
1318                         }
1319                         if (child) {
1320                                 // Set the parent name of the child document.
1321                                 // This makes insertion of citations and references in the child work,
1322                                 // when the target is in the parent or another child document.
1323                                 child->setParent(buffer);
1324                                 child->masterBuffer()->updateLabels();
1325                                 lyx_view_->setBuffer(child);
1326                                 if (parsed)
1327                                         child->errors("Parse");
1328                         }
1329
1330                         // If a screen update is required (in case where auto_open is false), 
1331                         // setBuffer() would have taken care of it already. Otherwise we shall 
1332                         // reset the update flag because it can cause a circular problem.
1333                         // See bug 3970.
1334                         updateFlags = Update::None;
1335                         break;
1336                 }
1337
1338                 case LFUN_CURSOR_FOLLOWS_SCROLLBAR_TOGGLE:
1339                         LASSERT(lyx_view_, /**/);
1340                         lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1341                         break;
1342
1343                 case LFUN_KEYMAP_OFF:
1344                         LASSERT(lyx_view_ && lyx_view_->view(), /**/);
1345                         lyx_view_->currentBufferView()->getIntl().keyMapOn(false);
1346                         break;
1347
1348                 case LFUN_KEYMAP_PRIMARY:
1349                         LASSERT(lyx_view_ && lyx_view_->currentBufferView(), /**/);
1350                         lyx_view_->currentBufferView()->getIntl().keyMapPrim();
1351                         break;
1352
1353                 case LFUN_KEYMAP_SECONDARY:
1354                         LASSERT(lyx_view_ && lyx_view_->currentBufferView(), /**/);
1355                         lyx_view_->currentBufferView()->getIntl().keyMapSec();
1356                         break;
1357
1358                 case LFUN_KEYMAP_TOGGLE:
1359                         LASSERT(lyx_view_ && lyx_view_->currentBufferView(), /**/);
1360                         lyx_view_->currentBufferView()->getIntl().toggleKeyMap();
1361                         break;
1362
1363                 case LFUN_REPEAT: {
1364                         // repeat command
1365                         string countstr;
1366                         string rest = split(argument, countstr, ' ');
1367                         istringstream is(countstr);
1368                         int count = 0;
1369                         is >> count;
1370                         //lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1371                         for (int i = 0; i < count; ++i)
1372                                 dispatch(lyxaction.lookupFunc(rest));
1373                         break;
1374                 }
1375
1376                 case LFUN_COMMAND_SEQUENCE: {
1377                         // argument contains ';'-terminated commands
1378                         string arg = argument;
1379                         if (theBufferList().isLoaded(buffer))
1380                                 buffer->undo().beginUndoGroup();
1381                         while (!arg.empty()) {
1382                                 string first;
1383                                 arg = split(arg, first, ';');
1384                                 FuncRequest func(lyxaction.lookupFunc(first));
1385                                 func.origin = cmd.origin;
1386                                 dispatch(func);
1387                         }
1388                         if (theBufferList().isLoaded(buffer))
1389                                 buffer->undo().endUndoGroup();
1390                         break;
1391                 }
1392
1393                 case LFUN_COMMAND_ALTERNATIVES: {
1394                         // argument contains ';'-terminated commands
1395                         string arg = argument;
1396                         while (!arg.empty()) {
1397                                 string first;
1398                                 arg = split(arg, first, ';');
1399                                 FuncRequest func(lyxaction.lookupFunc(first));
1400                                 func.origin = cmd.origin;
1401                                 FuncStatus stat = getStatus(func);
1402                                 if (stat.enabled()) {
1403                                         dispatch(func);
1404                                         break;
1405                                 }
1406                         }
1407                         break;
1408                 }
1409
1410                 case LFUN_CALL: {
1411                         FuncRequest func;
1412                         if (theTopLevelCmdDef().lock(argument, func)) {
1413                                 func.origin = cmd.origin;
1414                                 dispatch(func);
1415                                 theTopLevelCmdDef().release(argument);
1416                         } else {
1417                                 if (func.action == LFUN_UNKNOWN_ACTION) {
1418                                         // unknown command definition
1419                                         lyxerr << "Warning: unknown command definition `"
1420                                                    << argument << "'"
1421                                                    << endl;
1422                                 } else {
1423                                         // recursion detected
1424                                         lyxerr << "Warning: Recursion in the command definition `"
1425                                                    << argument << "' detected"
1426                                                    << endl;
1427                                 }
1428                         }
1429                         break;
1430                 }
1431
1432                 case LFUN_PREFERENCES_SAVE: {
1433                         lyxrc.write(makeAbsPath("preferences",
1434                                                 package().user_support().absFilename()),
1435                                     false);
1436                         break;
1437                 }
1438
1439                 case LFUN_MESSAGE:
1440                         LASSERT(lyx_view_, /**/);
1441                         lyx_view_->message(from_utf8(argument));
1442                         break;
1443
1444                 case LFUN_BUFFER_LANGUAGE: {
1445                         LASSERT(lyx_view_, /**/);
1446                         Language const * oldL = buffer->params().language;
1447                         Language const * newL = languages.getLanguage(argument);
1448                         if (!newL || oldL == newL)
1449                                 break;
1450
1451                         if (oldL->rightToLeft() == newL->rightToLeft()
1452                             && !buffer->isMultiLingual())
1453                                 buffer->changeLanguage(oldL, newL);
1454                         break;
1455                 }
1456
1457                 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1458                         string const fname =
1459                                 addName(addPath(package().user_support().absFilename(), "templates/"),
1460                                         "defaults.lyx");
1461                         Buffer defaults(fname);
1462
1463                         istringstream ss(argument);
1464                         Lexer lex;
1465                         lex.setStream(ss);
1466                         int const unknown_tokens = defaults.readHeader(lex);
1467
1468                         if (unknown_tokens != 0) {
1469                                 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1470                                        << unknown_tokens << " unknown token"
1471                                        << (unknown_tokens == 1 ? "" : "s")
1472                                        << endl;
1473                         }
1474
1475                         if (defaults.writeFile(FileName(defaults.absFileName())))
1476                                 setMessage(bformat(_("Document defaults saved in %1$s"),
1477                                                    makeDisplayPath(fname)));
1478                         else
1479                                 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1480                         break;
1481                 }
1482
1483                 case LFUN_BUFFER_PARAMS_APPLY: {
1484                         LASSERT(lyx_view_, /**/);
1485                         
1486                         DocumentClass const * const oldClass = buffer->params().documentClassPtr();
1487                         Cursor & cur = view()->cursor();
1488                         cur.recordUndoFullDocument();
1489                         
1490                         istringstream ss(argument);
1491                         Lexer lex;
1492                         lex.setStream(ss);
1493                         int const unknown_tokens = buffer->readHeader(lex);
1494
1495                         if (unknown_tokens != 0) {
1496                                 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1497                                                 << unknown_tokens << " unknown token"
1498                                                 << (unknown_tokens == 1 ? "" : "s")
1499                                                 << endl;
1500                         }
1501                         
1502                         updateLayout(oldClass, buffer);
1503                         
1504                         updateFlags = Update::Force | Update::FitCursor;
1505                         // We are most certainly here because of a change in the document
1506                         // It is then better to make sure that all dialogs are in sync with
1507                         // current document settings. LyXView::restartCursor() achieve this.
1508                         lyx_view_->restartCursor();
1509                         break;
1510                 }
1511                 
1512                 case LFUN_LAYOUT_MODULES_CLEAR: {
1513                         LASSERT(lyx_view_, /**/);
1514                         DocumentClass const * const oldClass = buffer->params().documentClassPtr();
1515                         view()->cursor().recordUndoFullDocument();
1516                         buffer->params().clearLayoutModules();
1517                         buffer->params().makeDocumentClass();
1518                         updateLayout(oldClass, buffer);
1519                         updateFlags = Update::Force | Update::FitCursor;
1520                         break;
1521                 }
1522                 
1523                 case LFUN_LAYOUT_MODULE_ADD: {
1524                         LASSERT(lyx_view_, /**/);
1525                         BufferParams const & params = buffer->params();
1526                         if (!params.moduleCanBeAdded(argument)) {
1527                                 LYXERR0("Module `" << argument << 
1528                                                 "' cannot be added due to failed requirements or "
1529                                                 "conflicts with installed modules.");
1530                                 break;
1531                         }
1532                         DocumentClass const * const oldClass = params.documentClassPtr();
1533                         view()->cursor().recordUndoFullDocument();
1534                         buffer->params().addLayoutModule(argument);
1535                         buffer->params().makeDocumentClass();
1536                         updateLayout(oldClass, buffer);
1537                         updateFlags = Update::Force | Update::FitCursor;
1538                         break;
1539                 }
1540
1541                 case LFUN_TEXTCLASS_APPLY: {
1542                         LASSERT(lyx_view_, /**/);
1543
1544                         if (!loadLayoutFile(argument, buffer->temppath()) &&
1545                                 !loadLayoutFile(argument, buffer->filePath()))
1546                                 break;
1547
1548                         LayoutFile const * old_layout = buffer->params().baseClass();
1549                         LayoutFile const * new_layout = &(LayoutFileList::get()[argument]);
1550
1551                         if (old_layout == new_layout)
1552                                 // nothing to do
1553                                 break;
1554
1555                         //Save the old, possibly modular, layout for use in conversion.
1556                         DocumentClass const * const oldDocClass = buffer->params().documentClassPtr();
1557                         view()->cursor().recordUndoFullDocument();
1558                         buffer->params().setBaseClass(argument);
1559                         buffer->params().makeDocumentClass();
1560                         updateLayout(oldDocClass, buffer);
1561                         updateFlags = Update::Force | Update::FitCursor;
1562                         break;
1563                 }
1564                 
1565                 case LFUN_LAYOUT_RELOAD: {
1566                         LASSERT(lyx_view_, /**/);
1567                         DocumentClass const * const oldClass = buffer->params().documentClassPtr();
1568                         LayoutFileIndex bc = buffer->params().baseClassID();
1569                         LayoutFileList::get().reset(bc);
1570                         buffer->params().setBaseClass(bc);
1571                         buffer->params().makeDocumentClass();
1572                         updateLayout(oldClass, buffer);
1573                         updateFlags = Update::Force | Update::FitCursor;
1574                         break;
1575                 }
1576
1577                 case LFUN_TEXTCLASS_LOAD:
1578                         loadLayoutFile(argument, buffer->temppath()) ||
1579                         loadLayoutFile(argument, buffer->filePath());
1580                         break;
1581
1582                 case LFUN_LYXRC_APPLY: {
1583                         // reset active key sequences, since the bindings
1584                         // are updated (bug 6064)
1585                         keyseq.reset();
1586                         LyXRC const lyxrc_orig = lyxrc;
1587
1588                         istringstream ss(argument);
1589                         bool const success = lyxrc.read(ss) == 0;
1590
1591                         if (!success) {
1592                                 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1593                                        << "Unable to read lyxrc data"
1594                                        << endl;
1595                                 break;
1596                         }
1597
1598                         actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1599
1600                         setSpellChecker();
1601
1602                         theApp()->resetGui();
1603
1604                         /// We force the redraw in any case because there might be
1605                         /// some screen font changes.
1606                         /// FIXME: only the current view will be updated. the Gui
1607                         /// class is able to furnish the list of views.
1608                         updateFlags = Update::Force;
1609                         break;
1610                 }
1611
1612                 case LFUN_BOOKMARK_GOTO:
1613                         // go to bookmark, open unopened file and switch to buffer if necessary
1614                         gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
1615                         updateFlags = Update::FitCursor;
1616                         break;
1617
1618                 case LFUN_BOOKMARK_CLEAR:
1619                         theSession().bookmarks().clear();
1620                         break;
1621
1622                 case LFUN_VC_COMMAND: {
1623                         string flag = cmd.getArg(0);
1624                         if (buffer && contains(flag, 'R') && !ensureBufferClean(view()))
1625                                 break;
1626                         docstring message;
1627                         if (contains(flag, 'M'))
1628                                 if (!Alert::askForText(message, _("LyX VC: Log Message")))
1629                                         break;
1630
1631                         string path = cmd.getArg(1);
1632                         if (contains(path, "$$p") && buffer)
1633                                 path = subst(path, "$$p", buffer->filePath());
1634                         LYXERR(Debug::LYXVC, "Directory: " << path);
1635                         FileName pp(path);
1636                         if (!pp.isReadableDirectory()) {
1637                                 lyxerr << _("Directory is not accessible.") << endl;
1638                                 break;
1639                         }
1640                         support::PathChanger p(pp);
1641
1642                         string command = cmd.getArg(2);
1643                         if (command.empty())
1644                                 break;
1645                         if (buffer) {
1646                                 command = subst(command, "$$i", buffer->absFileName());
1647                                 command = subst(command, "$$p", buffer->filePath());
1648                         }
1649                         command = subst(command, "$$m", to_utf8(message));
1650                         LYXERR(Debug::LYXVC, "Command: " << command);
1651                         Systemcall one;
1652                         one.startscript(Systemcall::Wait, command);
1653
1654                         if (!buffer)
1655                                 break;
1656                         if (contains(flag, 'I'))
1657                                 buffer->markDirty();
1658                         if (contains(flag, 'R'))
1659                                 reloadBuffer();
1660
1661                         break;
1662                 }
1663
1664                 default:
1665                         LASSERT(theApp(), /**/);
1666                         // Let the frontend dispatch its own actions.
1667                         if (theApp()->dispatch(cmd))
1668                                 // Nothing more to do.
1669                                 return;
1670
1671                         // Everything below is only for active lyx_view_
1672                         if (lyx_view_ == 0)
1673                                 break;
1674
1675                         // Start an undo group. This may be needed for
1676                         // some stuff like inset-apply on labels.
1677                         if (theBufferList().isLoaded(buffer))
1678                                 buffer->undo().beginUndoGroup();
1679                                 
1680                         // Let the current LyXView dispatch its own actions.
1681                         if (lyx_view_->dispatch(cmd)) {
1682                                 if (lyx_view_->currentBufferView()) {
1683                                         updateFlags = lyx_view_->currentBufferView()->cursor().result().update();
1684                                         if (theBufferList().isLoaded(buffer))
1685                                                 buffer->undo().endUndoGroup();
1686                                 }
1687                                 break;
1688                         }
1689
1690                         LASSERT(lyx_view_->currentBufferView(), /**/);
1691
1692                         // Let the current BufferView dispatch its own actions.
1693                         if (view()->dispatch(cmd)) {
1694                                 // The BufferView took care of its own updates if needed.
1695                                 updateFlags = Update::None;
1696                                 if (theBufferList().isLoaded(buffer))
1697                                         buffer->undo().endUndoGroup();
1698                                 break;
1699                         }
1700
1701                         // OK, so try the Buffer itself
1702                         DispatchResult dr;
1703                         view()->buffer().dispatch(cmd, dr);
1704                         if (dr.dispatched()) {
1705                                 updateFlags = dr.update();
1706                                 break;
1707                         }
1708
1709                         // Is this a function that acts on inset at point?
1710                         Inset * inset = view()->cursor().nextInset();
1711                         if (lyxaction.funcHasFlag(action, LyXAction::AtPoint)
1712                             && inset) {
1713                                 view()->cursor().result().dispatched(true);
1714                                 view()->cursor().result().update(Update::FitCursor | Update::Force);
1715                                 FuncRequest tmpcmd = cmd;
1716                                 inset->dispatch(view()->cursor(), tmpcmd);
1717                                 if (view()->cursor().result().dispatched()) {
1718                                         updateFlags = view()->cursor().result().update();
1719                                         break;
1720                                 }
1721                         }
1722
1723                         // Let the current Cursor dispatch its own actions.
1724                         Cursor old = view()->cursor();
1725                         view()->cursor().getPos(cursorPosBeforeDispatchX_,
1726                                                 cursorPosBeforeDispatchY_);
1727                         view()->cursor().dispatch(cmd);
1728
1729                         // notify insets we just left
1730                         if (view()->cursor() != old) {
1731                                 old.fixIfBroken();
1732                                 bool badcursor = notifyCursorLeavesOrEnters(old, view()->cursor());
1733                                 if (badcursor)
1734                                         view()->cursor().fixIfBroken();
1735                         }
1736
1737                         if (theBufferList().isLoaded(buffer))
1738                                 buffer->undo().endUndoGroup();
1739
1740                         // update completion. We do it here and not in
1741                         // processKeySym to avoid another redraw just for a
1742                         // changed inline completion
1743                         if (cmd.origin == FuncRequest::KEYBOARD) {
1744                                 if (cmd.action == LFUN_SELF_INSERT
1745                                     || (cmd.action == LFUN_ERT_INSERT && view()->cursor().inMathed()))
1746                                         lyx_view_->updateCompletion(view()->cursor(), true, true);
1747                                 else if (cmd.action == LFUN_CHAR_DELETE_BACKWARD)
1748                                         lyx_view_->updateCompletion(view()->cursor(), false, true);
1749                                 else
1750                                         lyx_view_->updateCompletion(view()->cursor(), false, false);
1751                         }
1752
1753                         updateFlags = view()->cursor().result().update();
1754                 }
1755
1756                 // if we executed a mutating lfun, mark the buffer as dirty
1757                 if (theBufferList().isLoaded(buffer) && flag.enabled()
1758                     && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
1759                     && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
1760                         buffer->markDirty();                    
1761
1762                 if (lyx_view_ && lyx_view_->buffer()) {
1763                         // BufferView::update() updates the ViewMetricsInfo and
1764                         // also initializes the position cache for all insets in
1765                         // (at least partially) visible top-level paragraphs.
1766                         // We will redraw the screen only if needed.
1767                         view()->processUpdateFlags(updateFlags);
1768
1769                         // Do we have a selection?
1770                         theSelection().haveSelection(view()->cursor().selection());
1771                         
1772                         // update gui
1773                         lyx_view_->restartCursor();
1774                 }
1775         }
1776         if (lyx_view_) {
1777                 // Some messages may already be translated, so we cannot use _()
1778                 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
1779         }
1780 }
1781
1782
1783 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
1784 {
1785         const bool verbose = (cmd.origin == FuncRequest::MENU
1786                               || cmd.origin == FuncRequest::TOOLBAR
1787                               || cmd.origin == FuncRequest::COMMANDBUFFER);
1788
1789         if (cmd.action == LFUN_SELF_INSERT || !verbose) {
1790                 LYXERR(Debug::ACTION, "dispatch msg is " << to_utf8(msg));
1791                 if (!msg.empty())
1792                         lyx_view_->message(msg);
1793                 return;
1794         }
1795
1796         docstring dispatch_msg = msg;
1797         if (!dispatch_msg.empty())
1798                 dispatch_msg += ' ';
1799
1800         docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
1801
1802         bool argsadded = false;
1803
1804         if (!cmd.argument().empty()) {
1805                 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1806                         comname += ' ' + cmd.argument();
1807                         argsadded = true;
1808                 }
1809         }
1810
1811         docstring const shortcuts = theTopLevelKeymap().printBindings(cmd, KeySequence::ForGui);
1812
1813         if (!shortcuts.empty())
1814                 comname += ": " + shortcuts;
1815         else if (!argsadded && !cmd.argument().empty())
1816                 comname += ' ' + cmd.argument();
1817
1818         if (!comname.empty()) {
1819                 comname = rtrim(comname);
1820                 dispatch_msg += '(' + rtrim(comname) + ')';
1821         }
1822
1823         LYXERR(Debug::ACTION, "verbose dispatch msg " << to_utf8(dispatch_msg));
1824         if (!dispatch_msg.empty())
1825                 lyx_view_->message(dispatch_msg);
1826 }
1827
1828
1829 void LyXFunc::reloadBuffer()
1830 {
1831         FileName filename = lyx_view_->buffer()->fileName();
1832         // The user has already confirmed that the changes, if any, should
1833         // be discarded. So we just release the Buffer and don't call closeBuffer();
1834         theBufferList().release(lyx_view_->buffer());
1835         // if the lyx_view_ has been destroyed, create a new one
1836         if (!lyx_view_)
1837                 theApp()->dispatch(FuncRequest(LFUN_WINDOW_NEW));
1838         Buffer * buf = lyx_view_->loadDocument(filename);
1839         docstring const disp_fn = makeDisplayPath(filename.absFilename());
1840         docstring str;
1841         if (buf) {
1842                 buf->updateLabels();
1843                 lyx_view_->setBuffer(buf);
1844                 buf->errors("Parse");
1845                 str = bformat(_("Document %1$s reloaded."), disp_fn);
1846         } else {
1847                 str = bformat(_("Could not reload document %1$s"), disp_fn);
1848         }
1849         lyx_view_->message(str);
1850 }
1851
1852 // Each "lyx_view_" should have it's own message method. lyxview and
1853 // the minibuffer would use the minibuffer, but lyxserver would
1854 // send an ERROR signal to its client.  Alejandro 970603
1855 // This function is bit problematic when it comes to NLS, to make the
1856 // lyx servers client be language indepenent we must not translate
1857 // strings sent to this func.
1858 void LyXFunc::setErrorMessage(docstring const & m) const
1859 {
1860         dispatch_buffer = m;
1861         errorstat = true;
1862 }
1863
1864
1865 void LyXFunc::setMessage(docstring const & m) const
1866 {
1867         dispatch_buffer = m;
1868 }
1869
1870
1871 docstring LyXFunc::viewStatusMessage()
1872 {
1873         // When meta-fake key is pressed, show the key sequence so far + "M-".
1874         if (wasMetaKey())
1875                 return keyseq.print(KeySequence::ForGui) + "M-";
1876
1877         // Else, when a non-complete key sequence is pressed,
1878         // show the available options.
1879         if (keyseq.length() > 0 && !keyseq.deleted())
1880                 return keyseq.printOptions(true);
1881
1882         LASSERT(lyx_view_, /**/);
1883         if (!lyx_view_->buffer())
1884                 return _("Welcome to LyX!");
1885
1886         return view()->cursor().currentState();
1887 }
1888
1889
1890 BufferView * LyXFunc::view() const
1891 {
1892         LASSERT(lyx_view_, /**/);
1893         return lyx_view_->currentBufferView();
1894 }
1895
1896
1897 bool LyXFunc::wasMetaKey() const
1898 {
1899         return (meta_fake_bit != NoModifier);
1900 }
1901
1902
1903 void LyXFunc::updateLayout(DocumentClass const * const oldlayout, Buffer * buf)
1904 {
1905         lyx_view_->message(_("Converting document to new document class..."));
1906         
1907         StableDocIterator backcur(view()->cursor());
1908         ErrorList & el = buf->errorList("Class Switch");
1909         cap::switchBetweenClasses(
1910                         oldlayout, buf->params().documentClassPtr(),
1911                         static_cast<InsetText &>(buf->inset()), el);
1912
1913         view()->setCursor(backcur.asDocIterator(buf));
1914
1915         buf->errors("Class Switch");
1916         buf->updateLabels();
1917 }
1918
1919
1920 namespace {
1921
1922 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
1923 {
1924         // Why the switch you might ask. It is a trick to ensure that all
1925         // the elements in the LyXRCTags enum is handled. As you can see
1926         // there are no breaks at all. So it is just a huge fall-through.
1927         // The nice thing is that we will get a warning from the compiler
1928         // if we forget an element.
1929         LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
1930         switch (tag) {
1931         case LyXRC::RC_ACCEPT_COMPOUND:
1932         case LyXRC::RC_ALT_LANG:
1933         case LyXRC::RC_PLAINTEXT_LINELEN:
1934         case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
1935         case LyXRC::RC_AUTOCORRECTION_MATH:
1936         case LyXRC::RC_AUTOREGIONDELETE:
1937         case LyXRC::RC_AUTORESET_OPTIONS:
1938         case LyXRC::RC_AUTOSAVE:
1939         case LyXRC::RC_AUTO_NUMBER:
1940         case LyXRC::RC_BACKUPDIR_PATH:
1941         case LyXRC::RC_BIBTEX_ALTERNATIVES:
1942         case LyXRC::RC_BIBTEX_COMMAND:
1943         case LyXRC::RC_BINDFILE:
1944         case LyXRC::RC_CHECKLASTFILES:
1945         case LyXRC::RC_COMPLETION_CURSOR_TEXT:
1946         case LyXRC::RC_COMPLETION_INLINE_DELAY:
1947         case LyXRC::RC_COMPLETION_INLINE_DOTS:
1948         case LyXRC::RC_COMPLETION_INLINE_MATH:
1949         case LyXRC::RC_COMPLETION_INLINE_TEXT:
1950         case LyXRC::RC_COMPLETION_POPUP_AFTER_COMPLETE:
1951         case LyXRC::RC_COMPLETION_POPUP_DELAY:
1952         case LyXRC::RC_COMPLETION_POPUP_MATH:
1953         case LyXRC::RC_COMPLETION_POPUP_TEXT:
1954         case LyXRC::RC_USELASTFILEPOS:
1955         case LyXRC::RC_LOADSESSION:
1956         case LyXRC::RC_CHKTEX_COMMAND:
1957         case LyXRC::RC_CONVERTER:
1958         case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
1959         case LyXRC::RC_COPIER:
1960         case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
1961         case LyXRC::RC_SCROLL_BELOW_DOCUMENT:
1962         case LyXRC::RC_DATE_INSERT_FORMAT:
1963         case LyXRC::RC_DEFAULT_LANGUAGE:
1964         case LyXRC::RC_GUI_LANGUAGE:
1965         case LyXRC::RC_DEFAULT_PAPERSIZE:
1966         case LyXRC::RC_DEFAULT_VIEW_FORMAT:
1967         case LyXRC::RC_DEFFILE:
1968         case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
1969         case LyXRC::RC_DISPLAY_GRAPHICS:
1970         case LyXRC::RC_DOCUMENTPATH:
1971                 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
1972                         FileName path(lyxrc_new.document_path);
1973                         if (path.exists() && path.isDirectory())
1974                                 package().document_dir() = FileName(lyxrc.document_path);
1975                 }
1976         case LyXRC::RC_ESC_CHARS:
1977         case LyXRC::RC_EXAMPLEPATH:
1978         case LyXRC::RC_FONT_ENCODING:
1979         case LyXRC::RC_FORMAT:
1980         case LyXRC::RC_GROUP_LAYOUTS:
1981         case LyXRC::RC_HUNSPELLDIR_PATH:
1982         case LyXRC::RC_INDEX_ALTERNATIVES:
1983         case LyXRC::RC_INDEX_COMMAND:
1984         case LyXRC::RC_JBIBTEX_COMMAND:
1985         case LyXRC::RC_JINDEX_COMMAND:
1986         case LyXRC::RC_NOMENCL_COMMAND:
1987         case LyXRC::RC_INPUT:
1988         case LyXRC::RC_KBMAP:
1989         case LyXRC::RC_KBMAP_PRIMARY:
1990         case LyXRC::RC_KBMAP_SECONDARY:
1991         case LyXRC::RC_LABEL_INIT_LENGTH:
1992         case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
1993         case LyXRC::RC_LANGUAGE_AUTO_END:
1994         case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
1995         case LyXRC::RC_LANGUAGE_COMMAND_END:
1996         case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
1997         case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
1998         case LyXRC::RC_LANGUAGE_PACKAGE:
1999         case LyXRC::RC_LANGUAGE_USE_BABEL:
2000         case LyXRC::RC_MAC_LIKE_WORD_MOVEMENT:
2001         case LyXRC::RC_MACRO_EDIT_STYLE:
2002         case LyXRC::RC_MAKE_BACKUP:
2003         case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2004         case LyXRC::RC_MOUSE_WHEEL_SPEED:
2005         case LyXRC::RC_NUMLASTFILES:
2006         case LyXRC::RC_PARAGRAPH_MARKERS:
2007         case LyXRC::RC_PATH_PREFIX:
2008                 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2009                         prependEnvPath("PATH", lyxrc.path_prefix);
2010                 }
2011         case LyXRC::RC_PERS_DICT:
2012         case LyXRC::RC_PREVIEW:
2013         case LyXRC::RC_PREVIEW_HASHED_LABELS:
2014         case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2015         case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2016         case LyXRC::RC_PRINTCOPIESFLAG:
2017         case LyXRC::RC_PRINTER:
2018         case LyXRC::RC_PRINTEVENPAGEFLAG:
2019         case LyXRC::RC_PRINTEXSTRAOPTIONS:
2020         case LyXRC::RC_PRINTFILEEXTENSION:
2021         case LyXRC::RC_PRINTLANDSCAPEFLAG:
2022         case LyXRC::RC_PRINTODDPAGEFLAG:
2023         case LyXRC::RC_PRINTPAGERANGEFLAG:
2024         case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2025         case LyXRC::RC_PRINTPAPERFLAG:
2026         case LyXRC::RC_PRINTREVERSEFLAG:
2027         case LyXRC::RC_PRINTSPOOL_COMMAND:
2028         case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2029         case LyXRC::RC_PRINTTOFILE:
2030         case LyXRC::RC_PRINTTOPRINTER:
2031         case LyXRC::RC_PRINT_ADAPTOUTPUT:
2032         case LyXRC::RC_PRINT_COMMAND:
2033         case LyXRC::RC_RTL_SUPPORT:
2034         case LyXRC::RC_SCREEN_DPI:
2035         case LyXRC::RC_SCREEN_FONT_ROMAN:
2036         case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2037         case LyXRC::RC_SCREEN_FONT_SANS:
2038         case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2039         case LyXRC::RC_SCREEN_FONT_SCALABLE:
2040         case LyXRC::RC_SCREEN_FONT_SIZES:
2041         case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2042         case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2043         case LyXRC::RC_GEOMETRY_SESSION:
2044         case LyXRC::RC_SCREEN_ZOOM:
2045         case LyXRC::RC_SERVERPIPE:
2046         case LyXRC::RC_SET_COLOR:
2047         case LyXRC::RC_SHOW_BANNER:
2048         case LyXRC::RC_OPEN_BUFFERS_IN_TABS:
2049         case LyXRC::RC_SPELL_COMMAND:
2050         case LyXRC::RC_SPELLCHECKER:
2051         case LyXRC::RC_SPELLCHECK_CONTINUOUSLY:
2052         case LyXRC::RC_SPLITINDEX_COMMAND:
2053         case LyXRC::RC_TEMPDIRPATH:
2054         case LyXRC::RC_TEMPLATEPATH:
2055         case LyXRC::RC_TEX_ALLOWS_SPACES:
2056         case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2057                 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2058                         os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2059                 }
2060         case LyXRC::RC_THESAURUSDIRPATH:
2061         case LyXRC::RC_UIFILE:
2062         case LyXRC::RC_USER_EMAIL:
2063         case LyXRC::RC_USER_NAME:
2064         case LyXRC::RC_USETEMPDIR:
2065         case LyXRC::RC_USE_ALT_LANG:
2066         case LyXRC::RC_USE_CONVERTER_CACHE:
2067         case LyXRC::RC_USE_ESC_CHARS:
2068         case LyXRC::RC_USE_INP_ENC:
2069         case LyXRC::RC_USE_PERS_DICT:
2070         case LyXRC::RC_USE_TOOLTIP:
2071         case LyXRC::RC_USE_PIXMAP_CACHE:
2072         case LyXRC::RC_USE_SPELL_LIB:
2073         case LyXRC::RC_VIEWDVI_PAPEROPTION:
2074         case LyXRC::RC_SORT_LAYOUTS:
2075         case LyXRC::RC_FULL_SCREEN_LIMIT:
2076         case LyXRC::RC_FULL_SCREEN_SCROLLBAR:
2077         case LyXRC::RC_FULL_SCREEN_MENUBAR:
2078         case LyXRC::RC_FULL_SCREEN_TABBAR:
2079         case LyXRC::RC_FULL_SCREEN_TOOLBARS:
2080         case LyXRC::RC_FULL_SCREEN_WIDTH:
2081         case LyXRC::RC_VISUAL_CURSOR:
2082         case LyXRC::RC_VIEWER:
2083         case LyXRC::RC_LAST:
2084                 break;
2085         }
2086 }
2087
2088 } // namespace anon
2089 } // namespace lyx