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