]> git.lyx.org Git - lyx.git/blob - src/LyXFunc.cpp
last commit was incomplete... not sure how I managed this..
[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 #include <vector>
22
23 #include "LyXFunc.h"
24
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 "Color.h"
32 #include "Cursor.h"
33 #include "CutAndPaste.h"
34 #include "debug.h"
35 #include "DispatchResult.h"
36 #include "Encoding.h"
37 #include "ErrorList.h"
38 #include "Exporter.h"
39 #include "Format.h"
40 #include "FuncRequest.h"
41 #include "FuncStatus.h"
42 #include "gettext.h"
43 #include "Importer.h"
44 #include "InsetIterator.h"
45 #include "Intl.h"
46 #include "KeyMap.h"
47 #include "Language.h"
48 #include "Lexer.h"
49 #include "LyXAction.h"
50 #include "lyxfind.h"
51 #include "LyX.h"
52 #include "LyXRC.h"
53 #include "LyXVC.h"
54 #include "Paragraph.h"
55 #include "ParagraphParameters.h"
56 #include "ParIterator.h"
57 #include "Row.h"
58 #include "Server.h"
59 #include "Session.h"
60 #include "TextClassList.h"
61 #include "ToolbarBackend.h"
62 #include "Undo.h"
63
64 #include "insets/InsetBox.h"
65 #include "insets/InsetBranch.h"
66 #include "insets/InsetCommand.h"
67 #include "insets/InsetERT.h"
68 #include "insets/InsetExternal.h"
69 #include "insets/InsetFloat.h"
70 #include "insets/InsetListings.h"
71 #include "insets/InsetGraphics.h"
72 #include "insets/InsetInclude.h"
73 #include "insets/InsetNote.h"
74 #include "insets/InsetTabular.h"
75 #include "insets/InsetVSpace.h"
76 #include "insets/InsetWrap.h"
77
78 #include "frontends/Application.h"
79 #include "frontends/alert.h"
80 #include "frontends/Dialogs.h"
81 #include "frontends/FileDialog.h"
82 #include "frontends/FontLoader.h"
83 #include "frontends/Gui.h"
84 #include "frontends/KeySymbol.h"
85 #include "frontends/LyXView.h"
86 #include "frontends/Selection.h"
87 #include "frontends/WorkArea.h"
88
89 #include "support/environment.h"
90 #include "support/FileFilterList.h"
91 #include "support/filetools.h"
92 #include "support/ForkedcallsController.h"
93 #include "support/fs_extras.h"
94 #include "support/lstrings.h"
95 #include "support/Path.h"
96 #include "support/Package.h"
97 #include "support/Systemcall.h"
98 #include "support/convert.h"
99 #include "support/os.h"
100
101 #include <boost/current_function.hpp>
102 #include <boost/filesystem/operations.hpp>
103
104 #include <sstream>
105
106 using std::endl;
107 using std::make_pair;
108 using std::pair;
109 using std::string;
110 using std::istringstream;
111 using std::ostringstream;
112
113 namespace fs = boost::filesystem;
114
115 namespace lyx {
116
117 using frontend::LyXView;
118
119 using support::absolutePath;
120 using support::addName;
121 using support::addPath;
122 using support::bformat;
123 using support::changeExtension;
124 using support::contains;
125 using support::FileFilterList;
126 using support::FileName;
127 using support::fileSearch;
128 using support::ForkedcallsController;
129 using support::i18nLibFileSearch;
130 using support::isDirWriteable;
131 using support::isFileReadable;
132 using support::isStrInt;
133 using support::makeAbsPath;
134 using support::makeDisplayPath;
135 using support::package;
136 using support::quoteName;
137 using support::rtrim;
138 using support::split;
139 using support::subst;
140 using support::Systemcall;
141 using support::token;
142 using support::trim;
143 using support::prefixIs;
144
145 namespace Alert = frontend::Alert;
146
147 extern bool quitting;
148
149 namespace {
150
151 // This function runs "configure" and then rereads lyx.defaults to
152 // reconfigure the automatic settings.
153 void reconfigure(LyXView & lv, string const & option)
154 {
155         // emit message signal.
156         lv.message(_("Running configure..."));
157
158         // Run configure in user lyx directory
159         support::Path p(package().user_support());
160         string configure_command = package().configure_command();
161         configure_command += option;
162         Systemcall one;
163         one.startscript(Systemcall::Wait, configure_command);
164         p.pop();
165         // emit message signal.
166         lv.message(_("Reloading configuration..."));
167         lyxrc.read(support::libFileSearch(string(), "lyxrc.defaults"));
168         // Re-read packages.lst
169         LaTeXFeatures::getAvailable();
170
171         Alert::information(_("System reconfigured"),
172                            _("The system has been reconfigured.\n"
173                              "You need to restart LyX to make use of any\n"
174                              "updated document class specifications."));
175 }
176
177
178 bool getLocalStatus(Cursor cursor, FuncRequest const & cmd, FuncStatus & status)
179 {
180         // Try to fix cursor in case it is broken.
181         cursor.fixIfBroken();
182
183         // This is, of course, a mess. Better create a new doc iterator and use
184         // this in Inset::getStatus. This might require an additional
185         // BufferView * arg, though (which should be avoided)
186         //Cursor safe = *this;
187         bool res = false;
188         for ( ; cursor.depth(); cursor.pop()) {
189                 //lyxerr << "\nCursor::getStatus: cmd: " << cmd << endl << *this << endl;
190                 BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
191                 BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
192                 BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
193
194                 // The inset's getStatus() will return 'true' if it made
195                 // a definitive decision on whether it want to handle the
196                 // request or not. The result of this decision is put into
197                 // the 'status' parameter.
198                 if (cursor.inset().getStatus(cursor, cmd, status)) {
199                         res = true;
200                         break;
201                 }
202         }
203         return res;
204 }
205
206
207 /** Return the change status at cursor position, taking in account the
208  * status at each level of the document iterator (a table in a deleted
209  * footnote is deleted).
210  * When \param outer is true, the top slice is not looked at.
211  */
212 Change::Type lookupChangeType(DocIterator const & dit, bool outer = false)
213 {
214         size_t const depth = dit.depth() - (outer ? 1 : 0);
215
216         for (size_t i = 0 ; i < depth ; ++i) {
217                 CursorSlice const & slice = dit[i];
218                 if (!slice.inset().inMathed()
219                     && slice.pos() < slice.paragraph().size()) {
220                         Change::Type const ch = slice.paragraph().lookupChange(slice.pos()).type;
221                         if (ch != Change::UNCHANGED)
222                                 return ch;
223                 }
224         }
225         return Change::UNCHANGED;
226 }
227
228 }
229
230
231 LyXFunc::LyXFunc()
232         : lyx_view_(0), encoded_last_key(0), meta_fake_bit(NoModifier)
233 {
234 }
235
236
237 void LyXFunc::initKeySequences(KeyMap * kb)
238 {
239         keyseq = KeySequence(kb, kb);
240         cancel_meta_seq = KeySequence(kb, kb);
241 }
242
243
244 void LyXFunc::setLyXView(LyXView * lv)
245 {
246         if (!quitting && lyx_view_ && lyx_view_->view() && lyx_view_ != lv)
247                 // save current selection to the selection buffer to allow
248                 // middle-button paste in another window
249                 cap::saveSelection(lyx_view_->view()->cursor());
250         lyx_view_ = lv;
251 }
252
253
254 void LyXFunc::handleKeyFunc(kb_action action)
255 {
256         char_type c = encoded_last_key;
257
258         if (keyseq.length())
259                 c = 0;
260
261         BOOST_ASSERT(lyx_view_ && lyx_view_->view());
262         lyx_view_->view()->getIntl().getTransManager().deadkey(
263                 c, get_accent(action).accent, view()->cursor().innerText(), view()->cursor());
264         // Need to clear, in case the minibuffer calls these
265         // actions
266         keyseq.clear();
267         // copied verbatim from do_accent_char
268         view()->cursor().resetAnchor();
269         view()->update();
270 }
271
272
273 void LyXFunc::gotoBookmark(unsigned int idx, bool openFile, bool switchToBuffer)
274 {
275         BOOST_ASSERT(lyx_view_);
276         if (!LyX::ref().session().bookmarks().isValid(idx))
277                 return;
278         BookmarksSection::Bookmark const & bm = LyX::ref().session().bookmarks().bookmark(idx);
279         BOOST_ASSERT(!bm.filename.empty());
280         string const file = bm.filename.absFilename();
281         // if the file is not opened, open it.
282         if (!theBufferList().exists(file)) {
283                 if (openFile)
284                         dispatch(FuncRequest(LFUN_FILE_OPEN, file));
285                 else
286                         return;
287         }
288         // open may fail, so we need to test it again
289         if (!theBufferList().exists(file))
290                 return;
291
292         // if the current buffer is not that one, switch to it.
293         if (lyx_view_->buffer()->fileName() != file) {
294                 if (!switchToBuffer)
295                         return;
296                 dispatch(FuncRequest(LFUN_BUFFER_SWITCH, file));
297         }
298         // moveToPosition try paragraph id first and then paragraph (pit, pos).
299         if (!view()->moveToPosition(bm.bottom_pit, bm.bottom_pos,
300                 bm.top_id, bm.top_pos))
301                 return;
302
303         // Cursor jump succeeded!
304         Cursor const & cur = view()->cursor();
305         pit_type new_pit = cur.pit();
306         pos_type new_pos = cur.pos();
307         int new_id = cur.paragraph().id();
308
309         // if bottom_pit, bottom_pos or top_id has been changed, update bookmark
310         // see http://bugzilla.lyx.org/show_bug.cgi?id=3092
311         if (bm.bottom_pit != new_pit || bm.bottom_pos != new_pos 
312                 || bm.top_id != new_id) {
313                 const_cast<BookmarksSection::Bookmark &>(bm).updatePos(
314                         new_pit, new_pos, new_id);
315         }
316 }
317
318
319 void LyXFunc::processKeySym(KeySymbol const & keysym, KeyModifier state)
320 {
321         LYXERR(Debug::KEY) << "KeySym is " << keysym.getSymbolName() << endl;
322
323         // Do nothing if we have nothing (JMarc)
324         if (!keysym.isOK()) {
325                 LYXERR(Debug::KEY) << "Empty kbd action (probably composing)"
326                                    << endl;
327                 return;
328         }
329
330         if (keysym.isModifier()) {
331                 LYXERR(Debug::KEY) << "isModifier true" << endl;
332                 return;
333         }
334
335         //Encoding const * encoding = view()->cursor().getEncoding();
336         //encoded_last_key = keysym.getISOEncoded(encoding ? encoding->name() : "");
337         // FIXME: encoded_last_key shadows the member variable of the same
338         // name. Is that intended?
339         char_type encoded_last_key = keysym.getUCSEncoded();
340
341         // Do a one-deep top-level lookup for
342         // cancel and meta-fake keys. RVDK_PATCH_5
343         cancel_meta_seq.reset();
344
345         FuncRequest func = cancel_meta_seq.addkey(keysym, state);
346         LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
347                            << " action first set to [" << func.action << ']'
348                            << endl;
349
350         // When not cancel or meta-fake, do the normal lookup.
351         // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
352         // Mostly, meta_fake_bit = NoModifier. RVDK_PATCH_5.
353         if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_PREFIX)) {
354                 // remove Caps Lock and Mod2 as a modifiers
355                 func = keyseq.addkey(keysym, (state | meta_fake_bit));
356                 LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
357                                    << "action now set to ["
358                                    << func.action << ']' << endl;
359         }
360
361         // Dont remove this unless you know what you are doing.
362         meta_fake_bit = NoModifier;
363
364         // Can this happen now ?
365         if (func.action == LFUN_NOACTION)
366                 func = FuncRequest(LFUN_COMMAND_PREFIX);
367
368         LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
369                << " Key [action="
370                << func.action << "]["
371                << to_utf8(keyseq.print(false)) << ']'
372                << endl;
373
374         // already here we know if it any point in going further
375         // why not return already here if action == -1 and
376         // num_bytes == 0? (Lgb)
377
378         if (keyseq.length() > 1)
379                 lyx_view_->message(keyseq.print(true));
380
381
382         // Maybe user can only reach the key via holding down shift.
383         // Let's see. But only if shift is the only modifier
384         if (func.action == LFUN_UNKNOWN_ACTION && state == ShiftModifier) {
385                 LYXERR(Debug::KEY) << "Trying without shift" << endl;
386                 func = keyseq.addkey(keysym, NoModifier);
387                 LYXERR(Debug::KEY) << "Action now " << func.action << endl;
388         }
389
390         if (func.action == LFUN_UNKNOWN_ACTION) {
391                 // Hmm, we didn't match any of the keysequences. See
392                 // if it's normal insertable text not already covered
393                 // by a binding
394                 if (keysym.isText() && keyseq.length() == 1) {
395                         LYXERR(Debug::KEY) << "isText() is true, inserting." << endl;
396                         func = FuncRequest(LFUN_SELF_INSERT,
397                                            FuncRequest::KEYBOARD);
398                 } else {
399                         LYXERR(Debug::KEY) << "Unknown, !isText() - giving up" << endl;
400                         lyx_view_->message(_("Unknown function."));
401                         return;
402                 }
403         }
404
405         if (func.action == LFUN_SELF_INSERT) {
406                 if (encoded_last_key != 0) {
407                         docstring const arg(1, encoded_last_key);
408                         dispatch(FuncRequest(LFUN_SELF_INSERT, arg,
409                                              FuncRequest::KEYBOARD));
410                         LYXERR(Debug::KEY)
411                                 << "SelfInsert arg[`" << to_utf8(arg) << "']" << endl;
412                 }
413         } else {
414                 dispatch(func);
415         }
416
417         /* When we move around, or type, it's nice to be able to see
418          * the cursor immediately after the keypress.
419          */
420         if (lyx_view_ && lyx_view_->currentWorkArea())
421                 lyx_view_->currentWorkArea()->startBlinkingCursor();
422 }
423
424
425 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
426 {
427         //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
428         FuncStatus flag;
429
430         Cursor & cur = view()->cursor();
431
432         /* In LyX/Mac, when a dialog is open, the menus of the
433            application can still be accessed without giving focus to
434            the main window. In this case, we want to disable the menu
435            entries that are buffer-related.
436
437            Note that this code is not perfect, as bug 1941 attests:
438            http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
439         */
440         Buffer * buf = lyx_view_? lyx_view_->buffer() : 0;
441         if (lyx_view_ && cmd.origin == FuncRequest::MENU && !lyx_view_->hasFocus())
442                 buf = 0;
443
444         if (cmd.action == LFUN_NOACTION) {
445                 flag.message(from_utf8(N_("Nothing to do")));
446                 flag.enabled(false);
447                 return flag;
448         }
449
450         switch (cmd.action) {
451         case LFUN_UNKNOWN_ACTION:
452 #ifndef HAVE_LIBAIKSAURUS
453         case LFUN_THESAURUS_ENTRY:
454 #endif
455                 flag.unknown(true);
456                 flag.enabled(false);
457                 break;
458
459         default:
460                 break;
461         }
462
463         if (flag.unknown()) {
464                 flag.message(from_utf8(N_("Unknown action")));
465                 return flag;
466         }
467
468         if (!flag.enabled()) {
469                 if (flag.message().empty())
470                         flag.message(from_utf8(N_("Command disabled")));
471                 return flag;
472         }
473
474         // Check whether we need a buffer
475         if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
476                 // no, exit directly
477                 flag.message(from_utf8(N_("Command not allowed with"
478                                     "out any document open")));
479                 flag.enabled(false);
480                 return flag;
481         }
482
483         // I would really like to avoid having this switch and rather try to
484         // encode this in the function itself.
485         // -- And I'd rather let an inset decide which LFUNs it is willing
486         // to handle (Andre')
487         bool enable = true;
488         switch (cmd.action) {
489         case LFUN_BUFFER_TOGGLE_READ_ONLY:
490                 flag.setOnOff(buf->isReadonly());
491                 break;
492
493         case LFUN_BUFFER_SWITCH:
494                 // toggle on the current buffer, but do not toggle off
495                 // the other ones (is that a good idea?)
496                 if (buf && to_utf8(cmd.argument()) == buf->fileName())
497                         flag.setOnOff(true);
498                 break;
499
500         case LFUN_BUFFER_EXPORT:
501                 enable = cmd.argument() == "custom"
502                         || Exporter::isExportable(*buf, to_utf8(cmd.argument()));
503                 break;
504
505         case LFUN_BUFFER_CHKTEX:
506                 enable = buf->isLatex() && !lyxrc.chktex_command.empty();
507                 break;
508
509         case LFUN_BUILD_PROGRAM:
510                 enable = Exporter::isExportable(*buf, "program");
511                 break;
512
513         case LFUN_LAYOUT_TABULAR:
514                 enable = cur.innerInsetOfType(Inset::TABULAR_CODE);
515                 break;
516
517         case LFUN_LAYOUT:
518         case LFUN_LAYOUT_PARAGRAPH:
519                 enable = !cur.inset().forceDefaultParagraphs(cur.idx());
520                 break;
521
522         case LFUN_VC_REGISTER:
523                 enable = !buf->lyxvc().inUse();
524                 break;
525         case LFUN_VC_CHECK_IN:
526                 enable = buf->lyxvc().inUse() && !buf->isReadonly();
527                 break;
528         case LFUN_VC_CHECK_OUT:
529                 enable = buf->lyxvc().inUse() && buf->isReadonly();
530                 break;
531         case LFUN_VC_REVERT:
532         case LFUN_VC_UNDO_LAST:
533                 enable = buf->lyxvc().inUse();
534                 break;
535         case LFUN_BUFFER_RELOAD:
536                 enable = !buf->isUnnamed() && fs::exists(buf->fileName())
537                         && (!buf->isClean() || buf->isExternallyModified(Buffer::timestamp_method));
538                 break;
539
540         case LFUN_INSET_SETTINGS: {
541                 enable = false;
542                 if (!cur)
543                         break;
544                 Inset::Code code = cur.inset().lyxCode();
545                 switch (code) {
546                         case Inset::TABULAR_CODE:
547                                 enable = cmd.argument() == "tabular";
548                                 break;
549                         case Inset::ERT_CODE:
550                                 enable = cmd.argument() == "ert";
551                                 break;
552                         case Inset::FLOAT_CODE:
553                                 enable = cmd.argument() == "float";
554                                 break;
555                         case Inset::WRAP_CODE:
556                                 enable = cmd.argument() == "wrap";
557                                 break;
558                         case Inset::NOTE_CODE:
559                                 enable = cmd.argument() == "note";
560                                 break;
561                         case Inset::BRANCH_CODE:
562                                 enable = cmd.argument() == "branch";
563                                 break;
564                         case Inset::BOX_CODE:
565                                 enable = cmd.argument() == "box";
566                                 break;
567                         case Inset::LISTINGS_CODE:
568                                 enable = cmd.argument() == "listings";
569                                 break;
570                         default:
571                                 break;
572                 }
573                 break;
574         }
575
576         case LFUN_INSET_APPLY: {
577                 string const name = cmd.getArg(0);
578                 Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
579                 if (inset) {
580                         FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
581                         FuncStatus fs;
582                         if (!inset->getStatus(cur, fr, fs)) {
583                                 // Every inset is supposed to handle this
584                                 BOOST_ASSERT(false);
585                         }
586                         flag |= fs;
587                 } else {
588                         FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
589                         flag |= getStatus(fr);
590                 }
591                 enable = flag.enabled();
592                 break;
593         }
594
595         case LFUN_DIALOG_TOGGLE:
596                 flag.setOnOff(lyx_view_->getDialogs().visible(cmd.getArg(0)));
597                 // fall through to set "enable"
598         case LFUN_DIALOG_SHOW: {
599                 string const name = cmd.getArg(0);
600                 if (!buf)
601                         enable = name == "aboutlyx"
602                                 || name == "file" //FIXME: should be removed.
603                                 || name == "prefs"
604                                 || name == "texinfo";
605                 else if (name == "print")
606                         enable = Exporter::isExportable(*buf, "dvi")
607                                 && lyxrc.print_command != "none";
608                 else if (name == "character")
609                         enable = cur.inset().lyxCode() != Inset::ERT_CODE &&
610                                 cur.inset().lyxCode() != Inset::LISTINGS_CODE;
611                 else if (name == "latexlog")
612                         enable = isFileReadable(FileName(buf->getLogName().second));
613                 else if (name == "spellchecker")
614 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
615                         enable = !buf->isReadonly();
616 #else
617                         enable = false;
618 #endif
619                 else if (name == "vclog")
620                         enable = buf->lyxvc().inUse();
621                 break;
622         }
623
624         case LFUN_DIALOG_SHOW_NEW_INSET:
625                 enable = cur.inset().lyxCode() != Inset::ERT_CODE &&
626                         cur.inset().lyxCode() != Inset::LISTINGS_CODE;
627                 if (cur.inset().lyxCode() == Inset::CAPTION_CODE) {
628                         FuncStatus flag;
629                         if (cur.inset().getStatus(cur, cmd, flag))
630                                 return flag;
631                 }
632                 break;
633
634         case LFUN_DIALOG_UPDATE: {
635                 string const name = cmd.getArg(0);
636                 if (!buf)
637                         enable = name == "prefs";
638                 break;
639         }
640
641         case LFUN_CITATION_INSERT: {
642                 FuncRequest fr(LFUN_INSET_INSERT, "citation");
643                 enable = getStatus(fr).enabled();
644                 break;
645         }
646
647         case LFUN_BUFFER_WRITE: {
648                 enable = lyx_view_->buffer()->isUnnamed()
649                         || !lyx_view_->buffer()->isClean();
650                 break;
651         }
652
653
654         case LFUN_BUFFER_WRITE_ALL: {
655         // We enable the command only if there are some modified buffers
656                 Buffer * first = theBufferList().first();
657                 bool modified = false;
658                 if (first) {
659                         Buffer * b = first;
660                 
661                 // We cannot use a for loop as the buffer list is a cycle.
662                         do {
663                                 if (!b->isClean()) {
664                                         modified = true;
665                                         break;
666                                 }
667                                 b = theBufferList().next(b);
668                         } while (b != first); 
669                 }
670         
671                 enable = modified;
672
673                 break;
674         }
675
676         case LFUN_BOOKMARK_GOTO: {
677                 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
678                 enable = LyX::ref().session().bookmarks().isValid(num);
679                 break;
680         }
681
682         case LFUN_BOOKMARK_CLEAR:
683                 enable = LyX::ref().session().bookmarks().size() > 0;
684                 break;
685
686         case LFUN_TOOLBAR_TOGGLE: {
687                 bool const current = lyx_view_->isToolbarVisible(cmd.getArg(0));
688                 flag.setOnOff(current);
689                 break;
690         }
691         case LFUN_WINDOW_CLOSE: {
692                 enable = (theApp()->gui().viewIds().size() > 1);
693                 break;
694         }
695
696         // this one is difficult to get right. As a half-baked
697         // solution, we consider only the first action of the sequence
698         case LFUN_COMMAND_SEQUENCE: {
699                 // argument contains ';'-terminated commands
700                 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
701                 FuncRequest func(lyxaction.lookupFunc(firstcmd));
702                 func.origin = cmd.origin;
703                 flag = getStatus(func);
704         }
705
706         case LFUN_BUFFER_NEW:
707         case LFUN_BUFFER_NEW_TEMPLATE:
708         case LFUN_WORD_FIND_FORWARD:
709         case LFUN_WORD_FIND_BACKWARD:
710         case LFUN_COMMAND_PREFIX:
711         case LFUN_COMMAND_EXECUTE:
712         case LFUN_CANCEL:
713         case LFUN_META_PREFIX:
714         case LFUN_BUFFER_CLOSE:
715         case LFUN_BUFFER_WRITE_AS:
716         case LFUN_BUFFER_UPDATE:
717         case LFUN_BUFFER_VIEW:
718         case LFUN_MASTER_BUFFER_UPDATE:
719         case LFUN_MASTER_BUFFER_VIEW:
720         case LFUN_BUFFER_IMPORT:
721         case LFUN_BUFFER_AUTO_SAVE:
722         case LFUN_RECONFIGURE:
723         case LFUN_HELP_OPEN:
724         case LFUN_FILE_NEW:
725         case LFUN_FILE_OPEN:
726         case LFUN_DROP_LAYOUTS_CHOICE:
727         case LFUN_MENU_OPEN:
728         case LFUN_SERVER_GET_NAME:
729         case LFUN_SERVER_NOTIFY:
730         case LFUN_SERVER_GOTO_FILE_ROW:
731         case LFUN_DIALOG_HIDE:
732         case LFUN_DIALOG_DISCONNECT_INSET:
733         case LFUN_BUFFER_CHILD_OPEN:
734         case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
735         case LFUN_KEYMAP_OFF:
736         case LFUN_KEYMAP_PRIMARY:
737         case LFUN_KEYMAP_SECONDARY:
738         case LFUN_KEYMAP_TOGGLE:
739         case LFUN_REPEAT:
740         case LFUN_BUFFER_EXPORT_CUSTOM:
741         case LFUN_BUFFER_PRINT:
742         case LFUN_PREFERENCES_SAVE:
743         case LFUN_SCREEN_FONT_UPDATE:
744         case LFUN_SET_COLOR:
745         case LFUN_MESSAGE:
746         case LFUN_EXTERNAL_EDIT:
747         case LFUN_GRAPHICS_EDIT:
748         case LFUN_ALL_INSETS_TOGGLE:
749         case LFUN_BUFFER_LANGUAGE:
750         case LFUN_TEXTCLASS_APPLY:
751         case LFUN_TEXTCLASS_LOAD:
752         case LFUN_BUFFER_SAVE_AS_DEFAULT:
753         case LFUN_BUFFER_PARAMS_APPLY:
754         case LFUN_LAYOUT_MODULES_CLEAR:
755         case LFUN_LAYOUT_MODULE_ADD:
756         case LFUN_LAYOUT_RELOAD:
757         case LFUN_LYXRC_APPLY:
758         case LFUN_BUFFER_NEXT:
759         case LFUN_BUFFER_PREVIOUS:
760         case LFUN_WINDOW_NEW:
761         case LFUN_LYX_QUIT:
762                 // these are handled in our dispatch()
763                 break;
764
765         default:
766                 if (!getLocalStatus(cur, cmd, flag))
767                         flag = view()->getStatus(cmd);
768         }
769
770         if (!enable)
771                 flag.enabled(false);
772
773         // Can we use a readonly buffer?
774         if (buf && buf->isReadonly()
775             && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
776             && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
777                 flag.message(from_utf8(N_("Document is read-only")));
778                 flag.enabled(false);
779         }
780
781         // Are we in a DELETED change-tracking region?
782         if (buf && lookupChangeType(cur, true) == Change::DELETED
783             && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
784             && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
785                 flag.message(from_utf8(N_("This portion of the document is deleted.")));
786                 flag.enabled(false);
787         }
788
789         // the default error message if we disable the command
790         if (!flag.enabled() && flag.message().empty())
791                 flag.message(from_utf8(N_("Command disabled")));
792
793         return flag;
794 }
795
796
797 bool LyXFunc::ensureBufferClean(BufferView * bv)
798 {
799         Buffer & buf = bv->buffer();
800         if (buf.isClean())
801                 return true;
802
803         docstring const file = makeDisplayPath(buf.fileName(), 30);
804         docstring text = bformat(_("The document %1$s has unsaved "
805                                              "changes.\n\nDo you want to save "
806                                              "the document?"), file);
807         int const ret = Alert::prompt(_("Save changed document?"),
808                                       text, 0, 1, _("&Save"),
809                                       _("&Cancel"));
810
811         if (ret == 0)
812                 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
813
814         return buf.isClean();
815 }
816
817
818 namespace {
819
820 void showPrintError(string const & name)
821 {
822         docstring str = bformat(_("Could not print the document %1$s.\n"
823                                             "Check that your printer is set up correctly."),
824                              makeDisplayPath(name, 50));
825         Alert::error(_("Print document failed"), str);
826 }
827
828
829 void loadTextClass(string const & name)
830 {
831         std::pair<bool, textclass_type> const tc_pair =
832                 textclasslist.numberOfClass(name);
833
834         if (!tc_pair.first) {
835                 lyxerr << "Document class \"" << name
836                        << "\" does not exist."
837                        << std::endl;
838                 return;
839         }
840
841         textclass_type const tc = tc_pair.second;
842
843         if (!textclasslist[tc].load()) {
844                 docstring s = bformat(_("The document class %1$s."
845                                    "could not be loaded."),
846                                    from_utf8(textclasslist[tc].name()));
847                 Alert::error(_("Could not load class"), s);
848         }
849 }
850
851
852 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
853
854 } //namespace anon
855
856
857 void LyXFunc::dispatch(FuncRequest const & cmd)
858 {
859         string const argument = to_utf8(cmd.argument());
860         kb_action const action = cmd.action;
861
862         LYXERR(Debug::ACTION) << endl << "LyXFunc::dispatch: cmd: " << cmd << endl;
863         //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
864
865         // we have not done anything wrong yet.
866         errorstat = false;
867         dispatch_buffer.erase();
868
869         // redraw the screen at the end (first of the two drawing steps).
870         //This is done unless explicitely requested otherwise
871         Update::flags updateFlags = Update::FitCursor;
872
873         FuncStatus const flag = getStatus(cmd);
874         if (!flag.enabled()) {
875                 // We cannot use this function here
876                 LYXERR(Debug::ACTION) << "LyXFunc::dispatch: "
877                        << lyxaction.getActionName(action)
878                        << " [" << action << "] is disabled at this location"
879                        << endl;
880                 setErrorMessage(flag.message());
881         } else {
882                 switch (action) {
883
884                 case LFUN_WORD_FIND_FORWARD:
885                 case LFUN_WORD_FIND_BACKWARD: {
886                         BOOST_ASSERT(lyx_view_ && lyx_view_->view());
887                         static docstring last_search;
888                         docstring searched_string;
889
890                         if (!cmd.argument().empty()) {
891                                 last_search = cmd.argument();
892                                 searched_string = cmd.argument();
893                         } else {
894                                 searched_string = last_search;
895                         }
896
897                         if (searched_string.empty())
898                                 break;
899
900                         bool const fw = action == LFUN_WORD_FIND_FORWARD;
901                         docstring const data =
902                                 find2string(searched_string, true, false, fw);
903                         find(view(), FuncRequest(LFUN_WORD_FIND, data));
904                         break;
905                 }
906
907                 case LFUN_COMMAND_PREFIX:
908                         BOOST_ASSERT(lyx_view_);
909                         lyx_view_->message(keyseq.printOptions(true));
910                         break;
911
912                 case LFUN_COMMAND_EXECUTE:
913                         BOOST_ASSERT(lyx_view_);
914                         lyx_view_->showMiniBuffer(true);
915                         break;
916
917                 case LFUN_CANCEL:
918                         BOOST_ASSERT(lyx_view_ && lyx_view_->view());
919                         keyseq.reset();
920                         meta_fake_bit = NoModifier;
921                         if (lyx_view_->buffer())
922                                 // cancel any selection
923                                 dispatch(FuncRequest(LFUN_MARK_OFF));
924                         setMessage(from_ascii(N_("Cancel")));
925                         break;
926
927                 case LFUN_META_PREFIX:
928                         meta_fake_bit = AltModifier;
929                         setMessage(keyseq.print(true));
930                         break;
931
932                 case LFUN_BUFFER_TOGGLE_READ_ONLY: {
933                         BOOST_ASSERT(lyx_view_ && lyx_view_->view() && lyx_view_->buffer());
934                         Buffer * buf = lyx_view_->buffer();
935                         if (buf->lyxvc().inUse())
936                                 buf->lyxvc().toggleReadOnly();
937                         else
938                                 buf->setReadonly(!lyx_view_->buffer()->isReadonly());
939                         break;
940                 }
941
942                 // --- Menus -----------------------------------------------
943                 case LFUN_BUFFER_NEW:
944                         menuNew(argument, false);
945                         updateFlags = Update::None;
946                         break;
947
948                 case LFUN_BUFFER_NEW_TEMPLATE:
949                         menuNew(argument, true);
950                         updateFlags = Update::None;
951                         break;
952
953                 case LFUN_BUFFER_CLOSE:
954                         closeBuffer();
955                         updateFlags = Update::None;
956                         break;
957
958                 case LFUN_BUFFER_WRITE:
959                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
960                         if (!lyx_view_->buffer()->isUnnamed()) {
961                                 docstring const str = bformat(_("Saving document %1$s..."),
962                                          makeDisplayPath(lyx_view_->buffer()->fileName()));
963                                 lyx_view_->message(str);
964                                 lyx_view_->buffer()->menuWrite();
965                                 lyx_view_->message(str + _(" done."));
966                         } else {
967                                 lyx_view_->buffer()->writeAs();
968                         }
969                         updateFlags = Update::None;
970                         break;
971
972                 case LFUN_BUFFER_WRITE_AS:
973                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
974                         lyx_view_->buffer()->writeAs(argument);
975                         updateFlags = Update::None;
976                         break;
977
978                 case LFUN_BUFFER_WRITE_ALL: {
979                         Buffer * first = theBufferList().first();
980                         if (first) {
981                                 Buffer * b = first;
982                                 lyx_view_->message(_("Saving all documents..."));
983                 
984                                 // We cannot use a for loop as the buffer list cycles.
985                                 do {
986                                         if (!b->isClean()) {
987                                                 if (!b->isUnnamed()) {
988                                                         b->menuWrite();
989                                                         lyxerr[Debug::ACTION] << "Saved " << b->fileName() << endl;
990                                                 } else
991                                                         b->writeAs();
992                                         }
993                                         b = theBufferList().next(b);
994                                 } while (b != first); 
995                                 lyx_view_->message(_("All documents saved."));
996                         } 
997         
998                         updateFlags = Update::None;
999                         break;
1000                 }
1001
1002                 case LFUN_BUFFER_RELOAD: {
1003                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1004                         docstring const file = makeDisplayPath(lyx_view_->buffer()->fileName(), 20);
1005                         docstring text = bformat(_("Any changes will be lost. Are you sure "
1006                                                              "you want to revert to the saved version of the document %1$s?"), file);
1007                         int const ret = Alert::prompt(_("Revert to saved document?"),
1008                                 text, 1, 1, _("&Revert"), _("&Cancel"));
1009
1010                         if (ret == 0)
1011                                 reloadBuffer();
1012                         break;
1013                 }
1014
1015                 case LFUN_BUFFER_UPDATE:
1016                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1017                         Exporter::Export(lyx_view_->buffer(), argument, true);
1018                         break;
1019
1020                 case LFUN_BUFFER_VIEW:
1021                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1022                         Exporter::preview(lyx_view_->buffer(), argument);
1023                         break;
1024
1025                 case LFUN_MASTER_BUFFER_UPDATE:
1026                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->getMasterBuffer());
1027                         Exporter::Export(lyx_view_->buffer()->getMasterBuffer(), argument, true);
1028                         break;
1029
1030                 case LFUN_MASTER_BUFFER_VIEW:
1031                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->getMasterBuffer());
1032                         Exporter::preview(lyx_view_->buffer()->getMasterBuffer(), argument);
1033                         break;
1034
1035                 case LFUN_BUILD_PROGRAM:
1036                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1037                         Exporter::Export(lyx_view_->buffer(), "program", true);
1038                         break;
1039
1040                 case LFUN_BUFFER_CHKTEX:
1041                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1042                         lyx_view_->buffer()->runChktex();
1043                         break;
1044
1045                 case LFUN_BUFFER_EXPORT:
1046                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1047                         if (argument == "custom")
1048                                 lyx_view_->getDialogs().show("sendto");
1049                         else {
1050                                 Exporter::Export(lyx_view_->buffer(), argument, false);
1051                         }
1052                         break;
1053
1054                 case LFUN_BUFFER_EXPORT_CUSTOM: {
1055                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1056                         string format_name;
1057                         string command = split(argument, format_name, ' ');
1058                         Format const * format = formats.getFormat(format_name);
1059                         if (!format) {
1060                                 lyxerr << "Format \"" << format_name
1061                                        << "\" not recognized!"
1062                                        << std::endl;
1063                                 break;
1064                         }
1065
1066                         Buffer * buffer = lyx_view_->buffer();
1067
1068                         // The name of the file created by the conversion process
1069                         string filename;
1070
1071                         // Output to filename
1072                         if (format->name() == "lyx") {
1073                                 string const latexname =
1074                                         buffer->getLatexName(false);
1075                                 filename = changeExtension(latexname,
1076                                                            format->extension());
1077                                 filename = addName(buffer->temppath(), filename);
1078
1079                                 if (!buffer->writeFile(FileName(filename)))
1080                                         break;
1081
1082                         } else {
1083                                 Exporter::Export(buffer, format_name, true, filename);
1084                         }
1085
1086                         // Substitute $$FName for filename
1087                         if (!contains(command, "$$FName"))
1088                                 command = "( " + command + " ) < $$FName";
1089                         command = subst(command, "$$FName", filename);
1090
1091                         // Execute the command in the background
1092                         Systemcall call;
1093                         call.startscript(Systemcall::DontWait, command);
1094                         break;
1095                 }
1096
1097                 case LFUN_BUFFER_PRINT: {
1098                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1099                         // FIXME: cmd.getArg() might fail if one of the arguments
1100                         // contains double quotes
1101                         string target = cmd.getArg(0);
1102                         string target_name = cmd.getArg(1);
1103                         string command = cmd.getArg(2);
1104
1105                         if (target.empty()
1106                             || target_name.empty()
1107                             || command.empty()) {
1108                                 lyxerr << "Unable to parse \""
1109                                        << argument << '"' << endl;
1110                                 break;
1111                         }
1112                         if (target != "printer" && target != "file") {
1113                                 lyxerr << "Unrecognized target \""
1114                                        << target << '"' << endl;
1115                                 break;
1116                         }
1117
1118                         Buffer * buffer = lyx_view_->buffer();
1119
1120                         if (!Exporter::Export(buffer, "dvi", true)) {
1121                                 showPrintError(buffer->fileName());
1122                                 break;
1123                         }
1124
1125                         // Push directory path.
1126                         string const path = buffer->temppath();
1127                         // Prevent the compiler from optimizing away p
1128                         FileName pp(path);
1129                         support::Path p(pp);
1130
1131                         // there are three cases here:
1132                         // 1. we print to a file
1133                         // 2. we print directly to a printer
1134                         // 3. we print using a spool command (print to file first)
1135                         Systemcall one;
1136                         int res = 0;
1137                         string const dviname =
1138                                 changeExtension(buffer->getLatexName(true),
1139                                                 "dvi");
1140
1141                         if (target == "printer") {
1142                                 if (!lyxrc.print_spool_command.empty()) {
1143                                         // case 3: print using a spool
1144                                         string const psname =
1145                                                 changeExtension(dviname,".ps");
1146                                         command += ' ' + lyxrc.print_to_file
1147                                                 + quoteName(psname)
1148                                                 + ' '
1149                                                 + quoteName(dviname);
1150
1151                                         string command2 =
1152                                                 lyxrc.print_spool_command + ' ';
1153                                         if (target_name != "default") {
1154                                                 command2 += lyxrc.print_spool_printerprefix
1155                                                         + target_name
1156                                                         + ' ';
1157                                         }
1158                                         command2 += quoteName(psname);
1159                                         // First run dvips.
1160                                         // If successful, then spool command
1161                                         res = one.startscript(
1162                                                 Systemcall::Wait,
1163                                                 command);
1164
1165                                         if (res == 0)
1166                                                 res = one.startscript(
1167                                                         Systemcall::DontWait,
1168                                                         command2);
1169                                 } else {
1170                                         // case 2: print directly to a printer
1171                                         if (target_name != "default")
1172                                                 command += ' ' + lyxrc.print_to_printer + target_name + ' ';
1173                                         res = one.startscript(
1174                                                 Systemcall::DontWait,
1175                                                 command + quoteName(dviname));
1176                                 }
1177
1178                         } else {
1179                                 // case 1: print to a file
1180                                 FileName const filename(makeAbsPath(target_name,
1181                                                         lyx_view_->buffer()->filePath()));
1182                                 FileName const dvifile(makeAbsPath(dviname, path));
1183                                 if (fs::exists(filename.toFilesystemEncoding())) {
1184                                         docstring text = bformat(
1185                                                 _("The file %1$s already exists.\n\n"
1186                                                   "Do you want to overwrite that file?"),
1187                                                 makeDisplayPath(filename.absFilename()));
1188                                         if (Alert::prompt(_("Overwrite file?"),
1189                                             text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
1190                                                 break;
1191                                 }
1192                                 command += ' ' + lyxrc.print_to_file
1193                                         + quoteName(filename.toFilesystemEncoding())
1194                                         + ' '
1195                                         + quoteName(dvifile.toFilesystemEncoding());
1196                                 res = one.startscript(Systemcall::DontWait,
1197                                                       command);
1198                         }
1199
1200                         if (res != 0)
1201                                 showPrintError(buffer->fileName());
1202                         break;
1203                 }
1204
1205                 case LFUN_BUFFER_IMPORT:
1206                         doImport(argument);
1207                         break;
1208
1209                 case LFUN_LYX_QUIT:
1210                         // quitting is triggered by the gui code
1211                         // (leaving the event loop).
1212                         lyx_view_->message(from_utf8(N_("Exiting.")));
1213                         if (theBufferList().quitWriteAll())
1214                                 theApp()->gui().closeAllViews();
1215                         break;
1216
1217                 case LFUN_BUFFER_AUTO_SAVE:
1218                         lyx_view_->buffer()->autoSave();
1219                         break;
1220
1221                 case LFUN_RECONFIGURE:
1222                         BOOST_ASSERT(lyx_view_);
1223                         // argument is any additional parameter to the configure.py command
1224                         reconfigure(*lyx_view_, argument);
1225                         break;
1226
1227                 case LFUN_HELP_OPEN: {
1228                         BOOST_ASSERT(lyx_view_);
1229                         string const arg = argument;
1230                         if (arg.empty()) {
1231                                 setErrorMessage(from_ascii(N_("Missing argument")));
1232                                 break;
1233                         }
1234                         FileName const fname = i18nLibFileSearch("doc", arg, "lyx");
1235                         if (fname.empty()) {
1236                                 lyxerr << "LyX: unable to find documentation file `"
1237                                                          << arg << "'. Bad installation?" << endl;
1238                                 break;
1239                         }
1240                         lyx_view_->message(bformat(_("Opening help file %1$s..."),
1241                                 makeDisplayPath(fname.absFilename())));
1242                         Buffer * buf = lyx_view_->loadLyXFile(fname, false);
1243                         if (buf) {
1244                                 updateLabels(*buf);
1245                                 lyx_view_->setBuffer(buf);
1246                                 lyx_view_->showErrorList("Parse");
1247                         }
1248                         updateFlags = Update::None;
1249                         break;
1250                 }
1251
1252                 // --- version control -------------------------------
1253                 case LFUN_VC_REGISTER:
1254                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1255                         if (!ensureBufferClean(view()))
1256                                 break;
1257                         if (!lyx_view_->buffer()->lyxvc().inUse()) {
1258                                 lyx_view_->buffer()->lyxvc().registrer();
1259                                 reloadBuffer();
1260                         }
1261                         updateFlags = Update::Force;
1262                         break;
1263
1264                 case LFUN_VC_CHECK_IN:
1265                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1266                         if (!ensureBufferClean(view()))
1267                                 break;
1268                         if (lyx_view_->buffer()->lyxvc().inUse()
1269                                         && !lyx_view_->buffer()->isReadonly()) {
1270                                 lyx_view_->buffer()->lyxvc().checkIn();
1271                                 reloadBuffer();
1272                         }
1273                         break;
1274
1275                 case LFUN_VC_CHECK_OUT:
1276                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1277                         if (!ensureBufferClean(view()))
1278                                 break;
1279                         if (lyx_view_->buffer()->lyxvc().inUse()
1280                                         && lyx_view_->buffer()->isReadonly()) {
1281                                 lyx_view_->buffer()->lyxvc().checkOut();
1282                                 reloadBuffer();
1283                         }
1284                         break;
1285
1286                 case LFUN_VC_REVERT:
1287                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1288                         lyx_view_->buffer()->lyxvc().revert();
1289                         reloadBuffer();
1290                         break;
1291
1292                 case LFUN_VC_UNDO_LAST:
1293                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1294                         lyx_view_->buffer()->lyxvc().undoLast();
1295                         reloadBuffer();
1296                         break;
1297
1298                 // --- buffers ----------------------------------------
1299                 case LFUN_BUFFER_SWITCH:
1300                         BOOST_ASSERT(lyx_view_);
1301                         lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1302                         updateFlags = Update::None;
1303                         break;
1304
1305                 case LFUN_BUFFER_NEXT:
1306                         BOOST_ASSERT(lyx_view_);
1307                         lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer()));
1308                         updateFlags = Update::None;
1309                         break;
1310
1311                 case LFUN_BUFFER_PREVIOUS:
1312                         BOOST_ASSERT(lyx_view_);
1313                         lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer()));
1314                         updateFlags = Update::None;
1315                         break;
1316
1317                 case LFUN_FILE_NEW: {
1318                         BOOST_ASSERT(lyx_view_);
1319                         string name;
1320                         string tmpname = split(argument, name, ':'); // Split filename
1321                         Buffer * const b = newFile(name, tmpname);
1322                         if (b)
1323                                 lyx_view_->setBuffer(b);
1324                         updateFlags = Update::None;
1325                         break;
1326                 }
1327
1328                 case LFUN_FILE_OPEN:
1329                         BOOST_ASSERT(lyx_view_);
1330                         open(argument);
1331                         updateFlags = Update::None;
1332                         break;
1333
1334                 case LFUN_DROP_LAYOUTS_CHOICE:
1335                         BOOST_ASSERT(lyx_view_);
1336                         lyx_view_->openLayoutList();
1337                         break;
1338
1339                 case LFUN_MENU_OPEN:
1340                         BOOST_ASSERT(lyx_view_);
1341                         lyx_view_->openMenu(from_utf8(argument));
1342                         break;
1343
1344                 // --- lyxserver commands ----------------------------
1345                 case LFUN_SERVER_GET_NAME:
1346                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1347                         setMessage(from_utf8(lyx_view_->buffer()->fileName()));
1348                         LYXERR(Debug::INFO) << "FNAME["
1349                                                          << lyx_view_->buffer()->fileName()
1350                                                          << "] " << endl;
1351                         break;
1352
1353                 case LFUN_SERVER_NOTIFY:
1354                         dispatch_buffer = keyseq.print(false);
1355                         theServer().notifyClient(to_utf8(dispatch_buffer));
1356                         break;
1357
1358                 case LFUN_SERVER_GOTO_FILE_ROW: {
1359                         BOOST_ASSERT(lyx_view_);
1360                         string file_name;
1361                         int row;
1362                         istringstream is(argument);
1363                         is >> file_name >> row;
1364                         Buffer * buf = 0;
1365                         bool loaded = false;
1366                         if (prefixIs(file_name, package().temp_dir().absFilename()))
1367                                 // Needed by inverse dvi search. If it is a file
1368                                 // in tmpdir, call the apropriated function
1369                                 buf = theBufferList().getBufferFromTmp(file_name);
1370                         else {
1371                                 // Must replace extension of the file to be .lyx
1372                                 // and get full path
1373                                 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1374                                 // Either change buffer or load the file
1375                                 if (theBufferList().exists(s.absFilename()))
1376                                         buf = theBufferList().getBuffer(s.absFilename());
1377                                 else {
1378                                         buf = lyx_view_->loadLyXFile(s);
1379                                         loaded = true;
1380                                 }
1381                         }
1382
1383                         if (!buf) {
1384                                 updateFlags = Update::None;
1385                                 break;
1386                         }
1387
1388                         updateLabels(*buf);
1389                         lyx_view_->setBuffer(buf);
1390                         view()->setCursorFromRow(row);
1391                         if (loaded)
1392                                 lyx_view_->showErrorList("Parse");
1393                         updateFlags = Update::FitCursor;
1394                         break;
1395                 }
1396
1397                 case LFUN_DIALOG_SHOW: {
1398                         BOOST_ASSERT(lyx_view_);
1399                         string const name = cmd.getArg(0);
1400                         string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1401
1402                         if (name == "character") {
1403                                 data = freefont2string();
1404                                 if (!data.empty())
1405                                         lyx_view_->getDialogs().show("character", data);
1406                         } else if (name == "latexlog") {
1407                                 pair<Buffer::LogType, string> const logfile =
1408                                         lyx_view_->buffer()->getLogName();
1409                                 switch (logfile.first) {
1410                                 case Buffer::latexlog:
1411                                         data = "latex ";
1412                                         break;
1413                                 case Buffer::buildlog:
1414                                         data = "literate ";
1415                                         break;
1416                                 }
1417                                 data += Lexer::quoteString(logfile.second);
1418                                 lyx_view_->getDialogs().show("log", data);
1419                         } else if (name == "vclog") {
1420                                 string const data = "vc " +
1421                                         Lexer::quoteString(lyx_view_->buffer()->lyxvc().getLogFile());
1422                                 lyx_view_->getDialogs().show("log", data);
1423                         } else
1424                                 lyx_view_->getDialogs().show(name, data);
1425                         break;
1426                 }
1427
1428                 case LFUN_DIALOG_SHOW_NEW_INSET: {
1429                         BOOST_ASSERT(lyx_view_);
1430                         string const name = cmd.getArg(0);
1431                         string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1432                         if (name == "bibitem" ||
1433                             name == "bibtex" ||
1434                             name == "index" ||
1435                             name == "label" ||
1436                             name == "nomenclature" ||
1437                             name == "ref" ||
1438                             name == "toc" ||
1439                             name == "url") {
1440                                 InsetCommandParams p(name);
1441                                 data = InsetCommandMailer::params2string(name, p);
1442                         } else if (name == "include") {
1443                                 // data is the include type: one of "include",
1444                                 // "input", "verbatiminput" or "verbatiminput*"
1445                                 if (data.empty())
1446                                         // default type is requested
1447                                         data = "include";
1448                                 InsetCommandParams p(data);
1449                                 data = InsetIncludeMailer::params2string(p);
1450                         } else if (name == "box") {
1451                                 // \c data == "Boxed" || "Frameless" etc
1452                                 InsetBoxParams p(data);
1453                                 data = InsetBoxMailer::params2string(p);
1454                         } else if (name == "branch") {
1455                                 InsetBranchParams p;
1456                                 data = InsetBranchMailer::params2string(p);
1457                         } else if (name == "citation") {
1458                                 InsetCommandParams p("citation");
1459                                 data = InsetCommandMailer::params2string(name, p);
1460                         } else if (name == "ert") {
1461                                 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1462                         } else if (name == "external") {
1463                                 InsetExternalParams p;
1464                                 Buffer const & buffer = *lyx_view_->buffer();
1465                                 data = InsetExternalMailer::params2string(p, buffer);
1466                         } else if (name == "float") {
1467                                 InsetFloatParams p;
1468                                 data = InsetFloatMailer::params2string(p);
1469                         } else if (name == "listings") {
1470                                 InsetListingsParams p;
1471                                 data = InsetListingsMailer::params2string(p);
1472                         } else if (name == "graphics") {
1473                                 InsetGraphicsParams p;
1474                                 Buffer const & buffer = *lyx_view_->buffer();
1475                                 data = InsetGraphicsMailer::params2string(p, buffer);
1476                         } else if (name == "note") {
1477                                 InsetNoteParams p;
1478                                 data = InsetNoteMailer::params2string(p);
1479                         } else if (name == "vspace") {
1480                                 VSpace space;
1481                                 data = InsetVSpaceMailer::params2string(space);
1482                         } else if (name == "wrap") {
1483                                 InsetWrapParams p;
1484                                 data = InsetWrapMailer::params2string(p);
1485                         }
1486                         lyx_view_->getDialogs().show(name, data, 0);
1487                         break;
1488                 }
1489
1490                 case LFUN_DIALOG_UPDATE: {
1491                         BOOST_ASSERT(lyx_view_);
1492                         string const & name = argument;
1493                         // Can only update a dialog connected to an existing inset
1494                         Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1495                         if (inset) {
1496                                 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1497                                 inset->dispatch(view()->cursor(), fr);
1498                         } else if (name == "paragraph") {
1499                                 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1500                         } else if (name == "prefs") {
1501                                 lyx_view_->getDialogs().update(name, string());
1502                         }
1503                         break;
1504                 }
1505
1506                 case LFUN_DIALOG_HIDE:
1507                         LyX::cref().hideDialogs(argument, 0);
1508                         break;
1509
1510                 case LFUN_DIALOG_TOGGLE: {
1511                         BOOST_ASSERT(lyx_view_);
1512                         if (lyx_view_->getDialogs().visible(cmd.getArg(0)))
1513                                 dispatch(FuncRequest(LFUN_DIALOG_HIDE, argument));
1514                         else
1515                                 dispatch(FuncRequest(LFUN_DIALOG_SHOW, argument));
1516                         break;
1517                 }
1518
1519                 case LFUN_DIALOG_DISCONNECT_INSET:
1520                         BOOST_ASSERT(lyx_view_);
1521                         lyx_view_->getDialogs().disconnect(argument);
1522                         break;
1523
1524
1525                 case LFUN_CITATION_INSERT: {
1526                         BOOST_ASSERT(lyx_view_);
1527                         if (!argument.empty()) {
1528                                 // we can have one optional argument, delimited by '|'
1529                                 // citation-insert <key>|<text_before>
1530                                 // this should be enhanced to also support text_after
1531                                 // and citation style
1532                                 string arg = argument;
1533                                 string opt1;
1534                                 if (contains(argument, "|")) {
1535                                         arg = token(argument, '|', 0);
1536                                         opt1 = token(argument, '|', 1);
1537                                 }
1538                                 InsetCommandParams icp("citation");
1539                                 icp["key"] = from_utf8(arg);
1540                                 if (!opt1.empty())
1541                                         icp["before"] = from_utf8(opt1);
1542                                 string icstr = InsetCommandMailer::params2string("citation", icp);
1543                                 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1544                                 dispatch(fr);
1545                         } else
1546                                 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1547                         break;
1548                 }
1549
1550                 case LFUN_BUFFER_CHILD_OPEN: {
1551                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1552                         Buffer * parent = lyx_view_->buffer();
1553                         FileName filename = makeAbsPath(argument, parent->filePath());
1554                         view()->saveBookmark(false);
1555                         Buffer * child = 0;
1556                         bool parsed = false;
1557                         if (theBufferList().exists(filename.absFilename())) {
1558                                 child = theBufferList().getBuffer(filename.absFilename());
1559                         } else {
1560                                 setMessage(bformat(_("Opening child document %1$s..."),
1561                                         makeDisplayPath(filename.absFilename())));
1562                                 child = lyx_view_->loadLyXFile(filename, true);
1563                                 parsed = true;
1564                         }
1565                         if (child) {
1566                                 // Set the parent name of the child document.
1567                                 // This makes insertion of citations and references in the child work,
1568                                 // when the target is in the parent or another child document.
1569                                 child->setParentName(parent->fileName());
1570                                 updateLabels(*child->getMasterBuffer());
1571                                 lyx_view_->setBuffer(child);
1572                                 if (parsed)
1573                                         lyx_view_->showErrorList("Parse");
1574                         }
1575
1576                         // If a screen update is required (in case where auto_open is false), 
1577                         // setBuffer() would have taken care of it already. Otherwise we shall 
1578                         // reset the update flag because it can cause a circular problem.
1579                         // See bug 3970.
1580                         updateFlags = Update::None;
1581                         break;
1582                 }
1583
1584                 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1585                         BOOST_ASSERT(lyx_view_);
1586                         lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1587                         break;
1588
1589                 case LFUN_KEYMAP_OFF:
1590                         BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1591                         lyx_view_->view()->getIntl().keyMapOn(false);
1592                         break;
1593
1594                 case LFUN_KEYMAP_PRIMARY:
1595                         BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1596                         lyx_view_->view()->getIntl().keyMapPrim();
1597                         break;
1598
1599                 case LFUN_KEYMAP_SECONDARY:
1600                         BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1601                         lyx_view_->view()->getIntl().keyMapSec();
1602                         break;
1603
1604                 case LFUN_KEYMAP_TOGGLE:
1605                         BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1606                         lyx_view_->view()->getIntl().toggleKeyMap();
1607                         break;
1608
1609                 case LFUN_REPEAT: {
1610                         // repeat command
1611                         string countstr;
1612                         string rest = split(argument, countstr, ' ');
1613                         istringstream is(countstr);
1614                         int count = 0;
1615                         is >> count;
1616                         lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1617                         for (int i = 0; i < count; ++i)
1618                                 dispatch(lyxaction.lookupFunc(rest));
1619                         break;
1620                 }
1621
1622                 case LFUN_COMMAND_SEQUENCE: {
1623                         // argument contains ';'-terminated commands
1624                         string arg = argument;
1625                         while (!arg.empty()) {
1626                                 string first;
1627                                 arg = split(arg, first, ';');
1628                                 FuncRequest func(lyxaction.lookupFunc(first));
1629                                 func.origin = cmd.origin;
1630                                 dispatch(func);
1631                         }
1632                         break;
1633                 }
1634
1635                 case LFUN_PREFERENCES_SAVE: {
1636                         lyxrc.write(makeAbsPath("preferences",
1637                                                 package().user_support().absFilename()),
1638                                     false);
1639                         break;
1640                 }
1641
1642                 case LFUN_SCREEN_FONT_UPDATE:
1643                         BOOST_ASSERT(lyx_view_);
1644                         // handle the screen font changes.
1645                         theFontLoader().update();
1646                         /// FIXME: only the current view will be updated. the Gui
1647                         /// class is able to furnish the list of views.
1648                         updateFlags = Update::Force;
1649                         break;
1650
1651                 case LFUN_SET_COLOR: {
1652                         string lyx_name;
1653                         string const x11_name = split(argument, lyx_name, ' ');
1654                         if (lyx_name.empty() || x11_name.empty()) {
1655                                 setErrorMessage(from_ascii(N_(
1656                                                 "Syntax: set-color <lyx_name>"
1657                                                 " <x11_name>")));
1658                                 break;
1659                         }
1660
1661                         bool const graphicsbg_changed =
1662                                 (lyx_name == lcolor.getLyXName(Color::graphicsbg) &&
1663                                  x11_name != lcolor.getX11Name(Color::graphicsbg));
1664
1665                         if (!lcolor.setColor(lyx_name, x11_name)) {
1666                                 setErrorMessage(
1667                                                 bformat(_("Set-color \"%1$s\" failed "
1668                                                                        "- color is undefined or "
1669                                                                        "may not be redefined"),
1670                                                                            from_utf8(lyx_name)));
1671                                 break;
1672                         }
1673
1674                         theApp()->updateColor(lcolor.getFromLyXName(lyx_name));
1675
1676                         if (graphicsbg_changed) {
1677                                 // FIXME: The graphics cache no longer has a changeDisplay method.
1678 #if 0
1679                                 graphics::GCache::get().changeDisplay(true);
1680 #endif
1681                         }
1682                         break;
1683                 }
1684
1685                 case LFUN_MESSAGE:
1686                         BOOST_ASSERT(lyx_view_);
1687                         lyx_view_->message(from_utf8(argument));
1688                         break;
1689
1690                 case LFUN_EXTERNAL_EDIT: {
1691                         BOOST_ASSERT(lyx_view_);
1692                         FuncRequest fr(action, argument);
1693                         InsetExternal().dispatch(view()->cursor(), fr);
1694                         break;
1695                 }
1696
1697                 case LFUN_GRAPHICS_EDIT: {
1698                         FuncRequest fr(action, argument);
1699                         InsetGraphics().dispatch(view()->cursor(), fr);
1700                         break;
1701                 }
1702
1703                 case LFUN_INSET_APPLY: {
1704                         BOOST_ASSERT(lyx_view_);
1705                         string const name = cmd.getArg(0);
1706                         Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1707                         if (inset) {
1708                                 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1709                                 inset->dispatch(view()->cursor(), fr);
1710                         } else {
1711                                 FuncRequest fr(LFUN_INSET_INSERT, argument);
1712                                 dispatch(fr);
1713                         }
1714                         // ideally, the update flag should be set by the insets,
1715                         // but this is not possible currently
1716                         updateFlags = Update::Force | Update::FitCursor;
1717                         break;
1718                 }
1719
1720                 case LFUN_ALL_INSETS_TOGGLE: {
1721                         BOOST_ASSERT(lyx_view_);
1722                         string action;
1723                         string const name = split(argument, action, ' ');
1724                         Inset::Code const inset_code =
1725                                 Inset::translate(name);
1726
1727                         Cursor & cur = view()->cursor();
1728                         FuncRequest fr(LFUN_INSET_TOGGLE, action);
1729
1730                         Inset & inset = lyx_view_->buffer()->inset();
1731                         InsetIterator it  = inset_iterator_begin(inset);
1732                         InsetIterator const end = inset_iterator_end(inset);
1733                         for (; it != end; ++it) {
1734                                 if (!it->asInsetMath()
1735                                     && (inset_code == Inset::NO_CODE
1736                                     || inset_code == it->lyxCode())) {
1737                                         Cursor tmpcur = cur;
1738                                         tmpcur.pushLeft(*it);
1739                                         it->dispatch(tmpcur, fr);
1740                                 }
1741                         }
1742                         updateFlags = Update::Force | Update::FitCursor;
1743                         break;
1744                 }
1745
1746                 case LFUN_BUFFER_LANGUAGE: {
1747                         BOOST_ASSERT(lyx_view_);
1748                         Buffer & buffer = *lyx_view_->buffer();
1749                         Language const * oldL = buffer.params().language;
1750                         Language const * newL = languages.getLanguage(argument);
1751                         if (!newL || oldL == newL)
1752                                 break;
1753
1754                         if (oldL->rightToLeft() == newL->rightToLeft()
1755                             && !buffer.isMultiLingual())
1756                                 buffer.changeLanguage(oldL, newL);
1757                         break;
1758                 }
1759
1760                 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1761                         string const fname =
1762                                 addName(addPath(package().user_support().absFilename(), "templates/"),
1763                                         "defaults.lyx");
1764                         Buffer defaults(fname);
1765
1766                         istringstream ss(argument);
1767                         Lexer lex(0,0);
1768                         lex.setStream(ss);
1769                         int const unknown_tokens = defaults.readHeader(lex);
1770
1771                         if (unknown_tokens != 0) {
1772                                 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1773                                        << unknown_tokens << " unknown token"
1774                                        << (unknown_tokens == 1 ? "" : "s")
1775                                        << endl;
1776                         }
1777
1778                         if (defaults.writeFile(FileName(defaults.fileName())))
1779                                 setMessage(bformat(_("Document defaults saved in %1$s"),
1780                                                    makeDisplayPath(fname)));
1781                         else
1782                                 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1783                         break;
1784                 }
1785
1786                 case LFUN_BUFFER_PARAMS_APPLY: {
1787                         BOOST_ASSERT(lyx_view_);
1788                         biblio::CiteEngine const oldEngine =
1789                                         lyx_view_->buffer()->params().getEngine();
1790                         
1791                         Buffer * buffer = lyx_view_->buffer();
1792
1793                         TextClassPtr oldClass = buffer->params().getTextClassPtr();
1794                         recordUndoFullDocument(view());
1795                         
1796                         istringstream ss(argument);
1797                         Lexer lex(0,0);
1798                         lex.setStream(ss);
1799                         int const unknown_tokens = buffer->readHeader(lex);
1800
1801                         if (unknown_tokens != 0) {
1802                                 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1803                                                 << unknown_tokens << " unknown token"
1804                                                 << (unknown_tokens == 1 ? "" : "s")
1805                                                 << endl;
1806                         }
1807                         
1808                         updateLayout(oldClass, buffer);
1809                         
1810                         biblio::CiteEngine const newEngine =
1811                                         lyx_view_->buffer()->params().getEngine();
1812                         
1813                         if (oldEngine != newEngine) {
1814                                 Cursor & cur = view()->cursor();
1815                                 FuncRequest fr(LFUN_INSET_REFRESH);
1816         
1817                                 Inset & inset = lyx_view_->buffer()->inset();
1818                                 InsetIterator it  = inset_iterator_begin(inset);
1819                                 InsetIterator const end = inset_iterator_end(inset);
1820                                 for (; it != end; ++it)
1821                                         if (it->lyxCode() == Inset::CITE_CODE)
1822                                                 it->dispatch(cur, fr);
1823                         }
1824                         
1825                         updateFlags = Update::Force | Update::FitCursor;
1826                         break;
1827                 }
1828                 
1829                 case LFUN_LAYOUT_MODULES_CLEAR: {
1830                         BOOST_ASSERT(lyx_view_);
1831                         Buffer * buffer = lyx_view_->buffer();
1832                         TextClassPtr oldClass = buffer->params().getTextClassPtr();
1833                         recordUndoFullDocument(view());
1834                         buffer->params().clearLayoutModules();
1835                         updateLayout(oldClass, buffer);
1836                         updateFlags = Update::Force | Update::FitCursor;
1837                         break;
1838                 }
1839                 
1840                 case LFUN_LAYOUT_MODULE_ADD: {
1841                         BOOST_ASSERT(lyx_view_);
1842                         Buffer * buffer = lyx_view_->buffer();
1843                         TextClassPtr oldClass = buffer->params().getTextClassPtr();
1844                         recordUndoFullDocument(view());
1845                         buffer->params().addLayoutModule(argument);
1846                         updateLayout(oldClass, buffer);
1847                         updateFlags = Update::Force | Update::FitCursor;
1848                         break;
1849                 }
1850
1851                 case LFUN_TEXTCLASS_APPLY: {
1852                         BOOST_ASSERT(lyx_view_);
1853                         Buffer * buffer = lyx_view_->buffer();
1854
1855                         loadTextClass(argument);
1856
1857                         std::pair<bool, textclass_type> const tc_pair =
1858                                 textclasslist.numberOfClass(argument);
1859
1860                         if (!tc_pair.first)
1861                                 break;
1862
1863                         textclass_type const old_class = buffer->params().getBaseClass();
1864                         textclass_type const new_class = tc_pair.second;
1865
1866                         if (old_class == new_class)
1867                                 // nothing to do
1868                                 break;
1869
1870                         //Save the old, possibly modular, layout for use in conversion.
1871                         TextClassPtr oldClass = buffer->params().getTextClassPtr();
1872                         recordUndoFullDocument(view());
1873                         buffer->params().setBaseClass(new_class);
1874                         updateLayout(oldClass, buffer);
1875                         updateFlags = Update::Force | Update::FitCursor;
1876                         break;
1877                 }
1878                 
1879                 case LFUN_LAYOUT_RELOAD: {
1880                         BOOST_ASSERT(lyx_view_);
1881                         Buffer * buffer = lyx_view_->buffer();
1882                         TextClassPtr oldClass = buffer->params().getTextClassPtr();
1883                         textclass_type const tc = buffer->params().getBaseClass();
1884                         textclasslist.reset(tc);
1885                         buffer->params().setBaseClass(tc);
1886                         updateLayout(oldClass, buffer);
1887                         updateFlags = Update::Force | Update::FitCursor;
1888                         break;
1889                 }
1890
1891                 case LFUN_TEXTCLASS_LOAD:
1892                         loadTextClass(argument);
1893                         break;
1894
1895                 case LFUN_LYXRC_APPLY: {
1896                         LyXRC const lyxrc_orig = lyxrc;
1897
1898                         istringstream ss(argument);
1899                         bool const success = lyxrc.read(ss) == 0;
1900
1901                         if (!success) {
1902                                 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1903                                        << "Unable to read lyxrc data"
1904                                        << endl;
1905                                 break;
1906                         }
1907
1908                         actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1909
1910                         /// We force the redraw in any case because there might be
1911                         /// some screen font changes.
1912                         /// FIXME: only the current view will be updated. the Gui
1913                         /// class is able to furnish the list of views.
1914                         updateFlags = Update::Force;
1915                         break;
1916                 }
1917
1918                 case LFUN_WINDOW_NEW:
1919                         LyX::ref().newLyXView();
1920                         break;
1921
1922                 case LFUN_WINDOW_CLOSE:
1923                         BOOST_ASSERT(lyx_view_);
1924                         BOOST_ASSERT(theApp());
1925                         // update bookmark pit of the current buffer before window close
1926                         for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
1927                                 gotoBookmark(i+1, false, false);
1928                         // ask the user for saving changes or cancel quit
1929                         if (!theBufferList().quitWriteAll())
1930                                 break;
1931                         lyx_view_->close();
1932                         return;
1933
1934                 case LFUN_BOOKMARK_GOTO:
1935                         // go to bookmark, open unopened file and switch to buffer if necessary
1936                         gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
1937                         break;
1938
1939                 case LFUN_BOOKMARK_CLEAR:
1940                         LyX::ref().session().bookmarks().clear();
1941                         break;
1942
1943                 case LFUN_TOOLBAR_TOGGLE: {
1944                         BOOST_ASSERT(lyx_view_);
1945                         string const name = cmd.getArg(0);
1946                         bool const allowauto = cmd.getArg(1) == "allowauto";
1947                         lyx_view_->toggleToolbarState(name, allowauto);
1948                         ToolbarInfo * tbi = lyx_view_->getToolbarInfo(name);
1949                         if (!tbi) {
1950                                 setMessage(bformat(_("Unknown toolbar \"%1$s\""),
1951                                                    from_utf8(name)));
1952                                 break;
1953                         }
1954                         docstring state;
1955                         if (tbi->flags & ToolbarInfo::ON)
1956                                 state = _("on");
1957                         else if (tbi->flags & ToolbarInfo::OFF)
1958                                 state = _("off");
1959                         else if (tbi->flags & ToolbarInfo::AUTO)
1960                                 state = _("auto");
1961
1962                         setMessage(bformat(_("Toolbar \"%1$s\" state set to %2$s"), 
1963                                            _(tbi->gui_name), state));
1964                         break;
1965                 }
1966
1967                 default: {
1968                         BOOST_ASSERT(lyx_view_);
1969                         view()->cursor().dispatch(cmd);
1970                         updateFlags = view()->cursor().result().update();
1971                         if (!view()->cursor().result().dispatched())
1972                                 updateFlags = view()->dispatch(cmd);
1973                         break;
1974                 }
1975                 }
1976
1977                 if (lyx_view_ && lyx_view_->buffer()) {
1978                         // BufferView::update() updates the ViewMetricsInfo and
1979                         // also initializes the position cache for all insets in
1980                         // (at least partially) visible top-level paragraphs.
1981                         // We will redraw the screen only if needed.
1982                         if (view()->update(updateFlags)) {
1983                                 // Buffer::changed() signals that a repaint is needed.
1984                                 // The frontend (WorkArea) knows which area to repaint
1985                                 // thanks to the ViewMetricsInfo updated above.
1986                                 lyx_view_->buffer()->changed();
1987                         }
1988
1989                         lyx_view_->updateStatusBar();
1990
1991                         // if we executed a mutating lfun, mark the buffer as dirty
1992                         if (flag.enabled()
1993                             && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
1994                             && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
1995                                 lyx_view_->buffer()->markDirty();
1996
1997                         //Do we have a selection?
1998                         theSelection().haveSelection(view()->cursor().selection());
1999
2000                         if (view()->cursor().inTexted()) {
2001                                 lyx_view_->updateLayoutChoice();
2002                         }
2003                 }
2004         }
2005         if (!quitting && lyx_view_) {
2006                 lyx_view_->updateToolbars();
2007                 // Some messages may already be translated, so we cannot use _()
2008                 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
2009         }
2010 }
2011
2012
2013 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
2014 {
2015         const bool verbose = (cmd.origin == FuncRequest::MENU
2016                               || cmd.origin == FuncRequest::TOOLBAR
2017                               || cmd.origin == FuncRequest::COMMANDBUFFER);
2018
2019         if (cmd.action == LFUN_SELF_INSERT || !verbose) {
2020                 LYXERR(Debug::ACTION) << "dispatch msg is " << to_utf8(msg) << endl;
2021                 if (!msg.empty())
2022                         lyx_view_->message(msg);
2023                 return;
2024         }
2025
2026         docstring dispatch_msg = msg;
2027         if (!dispatch_msg.empty())
2028                 dispatch_msg += ' ';
2029
2030         docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
2031
2032         bool argsadded = false;
2033
2034         if (!cmd.argument().empty()) {
2035                 if (cmd.action != LFUN_UNKNOWN_ACTION) {
2036                         comname += ' ' + cmd.argument();
2037                         argsadded = true;
2038                 }
2039         }
2040
2041         docstring const shortcuts = theTopLevelKeymap().printbindings(cmd);
2042
2043         if (!shortcuts.empty())
2044                 comname += ": " + shortcuts;
2045         else if (!argsadded && !cmd.argument().empty())
2046                 comname += ' ' + cmd.argument();
2047
2048         if (!comname.empty()) {
2049                 comname = rtrim(comname);
2050                 dispatch_msg += '(' + rtrim(comname) + ')';
2051         }
2052
2053         LYXERR(Debug::ACTION) << "verbose dispatch msg "
2054                 << to_utf8(dispatch_msg) << endl;
2055         if (!dispatch_msg.empty())
2056                 lyx_view_->message(dispatch_msg);
2057 }
2058
2059
2060 void LyXFunc::menuNew(string const & name, bool fromTemplate)
2061 {
2062         // FIXME: initpath is not used. What to do?
2063         string initpath = lyxrc.document_path;
2064         string filename(name);
2065
2066         if (lyx_view_->buffer()) {
2067                 string const trypath = lyx_view_->buffer()->filePath();
2068                 // If directory is writeable, use this as default.
2069                 if (isDirWriteable(FileName(trypath)))
2070                         initpath = trypath;
2071         }
2072
2073         static int newfile_number;
2074
2075         if (filename.empty()) {
2076                 filename = addName(lyxrc.document_path,
2077                             "newfile" + convert<string>(++newfile_number) + ".lyx");
2078                 while (theBufferList().exists(filename) ||
2079                        fs::is_readable(FileName(filename).toFilesystemEncoding())) {
2080                         ++newfile_number;
2081                         filename = addName(lyxrc.document_path,
2082                                            "newfile" +  convert<string>(newfile_number) +
2083                                     ".lyx");
2084                 }
2085         }
2086
2087         // The template stuff
2088         string templname;
2089         if (fromTemplate) {
2090                 FileDialog fileDlg(_("Select template file"),
2091                         LFUN_SELECT_FILE_SYNC,
2092                         make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2093                         make_pair(_("Templates|#T#t"), from_utf8(lyxrc.template_path)));
2094
2095                 FileDialog::Result result =
2096                         fileDlg.open(from_utf8(lyxrc.template_path),
2097                                      FileFilterList(_("LyX Documents (*.lyx)")),
2098                                      docstring());
2099
2100                 if (result.first == FileDialog::Later)
2101                         return;
2102                 if (result.second.empty())
2103                         return;
2104                 templname = to_utf8(result.second);
2105         }
2106
2107         Buffer * const b = newFile(filename, templname, !name.empty());
2108         if (b)
2109                 lyx_view_->setBuffer(b);
2110 }
2111
2112
2113 void LyXFunc::open(string const & fname)
2114 {
2115         string initpath = lyxrc.document_path;
2116
2117         if (lyx_view_->buffer()) {
2118                 string const trypath = lyx_view_->buffer()->filePath();
2119                 // If directory is writeable, use this as default.
2120                 if (isDirWriteable(FileName(trypath)))
2121                         initpath = trypath;
2122         }
2123
2124         string filename;
2125
2126         if (fname.empty()) {
2127                 FileDialog fileDlg(_("Select document to open"),
2128                         LFUN_FILE_OPEN,
2129                         make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2130                         make_pair(_("Examples|#E#e"), from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2131
2132                 FileDialog::Result result =
2133                         fileDlg.open(from_utf8(initpath),
2134                                      FileFilterList(_("LyX Documents (*.lyx)")),
2135                                      docstring());
2136
2137                 if (result.first == FileDialog::Later)
2138                         return;
2139
2140                 filename = to_utf8(result.second);
2141
2142                 // check selected filename
2143                 if (filename.empty()) {
2144                         lyx_view_->message(_("Canceled."));
2145                         return;
2146                 }
2147         } else
2148                 filename = fname;
2149
2150         // get absolute path of file and add ".lyx" to the filename if
2151         // necessary
2152         FileName const fullname = fileSearch(string(), filename, "lyx");
2153         if (!fullname.empty())
2154                 filename = fullname.absFilename();
2155
2156         // if the file doesn't exist, let the user create one
2157         if (!fs::exists(fullname.toFilesystemEncoding())) {
2158                 // the user specifically chose this name. Believe him.
2159                 Buffer * const b = newFile(filename, string(), true);
2160                 if (b)
2161                         lyx_view_->setBuffer(b);
2162                 return;
2163         }
2164
2165         docstring const disp_fn = makeDisplayPath(filename);
2166         lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
2167
2168         docstring str2;
2169         Buffer * buf = lyx_view_->loadLyXFile(fullname);
2170         if (buf) {
2171                 updateLabels(*buf);
2172                 lyx_view_->setBuffer(buf);
2173                 lyx_view_->showErrorList("Parse");
2174                 str2 = bformat(_("Document %1$s opened."), disp_fn);
2175         } else {
2176                 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2177         }
2178         lyx_view_->message(str2);
2179 }
2180
2181
2182 void LyXFunc::doImport(string const & argument)
2183 {
2184         string format;
2185         string filename = split(argument, format, ' ');
2186
2187         LYXERR(Debug::INFO) << "LyXFunc::doImport: " << format
2188                             << " file: " << filename << endl;
2189
2190         // need user interaction
2191         if (filename.empty()) {
2192                 string initpath = lyxrc.document_path;
2193
2194                 if (lyx_view_->buffer()) {
2195                         string const trypath = lyx_view_->buffer()->filePath();
2196                         // If directory is writeable, use this as default.
2197                         if (isDirWriteable(FileName(trypath)))
2198                                 initpath = trypath;
2199                 }
2200
2201                 docstring const text = bformat(_("Select %1$s file to import"),
2202                         formats.prettyName(format));
2203
2204                 FileDialog fileDlg(text,
2205                         LFUN_BUFFER_IMPORT,
2206                         make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
2207                         make_pair(_("Examples|#E#e"),
2208                                   from_utf8(addPath(package().system_support().absFilename(), "examples"))));
2209
2210                 docstring filter = formats.prettyName(format);
2211                 filter += " (*.";
2212                 // FIXME UNICODE
2213                 filter += from_utf8(formats.extension(format));
2214                 filter += ')';
2215
2216                 FileDialog::Result result =
2217                         fileDlg.open(from_utf8(initpath),
2218                                      FileFilterList(filter),
2219                                      docstring());
2220
2221                 if (result.first == FileDialog::Later)
2222                         return;
2223
2224                 filename = to_utf8(result.second);
2225
2226                 // check selected filename
2227                 if (filename.empty())
2228                         lyx_view_->message(_("Canceled."));
2229         }
2230
2231         if (filename.empty())
2232                 return;
2233
2234         // get absolute path of file
2235         FileName const fullname(makeAbsPath(filename));
2236
2237         FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
2238
2239         // Check if the document already is open
2240         if (use_gui && theBufferList().exists(lyxfile.absFilename())) {
2241                 if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) {
2242                         lyx_view_->message(_("Canceled."));
2243                         return;
2244                 }
2245         }
2246
2247         // if the file exists already, and we didn't do
2248         // -i lyx thefile.lyx, warn
2249         if (fs::exists(lyxfile.toFilesystemEncoding()) && fullname != lyxfile) {
2250                 docstring const file = makeDisplayPath(lyxfile.absFilename(), 30);
2251
2252                 docstring text = bformat(_("The document %1$s already exists.\n\n"
2253                                                      "Do you want to overwrite that document?"), file);
2254                 int const ret = Alert::prompt(_("Overwrite document?"),
2255                         text, 0, 1, _("&Overwrite"), _("&Cancel"));
2256
2257                 if (ret == 1) {
2258                         lyx_view_->message(_("Canceled."));
2259                         return;
2260                 }
2261         }
2262
2263         ErrorList errorList;
2264         Importer::Import(lyx_view_, fullname, format, errorList);
2265         // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2266 }
2267
2268
2269 void LyXFunc::closeBuffer()
2270 {
2271         // goto bookmark to update bookmark pit.
2272         for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2273                 gotoBookmark(i+1, false, false);
2274         
2275         theBufferList().close(lyx_view_->buffer(), true);
2276 }
2277
2278
2279 void LyXFunc::reloadBuffer()
2280 {
2281         FileName filename(lyx_view_->buffer()->fileName());
2282         docstring const disp_fn = makeDisplayPath(filename.absFilename());
2283         docstring str;
2284         closeBuffer();
2285         Buffer * buf = lyx_view_->loadLyXFile(filename);
2286         if (buf) {
2287                 updateLabels(*buf);
2288                 lyx_view_->setBuffer(buf);
2289                 lyx_view_->showErrorList("Parse");
2290                 str = bformat(_("Document %1$s reloaded."), disp_fn);
2291         } else {
2292                 str = bformat(_("Could not reload document %1$s"), disp_fn);
2293         }
2294         lyx_view_->message(str);
2295 }
2296
2297 // Each "lyx_view_" should have it's own message method. lyxview and
2298 // the minibuffer would use the minibuffer, but lyxserver would
2299 // send an ERROR signal to its client.  Alejandro 970603
2300 // This function is bit problematic when it comes to NLS, to make the
2301 // lyx servers client be language indepenent we must not translate
2302 // strings sent to this func.
2303 void LyXFunc::setErrorMessage(docstring const & m) const
2304 {
2305         dispatch_buffer = m;
2306         errorstat = true;
2307 }
2308
2309
2310 void LyXFunc::setMessage(docstring const & m) const
2311 {
2312         dispatch_buffer = m;
2313 }
2314
2315
2316 docstring const LyXFunc::viewStatusMessage()
2317 {
2318         // When meta-fake key is pressed, show the key sequence so far + "M-".
2319         if (wasMetaKey())
2320                 return keyseq.print(true) + "M-";
2321
2322         // Else, when a non-complete key sequence is pressed,
2323         // show the available options.
2324         if (keyseq.length() > 0 && !keyseq.deleted())
2325                 return keyseq.printOptions(true);
2326
2327         BOOST_ASSERT(lyx_view_);
2328         if (!lyx_view_->buffer())
2329                 return _("Welcome to LyX!");
2330
2331         return view()->cursor().currentState();
2332 }
2333
2334
2335 BufferView * LyXFunc::view() const
2336 {
2337         BOOST_ASSERT(lyx_view_);
2338         return lyx_view_->view();
2339 }
2340
2341
2342 bool LyXFunc::wasMetaKey() const
2343 {
2344         return (meta_fake_bit != NoModifier);
2345 }
2346
2347
2348 void LyXFunc::updateLayout(TextClassPtr const & oldlayout,
2349                            Buffer * buffer)
2350 {
2351         lyx_view_->message(_("Converting document to new document class..."));
2352         
2353         StableDocIterator backcur(view()->cursor());
2354         ErrorList & el = buffer->errorList("Class Switch");
2355         cap::switchBetweenClasses(
2356                         oldlayout, buffer->params().getTextClassPtr(),
2357                         static_cast<InsetText &>(buffer->inset()), el);
2358
2359         view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
2360
2361         buffer->errors("Class Switch");
2362         updateLabels(*buffer);
2363 }
2364
2365
2366 namespace {
2367
2368 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2369 {
2370         // Why the switch you might ask. It is a trick to ensure that all
2371         // the elements in the LyXRCTags enum is handled. As you can see
2372         // there are no breaks at all. So it is just a huge fall-through.
2373         // The nice thing is that we will get a warning from the compiler
2374         // if we forget an element.
2375         LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2376         switch (tag) {
2377         case LyXRC::RC_ACCEPT_COMPOUND:
2378         case LyXRC::RC_ALT_LANG:
2379         case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
2380         case LyXRC::RC_PLAINTEXT_LINELEN:
2381         case LyXRC::RC_AUTOREGIONDELETE:
2382         case LyXRC::RC_AUTORESET_OPTIONS:
2383         case LyXRC::RC_AUTOSAVE:
2384         case LyXRC::RC_AUTO_NUMBER:
2385         case LyXRC::RC_BACKUPDIR_PATH:
2386         case LyXRC::RC_BIBTEX_COMMAND:
2387         case LyXRC::RC_BINDFILE:
2388         case LyXRC::RC_CHECKLASTFILES:
2389         case LyXRC::RC_USELASTFILEPOS:
2390         case LyXRC::RC_LOADSESSION:
2391         case LyXRC::RC_CHKTEX_COMMAND:
2392         case LyXRC::RC_CONVERTER:
2393         case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
2394         case LyXRC::RC_COPIER:
2395         case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2396         case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2397         case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2398         case LyXRC::RC_DATE_INSERT_FORMAT:
2399         case LyXRC::RC_DEFAULT_LANGUAGE:
2400         case LyXRC::RC_DEFAULT_PAPERSIZE:
2401         case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2402         case LyXRC::RC_DISPLAY_GRAPHICS:
2403         case LyXRC::RC_DOCUMENTPATH:
2404                 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2405                         string const encoded = FileName(
2406                                 lyxrc_new.document_path).toFilesystemEncoding();
2407                         if (fs::exists(encoded) && fs::is_directory(encoded))
2408                                 support::package().document_dir() = FileName(lyxrc.document_path);
2409                 }
2410         case LyXRC::RC_ESC_CHARS:
2411         case LyXRC::RC_FONT_ENCODING:
2412         case LyXRC::RC_FORMAT:
2413         case LyXRC::RC_INDEX_COMMAND:
2414         case LyXRC::RC_INPUT:
2415         case LyXRC::RC_KBMAP:
2416         case LyXRC::RC_KBMAP_PRIMARY:
2417         case LyXRC::RC_KBMAP_SECONDARY:
2418         case LyXRC::RC_LABEL_INIT_LENGTH:
2419         case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2420         case LyXRC::RC_LANGUAGE_AUTO_END:
2421         case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2422         case LyXRC::RC_LANGUAGE_COMMAND_END:
2423         case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2424         case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2425         case LyXRC::RC_LANGUAGE_PACKAGE:
2426         case LyXRC::RC_LANGUAGE_USE_BABEL:
2427         case LyXRC::RC_MAKE_BACKUP:
2428         case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2429         case LyXRC::RC_NUMLASTFILES:
2430         case LyXRC::RC_PATH_PREFIX:
2431                 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2432                         support::prependEnvPath("PATH", lyxrc.path_prefix);
2433                 }
2434         case LyXRC::RC_PERS_DICT:
2435         case LyXRC::RC_PREVIEW:
2436         case LyXRC::RC_PREVIEW_HASHED_LABELS:
2437         case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2438         case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2439         case LyXRC::RC_PRINTCOPIESFLAG:
2440         case LyXRC::RC_PRINTER:
2441         case LyXRC::RC_PRINTEVENPAGEFLAG:
2442         case LyXRC::RC_PRINTEXSTRAOPTIONS:
2443         case LyXRC::RC_PRINTFILEEXTENSION:
2444         case LyXRC::RC_PRINTLANDSCAPEFLAG:
2445         case LyXRC::RC_PRINTODDPAGEFLAG:
2446         case LyXRC::RC_PRINTPAGERANGEFLAG:
2447         case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2448         case LyXRC::RC_PRINTPAPERFLAG:
2449         case LyXRC::RC_PRINTREVERSEFLAG:
2450         case LyXRC::RC_PRINTSPOOL_COMMAND:
2451         case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2452         case LyXRC::RC_PRINTTOFILE:
2453         case LyXRC::RC_PRINTTOPRINTER:
2454         case LyXRC::RC_PRINT_ADAPTOUTPUT:
2455         case LyXRC::RC_PRINT_COMMAND:
2456         case LyXRC::RC_RTL_SUPPORT:
2457         case LyXRC::RC_SCREEN_DPI:
2458         case LyXRC::RC_SCREEN_FONT_ROMAN:
2459         case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2460         case LyXRC::RC_SCREEN_FONT_SANS:
2461         case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2462         case LyXRC::RC_SCREEN_FONT_SCALABLE:
2463         case LyXRC::RC_SCREEN_FONT_SIZES:
2464         case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2465         case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2466         case LyXRC::RC_SCREEN_GEOMETRY_HEIGHT:
2467         case LyXRC::RC_SCREEN_GEOMETRY_WIDTH:
2468         case LyXRC::RC_SCREEN_GEOMETRY_XYSAVED:
2469         case LyXRC::RC_SCREEN_ZOOM:
2470         case LyXRC::RC_SERVERPIPE:
2471         case LyXRC::RC_SET_COLOR:
2472         case LyXRC::RC_SHOW_BANNER:
2473         case LyXRC::RC_SPELL_COMMAND:
2474         case LyXRC::RC_TEMPDIRPATH:
2475         case LyXRC::RC_TEMPLATEPATH:
2476         case LyXRC::RC_TEX_ALLOWS_SPACES:
2477         case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2478                 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2479                         support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2480                 }
2481         case LyXRC::RC_UIFILE:
2482         case LyXRC::RC_USER_EMAIL:
2483         case LyXRC::RC_USER_NAME:
2484         case LyXRC::RC_USETEMPDIR:
2485         case LyXRC::RC_USE_ALT_LANG:
2486         case LyXRC::RC_USE_CONVERTER_CACHE:
2487         case LyXRC::RC_USE_ESC_CHARS:
2488         case LyXRC::RC_USE_INP_ENC:
2489         case LyXRC::RC_USE_PERS_DICT:
2490         case LyXRC::RC_USE_SPELL_LIB:
2491         case LyXRC::RC_VIEWDVI_PAPEROPTION:
2492         case LyXRC::RC_VIEWER:
2493         case LyXRC::RC_LAST:
2494                 break;
2495         }
2496 }
2497
2498 } // namespace anon
2499
2500
2501 } // namespace lyx