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