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