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