]> git.lyx.org Git - lyx.git/blob - src/LyXFunc.cpp
Cosmetics
[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                 // Let lyx_view_ dispatch its own actions.
924                 case LFUN_COMMAND_EXECUTE:
925                 case LFUN_DROP_LAYOUTS_CHOICE:
926                 case LFUN_MENU_OPEN:
927                 case LFUN_TOOLBAR_TOGGLE:
928                         BOOST_ASSERT(lyx_view_);
929                         lyx_view_->dispatch(cmd);
930                         break;
931
932                 case LFUN_WORD_FIND_FORWARD:
933                 case LFUN_WORD_FIND_BACKWARD: {
934                         BOOST_ASSERT(lyx_view_ && lyx_view_->view());
935                         static docstring last_search;
936                         docstring searched_string;
937
938                         if (!cmd.argument().empty()) {
939                                 last_search = cmd.argument();
940                                 searched_string = cmd.argument();
941                         } else {
942                                 searched_string = last_search;
943                         }
944
945                         if (searched_string.empty())
946                                 break;
947
948                         bool const fw = action == LFUN_WORD_FIND_FORWARD;
949                         docstring const data =
950                                 find2string(searched_string, true, false, fw);
951                         find(view(), FuncRequest(LFUN_WORD_FIND, data));
952                         break;
953                 }
954
955                 case LFUN_COMMAND_PREFIX:
956                         BOOST_ASSERT(lyx_view_);
957                         lyx_view_->message(keyseq.printOptions(true));
958                         break;
959
960                 case LFUN_CANCEL:
961                         BOOST_ASSERT(lyx_view_ && lyx_view_->view());
962                         keyseq.reset();
963                         meta_fake_bit = NoModifier;
964                         if (lyx_view_->buffer())
965                                 // cancel any selection
966                                 dispatch(FuncRequest(LFUN_MARK_OFF));
967                         setMessage(from_ascii(N_("Cancel")));
968                         break;
969
970                 case LFUN_META_PREFIX:
971                         meta_fake_bit = AltModifier;
972                         setMessage(keyseq.print(KeySequence::ForGui));
973                         break;
974
975                 case LFUN_BUFFER_TOGGLE_READ_ONLY: {
976                         BOOST_ASSERT(lyx_view_ && lyx_view_->view() && lyx_view_->buffer());
977                         Buffer * buf = lyx_view_->buffer();
978                         if (buf->lyxvc().inUse())
979                                 buf->lyxvc().toggleReadOnly();
980                         else
981                                 buf->setReadonly(!lyx_view_->buffer()->isReadonly());
982                         break;
983                 }
984
985                 // --- Menus -----------------------------------------------
986                 case LFUN_BUFFER_NEW:
987                         menuNew(argument, false);
988                         updateFlags = Update::None;
989                         break;
990
991                 case LFUN_BUFFER_NEW_TEMPLATE:
992                         menuNew(argument, true);
993                         updateFlags = Update::None;
994                         break;
995
996                 case LFUN_BUFFER_CLOSE:
997                         closeBuffer();
998                         updateFlags = Update::None;
999                         break;
1000
1001                 case LFUN_BUFFER_WRITE:
1002                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1003                         if (!lyx_view_->buffer()->isUnnamed()) {
1004                                 docstring const str = bformat(_("Saving document %1$s..."),
1005                                          makeDisplayPath(lyx_view_->buffer()->absFileName()));
1006                                 lyx_view_->message(str);
1007                                 lyx_view_->buffer()->menuWrite();
1008                                 lyx_view_->message(str + _(" done."));
1009                         } else {
1010                                 lyx_view_->buffer()->writeAs();
1011                         }
1012                         updateFlags = Update::None;
1013                         break;
1014
1015                 case LFUN_BUFFER_WRITE_AS:
1016                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1017                         lyx_view_->buffer()->writeAs(argument);
1018                         updateFlags = Update::None;
1019                         break;
1020
1021                 case LFUN_BUFFER_WRITE_ALL: {
1022                         Buffer * first = theBufferList().first();
1023                         if (first) {
1024                                 Buffer * b = first;
1025                                 lyx_view_->message(_("Saving all documents..."));
1026                 
1027                                 // We cannot use a for loop as the buffer list cycles.
1028                                 do {
1029                                         if (!b->isClean()) {
1030                                                 if (!b->isUnnamed()) {
1031                                                         b->menuWrite();
1032                                                         lyxerr[Debug::ACTION] << "Saved " << b->absFileName() << endl;
1033                                                 } else
1034                                                         b->writeAs();
1035                                         }
1036                                         b = theBufferList().next(b);
1037                                 } while (b != first); 
1038                                 lyx_view_->message(_("All documents saved."));
1039                         } 
1040         
1041                         updateFlags = Update::None;
1042                         break;
1043                 }
1044
1045                 case LFUN_BUFFER_RELOAD: {
1046                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1047                         docstring const file = makeDisplayPath(lyx_view_->buffer()->absFileName(), 20);
1048                         docstring text = bformat(_("Any changes will be lost. Are you sure "
1049                                                              "you want to revert to the saved version of the document %1$s?"), file);
1050                         int const ret = Alert::prompt(_("Revert to saved document?"),
1051                                 text, 1, 1, _("&Revert"), _("&Cancel"));
1052
1053                         if (ret == 0)
1054                                 reloadBuffer();
1055                         break;
1056                 }
1057
1058                 case LFUN_BUFFER_UPDATE:
1059                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1060                         lyx_view_->buffer()->doExport(argument, true);
1061                         break;
1062
1063                 case LFUN_BUFFER_VIEW:
1064                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1065                         lyx_view_->buffer()->preview(argument);
1066                         break;
1067
1068                 case LFUN_MASTER_BUFFER_UPDATE:
1069                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->masterBuffer());
1070                         lyx_view_->buffer()->masterBuffer()->doExport(argument, true);
1071                         break;
1072
1073                 case LFUN_MASTER_BUFFER_VIEW:
1074                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer() && lyx_view_->buffer()->masterBuffer());
1075                         lyx_view_->buffer()->masterBuffer()->preview(argument);
1076                         break;
1077
1078                 case LFUN_BUILD_PROGRAM:
1079                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1080                         lyx_view_->buffer()->doExport("program", true);
1081                         break;
1082
1083                 case LFUN_BUFFER_CHKTEX:
1084                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1085                         lyx_view_->buffer()->runChktex();
1086                         break;
1087
1088                 case LFUN_BUFFER_EXPORT:
1089                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1090                         if (argument == "custom")
1091                                 lyx_view_->showDialog("sendto");
1092                         else
1093                                 lyx_view_->buffer()->doExport(argument, false);
1094                         break;
1095
1096                 case LFUN_BUFFER_EXPORT_CUSTOM: {
1097                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1098                         string format_name;
1099                         string command = split(argument, format_name, ' ');
1100                         Format const * format = formats.getFormat(format_name);
1101                         if (!format) {
1102                                 lyxerr << "Format \"" << format_name
1103                                        << "\" not recognized!"
1104                                        << std::endl;
1105                                 break;
1106                         }
1107
1108                         Buffer * buffer = lyx_view_->buffer();
1109
1110                         // The name of the file created by the conversion process
1111                         string filename;
1112
1113                         // Output to filename
1114                         if (format->name() == "lyx") {
1115                                 string const latexname = buffer->latexName(false);
1116                                 filename = changeExtension(latexname,
1117                                                            format->extension());
1118                                 filename = addName(buffer->temppath(), filename);
1119
1120                                 if (!buffer->writeFile(FileName(filename)))
1121                                         break;
1122
1123                         } else {
1124                                 buffer->doExport(format_name, true, filename);
1125                         }
1126
1127                         // Substitute $$FName for filename
1128                         if (!contains(command, "$$FName"))
1129                                 command = "( " + command + " ) < $$FName";
1130                         command = subst(command, "$$FName", filename);
1131
1132                         // Execute the command in the background
1133                         Systemcall call;
1134                         call.startscript(Systemcall::DontWait, command);
1135                         break;
1136                 }
1137
1138                 case LFUN_BUFFER_PRINT: {
1139                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1140                         // FIXME: cmd.getArg() might fail if one of the arguments
1141                         // contains double quotes
1142                         string target = cmd.getArg(0);
1143                         string target_name = cmd.getArg(1);
1144                         string command = cmd.getArg(2);
1145
1146                         if (target.empty()
1147                             || target_name.empty()
1148                             || command.empty()) {
1149                                 lyxerr << "Unable to parse \""
1150                                        << argument << '"' << endl;
1151                                 break;
1152                         }
1153                         if (target != "printer" && target != "file") {
1154                                 lyxerr << "Unrecognized target \""
1155                                        << target << '"' << endl;
1156                                 break;
1157                         }
1158
1159                         Buffer * buffer = lyx_view_->buffer();
1160
1161                         if (!buffer->doExport("dvi", true)) {
1162                                 showPrintError(buffer->absFileName());
1163                                 break;
1164                         }
1165
1166                         // Push directory path.
1167                         string const path = buffer->temppath();
1168                         // Prevent the compiler from optimizing away p
1169                         FileName pp(path);
1170                         support::PathChanger p(pp);
1171
1172                         // there are three cases here:
1173                         // 1. we print to a file
1174                         // 2. we print directly to a printer
1175                         // 3. we print using a spool command (print to file first)
1176                         Systemcall one;
1177                         int res = 0;
1178                         string const dviname =
1179                                 changeExtension(buffer->latexName(true), "dvi");
1180
1181                         if (target == "printer") {
1182                                 if (!lyxrc.print_spool_command.empty()) {
1183                                         // case 3: print using a spool
1184                                         string const psname =
1185                                                 changeExtension(dviname,".ps");
1186                                         command += ' ' + lyxrc.print_to_file
1187                                                 + quoteName(psname)
1188                                                 + ' '
1189                                                 + quoteName(dviname);
1190
1191                                         string command2 =
1192                                                 lyxrc.print_spool_command + ' ';
1193                                         if (target_name != "default") {
1194                                                 command2 += lyxrc.print_spool_printerprefix
1195                                                         + target_name
1196                                                         + ' ';
1197                                         }
1198                                         command2 += quoteName(psname);
1199                                         // First run dvips.
1200                                         // If successful, then spool command
1201                                         res = one.startscript(
1202                                                 Systemcall::Wait,
1203                                                 command);
1204
1205                                         if (res == 0)
1206                                                 res = one.startscript(
1207                                                         Systemcall::DontWait,
1208                                                         command2);
1209                                 } else {
1210                                         // case 2: print directly to a printer
1211                                         if (target_name != "default")
1212                                                 command += ' ' + lyxrc.print_to_printer + target_name + ' ';
1213                                         res = one.startscript(
1214                                                 Systemcall::DontWait,
1215                                                 command + quoteName(dviname));
1216                                 }
1217
1218                         } else {
1219                                 // case 1: print to a file
1220                                 FileName const filename(makeAbsPath(target_name,
1221                                                         lyx_view_->buffer()->filePath()));
1222                                 FileName const dvifile(makeAbsPath(dviname, path));
1223                                 if (filename.exists()) {
1224                                         docstring text = bformat(
1225                                                 _("The file %1$s already exists.\n\n"
1226                                                   "Do you want to overwrite that file?"),
1227                                                 makeDisplayPath(filename.absFilename()));
1228                                         if (Alert::prompt(_("Overwrite file?"),
1229                                             text, 0, 1, _("&Overwrite"), _("&Cancel")) != 0)
1230                                                 break;
1231                                 }
1232                                 command += ' ' + lyxrc.print_to_file
1233                                         + quoteName(filename.toFilesystemEncoding())
1234                                         + ' '
1235                                         + quoteName(dvifile.toFilesystemEncoding());
1236                                 res = one.startscript(Systemcall::DontWait,
1237                                                       command);
1238                         }
1239
1240                         if (res != 0)
1241                                 showPrintError(buffer->absFileName());
1242                         break;
1243                 }
1244
1245                 case LFUN_BUFFER_IMPORT:
1246                         doImport(argument);
1247                         break;
1248
1249                 case LFUN_LYX_QUIT:
1250                         // quitting is triggered by the gui code
1251                         // (leaving the event loop).
1252                         lyx_view_->message(from_utf8(N_("Exiting.")));
1253                         if (theBufferList().quitWriteAll())
1254                                 theApp()->gui().closeAllViews();
1255                         break;
1256
1257                 case LFUN_BUFFER_AUTO_SAVE:
1258                         lyx_view_->buffer()->autoSave();
1259                         break;
1260
1261                 case LFUN_RECONFIGURE:
1262                         BOOST_ASSERT(lyx_view_);
1263                         // argument is any additional parameter to the configure.py command
1264                         reconfigure(*lyx_view_, argument);
1265                         break;
1266
1267                 case LFUN_HELP_OPEN: {
1268                         BOOST_ASSERT(lyx_view_);
1269                         string const arg = argument;
1270                         if (arg.empty()) {
1271                                 setErrorMessage(from_ascii(N_("Missing argument")));
1272                                 break;
1273                         }
1274                         FileName const fname = i18nLibFileSearch("doc", arg, "lyx");
1275                         if (fname.empty()) {
1276                                 lyxerr << "LyX: unable to find documentation file `"
1277                                                          << arg << "'. Bad installation?" << endl;
1278                                 break;
1279                         }
1280                         lyx_view_->message(bformat(_("Opening help file %1$s..."),
1281                                 makeDisplayPath(fname.absFilename())));
1282                         Buffer * buf = lyx_view_->loadLyXFile(fname, false);
1283                         if (buf) {
1284                                 updateLabels(*buf);
1285                                 lyx_view_->setBuffer(buf);
1286                                 lyx_view_->errors("Parse");
1287                         }
1288                         updateFlags = Update::None;
1289                         break;
1290                 }
1291
1292                 // --- version control -------------------------------
1293                 case LFUN_VC_REGISTER:
1294                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1295                         if (!ensureBufferClean(view()))
1296                                 break;
1297                         if (!lyx_view_->buffer()->lyxvc().inUse()) {
1298                                 lyx_view_->buffer()->lyxvc().registrer();
1299                                 reloadBuffer();
1300                         }
1301                         updateFlags = Update::Force;
1302                         break;
1303
1304                 case LFUN_VC_CHECK_IN:
1305                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1306                         if (!ensureBufferClean(view()))
1307                                 break;
1308                         if (lyx_view_->buffer()->lyxvc().inUse()
1309                                         && !lyx_view_->buffer()->isReadonly()) {
1310                                 lyx_view_->buffer()->lyxvc().checkIn();
1311                                 reloadBuffer();
1312                         }
1313                         break;
1314
1315                 case LFUN_VC_CHECK_OUT:
1316                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1317                         if (!ensureBufferClean(view()))
1318                                 break;
1319                         if (lyx_view_->buffer()->lyxvc().inUse()
1320                                         && lyx_view_->buffer()->isReadonly()) {
1321                                 lyx_view_->buffer()->lyxvc().checkOut();
1322                                 reloadBuffer();
1323                         }
1324                         break;
1325
1326                 case LFUN_VC_REVERT:
1327                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1328                         lyx_view_->buffer()->lyxvc().revert();
1329                         reloadBuffer();
1330                         break;
1331
1332                 case LFUN_VC_UNDO_LAST:
1333                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1334                         lyx_view_->buffer()->lyxvc().undoLast();
1335                         reloadBuffer();
1336                         break;
1337
1338                 // --- buffers ----------------------------------------
1339                 case LFUN_BUFFER_SWITCH:
1340                         BOOST_ASSERT(lyx_view_);
1341                         lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1342                         updateFlags = Update::None;
1343                         break;
1344
1345                 case LFUN_BUFFER_NEXT:
1346                         BOOST_ASSERT(lyx_view_);
1347                         lyx_view_->setBuffer(theBufferList().next(lyx_view_->buffer()));
1348                         updateFlags = Update::None;
1349                         break;
1350
1351                 case LFUN_BUFFER_PREVIOUS:
1352                         BOOST_ASSERT(lyx_view_);
1353                         lyx_view_->setBuffer(theBufferList().previous(lyx_view_->buffer()));
1354                         updateFlags = Update::None;
1355                         break;
1356
1357                 case LFUN_FILE_NEW: {
1358                         BOOST_ASSERT(lyx_view_);
1359                         string name;
1360                         string tmpname = split(argument, name, ':'); // Split filename
1361                         Buffer * const b = newFile(name, tmpname);
1362                         if (b)
1363                                 lyx_view_->setBuffer(b);
1364                         updateFlags = Update::None;
1365                         break;
1366                 }
1367
1368                 case LFUN_FILE_OPEN:
1369                         BOOST_ASSERT(lyx_view_);
1370                         open(argument);
1371                         updateFlags = Update::None;
1372                         break;
1373
1374                 // --- lyxserver commands ----------------------------
1375                 case LFUN_SERVER_GET_NAME:
1376                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1377                         setMessage(from_utf8(lyx_view_->buffer()->absFileName()));
1378                         LYXERR(Debug::INFO) << "FNAME["
1379                                                          << lyx_view_->buffer()->absFileName()
1380                                                          << "] " << endl;
1381                         break;
1382
1383                 case LFUN_SERVER_NOTIFY:
1384                         dispatch_buffer = keyseq.print(KeySequence::Portable);
1385                         theServer().notifyClient(to_utf8(dispatch_buffer));
1386                         break;
1387
1388                 case LFUN_SERVER_GOTO_FILE_ROW: {
1389                         BOOST_ASSERT(lyx_view_);
1390                         string file_name;
1391                         int row;
1392                         istringstream is(argument);
1393                         is >> file_name >> row;
1394                         Buffer * buf = 0;
1395                         bool loaded = false;
1396                         if (prefixIs(file_name, package().temp_dir().absFilename()))
1397                                 // Needed by inverse dvi search. If it is a file
1398                                 // in tmpdir, call the apropriated function
1399                                 buf = theBufferList().getBufferFromTmp(file_name);
1400                         else {
1401                                 // Must replace extension of the file to be .lyx
1402                                 // and get full path
1403                                 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
1404                                 // Either change buffer or load the file
1405                                 if (theBufferList().exists(s.absFilename()))
1406                                         buf = theBufferList().getBuffer(s.absFilename());
1407                                 else {
1408                                         buf = lyx_view_->loadLyXFile(s);
1409                                         loaded = true;
1410                                 }
1411                         }
1412
1413                         if (!buf) {
1414                                 updateFlags = Update::None;
1415                                 break;
1416                         }
1417
1418                         updateLabels(*buf);
1419                         lyx_view_->setBuffer(buf);
1420                         view()->setCursorFromRow(row);
1421                         if (loaded)
1422                                 lyx_view_->errors("Parse");
1423                         updateFlags = Update::FitCursor;
1424                         break;
1425                 }
1426
1427                 case LFUN_DIALOG_SHOW: {
1428                         BOOST_ASSERT(lyx_view_);
1429                         string const name = cmd.getArg(0);
1430                         string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1431
1432                         if (name == "character") {
1433                                 data = freefont2string();
1434                                 if (!data.empty())
1435                                         lyx_view_->showDialogWithData("character", data);
1436                         } else if (name == "latexlog") {
1437                                 Buffer::LogType type; 
1438                                 string const logfile = lyx_view_->buffer()->logName(&type);
1439                                 switch (type) {
1440                                 case Buffer::latexlog:
1441                                         data = "latex ";
1442                                         break;
1443                                 case Buffer::buildlog:
1444                                         data = "literate ";
1445                                         break;
1446                                 }
1447                                 data += Lexer::quoteString(logfile);
1448                                 lyx_view_->showDialogWithData("log", data);
1449                         } else if (name == "vclog") {
1450                                 string const data = "vc " +
1451                                         Lexer::quoteString(lyx_view_->buffer()->lyxvc().getLogFile());
1452                                 lyx_view_->showDialogWithData("log", data);
1453                         } else
1454                                 lyx_view_->showDialogWithData(name, data);
1455                         break;
1456                 }
1457
1458                 case LFUN_DIALOG_SHOW_NEW_INSET: {
1459                         BOOST_ASSERT(lyx_view_);
1460                         string const name = cmd.getArg(0);
1461                         InsetCode code = insetCode(name);
1462                         string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1463                         bool insetCodeOK = true;
1464                         switch (code) {
1465                         case BIBITEM_CODE:
1466                         case BIBTEX_CODE:
1467                         case INDEX_CODE:
1468                         case LABEL_CODE:
1469                         case NOMENCL_CODE:
1470                         case REF_CODE:
1471                         case TOC_CODE:
1472                         case HYPERLINK_CODE: {
1473                                 InsetCommandParams p(code);
1474                                 data = InsetCommandMailer::params2string(name, p);
1475                                 break;
1476                         } 
1477                         case INCLUDE_CODE: {
1478                                 // data is the include type: one of "include",
1479                                 // "input", "verbatiminput" or "verbatiminput*"
1480                                 if (data.empty())
1481                                         // default type is requested
1482                                         data = "include";
1483                                 InsetCommandParams p(INCLUDE_CODE, data);
1484                                 data = InsetCommandMailer::params2string("include", p);
1485                                 break;
1486                         } 
1487                         case BOX_CODE: {
1488                                 // \c data == "Boxed" || "Frameless" etc
1489                                 InsetBoxParams p(data);
1490                                 data = InsetBoxMailer::params2string(p);
1491                                 break;
1492                         } 
1493                         case BRANCH_CODE: {
1494                                 InsetBranchParams p;
1495                                 data = InsetBranchMailer::params2string(p);
1496                                 break;
1497                         } 
1498                         case CITE_CODE: {
1499                                 InsetCommandParams p(CITE_CODE);
1500                                 data = InsetCommandMailer::params2string(name, p);
1501                                 break;
1502                         } 
1503                         case ERT_CODE: {
1504                                 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1505                                 break;
1506                         } 
1507                         case EXTERNAL_CODE: {
1508                                 InsetExternalParams p;
1509                                 Buffer const & buffer = *lyx_view_->buffer();
1510                                 data = InsetExternalMailer::params2string(p, buffer);
1511                                 break;
1512                         } 
1513                         case FLOAT_CODE:  {
1514                                 InsetFloatParams p;
1515                                 data = InsetFloatMailer::params2string(p);
1516                                 break;
1517                         } 
1518                         case LISTINGS_CODE: {
1519                                 InsetListingsParams p;
1520                                 data = InsetListingsMailer::params2string(p);
1521                                 break;
1522                         } 
1523                         case GRAPHICS_CODE: {
1524                                 InsetGraphicsParams p;
1525                                 Buffer const & buffer = *lyx_view_->buffer();
1526                                 data = InsetGraphicsMailer::params2string(p, buffer);
1527                                 break;
1528                         } 
1529                         case NOTE_CODE: {
1530                                 InsetNoteParams p;
1531                                 data = InsetNoteMailer::params2string(p);
1532                                 break;
1533                         } 
1534                         case VSPACE_CODE: {
1535                                 VSpace space;
1536                                 data = InsetVSpaceMailer::params2string(space);
1537                                 break;
1538                         } 
1539                         case WRAP_CODE: {
1540                                 InsetWrapParams p;
1541                                 data = InsetWrapMailer::params2string(p);
1542                                 break;
1543                         }
1544                         default:
1545                                 lyxerr << "Inset type '" << name << 
1546                                         "' not recognized in LFUN_DIALOG_SHOW_NEW_INSET" << std:: endl;
1547                                 insetCodeOK = false;
1548                                 break;
1549                         } // end switch(code)
1550                         if (insetCodeOK)
1551                                 lyx_view_->getDialogs().show(name, data, 0);
1552                         break;
1553                 }
1554
1555                 case LFUN_DIALOG_UPDATE: {
1556                         BOOST_ASSERT(lyx_view_);
1557                         string const & name = argument;
1558                         // Can only update a dialog connected to an existing inset
1559                         Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1560                         if (inset) {
1561                                 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1562                                 inset->dispatch(view()->cursor(), fr);
1563                         } else if (name == "paragraph") {
1564                                 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1565                         } else if (name == "prefs") {
1566                                 lyx_view_->updateDialog(name, string());
1567                         }
1568                         break;
1569                 }
1570
1571                 case LFUN_DIALOG_HIDE:
1572                         LyX::cref().hideDialogs(argument, 0);
1573                         break;
1574
1575                 case LFUN_DIALOG_TOGGLE: {
1576                         BOOST_ASSERT(lyx_view_);
1577                         if (lyx_view_->getDialogs().visible(cmd.getArg(0)))
1578                                 dispatch(FuncRequest(LFUN_DIALOG_HIDE, argument));
1579                         else
1580                                 dispatch(FuncRequest(LFUN_DIALOG_SHOW, argument));
1581                         break;
1582                 }
1583
1584                 case LFUN_DIALOG_DISCONNECT_INSET:
1585                         BOOST_ASSERT(lyx_view_);
1586                         lyx_view_->getDialogs().disconnect(argument);
1587                         break;
1588
1589
1590                 case LFUN_CITATION_INSERT: {
1591                         BOOST_ASSERT(lyx_view_);
1592                         if (!argument.empty()) {
1593                                 // we can have one optional argument, delimited by '|'
1594                                 // citation-insert <key>|<text_before>
1595                                 // this should be enhanced to also support text_after
1596                                 // and citation style
1597                                 string arg = argument;
1598                                 string opt1;
1599                                 if (contains(argument, "|")) {
1600                                         arg = token(argument, '|', 0);
1601                                         opt1 = token(argument, '|', 1);
1602                                 }
1603                                 InsetCommandParams icp(CITE_CODE);
1604                                 icp["key"] = from_utf8(arg);
1605                                 if (!opt1.empty())
1606                                         icp["before"] = from_utf8(opt1);
1607                                 string icstr = InsetCommandMailer::params2string("citation", icp);
1608                                 FuncRequest fr(LFUN_INSET_INSERT, icstr);
1609                                 dispatch(fr);
1610                         } else
1611                                 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
1612                         break;
1613                 }
1614
1615                 case LFUN_BUFFER_CHILD_OPEN: {
1616                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1617                         Buffer * parent = lyx_view_->buffer();
1618                         FileName filename = makeAbsPath(argument, parent->filePath());
1619                         view()->saveBookmark(false);
1620                         Buffer * child = 0;
1621                         bool parsed = false;
1622                         if (theBufferList().exists(filename.absFilename())) {
1623                                 child = theBufferList().getBuffer(filename.absFilename());
1624                         } else {
1625                                 setMessage(bformat(_("Opening child document %1$s..."),
1626                                         makeDisplayPath(filename.absFilename())));
1627                                 child = lyx_view_->loadLyXFile(filename, true);
1628                                 parsed = true;
1629                         }
1630                         if (child) {
1631                                 // Set the parent name of the child document.
1632                                 // This makes insertion of citations and references in the child work,
1633                                 // when the target is in the parent or another child document.
1634                                 child->setParentName(parent->absFileName());
1635                                 updateLabels(*child->masterBuffer());
1636                                 lyx_view_->setBuffer(child);
1637                                 if (parsed)
1638                                         lyx_view_->errors("Parse");
1639                         }
1640
1641                         // If a screen update is required (in case where auto_open is false), 
1642                         // setBuffer() would have taken care of it already. Otherwise we shall 
1643                         // reset the update flag because it can cause a circular problem.
1644                         // See bug 3970.
1645                         updateFlags = Update::None;
1646                         break;
1647                 }
1648
1649                 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1650                         BOOST_ASSERT(lyx_view_);
1651                         lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1652                         break;
1653
1654                 case LFUN_KEYMAP_OFF:
1655                         BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1656                         lyx_view_->view()->getIntl().keyMapOn(false);
1657                         break;
1658
1659                 case LFUN_KEYMAP_PRIMARY:
1660                         BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1661                         lyx_view_->view()->getIntl().keyMapPrim();
1662                         break;
1663
1664                 case LFUN_KEYMAP_SECONDARY:
1665                         BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1666                         lyx_view_->view()->getIntl().keyMapSec();
1667                         break;
1668
1669                 case LFUN_KEYMAP_TOGGLE:
1670                         BOOST_ASSERT(lyx_view_ && lyx_view_->view());
1671                         lyx_view_->view()->getIntl().toggleKeyMap();
1672                         break;
1673
1674                 case LFUN_REPEAT: {
1675                         // repeat command
1676                         string countstr;
1677                         string rest = split(argument, countstr, ' ');
1678                         istringstream is(countstr);
1679                         int count = 0;
1680                         is >> count;
1681                         lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1682                         for (int i = 0; i < count; ++i)
1683                                 dispatch(lyxaction.lookupFunc(rest));
1684                         break;
1685                 }
1686
1687                 case LFUN_COMMAND_SEQUENCE: {
1688                         // argument contains ';'-terminated commands
1689                         string arg = argument;
1690                         while (!arg.empty()) {
1691                                 string first;
1692                                 arg = split(arg, first, ';');
1693                                 FuncRequest func(lyxaction.lookupFunc(first));
1694                                 func.origin = cmd.origin;
1695                                 dispatch(func);
1696                         }
1697                         break;
1698                 }
1699
1700                 case LFUN_CALL: {
1701                         FuncRequest func;
1702                         if (LyX::ref().topLevelCmdDef().lock(argument, func)) {
1703                                 func.origin = cmd.origin;
1704                                 dispatch(func);
1705                                 LyX::ref().topLevelCmdDef().release(argument);
1706                         } else {
1707                                 if (func.action == LFUN_UNKNOWN_ACTION) {
1708                                         // unknown command definition
1709                                         lyxerr << "Warning: unknown command definition `"
1710                                                    << argument << "'"
1711                                                    << endl;
1712                                 } else {
1713                                         // recursion detected
1714                                         lyxerr << "Warning: Recursion in the command definition `"
1715                                                    << argument << "' detected"
1716                                                    << endl;
1717                                 }
1718                         }
1719                         break;
1720                 }
1721
1722                 case LFUN_PREFERENCES_SAVE: {
1723                         lyxrc.write(makeAbsPath("preferences",
1724                                                 package().user_support().absFilename()),
1725                                     false);
1726                         break;
1727                 }
1728
1729                 case LFUN_SCREEN_FONT_UPDATE:
1730                         BOOST_ASSERT(lyx_view_);
1731                         // handle the screen font changes.
1732                         theFontLoader().update();
1733                         /// FIXME: only the current view will be updated. the Gui
1734                         /// class is able to furnish the list of views.
1735                         updateFlags = Update::Force;
1736                         break;
1737
1738                 case LFUN_SET_COLOR: {
1739                         string lyx_name;
1740                         string const x11_name = split(argument, lyx_name, ' ');
1741                         if (lyx_name.empty() || x11_name.empty()) {
1742                                 setErrorMessage(from_ascii(N_(
1743                                                 "Syntax: set-color <lyx_name>"
1744                                                 " <x11_name>")));
1745                                 break;
1746                         }
1747
1748                         bool const graphicsbg_changed =
1749                                 (lyx_name == lcolor.getLyXName(Color_graphicsbg) &&
1750                                  x11_name != lcolor.getX11Name(Color_graphicsbg));
1751
1752                         if (!lcolor.setColor(lyx_name, x11_name)) {
1753                                 setErrorMessage(
1754                                                 bformat(_("Set-color \"%1$s\" failed "
1755                                                                        "- color is undefined or "
1756                                                                        "may not be redefined"),
1757                                                                            from_utf8(lyx_name)));
1758                                 break;
1759                         }
1760
1761                         theApp()->updateColor(lcolor.getFromLyXName(lyx_name));
1762
1763                         if (graphicsbg_changed) {
1764                                 // FIXME: The graphics cache no longer has a changeDisplay method.
1765 #if 0
1766                                 graphics::GCache::get().changeDisplay(true);
1767 #endif
1768                         }
1769                         break;
1770                 }
1771
1772                 case LFUN_MESSAGE:
1773                         BOOST_ASSERT(lyx_view_);
1774                         lyx_view_->message(from_utf8(argument));
1775                         break;
1776
1777                 case LFUN_EXTERNAL_EDIT: {
1778                         BOOST_ASSERT(lyx_view_);
1779                         FuncRequest fr(action, argument);
1780                         InsetExternal().dispatch(view()->cursor(), fr);
1781                         break;
1782                 }
1783
1784                 case LFUN_GRAPHICS_EDIT: {
1785                         FuncRequest fr(action, argument);
1786                         InsetGraphics().dispatch(view()->cursor(), fr);
1787                         break;
1788                 }
1789
1790                 case LFUN_INSET_APPLY: {
1791                         BOOST_ASSERT(lyx_view_);
1792                         string const name = cmd.getArg(0);
1793                         Inset * inset = lyx_view_->getDialogs().getOpenInset(name);
1794                         if (inset) {
1795                                 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1796                                 inset->dispatch(view()->cursor(), fr);
1797                         } else {
1798                                 FuncRequest fr(LFUN_INSET_INSERT, argument);
1799                                 dispatch(fr);
1800                         }
1801                         // ideally, the update flag should be set by the insets,
1802                         // but this is not possible currently
1803                         updateFlags = Update::Force | Update::FitCursor;
1804                         break;
1805                 }
1806
1807                 case LFUN_ALL_INSETS_TOGGLE: {
1808                         BOOST_ASSERT(lyx_view_);
1809                         string action;
1810                         string const name = split(argument, action, ' ');
1811                         InsetCode const inset_code = insetCode(name);
1812
1813                         Cursor & cur = view()->cursor();
1814                         FuncRequest fr(LFUN_INSET_TOGGLE, action);
1815
1816                         Inset & inset = lyx_view_->buffer()->inset();
1817                         InsetIterator it  = inset_iterator_begin(inset);
1818                         InsetIterator const end = inset_iterator_end(inset);
1819                         for (; it != end; ++it) {
1820                                 if (!it->asInsetMath()
1821                                     && (inset_code == NO_CODE
1822                                     || inset_code == it->lyxCode())) {
1823                                         Cursor tmpcur = cur;
1824                                         tmpcur.pushBackward(*it);
1825                                         it->dispatch(tmpcur, fr);
1826                                 }
1827                         }
1828                         updateFlags = Update::Force | Update::FitCursor;
1829                         break;
1830                 }
1831
1832                 case LFUN_BUFFER_LANGUAGE: {
1833                         BOOST_ASSERT(lyx_view_);
1834                         Buffer & buffer = *lyx_view_->buffer();
1835                         Language const * oldL = buffer.params().language;
1836                         Language const * newL = languages.getLanguage(argument);
1837                         if (!newL || oldL == newL)
1838                                 break;
1839
1840                         if (oldL->rightToLeft() == newL->rightToLeft()
1841                             && !buffer.isMultiLingual())
1842                                 buffer.changeLanguage(oldL, newL);
1843                         break;
1844                 }
1845
1846                 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1847                         string const fname =
1848                                 addName(addPath(package().user_support().absFilename(), "templates/"),
1849                                         "defaults.lyx");
1850                         Buffer defaults(fname);
1851
1852                         istringstream ss(argument);
1853                         Lexer lex(0,0);
1854                         lex.setStream(ss);
1855                         int const unknown_tokens = defaults.readHeader(lex);
1856
1857                         if (unknown_tokens != 0) {
1858                                 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1859                                        << unknown_tokens << " unknown token"
1860                                        << (unknown_tokens == 1 ? "" : "s")
1861                                        << endl;
1862                         }
1863
1864                         if (defaults.writeFile(FileName(defaults.absFileName())))
1865                                 setMessage(bformat(_("Document defaults saved in %1$s"),
1866                                                    makeDisplayPath(fname)));
1867                         else
1868                                 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1869                         break;
1870                 }
1871
1872                 case LFUN_BUFFER_PARAMS_APPLY: {
1873                         BOOST_ASSERT(lyx_view_);
1874                         biblio::CiteEngine const oldEngine =
1875                                         lyx_view_->buffer()->params().getEngine();
1876                         
1877                         Buffer * buffer = lyx_view_->buffer();
1878
1879                         TextClassPtr oldClass = buffer->params().getTextClassPtr();
1880
1881                         Cursor & cur = view()->cursor();
1882                         cur.recordUndoFullDocument();
1883                         
1884                         istringstream ss(argument);
1885                         Lexer lex(0,0);
1886                         lex.setStream(ss);
1887                         int const unknown_tokens = buffer->readHeader(lex);
1888
1889                         if (unknown_tokens != 0) {
1890                                 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1891                                                 << unknown_tokens << " unknown token"
1892                                                 << (unknown_tokens == 1 ? "" : "s")
1893                                                 << endl;
1894                         }
1895                         
1896                         updateLayout(oldClass, buffer);
1897                         
1898                         biblio::CiteEngine const newEngine =
1899                                         lyx_view_->buffer()->params().getEngine();
1900                         
1901                         if (oldEngine != newEngine) {
1902                                 FuncRequest fr(LFUN_INSET_REFRESH);
1903         
1904                                 Inset & inset = lyx_view_->buffer()->inset();
1905                                 InsetIterator it  = inset_iterator_begin(inset);
1906                                 InsetIterator const end = inset_iterator_end(inset);
1907                                 for (; it != end; ++it)
1908                                         if (it->lyxCode() == CITE_CODE)
1909                                                 it->dispatch(cur, fr);
1910                         }
1911                         
1912                         updateFlags = Update::Force | Update::FitCursor;
1913                         break;
1914                 }
1915                 
1916                 case LFUN_LAYOUT_MODULES_CLEAR: {
1917                         BOOST_ASSERT(lyx_view_);
1918                         Buffer * buffer = lyx_view_->buffer();
1919                         TextClassPtr oldClass = buffer->params().getTextClassPtr();
1920                         view()->cursor().recordUndoFullDocument();
1921                         buffer->params().clearLayoutModules();
1922                         updateLayout(oldClass, buffer);
1923                         updateFlags = Update::Force | Update::FitCursor;
1924                         break;
1925                 }
1926                 
1927                 case LFUN_LAYOUT_MODULE_ADD: {
1928                         BOOST_ASSERT(lyx_view_);
1929                         Buffer * buffer = lyx_view_->buffer();
1930                         TextClassPtr oldClass = buffer->params().getTextClassPtr();
1931                         view()->cursor().recordUndoFullDocument();
1932                         buffer->params().addLayoutModule(argument);
1933                         updateLayout(oldClass, buffer);
1934                         updateFlags = Update::Force | Update::FitCursor;
1935                         break;
1936                 }
1937
1938                 case LFUN_TEXTCLASS_APPLY: {
1939                         BOOST_ASSERT(lyx_view_);
1940                         Buffer * buffer = lyx_view_->buffer();
1941
1942                         loadTextClass(argument);
1943
1944                         std::pair<bool, textclass_type> const tc_pair =
1945                                 textclasslist.numberOfClass(argument);
1946
1947                         if (!tc_pair.first)
1948                                 break;
1949
1950                         textclass_type const old_class = buffer->params().getBaseClass();
1951                         textclass_type const new_class = tc_pair.second;
1952
1953                         if (old_class == new_class)
1954                                 // nothing to do
1955                                 break;
1956
1957                         //Save the old, possibly modular, layout for use in conversion.
1958                         TextClassPtr oldClass = buffer->params().getTextClassPtr();
1959                         view()->cursor().recordUndoFullDocument();
1960                         buffer->params().setBaseClass(new_class);
1961                         updateLayout(oldClass, buffer);
1962                         updateFlags = Update::Force | Update::FitCursor;
1963                         break;
1964                 }
1965                 
1966                 case LFUN_LAYOUT_RELOAD: {
1967                         BOOST_ASSERT(lyx_view_);
1968                         Buffer * buffer = lyx_view_->buffer();
1969                         TextClassPtr oldClass = buffer->params().getTextClassPtr();
1970                         textclass_type const tc = buffer->params().getBaseClass();
1971                         textclasslist.reset(tc);
1972                         buffer->params().setBaseClass(tc);
1973                         updateLayout(oldClass, buffer);
1974                         updateFlags = Update::Force | Update::FitCursor;
1975                         break;
1976                 }
1977
1978                 case LFUN_TEXTCLASS_LOAD:
1979                         loadTextClass(argument);
1980                         break;
1981
1982                 case LFUN_LYXRC_APPLY: {
1983                         LyXRC const lyxrc_orig = lyxrc;
1984
1985                         istringstream ss(argument);
1986                         bool const success = lyxrc.read(ss) == 0;
1987
1988                         if (!success) {
1989                                 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1990                                        << "Unable to read lyxrc data"
1991                                        << endl;
1992                                 break;
1993                         }
1994
1995                         actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1996
1997                         if (lyx_view_ && lyx_view_->buffer())
1998                                 lyx_view_->updateLayoutChoice(true);
1999
2000                         /// We force the redraw in any case because there might be
2001                         /// some screen font changes.
2002                         /// FIXME: only the current view will be updated. the Gui
2003                         /// class is able to furnish the list of views.
2004                         updateFlags = Update::Force;
2005                         break;
2006                 }
2007
2008                 case LFUN_WINDOW_NEW:
2009                         LyX::ref().newLyXView();
2010                         break;
2011
2012                 case LFUN_WINDOW_CLOSE:
2013                         BOOST_ASSERT(lyx_view_);
2014                         BOOST_ASSERT(theApp());
2015                         // update bookmark pit of the current buffer before window close
2016                         for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2017                                 gotoBookmark(i+1, false, false);
2018                         // ask the user for saving changes or cancel quit
2019                         if (!theBufferList().quitWriteAll())
2020                                 break;
2021                         lyx_view_->close();
2022                         return;
2023
2024                 case LFUN_BOOKMARK_GOTO:
2025                         // go to bookmark, open unopened file and switch to buffer if necessary
2026                         gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
2027                         break;
2028
2029                 case LFUN_BOOKMARK_CLEAR:
2030                         LyX::ref().session().bookmarks().clear();
2031                         break;
2032
2033                 default: {
2034                         BOOST_ASSERT(lyx_view_);
2035                         view()->cursor().dispatch(cmd);
2036                         updateFlags = view()->cursor().result().update();
2037                         if (!view()->cursor().result().dispatched())
2038                                 updateFlags = view()->dispatch(cmd);
2039                         break;
2040                 }
2041                 }
2042
2043                 if (lyx_view_ && lyx_view_->buffer()) {
2044                         // BufferView::update() updates the ViewMetricsInfo and
2045                         // also initializes the position cache for all insets in
2046                         // (at least partially) visible top-level paragraphs.
2047                         // We will redraw the screen only if needed.
2048                         view()->processUpdateFlags(updateFlags);
2049                         lyx_view_->updateStatusBar();
2050
2051                         // if we executed a mutating lfun, mark the buffer as dirty
2052                         if (flag.enabled()
2053                             && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
2054                             && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
2055                                 lyx_view_->buffer()->markDirty();
2056
2057                         //Do we have a selection?
2058                         theSelection().haveSelection(view()->cursor().selection());
2059
2060                         if (view()->cursor().inTexted()) {
2061                                 lyx_view_->updateLayoutChoice(false);
2062                         }
2063                 }
2064         }
2065         if (!quitting && lyx_view_) {
2066                 lyx_view_->updateToolbars();
2067                 // Some messages may already be translated, so we cannot use _()
2068                 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
2069         }
2070 }
2071
2072
2073 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
2074 {
2075         const bool verbose = (cmd.origin == FuncRequest::MENU
2076                               || cmd.origin == FuncRequest::TOOLBAR
2077                               || cmd.origin == FuncRequest::COMMANDBUFFER);
2078
2079         if (cmd.action == LFUN_SELF_INSERT || !verbose) {
2080                 LYXERR(Debug::ACTION) << "dispatch msg is " << to_utf8(msg) << endl;
2081                 if (!msg.empty())
2082                         lyx_view_->message(msg);
2083                 return;
2084         }
2085
2086         docstring dispatch_msg = msg;
2087         if (!dispatch_msg.empty())
2088                 dispatch_msg += ' ';
2089
2090         docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
2091
2092         bool argsadded = false;
2093
2094         if (!cmd.argument().empty()) {
2095                 if (cmd.action != LFUN_UNKNOWN_ACTION) {
2096                         comname += ' ' + cmd.argument();
2097                         argsadded = true;
2098                 }
2099         }
2100
2101         docstring const shortcuts = theTopLevelKeymap().printBindings(cmd);
2102
2103         if (!shortcuts.empty())
2104                 comname += ": " + shortcuts;
2105         else if (!argsadded && !cmd.argument().empty())
2106                 comname += ' ' + cmd.argument();
2107
2108         if (!comname.empty()) {
2109                 comname = rtrim(comname);
2110                 dispatch_msg += '(' + rtrim(comname) + ')';
2111         }
2112
2113         LYXERR(Debug::ACTION) << "verbose dispatch msg "
2114                 << to_utf8(dispatch_msg) << endl;
2115         if (!dispatch_msg.empty())
2116                 lyx_view_->message(dispatch_msg);
2117 }
2118
2119
2120 void LyXFunc::menuNew(string const & name, bool fromTemplate)
2121 {
2122         // FIXME: initpath is not used. What to do?
2123         string initpath = lyxrc.document_path;
2124         string filename(name);
2125
2126         if (lyx_view_->buffer()) {
2127                 string const trypath = lyx_view_->buffer()->filePath();
2128                 // If directory is writeable, use this as default.
2129                 if (FileName(trypath).isDirWritable())
2130                         initpath = trypath;
2131         }
2132
2133         static int newfile_number;
2134
2135         if (filename.empty()) {
2136                 filename = addName(lyxrc.document_path,
2137                             "newfile" + convert<string>(++newfile_number) + ".lyx");
2138                 while (theBufferList().exists(filename) ||
2139                        FileName(filename).isReadable()) {
2140                         ++newfile_number;
2141                         filename = addName(lyxrc.document_path,
2142                                            "newfile" +  convert<string>(newfile_number) +
2143                                     ".lyx");
2144                 }
2145         }
2146
2147         // The template stuff
2148         string templname;
2149         if (fromTemplate) {
2150                 FileDialog dlg(_("Select template file"));
2151                 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
2152                 dlg.setButton1(_("Templates|#T#t"), from_utf8(lyxrc.template_path));
2153
2154                 FileDialog::Result result =
2155                         dlg.open(from_utf8(lyxrc.template_path),
2156                                      FileFilterList(_("LyX Documents (*.lyx)")),
2157                                      docstring());
2158
2159                 if (result.first == FileDialog::Later)
2160                         return;
2161                 if (result.second.empty())
2162                         return;
2163                 templname = to_utf8(result.second);
2164         }
2165
2166         Buffer * const b = newFile(filename, templname, !name.empty());
2167         if (b)
2168                 lyx_view_->setBuffer(b);
2169 }
2170
2171
2172 void LyXFunc::open(string const & fname)
2173 {
2174         string initpath = lyxrc.document_path;
2175
2176         if (lyx_view_->buffer()) {
2177                 string const trypath = lyx_view_->buffer()->filePath();
2178                 // If directory is writeable, use this as default.
2179                 if (FileName(trypath).isDirWritable())
2180                         initpath = trypath;
2181         }
2182
2183         string filename;
2184
2185         if (fname.empty()) {
2186                 FileDialog dlg(_("Select document to open"), LFUN_FILE_OPEN);
2187                 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
2188                 dlg.setButton2(_("Examples|#E#e"),
2189                                 from_utf8(addPath(package().system_support().absFilename(), "examples")));
2190
2191                 FileDialog::Result result =
2192                         dlg.open(from_utf8(initpath),
2193                                      FileFilterList(_("LyX Documents (*.lyx)")),
2194                                      docstring());
2195
2196                 if (result.first == FileDialog::Later)
2197                         return;
2198
2199                 filename = to_utf8(result.second);
2200
2201                 // check selected filename
2202                 if (filename.empty()) {
2203                         lyx_view_->message(_("Canceled."));
2204                         return;
2205                 }
2206         } else
2207                 filename = fname;
2208
2209         // get absolute path of file and add ".lyx" to the filename if
2210         // necessary
2211         FileName const fullname = fileSearch(string(), filename, "lyx");
2212         if (!fullname.empty())
2213                 filename = fullname.absFilename();
2214
2215         // if the file doesn't exist, let the user create one
2216         if (!fullname.exists()) {
2217                 // the user specifically chose this name. Believe him.
2218                 Buffer * const b = newFile(filename, string(), true);
2219                 if (b)
2220                         lyx_view_->setBuffer(b);
2221                 return;
2222         }
2223
2224         docstring const disp_fn = makeDisplayPath(filename);
2225         lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
2226
2227         docstring str2;
2228         Buffer * buf = lyx_view_->loadLyXFile(fullname);
2229         if (buf) {
2230                 updateLabels(*buf);
2231                 lyx_view_->setBuffer(buf);
2232                 lyx_view_->errors("Parse");
2233                 str2 = bformat(_("Document %1$s opened."), disp_fn);
2234         } else {
2235                 str2 = bformat(_("Could not open document %1$s"), disp_fn);
2236         }
2237         lyx_view_->message(str2);
2238 }
2239
2240
2241 void LyXFunc::doImport(string const & argument)
2242 {
2243         string format;
2244         string filename = split(argument, format, ' ');
2245
2246         LYXERR(Debug::INFO) << "LyXFunc::doImport: " << format
2247                             << " file: " << filename << endl;
2248
2249         // need user interaction
2250         if (filename.empty()) {
2251                 string initpath = lyxrc.document_path;
2252
2253                 if (lyx_view_->buffer()) {
2254                         string const trypath = lyx_view_->buffer()->filePath();
2255                         // If directory is writeable, use this as default.
2256                         if (FileName(trypath).isDirWritable())
2257                                 initpath = trypath;
2258                 }
2259
2260                 docstring const text = bformat(_("Select %1$s file to import"),
2261                         formats.prettyName(format));
2262
2263                 FileDialog dlg(text, LFUN_BUFFER_IMPORT);
2264                 dlg.setButton1(_("Documents|#o#O"), from_utf8(lyxrc.document_path));
2265                 dlg.setButton2(_("Examples|#E#e"),
2266                         from_utf8(addPath(package().system_support().absFilename(), "examples")));
2267
2268                 docstring filter = formats.prettyName(format);
2269                 filter += " (*.";
2270                 // FIXME UNICODE
2271                 filter += from_utf8(formats.extension(format));
2272                 filter += ')';
2273
2274                 FileDialog::Result result =
2275                         dlg.open(from_utf8(initpath),
2276                                      FileFilterList(filter),
2277                                      docstring());
2278
2279                 if (result.first == FileDialog::Later)
2280                         return;
2281
2282                 filename = to_utf8(result.second);
2283
2284                 // check selected filename
2285                 if (filename.empty())
2286                         lyx_view_->message(_("Canceled."));
2287         }
2288
2289         if (filename.empty())
2290                 return;
2291
2292         // get absolute path of file
2293         FileName const fullname(makeAbsPath(filename));
2294
2295         FileName const lyxfile(changeExtension(fullname.absFilename(), ".lyx"));
2296
2297         // Check if the document already is open
2298         if (use_gui && theBufferList().exists(lyxfile.absFilename())) {
2299                 if (!theBufferList().close(theBufferList().getBuffer(lyxfile.absFilename()), true)) {
2300                         lyx_view_->message(_("Canceled."));
2301                         return;
2302                 }
2303         }
2304
2305         // if the file exists already, and we didn't do
2306         // -i lyx thefile.lyx, warn
2307         if (lyxfile.exists() && fullname != lyxfile) {
2308                 docstring const file = makeDisplayPath(lyxfile.absFilename(), 30);
2309
2310                 docstring text = bformat(_("The document %1$s already exists.\n\n"
2311                                                      "Do you want to overwrite that document?"), file);
2312                 int const ret = Alert::prompt(_("Overwrite document?"),
2313                         text, 0, 1, _("&Overwrite"), _("&Cancel"));
2314
2315                 if (ret == 1) {
2316                         lyx_view_->message(_("Canceled."));
2317                         return;
2318                 }
2319         }
2320
2321         ErrorList errorList;
2322         import(lyx_view_, fullname, format, errorList);
2323         // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
2324 }
2325
2326
2327 void LyXFunc::closeBuffer()
2328 {
2329         // goto bookmark to update bookmark pit.
2330         for (size_t i = 0; i < LyX::ref().session().bookmarks().size(); ++i)
2331                 gotoBookmark(i+1, false, false);
2332         
2333         theBufferList().close(lyx_view_->buffer(), true);
2334 }
2335
2336
2337 void LyXFunc::reloadBuffer()
2338 {
2339         FileName filename(lyx_view_->buffer()->absFileName());
2340         docstring const disp_fn = makeDisplayPath(filename.absFilename());
2341         docstring str;
2342         closeBuffer();
2343         Buffer * buf = lyx_view_->loadLyXFile(filename);
2344         if (buf) {
2345                 updateLabels(*buf);
2346                 lyx_view_->setBuffer(buf);
2347                 lyx_view_->errors("Parse");
2348                 str = bformat(_("Document %1$s reloaded."), disp_fn);
2349         } else {
2350                 str = bformat(_("Could not reload document %1$s"), disp_fn);
2351         }
2352         lyx_view_->message(str);
2353 }
2354
2355 // Each "lyx_view_" should have it's own message method. lyxview and
2356 // the minibuffer would use the minibuffer, but lyxserver would
2357 // send an ERROR signal to its client.  Alejandro 970603
2358 // This function is bit problematic when it comes to NLS, to make the
2359 // lyx servers client be language indepenent we must not translate
2360 // strings sent to this func.
2361 void LyXFunc::setErrorMessage(docstring const & m) const
2362 {
2363         dispatch_buffer = m;
2364         errorstat = true;
2365 }
2366
2367
2368 void LyXFunc::setMessage(docstring const & m) const
2369 {
2370         dispatch_buffer = m;
2371 }
2372
2373
2374 docstring const LyXFunc::viewStatusMessage()
2375 {
2376         // When meta-fake key is pressed, show the key sequence so far + "M-".
2377         if (wasMetaKey())
2378                 return keyseq.print(KeySequence::ForGui) + "M-";
2379
2380         // Else, when a non-complete key sequence is pressed,
2381         // show the available options.
2382         if (keyseq.length() > 0 && !keyseq.deleted())
2383                 return keyseq.printOptions(true);
2384
2385         BOOST_ASSERT(lyx_view_);
2386         if (!lyx_view_->buffer())
2387                 return _("Welcome to LyX!");
2388
2389         return view()->cursor().currentState();
2390 }
2391
2392
2393 BufferView * LyXFunc::view() const
2394 {
2395         BOOST_ASSERT(lyx_view_);
2396         return lyx_view_->view();
2397 }
2398
2399
2400 bool LyXFunc::wasMetaKey() const
2401 {
2402         return (meta_fake_bit != NoModifier);
2403 }
2404
2405
2406 void LyXFunc::updateLayout(TextClassPtr const & oldlayout,
2407                            Buffer * buffer)
2408 {
2409         lyx_view_->message(_("Converting document to new document class..."));
2410         
2411         StableDocIterator backcur(view()->cursor());
2412         ErrorList & el = buffer->errorList("Class Switch");
2413         cap::switchBetweenClasses(
2414                         oldlayout, buffer->params().getTextClassPtr(),
2415                         static_cast<InsetText &>(buffer->inset()), el);
2416
2417         view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
2418
2419         buffer->errors("Class Switch");
2420         updateLabels(*buffer);
2421 }
2422
2423
2424 namespace {
2425
2426 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2427 {
2428         // Why the switch you might ask. It is a trick to ensure that all
2429         // the elements in the LyXRCTags enum is handled. As you can see
2430         // there are no breaks at all. So it is just a huge fall-through.
2431         // The nice thing is that we will get a warning from the compiler
2432         // if we forget an element.
2433         LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2434         switch (tag) {
2435         case LyXRC::RC_ACCEPT_COMPOUND:
2436         case LyXRC::RC_ALT_LANG:
2437         case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
2438         case LyXRC::RC_PLAINTEXT_LINELEN:
2439         case LyXRC::RC_AUTOREGIONDELETE:
2440         case LyXRC::RC_AUTORESET_OPTIONS:
2441         case LyXRC::RC_AUTOSAVE:
2442         case LyXRC::RC_AUTO_NUMBER:
2443         case LyXRC::RC_BACKUPDIR_PATH:
2444         case LyXRC::RC_BIBTEX_COMMAND:
2445         case LyXRC::RC_BINDFILE:
2446         case LyXRC::RC_CHECKLASTFILES:
2447         case LyXRC::RC_USELASTFILEPOS:
2448         case LyXRC::RC_LOADSESSION:
2449         case LyXRC::RC_CHKTEX_COMMAND:
2450         case LyXRC::RC_CONVERTER:
2451         case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
2452         case LyXRC::RC_COPIER:
2453         case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2454         case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2455         case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2456         case LyXRC::RC_DATE_INSERT_FORMAT:
2457         case LyXRC::RC_DEFAULT_LANGUAGE:
2458         case LyXRC::RC_DEFAULT_PAPERSIZE:
2459         case LyXRC::RC_DEFFILE:
2460         case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2461         case LyXRC::RC_DISPLAY_GRAPHICS:
2462         case LyXRC::RC_DOCUMENTPATH:
2463                 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2464                         FileName path(lyxrc_new.document_path);
2465                         if (path.exists() && path.isDirectory())
2466                                 support::package().document_dir() = FileName(lyxrc.document_path);
2467                 }
2468         case LyXRC::RC_ESC_CHARS:
2469         case LyXRC::RC_FONT_ENCODING:
2470         case LyXRC::RC_FORMAT:
2471         case LyXRC::RC_INDEX_COMMAND:
2472         case LyXRC::RC_INPUT:
2473         case LyXRC::RC_KBMAP:
2474         case LyXRC::RC_KBMAP_PRIMARY:
2475         case LyXRC::RC_KBMAP_SECONDARY:
2476         case LyXRC::RC_LABEL_INIT_LENGTH:
2477         case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2478         case LyXRC::RC_LANGUAGE_AUTO_END:
2479         case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2480         case LyXRC::RC_LANGUAGE_COMMAND_END:
2481         case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2482         case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2483         case LyXRC::RC_LANGUAGE_PACKAGE:
2484         case LyXRC::RC_LANGUAGE_USE_BABEL:
2485         case LyXRC::RC_MAKE_BACKUP:
2486         case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2487         case LyXRC::RC_NUMLASTFILES:
2488         case LyXRC::RC_PATH_PREFIX:
2489                 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2490                         support::prependEnvPath("PATH", lyxrc.path_prefix);
2491                 }
2492         case LyXRC::RC_PERS_DICT:
2493         case LyXRC::RC_PREVIEW:
2494         case LyXRC::RC_PREVIEW_HASHED_LABELS:
2495         case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2496         case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2497         case LyXRC::RC_PRINTCOPIESFLAG:
2498         case LyXRC::RC_PRINTER:
2499         case LyXRC::RC_PRINTEVENPAGEFLAG:
2500         case LyXRC::RC_PRINTEXSTRAOPTIONS:
2501         case LyXRC::RC_PRINTFILEEXTENSION:
2502         case LyXRC::RC_PRINTLANDSCAPEFLAG:
2503         case LyXRC::RC_PRINTODDPAGEFLAG:
2504         case LyXRC::RC_PRINTPAGERANGEFLAG:
2505         case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2506         case LyXRC::RC_PRINTPAPERFLAG:
2507         case LyXRC::RC_PRINTREVERSEFLAG:
2508         case LyXRC::RC_PRINTSPOOL_COMMAND:
2509         case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2510         case LyXRC::RC_PRINTTOFILE:
2511         case LyXRC::RC_PRINTTOPRINTER:
2512         case LyXRC::RC_PRINT_ADAPTOUTPUT:
2513         case LyXRC::RC_PRINT_COMMAND:
2514         case LyXRC::RC_RTL_SUPPORT:
2515         case LyXRC::RC_SCREEN_DPI:
2516         case LyXRC::RC_SCREEN_FONT_ROMAN:
2517         case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2518         case LyXRC::RC_SCREEN_FONT_SANS:
2519         case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2520         case LyXRC::RC_SCREEN_FONT_SCALABLE:
2521         case LyXRC::RC_SCREEN_FONT_SIZES:
2522         case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2523         case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2524         case LyXRC::RC_SCREEN_GEOMETRY_HEIGHT:
2525         case LyXRC::RC_SCREEN_GEOMETRY_WIDTH:
2526         case LyXRC::RC_SCREEN_GEOMETRY_XYSAVED:
2527         case LyXRC::RC_SCREEN_ZOOM:
2528         case LyXRC::RC_SERVERPIPE:
2529         case LyXRC::RC_SET_COLOR:
2530         case LyXRC::RC_SHOW_BANNER:
2531         case LyXRC::RC_SPELL_COMMAND:
2532         case LyXRC::RC_TEMPDIRPATH:
2533         case LyXRC::RC_TEMPLATEPATH:
2534         case LyXRC::RC_TEX_ALLOWS_SPACES:
2535         case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2536                 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2537                         support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2538                 }
2539         case LyXRC::RC_UIFILE:
2540         case LyXRC::RC_USER_EMAIL:
2541         case LyXRC::RC_USER_NAME:
2542         case LyXRC::RC_USETEMPDIR:
2543         case LyXRC::RC_USE_ALT_LANG:
2544         case LyXRC::RC_USE_CONVERTER_CACHE:
2545         case LyXRC::RC_USE_ESC_CHARS:
2546         case LyXRC::RC_USE_INP_ENC:
2547         case LyXRC::RC_USE_PERS_DICT:
2548         case LyXRC::RC_USE_PIXMAP_CACHE:
2549         case LyXRC::RC_USE_SPELL_LIB:
2550         case LyXRC::RC_VIEWDVI_PAPEROPTION:
2551         case LyXRC::RC_SORT_LAYOUTS:
2552         case LyXRC::RC_VIEWER:
2553         case LyXRC::RC_LAST:
2554                 break;
2555         }
2556 }
2557
2558 } // namespace anon
2559
2560
2561 } // namespace lyx