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