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