]> git.lyx.org Git - lyx.git/blob - src/LyXFunc.cpp
a743fd261a3ed33fd599e246ca17c5590b1a3cc8
[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/alert.h"
78 #include "frontends/Application.h"
79 #include "frontends/FileDialog.h"
80 #include "frontends/FontLoader.h"
81 #include "frontends/KeySymbol.h"
82 #include "frontends/LyXView.h"
83 #include "frontends/Selection.h"
84
85 #include "support/environment.h"
86 #include "support/FileFilterList.h"
87 #include "support/filetools.h"
88 #include "support/lstrings.h"
89 #include "support/Path.h"
90 #include "support/Package.h"
91 #include "support/Systemcall.h"
92 #include "support/convert.h"
93 #include "support/os.h"
94
95 #include <boost/current_function.hpp>
96
97 #include <sstream>
98
99 using std::endl;
100 using std::make_pair;
101 using std::pair;
102 using std::string;
103 using std::istringstream;
104 using std::ostringstream;
105 using std::find;
106 using std::vector;
107
108 namespace lyx {
109
110 using frontend::LyXView;
111
112 using support::absolutePath;
113 using support::addName;
114 using support::addPath;
115 using support::bformat;
116 using support::changeExtension;
117 using support::contains;
118 using support::FileFilterList;
119 using support::FileName;
120 using support::fileSearch;
121 using support::i18nLibFileSearch;
122 using support::makeDisplayPath;
123 using support::makeAbsPath;
124 using support::package;
125 using support::quoteName;
126 using support::rtrim;
127 using support::split;
128 using support::subst;
129 using support::Systemcall;
130 using support::token;
131 using support::trim;
132 using support::prefixIs;
133
134
135 namespace Alert = frontend::Alert;
136
137 extern bool quitting;
138 extern bool use_gui;
139
140 namespace {
141
142
143 bool import(LyXView * lv, FileName const & filename,
144                       string const & format, ErrorList & errorList)
145 {
146         docstring const displaypath = makeDisplayPath(filename.absFilename());
147         lv->message(bformat(_("Importing %1$s..."), displaypath));
148
149         FileName const lyxfile(changeExtension(filename.absFilename(), ".lyx"));
150
151         string loader_format;
152         vector<string> loaders = theConverters().loaders();
153         if (find(loaders.begin(), loaders.end(), format) == loaders.end()) {
154                 for (vector<string>::const_iterator it = loaders.begin();
155                      it != loaders.end(); ++it) {
156                         if (theConverters().isReachable(format, *it)) {
157                                 string const tofile =
158                                         changeExtension(filename.absFilename(),
159                                                 formats.extension(*it));
160                                 if (!theConverters().convert(0, filename, FileName(tofile),
161                                                         filename, format, *it, errorList))
162                                         return false;
163                                 loader_format = *it;
164                                 break;
165                         }
166                 }
167                 if (loader_format.empty()) {
168                         frontend::Alert::error(_("Couldn't import file"),
169                                      bformat(_("No information for importing the format %1$s."),
170                                          formats.prettyName(format)));
171                         return false;
172                 }
173         } else {
174                 loader_format = format;
175         }
176
177
178         if (loader_format == "lyx") {
179                 Buffer * buf = lv->loadLyXFile(lyxfile);
180                 if (!buf) {
181                         // we are done
182                         lv->message(_("file not imported!"));
183                         return false;
184                 }
185                 updateLabels(*buf);
186                 lv->setBuffer(buf);
187                 lv->errors("Parse");
188         } else {
189                 Buffer * const b = newFile(lyxfile.absFilename(), string(), true);
190                 if (b)
191                         lv->setBuffer(b);
192                 else
193                         return false;
194                 bool as_paragraphs = loader_format == "textparagraph";
195                 string filename2 = (loader_format == format) ? filename.absFilename()
196                         : changeExtension(filename.absFilename(),
197                                           formats.extension(loader_format));
198                 lv->view()->insertPlaintextFile(filename2, as_paragraphs);
199                 lv->dispatch(FuncRequest(LFUN_MARK_OFF));
200         }
201
202         // we are done
203         lv->message(_("imported."));
204         return true;
205 }
206
207
208
209 // This function runs "configure" and then rereads lyx.defaults to
210 // reconfigure the automatic settings.
211 void reconfigure(LyXView & lv, string const & option)
212 {
213         // emit message signal.
214         lv.message(_("Running configure..."));
215
216         // Run configure in user lyx directory
217         support::PathChanger p(package().user_support());
218         string configure_command = package().configure_command();
219         configure_command += option;
220         Systemcall one;
221         int ret = one.startscript(Systemcall::Wait, configure_command);
222         p.pop();
223         // emit message signal.
224         lv.message(_("Reloading configuration..."));
225         lyxrc.read(support::libFileSearch(string(), "lyxrc.defaults"));
226         // Re-read packages.lst
227         LaTeXFeatures::getAvailable();
228
229         if (ret)
230                 Alert::information(_("System reconfiguration failed"),
231                            _("The system reconfiguration has failed.\n"
232                                   "Default textclass is used but LyX may "
233                                   "not be able to work properly.\n"
234                                   "Please reconfigure again if needed."));
235         else
236
237                 Alert::information(_("System reconfigured"),
238                            _("The system has been reconfigured.\n"
239                              "You need to restart LyX to make use of any\n"
240                              "updated document class specifications."));
241 }
242
243
244 bool getLocalStatus(Cursor cursor, FuncRequest const & cmd, FuncStatus & status)
245 {
246         // Try to fix cursor in case it is broken.
247         cursor.fixIfBroken();
248
249         // This is, of course, a mess. Better create a new doc iterator and use
250         // this in Inset::getStatus. This might require an additional
251         // BufferView * arg, though (which should be avoided)
252         //Cursor safe = *this;
253         bool res = false;
254         for ( ; cursor.depth(); cursor.pop()) {
255                 //lyxerr << "\nCursor::getStatus: cmd: " << cmd << endl << *this << endl;
256                 BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
257                 BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
258                 BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
259
260                 // The inset's getStatus() will return 'true' if it made
261                 // a definitive decision on whether it want to handle the
262                 // request or not. The result of this decision is put into
263                 // the 'status' parameter.
264                 if (cursor.inset().getStatus(cursor, cmd, status)) {
265                         res = true;
266                         break;
267                 }
268         }
269         return res;
270 }
271
272
273 /** Return the change status at cursor position, taking in account the
274  * status at each level of the document iterator (a table in a deleted
275  * footnote is deleted).
276  * When \param outer is true, the top slice is not looked at.
277  */
278 Change::Type lookupChangeType(DocIterator const & dit, bool outer = false)
279 {
280         size_t const depth = dit.depth() - (outer ? 1 : 0);
281
282         for (size_t i = 0 ; i < depth ; ++i) {
283                 CursorSlice const & slice = dit[i];
284                 if (!slice.inset().inMathed()
285                     && slice.pos() < slice.paragraph().size()) {
286                         Change::Type const ch = slice.paragraph().lookupChange(slice.pos()).type;
287                         if (ch != Change::UNCHANGED)
288                                 return ch;
289                 }
290         }
291         return Change::UNCHANGED;
292 }
293
294 }
295
296
297 LyXFunc::LyXFunc()
298         : lyx_view_(0), encoded_last_key(0), meta_fake_bit(NoModifier)
299 {
300 }
301
302
303 void LyXFunc::initKeySequences(KeyMap * kb)
304 {
305         keyseq = KeySequence(kb, kb);
306         cancel_meta_seq = KeySequence(kb, kb);
307 }
308
309
310 void LyXFunc::setLyXView(LyXView * lv)
311 {
312         if (!quitting && lyx_view_ && lyx_view_->view() && lyx_view_ != lv)
313                 // save current selection to the selection buffer to allow
314                 // middle-button paste in another window
315                 cap::saveSelection(lyx_view_->view()->cursor());
316         lyx_view_ = lv;
317 }
318
319
320 void LyXFunc::handleKeyFunc(kb_action action)
321 {
322         char_type c = encoded_last_key;
323
324         if (keyseq.length())
325                 c = 0;
326
327         BOOST_ASSERT(lyx_view_ && lyx_view_->view());
328         lyx_view_->view()->getIntl().getTransManager().deadkey(
329                 c, get_accent(action).accent, view()->cursor().innerText(), view()->cursor());
330         // Need to clear, in case the minibuffer calls these
331         // actions
332         keyseq.clear();
333         // copied verbatim from do_accent_char
334         view()->cursor().resetAnchor();
335         view()->processUpdateFlags(Update::FitCursor);
336 }
337
338
339 void LyXFunc::gotoBookmark(unsigned int idx, bool openFile, bool switchToBuffer)
340 {
341         BOOST_ASSERT(lyx_view_);
342         if (!LyX::ref().session().bookmarks().isValid(idx))
343                 return;
344         BookmarksSection::Bookmark const & bm = LyX::ref().session().bookmarks().bookmark(idx);
345         BOOST_ASSERT(!bm.filename.empty());
346         string const file = bm.filename.absFilename();
347         // if the file is not opened, open it.
348         if (!theBufferList().exists(file)) {
349                 if (openFile)
350                         dispatch(FuncRequest(LFUN_FILE_OPEN, file));
351                 else
352                         return;
353         }
354         // open may fail, so we need to test it again
355         if (!theBufferList().exists(file))
356                 return;
357
358         // if the current buffer is not that one, switch to it.
359         if (lyx_view_->buffer()->absFileName() != file) {
360                 if (!switchToBuffer)
361                         return;
362                 dispatch(FuncRequest(LFUN_BUFFER_SWITCH, file));
363         }
364         // moveToPosition try paragraph id first and then paragraph (pit, pos).
365         if (!view()->moveToPosition(bm.bottom_pit, bm.bottom_pos,
366                 bm.top_id, bm.top_pos))
367                 return;
368
369         // Cursor jump succeeded!
370         Cursor const & cur = view()->cursor();
371         pit_type new_pit = cur.pit();
372         pos_type new_pos = cur.pos();
373         int new_id = cur.paragraph().id();
374
375         // if bottom_pit, bottom_pos or top_id has been changed, update bookmark
376         // see http://bugzilla.lyx.org/show_bug.cgi?id=3092
377         if (bm.bottom_pit != new_pit || bm.bottom_pos != new_pos 
378                 || bm.top_id != new_id) {
379                 const_cast<BookmarksSection::Bookmark &>(bm).updatePos(
380                         new_pit, new_pos, new_id);
381         }
382 }
383
384
385 void LyXFunc::processKeySym(KeySymbol const & keysym, KeyModifier state)
386 {
387         LYXERR(Debug::KEY, "KeySym is " << keysym.getSymbolName());
388
389         // Do nothing if we have nothing (JMarc)
390         if (!keysym.isOK()) {
391                 LYXERR(Debug::KEY, "Empty kbd action (probably composing)");
392                 lyx_view_->restartCursor();
393                 return;
394         }
395
396         if (keysym.isModifier()) {
397                 LYXERR(Debug::KEY, "isModifier true");
398                 lyx_view_->restartCursor();
399                 return;
400         }
401
402         //Encoding const * encoding = view()->cursor().getEncoding();
403         //encoded_last_key = keysym.getISOEncoded(encoding ? encoding->name() : "");
404         // FIXME: encoded_last_key shadows the member variable of the same
405         // name. Is that intended?
406         char_type encoded_last_key = keysym.getUCSEncoded();
407
408         // Do a one-deep top-level lookup for
409         // cancel and meta-fake keys. RVDK_PATCH_5
410         cancel_meta_seq.reset();
411
412         FuncRequest func = cancel_meta_seq.addkey(keysym, state);
413         LYXERR(Debug::KEY, BOOST_CURRENT_FUNCTION
414                            << " action first set to [" << func.action << ']');
415
416         // When not cancel or meta-fake, do the normal lookup.
417         // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
418         // Mostly, meta_fake_bit = NoModifier. RVDK_PATCH_5.
419         if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_PREFIX)) {
420                 // remove Caps Lock and Mod2 as a modifiers
421                 func = keyseq.addkey(keysym, (state | meta_fake_bit));
422                 LYXERR(Debug::KEY, BOOST_CURRENT_FUNCTION
423                         << "action now set to [" << func.action << ']');
424         }
425
426         // Dont remove this unless you know what you are doing.
427         meta_fake_bit = NoModifier;
428
429         // Can this happen now ?
430         if (func.action == LFUN_NOACTION)
431                 func = FuncRequest(LFUN_COMMAND_PREFIX);
432
433         LYXERR(Debug::KEY, BOOST_CURRENT_FUNCTION
434                 << " Key [action=" << func.action << "]["
435                 << to_utf8(keyseq.print(KeySequence::Portable)) << ']');
436
437         // already here we know if it any point in going further
438         // why not return already here if action == -1 and
439         // num_bytes == 0? (Lgb)
440
441         if (keyseq.length() > 1)
442                 lyx_view_->message(keyseq.print(KeySequence::ForGui));
443
444
445         // Maybe user can only reach the key via holding down shift.
446         // Let's see. But only if shift is the only modifier
447         if (func.action == LFUN_UNKNOWN_ACTION && state == ShiftModifier) {
448                 LYXERR(Debug::KEY, "Trying without shift");
449                 func = keyseq.addkey(keysym, NoModifier);
450                 LYXERR(Debug::KEY, "Action now " << func.action);
451         }
452
453         if (func.action == LFUN_UNKNOWN_ACTION) {
454                 // Hmm, we didn't match any of the keysequences. See
455                 // if it's normal insertable text not already covered
456                 // by a binding
457                 if (keysym.isText() && keyseq.length() == 1) {
458                         LYXERR(Debug::KEY, "isText() is true, inserting.");
459                         func = FuncRequest(LFUN_SELF_INSERT,
460                                            FuncRequest::KEYBOARD);
461                 } else {
462                         LYXERR(Debug::KEY, "Unknown, !isText() - giving up");
463                         lyx_view_->message(_("Unknown function."));
464                         lyx_view_->restartCursor();
465                         return;
466                 }
467         }
468
469         if (func.action == LFUN_SELF_INSERT) {
470                 if (encoded_last_key != 0) {
471                         docstring const arg(1, encoded_last_key);
472                         dispatch(FuncRequest(LFUN_SELF_INSERT, arg,
473                                              FuncRequest::KEYBOARD));
474                         LYXERR(Debug::KEY, "SelfInsert arg[`" << to_utf8(arg) << "']");
475                 }
476         } else {
477                 dispatch(func);
478         }
479
480         lyx_view_->restartCursor();
481 }
482
483
484 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
485 {
486         //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
487         FuncStatus flag;
488
489         /* In LyX/Mac, when a dialog is open, the menus of the
490            application can still be accessed without giving focus to
491            the main window. In this case, we want to disable the menu
492            entries that are buffer-related.
493
494            Note that this code is not perfect, as bug 1941 attests:
495            http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
496         */
497         Buffer * buf = lyx_view_? lyx_view_->buffer() : 0;
498         if (lyx_view_ && cmd.origin == FuncRequest::MENU && !lyx_view_->hasFocus())
499                 buf = 0;
500
501         if (cmd.action == LFUN_NOACTION) {
502                 flag.message(from_utf8(N_("Nothing to do")));
503                 flag.enabled(false);
504                 return flag;
505         }
506
507         switch (cmd.action) {
508         case LFUN_UNKNOWN_ACTION:
509 #ifndef HAVE_LIBAIKSAURUS
510         case LFUN_THESAURUS_ENTRY:
511 #endif
512                 flag.unknown(true);
513                 flag.enabled(false);
514                 break;
515
516         default:
517                 break;
518         }
519
520         if (flag.unknown()) {
521                 flag.message(from_utf8(N_("Unknown action")));
522                 return flag;
523         }
524
525         if (!flag.enabled()) {
526                 if (flag.message().empty())
527                         flag.message(from_utf8(N_("Command disabled")));
528                 return flag;
529         }
530
531         // Check whether we need a buffer
532         if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
533                 // no, exit directly
534                 flag.message(from_utf8(N_("Command not allowed with"
535                                     "out any document open")));
536                 flag.enabled(false);
537                 return flag;
538         }
539
540         // I would really like to avoid having this switch and rather try to
541         // encode this in the function itself.
542         // -- And I'd rather let an inset decide which LFUNs it is willing
543         // to handle (Andre')
544         bool enable = true;
545         switch (cmd.action) {
546         case LFUN_BUFFER_TOGGLE_READ_ONLY:
547                 flag.setOnOff(buf->isReadonly());
548                 break;
549
550         case LFUN_BUFFER_SWITCH:
551                 // toggle on the current buffer, but do not toggle off
552                 // the other ones (is that a good idea?)
553                 if (buf && to_utf8(cmd.argument()) == buf->absFileName())
554                         flag.setOnOff(true);
555                 break;
556
557         case LFUN_BUFFER_EXPORT:
558                 enable = cmd.argument() == "custom"
559                         || buf->isExportable(to_utf8(cmd.argument()));
560                 break;
561
562         case LFUN_BUFFER_CHKTEX:
563                 enable = buf->isLatex() && !lyxrc.chktex_command.empty();
564                 break;
565
566         case LFUN_BUILD_PROGRAM:
567                 enable = buf->isExportable("program");
568                 break;
569
570         case LFUN_VC_REGISTER:
571                 enable = !buf->lyxvc().inUse();
572                 break;
573         case LFUN_VC_CHECK_IN:
574                 enable = buf->lyxvc().inUse() && !buf->isReadonly();
575                 break;
576         case LFUN_VC_CHECK_OUT:
577                 enable = buf->lyxvc().inUse() && buf->isReadonly();
578                 break;
579         case LFUN_VC_REVERT:
580         case LFUN_VC_UNDO_LAST:
581                 enable = buf->lyxvc().inUse();
582                 break;
583         case LFUN_BUFFER_RELOAD:
584                 enable = !buf->isUnnamed() && buf->fileName().exists()
585                         && (!buf->isClean() || buf->isExternallyModified(Buffer::timestamp_method));
586                 break;
587
588         case LFUN_INSET_APPLY: {
589                 if (!view()) {
590                         enable = false;
591                         break;
592                 }
593                 string const name = cmd.getArg(0);
594                 Inset * inset = lyx_view_->getOpenInset(name);
595                 if (inset) {
596                         FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument());
597                         FuncStatus fs;
598                         if (!inset->getStatus(view()->cursor(), fr, fs)) {
599                                 // Every inset is supposed to handle this
600                                 BOOST_ASSERT(false);
601                         }
602                         flag |= fs;
603                 } else {
604                         FuncRequest fr(LFUN_INSET_INSERT, cmd.argument());
605                         flag |= getStatus(fr);
606                 }
607                 enable = flag.enabled();
608                 break;
609         }
610
611         case LFUN_DIALOG_TOGGLE:
612                 flag.setOnOff(lyx_view_->isDialogVisible(cmd.getArg(0)));
613                 // fall through to set "enable"
614         case LFUN_DIALOG_SHOW: {
615                 string const name = cmd.getArg(0);
616                 if (!buf)
617                         enable = name == "aboutlyx"
618                                 || name == "file" //FIXME: should be removed.
619                                 || name == "prefs"
620                                 || name == "texinfo";
621                 else if (name == "print")
622                         enable = buf->isExportable("dvi")
623                                 && lyxrc.print_command != "none";
624                 else if (name == "character") {
625                         if (!view())
626                                 enable = false;
627                         else {
628                                 InsetCode ic = view()->cursor().inset().lyxCode();
629                                 enable = ic != ERT_CODE && ic != LISTINGS_CODE;
630                         }
631                 }
632                 else if (name == "latexlog")
633                         enable = FileName(buf->logName()).isFileReadable();
634                 else if (name == "spellchecker")
635 #if defined (USE_ASPELL) || defined (USE_ISPELL) || defined (USE_PSPELL)
636                         enable = !buf->isReadonly();
637 #else
638                         enable = false;
639 #endif
640                 else if (name == "vclog")
641                         enable = buf->lyxvc().inUse();
642                 break;
643         }
644
645         case LFUN_DIALOG_UPDATE: {
646                 string const name = cmd.getArg(0);
647                 if (!buf)
648                         enable = name == "prefs";
649                 break;
650         }
651
652         case LFUN_CITATION_INSERT: {
653                 FuncRequest fr(LFUN_INSET_INSERT, "citation");
654                 enable = getStatus(fr).enabled();
655                 break;
656         }
657
658         case LFUN_BUFFER_WRITE: {
659                 enable = lyx_view_->buffer()->isUnnamed()
660                         || !lyx_view_->buffer()->isClean();
661                 break;
662         }
663
664
665         case LFUN_BUFFER_WRITE_ALL: {
666         // We enable the command only if there are some modified buffers
667                 Buffer * first = theBufferList().first();
668                 bool modified = false;
669                 if (first) {
670                         Buffer * b = first;
671                 
672                 // We cannot use a for loop as the buffer list is a cycle.
673                         do {
674                                 if (!b->isClean()) {
675                                         modified = true;
676                                         break;
677                                 }
678                                 b = theBufferList().next(b);
679                         } while (b != first); 
680                 }
681         
682                 enable = modified;
683
684                 break;
685         }
686
687         case LFUN_BOOKMARK_GOTO: {
688                 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
689                 enable = LyX::ref().session().bookmarks().isValid(num);
690                 break;
691         }
692
693         case LFUN_BOOKMARK_CLEAR:
694                 enable = LyX::ref().session().bookmarks().size() > 0;
695                 break;
696
697         case LFUN_TOOLBAR_TOGGLE: {
698                 bool const current = lyx_view_->isToolbarVisible(cmd.getArg(0));
699                 flag.setOnOff(current);
700                 break;
701         }
702         case LFUN_WINDOW_CLOSE: {
703                 enable = theApp()->viewCount() > 0;
704                 break;
705         }
706
707         // this one is difficult to get right. As a half-baked
708         // solution, we consider only the first action of the sequence
709         case LFUN_COMMAND_SEQUENCE: {
710                 // argument contains ';'-terminated commands
711                 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
712                 FuncRequest func(lyxaction.lookupFunc(firstcmd));
713                 func.origin = cmd.origin;
714                 flag = getStatus(func);
715                 break;
716         }
717
718         case LFUN_CALL: {
719                 FuncRequest func;
720                 std::string name = to_utf8(cmd.argument());
721                 if (LyX::ref().topLevelCmdDef().lock(name, func)) {
722                         func.origin = cmd.origin;
723                         flag = getStatus(func);
724                         LyX::ref().topLevelCmdDef().release(name);
725                 } else {
726                         // catch recursion or unknown command definiton
727                         // all operations until the recursion or unknown command 
728                         // definiton occures are performed, so set the state to enabled
729                         enable = true;
730                 }
731                 break;
732         }
733
734         case LFUN_BUFFER_NEW:
735         case LFUN_BUFFER_NEW_TEMPLATE:
736         case LFUN_WORD_FIND_FORWARD:
737         case LFUN_WORD_FIND_BACKWARD:
738         case LFUN_COMMAND_PREFIX:
739         case LFUN_COMMAND_EXECUTE:
740         case LFUN_CANCEL:
741         case LFUN_META_PREFIX:
742         case LFUN_BUFFER_CLOSE:
743         case LFUN_BUFFER_WRITE_AS:
744         case LFUN_BUFFER_UPDATE:
745         case LFUN_BUFFER_VIEW:
746         case LFUN_MASTER_BUFFER_UPDATE:
747         case LFUN_MASTER_BUFFER_VIEW:
748         case LFUN_BUFFER_IMPORT:
749         case LFUN_BUFFER_AUTO_SAVE:
750         case LFUN_RECONFIGURE:
751         case LFUN_HELP_OPEN:
752         case LFUN_FILE_NEW:
753         case LFUN_FILE_OPEN:
754         case LFUN_DROP_LAYOUTS_CHOICE:
755         case LFUN_MENU_OPEN:
756         case LFUN_SERVER_GET_NAME:
757         case LFUN_SERVER_NOTIFY:
758         case LFUN_SERVER_GOTO_FILE_ROW:
759         case LFUN_DIALOG_HIDE:
760         case LFUN_DIALOG_DISCONNECT_INSET:
761         case LFUN_BUFFER_CHILD_OPEN:
762         case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
763         case LFUN_KEYMAP_OFF:
764         case LFUN_KEYMAP_PRIMARY:
765         case LFUN_KEYMAP_SECONDARY:
766         case LFUN_KEYMAP_TOGGLE:
767         case LFUN_REPEAT:
768         case LFUN_BUFFER_EXPORT_CUSTOM:
769         case LFUN_BUFFER_PRINT:
770         case LFUN_PREFERENCES_SAVE:
771         case LFUN_SCREEN_FONT_UPDATE:
772         case LFUN_SET_COLOR:
773         case LFUN_MESSAGE:
774         case LFUN_EXTERNAL_EDIT:
775         case LFUN_GRAPHICS_EDIT:
776         case LFUN_ALL_INSETS_TOGGLE:
777         case LFUN_BUFFER_LANGUAGE:
778         case LFUN_TEXTCLASS_APPLY:
779         case LFUN_TEXTCLASS_LOAD:
780         case LFUN_BUFFER_SAVE_AS_DEFAULT:
781         case LFUN_BUFFER_PARAMS_APPLY:
782         case LFUN_LAYOUT_MODULES_CLEAR:
783         case LFUN_LAYOUT_MODULE_ADD:
784         case LFUN_LAYOUT_RELOAD:
785         case LFUN_LYXRC_APPLY:
786         case LFUN_BUFFER_NEXT:
787         case LFUN_BUFFER_PREVIOUS:
788         case LFUN_WINDOW_NEW:
789         case LFUN_LYX_QUIT:
790                 // these are handled in our dispatch()
791                 break;
792
793         default:
794                 if (!view()) {
795                         enable = false;
796                         break;
797                 }
798                 if (!getLocalStatus(view()->cursor(), cmd, flag))
799                         flag = view()->getStatus(cmd);
800         }
801
802         if (!enable)
803                 flag.enabled(false);
804
805         // Can we use a readonly buffer?
806         if (buf && buf->isReadonly()
807             && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
808             && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
809                 flag.message(from_utf8(N_("Document is read-only")));
810                 flag.enabled(false);
811         }
812
813         // Are we in a DELETED change-tracking region?
814         if (buf && view() 
815                 && lookupChangeType(view()->cursor(), true) == Change::DELETED
816             && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
817             && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
818                 flag.message(from_utf8(N_("This portion of the document is deleted.")));
819                 flag.enabled(false);
820         }
821
822         // the default error message if we disable the command
823         if (!flag.enabled() && flag.message().empty())
824                 flag.message(from_utf8(N_("Command disabled")));
825
826         return flag;
827 }
828
829
830 bool LyXFunc::ensureBufferClean(BufferView * bv)
831 {
832         Buffer & buf = bv->buffer();
833         if (buf.isClean())
834                 return true;
835
836         docstring const file = buf.fileName().displayName(30);
837         docstring text = bformat(_("The document %1$s has unsaved "
838                                              "changes.\n\nDo you want to save "
839                                              "the document?"), file);
840         int const ret = Alert::prompt(_("Save changed document?"),
841                                       text, 0, 1, _("&Save"),
842                                       _("&Cancel"));
843
844         if (ret == 0)
845                 dispatch(FuncRequest(LFUN_BUFFER_WRITE));
846
847         return buf.isClean();
848 }
849
850
851 namespace {
852
853 void showPrintError(string const & name)
854 {
855         docstring str = bformat(_("Could not print the document %1$s.\n"
856                                             "Check that your printer is set up correctly."),
857                              makeDisplayPath(name, 50));
858         Alert::error(_("Print document failed"), str);
859 }
860
861
862 void loadTextClass(string const & name)
863 {
864         std::pair<bool, textclass_type> const tc_pair =
865                 textclasslist.numberOfClass(name);
866
867         if (!tc_pair.first) {
868                 lyxerr << "Document class \"" << name
869                        << "\" does not exist."
870                        << std::endl;
871                 return;
872         }
873
874         textclass_type const tc = tc_pair.second;
875
876         if (!textclasslist[tc].load()) {
877                 docstring s = bformat(_("The document class %1$s."
878                                    "could not be loaded."),
879                                    from_utf8(textclasslist[tc].name()));
880                 Alert::error(_("Could not load class"), s);
881         }
882 }
883
884
885 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
886
887 } //namespace anon
888
889
890 void LyXFunc::dispatch(FuncRequest const & cmd)
891 {
892         string const argument = to_utf8(cmd.argument());
893         kb_action const action = cmd.action;
894
895         LYXERR(Debug::ACTION, "\nLyXFunc::dispatch: cmd: " << cmd);
896         //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
897
898         // we have not done anything wrong yet.
899         errorstat = false;
900         dispatch_buffer.erase();
901
902         // redraw the screen at the end (first of the two drawing steps).
903         //This is done unless explicitely requested otherwise
904         Update::flags updateFlags = Update::FitCursor;
905
906         FuncStatus const flag = getStatus(cmd);
907         if (!flag.enabled()) {
908                 // We cannot use this function here
909                 LYXERR(Debug::ACTION, "LyXFunc::dispatch: "
910                        << lyxaction.getActionName(action)
911                        << " [" << action << "] is disabled at this location");
912                 setErrorMessage(flag.message());
913         } else {
914                 switch (action) {
915                 // Let lyx_view_ dispatch its own actions.
916                 case LFUN_COMMAND_EXECUTE:
917                 case LFUN_DROP_LAYOUTS_CHOICE:
918                 case LFUN_MENU_OPEN:
919                 case LFUN_TOOLBAR_TOGGLE:
920                         BOOST_ASSERT(lyx_view_);
921                         lyx_view_->dispatch(cmd);
922                         break;
923
924                 case LFUN_WORD_FIND_FORWARD:
925                 case LFUN_WORD_FIND_BACKWARD: {
926                         BOOST_ASSERT(lyx_view_ && lyx_view_->view());
927                         static docstring last_search;
928                         docstring searched_string;
929
930                         if (!cmd.argument().empty()) {
931                                 last_search = cmd.argument();
932                                 searched_string = cmd.argument();
933                         } else {
934                                 searched_string = last_search;
935                         }
936
937                         if (searched_string.empty())
938                                 break;
939
940                         bool const fw = action == LFUN_WORD_FIND_FORWARD;
941                         docstring const data =
942                                 find2string(searched_string, true, false, fw);
943                         find(view(), FuncRequest(LFUN_WORD_FIND, data));
944                         break;
945                 }
946
947                 case LFUN_COMMAND_PREFIX:
948                         BOOST_ASSERT(lyx_view_);
949                         lyx_view_->message(keyseq.printOptions(true));
950                         break;
951
952                 case LFUN_CANCEL:
953                         BOOST_ASSERT(lyx_view_ && lyx_view_->view());
954                         keyseq.reset();
955                         meta_fake_bit = NoModifier;
956                         if (lyx_view_->buffer())
957                                 // cancel any selection
958                                 dispatch(FuncRequest(LFUN_MARK_OFF));
959                         setMessage(from_ascii(N_("Cancel")));
960                         break;
961
962                 case LFUN_META_PREFIX:
963                         meta_fake_bit = AltModifier;
964                         setMessage(keyseq.print(KeySequence::ForGui));
965                         break;
966
967                 case LFUN_BUFFER_TOGGLE_READ_ONLY: {
968                         BOOST_ASSERT(lyx_view_ && lyx_view_->view() && lyx_view_->buffer());
969                         Buffer * buf = lyx_view_->buffer();
970                         if (buf->lyxvc().inUse())
971                                 buf->lyxvc().toggleReadOnly();
972                         else
973                                 buf->setReadonly(!lyx_view_->buffer()->isReadonly());
974                         break;
975                 }
976
977                 // --- Menus -----------------------------------------------
978                 case LFUN_BUFFER_NEW:
979                         menuNew(argument, false);
980                         updateFlags = Update::None;
981                         break;
982
983                 case LFUN_BUFFER_NEW_TEMPLATE:
984                         menuNew(argument, true);
985                         updateFlags = Update::None;
986                         break;
987
988                 case LFUN_BUFFER_CLOSE:
989                         closeBuffer();
990                         updateFlags = Update::None;
991                         break;
992
993                 case LFUN_BUFFER_WRITE:
994                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
995                         if (!lyx_view_->buffer()->isUnnamed()) {
996                                 docstring const str = bformat(_("Saving document %1$s..."),
997                                          makeDisplayPath(lyx_view_->buffer()->absFileName()));
998                                 lyx_view_->message(str);
999                                 lyx_view_->buffer()->menuWrite();
1000                                 lyx_view_->message(str + _(" done."));
1001                         } else {
1002                                 lyx_view_->buffer()->writeAs();
1003                         }
1004                         updateFlags = Update::None;
1005                         break;
1006
1007                 case LFUN_BUFFER_WRITE_AS:
1008                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1009                         lyx_view_->buffer()->writeAs(argument);
1010                         updateFlags = Update::None;
1011                         break;
1012
1013                 case LFUN_BUFFER_WRITE_ALL: {
1014                         Buffer * first = theBufferList().first();
1015                         if (first) {
1016                                 Buffer * b = first;
1017                                 lyx_view_->message(_("Saving all documents..."));
1018                 
1019                                 // We cannot use a for loop as the buffer list cycles.
1020                                 do {
1021                                         if (!b->isClean()) {
1022                                                 if (!b->isUnnamed()) {
1023                                                         b->menuWrite();
1024                                                         lyxerr[Debug::ACTION] << "Saved " << b->absFileName() << endl;
1025                                                 } else
1026                                                         b->writeAs();
1027                                         }
1028                                         b = theBufferList().next(b);
1029                                 } while (b != first); 
1030                                 lyx_view_->message(_("All documents saved."));
1031                         } 
1032         
1033                         updateFlags = Update::None;
1034                         break;
1035                 }
1036
1037                 case LFUN_BUFFER_RELOAD: {
1038                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1039                         docstring const file = makeDisplayPath(lyx_view_->buffer()->absFileName(), 20);
1040                         docstring text = bformat(_("Any changes will be lost. Are you sure "
1041                                                              "you want to revert to the saved version of the document %1$s?"), file);
1042                         int const ret = Alert::prompt(_("Revert to saved document?"),
1043                                 text, 1, 1, _("&Revert"), _("&Cancel"));
1044
1045                         if (ret == 0)
1046                                 reloadBuffer();
1047                         break;
1048                 }
1049
1050                 case LFUN_BUFFER_UPDATE:
1051                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1052                         lyx_view_->buffer()->doExport(argument, true);
1053                         break;
1054
1055                 case LFUN_BUFFER_VIEW:
1056                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1057                         lyx_view_->buffer()->preview(argument);
1058                         break;
1059
1060                 case LFUN_MASTER_BUFFER_UPDATE:
1061                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->masterBuffer());
1062                         lyx_view_->buffer()->masterBuffer()->doExport(argument, true);
1063                         break;
1064
1065                 case LFUN_MASTER_BUFFER_VIEW:
1066                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->masterBuffer());
1067                         lyx_view_->buffer()->masterBuffer()->preview(argument);
1068                         break;
1069
1070                 case LFUN_BUILD_PROGRAM:
1071                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1072                         lyx_view_->buffer()->doExport("program", true);
1073                         break;
1074
1075                 case LFUN_BUFFER_CHKTEX:
1076                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1077                         lyx_view_->buffer()->runChktex();
1078                         break;
1079
1080                 case LFUN_BUFFER_EXPORT:
1081                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1082                         if (argument == "custom")
1083                                 lyx_view_->showDialog("sendto");
1084                         else
1085                                 lyx_view_->buffer()->doExport(argument, false);
1086                         break;
1087
1088                 case LFUN_BUFFER_EXPORT_CUSTOM: {
1089                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1090                         string format_name;
1091                         string command = split(argument, format_name, ' ');
1092                         Format const * format = formats.getFormat(format_name);
1093                         if (!format) {
1094                                 lyxerr << "Format \"" << format_name
1095                                        << "\" not recognized!"
1096                                        << std::endl;
1097                                 break;
1098                         }
1099
1100                         Buffer * buffer = lyx_view_->buffer();
1101
1102                         // The name of the file created by the conversion process
1103                         string filename;
1104
1105                         // Output to filename
1106                         if (format->name() == "lyx") {
1107                                 string const latexname = buffer->latexName(false);
1108                                 filename = changeExtension(latexname,
1109                                                            format->extension());
1110                                 filename = addName(buffer->temppath(), filename);
1111
1112                                 if (!buffer->writeFile(FileName(filename)))
1113                                         break;
1114
1115                         } else {
1116                                 buffer->doExport(format_name, true, filename);
1117                         }
1118
1119                         // Substitute $$FName for filename
1120                         if (!contains(command, "$$FName"))
1121                                 command = "( " + command + " ) < $$FName";
1122                         command = subst(command, "$$FName", filename);
1123
1124                         // Execute the command in the background
1125                         Systemcall call;
1126                         call.startscript(Systemcall::DontWait, command);
1127                         break;
1128                 }
1129
1130                 case LFUN_BUFFER_PRINT: {
1131                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1132                         // FIXME: cmd.getArg() might fail if one of the arguments
1133                         // contains double quotes
1134                         string target = cmd.getArg(0);
1135                         string target_name = cmd.getArg(1);
1136                         string command = cmd.getArg(2);
1137
1138                         if (target.empty()
1139                             || target_name.empty()
1140                             || command.empty()) {
1141                                 lyxerr << "Unable to parse \""
1142                                        << argument << '"' << endl;
1143                                 break;
1144                         }
1145                         if (target != "printer" && target != "file") {
1146                                 lyxerr << "Unrecognized target \""
1147                                        << target << '"' << endl;
1148                                 break;
1149                         }
1150
1151                         Buffer * buffer = lyx_view_->buffer();
1152
1153                         if (!buffer->doExport("dvi", true)) {
1154                                 showPrintError(buffer->absFileName());
1155                                 break;
1156                         }
1157
1158                         // Push directory path.
1159                         string const path = buffer->temppath();
1160                         // Prevent the compiler from optimizing away p
1161                         FileName pp(path);
1162                         support::PathChanger p(pp);
1163
1164                         // there are three cases here:
1165                         // 1. we print to a file
1166                         // 2. we print directly to a printer
1167                         // 3. we print using a spool command (print to file first)
1168                         Systemcall one;
1169                         int res = 0;
1170                         string const dviname =
1171                                 changeExtension(buffer->latexName(true), "dvi");
1172
1173                         if (target == "printer") {
1174                                 if (!lyxrc.print_spool_command.empty()) {
1175                                         // case 3: print using a spool
1176                                         string const psname =
1177                                                 changeExtension(dviname,".ps");
1178                                         command += ' ' + lyxrc.print_to_file
1179                                                 + quoteName(psname)
1180                                                 + ' '
1181                                                 + quoteName(dviname);
1182
1183                                         string command2 =
1184                                                 lyxrc.print_spool_command + ' ';
1185                                         if (target_name != "default") {
1186                                                 command2 += lyxrc.print_spool_printerprefix
1187                                                         + target_name
1188                                                         + ' ';
1189                                         }
1190                                         command2 += quoteName(psname);
1191                                         // First run dvips.
1192                                         // If successful, then spool command
1193                                         res = one.startscript(
1194                                                 Systemcall::Wait,
1195                                                 command);
1196
1197                                         if (res == 0)
1198                                                 res = one.startscript(
1199                                                         Systemcall::DontWait,
1200                                                         command2);
1201                                 } else {
1202                                         // case 2: print directly to a printer
1203                                         if (target_name != "default")
1204                                                 command += ' ' + lyxrc.print_to_printer + target_name + ' ';
1205                                         res = one.startscript(
1206                                                 Systemcall::DontWait,
1207                                                 command + quoteName(dviname));
1208                                 }
1209
1210                         } else {
1211                                 // case 1: print to a file
1212                                 FileName const filename(makeAbsPath(target_name,
1213                                                         lyx_view_->buffer()->filePath()));
1214                                 FileName const dvifile(makeAbsPath(dviname, path));
1215                                 if (filename.exists()) {
1216                                         docstring text = bformat(
1217                                                 _("The file %1$s already exists.\n\n"
1218                                                   "Do you want to overwrite that file?"),
1219                                                 makeDisplayPath(filename.absFilename()));
1220                                         if (Alert::prompt(_("Overwrite file?"),
1221                                             text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
1222                                                 break;
1223                                 }
1224                                 command += ' ' + lyxrc.print_to_file
1225                                         + quoteName(filename.toFilesystemEncoding())
1226                                         + ' '
1227                                         + quoteName(dvifile.toFilesystemEncoding());
1228                                 res = one.startscript(Systemcall::DontWait,
1229                                                       command);
1230                         }
1231
1232                         if (res != 0)
1233                                 showPrintError(buffer->absFileName());
1234                         break;
1235                 }
1236
1237                 case LFUN_BUFFER_IMPORT:
1238                         doImport(argument);
1239                         break;
1240
1241                 case LFUN_LYX_QUIT:
1242                         // quitting is triggered by the gui code
1243                         // (leaving the event loop).
1244                         lyx_view_->message(from_utf8(N_("Exiting.")));
1245                         if (theBufferList().quitWriteAll())
1246                                 theApp()->closeAllViews();
1247                         break;
1248
1249                 case LFUN_BUFFER_AUTO_SAVE:
1250                         lyx_view_->buffer()->autoSave();
1251                         break;
1252
1253                 case LFUN_RECONFIGURE:
1254                         BOOST_ASSERT(lyx_view_);
1255                         // argument is any additional parameter to the configure.py command
1256                         reconfigure(*lyx_view_, argument);
1257                         break;
1258
1259                 case LFUN_HELP_OPEN: {
1260                         BOOST_ASSERT(lyx_view_);
1261                         string const arg = argument;
1262                         if (arg.empty()) {
1263                                 setErrorMessage(from_ascii(N_("Missing argument")));
1264                                 break;
1265                         }
1266                         FileName const fname = i18nLibFileSearch("doc", arg, "lyx");
1267                         if (fname.empty()) {
1268                                 lyxerr << "LyX: unable to find documentation file `"
1269                                                          << arg << "'. Bad installation?" << endl;
1270                                 break;
1271                         }
1272                         lyx_view_->message(bformat(_("Opening help file %1$s..."),
1273                                 makeDisplayPath(fname.absFilename())));
1274                         Buffer * buf = lyx_view_->loadLyXFile(fname, false);
1275                         if (buf) {
1276                                 updateLabels(*buf);
1277                                 lyx_view_->setBuffer(buf);
1278                                 lyx_view_->errors("Parse");
1279                         }
1280                         updateFlags = Update::None;
1281                         break;
1282                 }
1283
1284                 // --- version control -------------------------------
1285                 case LFUN_VC_REGISTER:
1286                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1287                         if (!ensureBufferClean(view()))
1288                                 break;
1289                         if (!lyx_view_->buffer()->lyxvc().inUse()) {
1290                                 lyx_view_->buffer()->lyxvc().registrer();
1291                                 reloadBuffer();
1292                         }
1293                         updateFlags = Update::Force;
1294                         break;
1295
1296                 case LFUN_VC_CHECK_IN:
1297                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1298                         if (!ensureBufferClean(view()))
1299                                 break;
1300                         if (lyx_view_->buffer()->lyxvc().inUse()
1301                                         && !lyx_view_->buffer()->isReadonly()) {
1302                                 lyx_view_->buffer()->lyxvc().checkIn();
1303                                 reloadBuffer();
1304                         }
1305                         break;
1306
1307                 case LFUN_VC_CHECK_OUT:
1308                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1309                         if (!ensureBufferClean(view()))
1310                                 break;
1311                         if (lyx_view_->buffer()->lyxvc().inUse()
1312                                         && lyx_view_->buffer()->isReadonly()) {
1313                                 lyx_view_->buffer()->lyxvc().checkOut();
1314                                 reloadBuffer();
1315                         }
1316                         break;
1317
1318                 case LFUN_VC_REVERT:
1319                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1320                         lyx_view_->buffer()->lyxvc().revert();
1321                         reloadBuffer();
1322                         break;
1323
1324                 case LFUN_VC_UNDO_LAST:
1325                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1326                         lyx_view_->buffer()->lyxvc().undoLast();
1327                         reloadBuffer();
1328                         break;
1329
1330                 // --- buffers ----------------------------------------
1331                 case LFUN_BUFFER_SWITCH:
1332                         BOOST_ASSERT(lyx_view_);
1333                         lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1334                         updateFlags = Update::None;
1335                         break;
1336
1337                 case LFUN_BUFFER_NEXT:
1338                         BOOST_ASSERT(lyx_view_);
1339                         lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer()));
1340                         updateFlags = Update::None;
1341                         break;
1342
1343                 case LFUN_BUFFER_PREVIOUS:
1344                         BOOST_ASSERT(lyx_view_);
1345                         lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer()));
1346                         updateFlags = Update::None;
1347                         break;
1348
1349                 case LFUN_FILE_NEW: {
1350                         BOOST_ASSERT(lyx_view_);
1351                         string name;
1352                         string tmpname = split(argument, name, ':'); // Split filename
1353                         Buffer * const b = newFile(name, tmpname);
1354                         if (b)
1355                                 lyx_view_->setBuffer(b);
1356                         updateFlags = Update::None;
1357                         break;
1358                 }
1359
1360                 case LFUN_FILE_OPEN:
1361                         BOOST_ASSERT(lyx_view_);
1362                         open(argument);
1363                         updateFlags = Update::None;
1364                         break;
1365
1366                 // --- lyxserver commands ----------------------------
1367                 case LFUN_SERVER_GET_NAME:
1368                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1369                         setMessage(from_utf8(lyx_view_->buffer()->absFileName()));
1370                         LYXERR(Debug::INFO, "FNAME["
1371                                 << lyx_view_->buffer()->absFileName() << ']');
1372                         break;
1373
1374                 case LFUN_SERVER_NOTIFY:
1375                         dispatch_buffer = keyseq.print(KeySequence::Portable);
1376                         theServer().notifyClient(to_utf8(dispatch_buffer));
1377                         break;
1378
1379                 case LFUN_SERVER_GOTO_FILE_ROW: {
1380                         BOOST_ASSERT(lyx_view_);
1381                         string file_name;
1382                         int row;
1383                         istringstream is(argument);
1384                         is >> file_name >> row;
1385                         Buffer * buf = 0;
1386                         bool loaded = false;
1387                         if (prefixIs(file_name, package().temp_dir().absFilename()))
1388                                 // Needed by inverse dvi search. If it is a file
1389                                 // in tmpdir, call the apropriated function
1390                                 buf = theBufferList().getBufferFromTmp(file_name);
1391                         else {
1392                                 // Must replace extension of the file to be .lyx
1393                                 // and get full path
1394                                 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1395                                 // Either change buffer or load the file
1396                                 if (theBufferList().exists(s.absFilename()))
1397                                         buf = theBufferList().getBuffer(s.absFilename());
1398                                 else {
1399                                         buf = lyx_view_->loadLyXFile(s);
1400                                         loaded = true;
1401                                 }
1402                         }
1403
1404                         if (!buf) {
1405                                 updateFlags = Update::None;
1406                                 break;
1407                         }
1408
1409                         updateLabels(*buf);
1410                         lyx_view_->setBuffer(buf);
1411                         view()->setCursorFromRow(row);
1412                         if (loaded)
1413                                 lyx_view_->errors("Parse");
1414                         updateFlags = Update::FitCursor;
1415                         break;
1416                 }
1417
1418                 case LFUN_DIALOG_SHOW: {
1419                         BOOST_ASSERT(lyx_view_);
1420                         string const name = cmd.getArg(0);
1421                         string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1422
1423                         if (name == "character") {
1424                                 data = freefont2string();
1425                                 if (!data.empty())
1426                                         lyx_view_->showDialogWithData("character", data);
1427                         } else if (name == "latexlog") {
1428                                 Buffer::LogType type; 
1429                                 string const logfile = lyx_view_->buffer()->logName(&type);
1430                                 switch (type) {
1431                                 case Buffer::latexlog:
1432                                         data = "latex ";
1433                                         break;
1434                                 case Buffer::buildlog:
1435                                         data = "literate ";
1436                                         break;
1437                                 }
1438                                 data += Lexer::quoteString(logfile);
1439                                 lyx_view_->showDialogWithData("log", data);
1440                         } else if (name == "vclog") {
1441                                 string const data = "vc " +
1442                                         Lexer::quoteString(lyx_view_->buffer()->lyxvc().getLogFile());
1443                                 lyx_view_->showDialogWithData("log", data);
1444                         } else
1445                                 lyx_view_->showDialogWithData(name, data);
1446                         break;
1447                 }
1448
1449                 case LFUN_DIALOG_SHOW_NEW_INSET: {
1450                         BOOST_ASSERT(lyx_view_);
1451                         string const name = cmd.getArg(0);
1452                         InsetCode code = insetCode(name);
1453                         string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1454                         bool insetCodeOK = true;
1455                         switch (code) {
1456                         case BIBITEM_CODE:
1457                         case BIBTEX_CODE:
1458                         case INDEX_CODE:
1459                         case LABEL_CODE:
1460                         case NOMENCL_CODE:
1461                         case REF_CODE:
1462                         case TOC_CODE:
1463                         case HYPERLINK_CODE: {
1464                                 InsetCommandParams p(code);
1465                                 data = InsetCommandMailer::params2string(name, p);
1466                                 break;
1467                         } 
1468                         case INCLUDE_CODE: {
1469                                 // data is the include type: one of "include",
1470                                 // "input", "verbatiminput" or "verbatiminput*"
1471                                 if (data.empty())
1472                                         // default type is requested
1473                                         data = "include";
1474                                 InsetCommandParams p(INCLUDE_CODE, data);
1475                                 data = InsetCommandMailer::params2string("include", p);
1476                                 break;
1477                         } 
1478                         case BOX_CODE: {
1479                                 // \c data == "Boxed" || "Frameless" etc
1480                                 InsetBoxParams p(data);
1481                                 data = InsetBoxMailer::params2string(p);
1482                                 break;
1483                         } 
1484                         case BRANCH_CODE: {
1485                                 InsetBranchParams p;
1486                                 data = InsetBranchMailer::params2string(p);
1487                                 break;
1488                         } 
1489                         case CITE_CODE: {
1490                                 InsetCommandParams p(CITE_CODE);
1491                                 data = InsetCommandMailer::params2string(name, p);
1492                                 break;
1493                         } 
1494                         case ERT_CODE: {
1495                                 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1496                                 break;
1497                         } 
1498                         case EXTERNAL_CODE: {
1499                                 InsetExternalParams p;
1500                                 Buffer const & buffer = *lyx_view_->buffer();
1501                                 data = InsetExternalMailer::params2string(p, buffer);
1502                                 break;
1503                         } 
1504                         case FLOAT_CODE:  {
1505                                 InsetFloatParams p;
1506                                 data = InsetFloatMailer::params2string(p);
1507                                 break;
1508                         } 
1509                         case LISTINGS_CODE: {
1510                                 InsetListingsParams p;
1511                                 data = InsetListingsMailer::params2string(p);
1512                                 break;
1513                         } 
1514                         case GRAPHICS_CODE: {
1515                                 InsetGraphicsParams p;
1516                                 Buffer const & buffer = *lyx_view_->buffer();
1517                                 data = InsetGraphicsMailer::params2string(p, buffer);
1518                                 break;
1519                         } 
1520                         case NOTE_CODE: {
1521                                 InsetNoteParams p;
1522                                 data = InsetNoteMailer::params2string(p);
1523                                 break;
1524                         } 
1525                         case VSPACE_CODE: {
1526                                 VSpace space;
1527                                 data = InsetVSpaceMailer::params2string(space);
1528                                 break;
1529                         } 
1530                         case WRAP_CODE: {
1531                                 InsetWrapParams p;
1532                                 data = InsetWrapMailer::params2string(p);
1533                                 break;
1534                         }
1535                         default:
1536                                 lyxerr << "Inset type '" << name << 
1537                                         "' not recognized in LFUN_DIALOG_SHOW_NEW_INSET" << std:: endl;
1538                                 insetCodeOK = false;
1539                                 break;
1540                         } // end switch(code)
1541                         if (insetCodeOK)
1542                                 lyx_view_->showDialog(name, data, 0);
1543                         break;
1544                 }
1545
1546                 case LFUN_DIALOG_UPDATE: {
1547                         BOOST_ASSERT(lyx_view_);
1548                         string const & name = argument;
1549                         // Can only update a dialog connected to an existing inset
1550                         Inset * inset = lyx_view_->getOpenInset(name);
1551                         if (inset) {
1552                                 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1553                                 inset->dispatch(view()->cursor(), fr);
1554                         } else if (name == "paragraph") {
1555                                 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1556                         } else if (name == "prefs") {
1557                                 lyx_view_->updateDialog(name, string());
1558                         }
1559                         break;
1560                 }
1561
1562                 case LFUN_DIALOG_HIDE: {
1563                         if (quitting || !use_gui)
1564                                 break;
1565                         theApp()->hideDialogs(argument, 0);
1566                         break;
1567                 }
1568
1569                 case LFUN_DIALOG_TOGGLE: {
1570                         BOOST_ASSERT(lyx_view_);
1571                         if (lyx_view_->isDialogVisible(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_->disconnectDialog(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_->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