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