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