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