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