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