]> git.lyx.org Git - features.git/blob - src/lyxfunc.C
This commit creates a error_lists map member inside the Buffer class.
[features.git] / src / lyxfunc.C
1 /**
2  * \file lyxfunc.C
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
22 #include "lyxfunc.h"
23
24 #include "BranchList.h"
25 #include "buffer.h"
26 #include "buffer_funcs.h"
27 #include "bufferlist.h"
28 #include "bufferparams.h"
29 #include "BufferView.h"
30 #include "cursor.h"
31 #include "CutAndPaste.h"
32 #include "debug.h"
33 #include "dispatchresult.h"
34 #include "encoding.h"
35 #include "errorlist.h"
36 #include "exporter.h"
37 #include "format.h"
38 #include "funcrequest.h"
39 #include "gettext.h"
40 #include "importer.h"
41 #include "insetiterator.h"
42 #include "intl.h"
43 #include "kbmap.h"
44 #include "language.h"
45 #include "LColor.h"
46 #include "session.h"
47 #include "lyx_main.h"
48 #include "lyx_cb.h"
49 #include "LyXAction.h"
50 #include "lyxfind.h"
51 #include "lyxlex.h"
52 #include "lyxrc.h"
53 #include "lyxrow.h"
54 #include "lyxserver.h"
55 #include "lyxtextclasslist.h"
56 #include "lyxvc.h"
57 #include "paragraph.h"
58 #include "pariterator.h"
59 #include "ParagraphParameters.h"
60 #include "undo.h"
61
62 #include "insets/insetbox.h"
63 #include "insets/insetbranch.h"
64 #include "insets/insetcommand.h"
65 #include "insets/insetert.h"
66 #include "insets/insetexternal.h"
67 #include "insets/insetfloat.h"
68 #include "insets/insetgraphics.h"
69 #include "insets/insetinclude.h"
70 #include "insets/insetnote.h"
71 #include "insets/insettabular.h"
72 #include "insets/insetvspace.h"
73 #include "insets/insetwrap.h"
74
75 #include "frontends/Alert.h"
76 #include "frontends/Dialogs.h"
77 #include "frontends/FileDialog.h"
78 #include "frontends/lyx_gui.h"
79 #include "frontends/LyXKeySym.h"
80 #include "frontends/LyXView.h"
81 #include "frontends/Menubar.h"
82 #include "frontends/Toolbars.h"
83
84 #include "support/environment.h"
85 #include "support/filefilterlist.h"
86 #include "support/filetools.h"
87 #include "support/forkedcontr.h"
88 #include "support/fs_extras.h"
89 #include "support/lstrings.h"
90 #include "support/path.h"
91 #include "support/package.h"
92 #include "support/systemcall.h"
93 #include "support/convert.h"
94 #include "support/os.h"
95
96 #include <boost/current_function.hpp>
97 #include <boost/filesystem/operations.hpp>
98
99 #include <sstream>
100
101 using bv_funcs::freefont2string;
102
103 using lyx::support::absolutePath;
104 using lyx::support::addName;
105 using lyx::support::addPath;
106 using lyx::support::bformat;
107 using lyx::support::changeExtension;
108 using lyx::support::contains;
109 using lyx::support::FileFilterList;
110 using lyx::support::fileSearch;
111 using lyx::support::ForkedcallsController;
112 using lyx::support::i18nLibFileSearch;
113 using lyx::support::isDirWriteable;
114 using lyx::support::isFileReadable;
115 using lyx::support::isStrInt;
116 using lyx::support::makeAbsPath;
117 using lyx::support::makeDisplayPath;
118 using lyx::support::package;
119 using lyx::support::Path;
120 using lyx::support::quoteName;
121 using lyx::support::rtrim;
122 using lyx::support::split;
123 using lyx::support::subst;
124 using lyx::support::Systemcall;
125 using lyx::support::token;
126 using lyx::support::trim;
127 using lyx::support::prefixIs;
128
129 using std::endl;
130 using std::make_pair;
131 using std::pair;
132 using std::string;
133 using std::istringstream;
134 using std::ostringstream;
135
136 namespace biblio = lyx::biblio;
137 namespace fs = boost::filesystem;
138
139
140 extern BufferList bufferlist;
141 extern LyXServer * lyxserver;
142
143 extern boost::scoped_ptr<kb_keymap> toplevel_keymap;
144
145 // (alkis)
146 extern tex_accent_struct get_accent(kb_action action);
147
148
149 namespace {
150
151 bool getStatus(LCursor cursor,
152                FuncRequest const & cmd, FuncStatus & status)
153 {
154         // Try to fix cursor in case it is broken.
155         cursor.fixIfBroken();
156
157         // This is, of course, a mess. Better create a new doc iterator and use
158         // this in Inset::getStatus. This might require an additional
159         // BufferView * arg, though (which should be avoided)
160         //LCursor safe = *this;
161         bool res = false;
162         for ( ; cursor.depth(); cursor.pop()) {
163                 //lyxerr << "\nLCursor::getStatus: cmd: " << cmd << endl << *this << endl;
164                 BOOST_ASSERT(cursor.idx() <= cursor.lastidx());
165                 BOOST_ASSERT(cursor.pit() <= cursor.lastpit());
166                 BOOST_ASSERT(cursor.pos() <= cursor.lastpos());
167
168                 // The inset's getStatus() will return 'true' if it made
169                 // a definitive decision on whether it want to handle the
170                 // request or not. The result of this decision is put into
171                 // the 'status' parameter.
172                 if (cursor.inset().getStatus(cursor, cmd, status)) {
173                         res = true;
174                         break;
175                 }
176         }
177         return res;
178 }
179
180
181 /** Return the change status at cursor position, taking in account the
182  * status at each level of the document iterator (a table in a deleted
183  * footnote is deleted).
184  * When \param outer is true, the top slice is not looked at.
185  */
186 Change::Type lookupChangeType(DocIterator const & dit, bool outer = false)
187 {
188         size_t const depth = dit.depth() - (outer ? 1 : 0);
189
190         for (size_t i = 0 ; i < depth ; ++i) {
191                 CursorSlice const & slice = dit[i];
192                 if (!slice.inset().inMathed()
193                     && slice.pos() < slice.paragraph().size()) {
194                         Change::Type const ch = slice.paragraph().lookupChange(slice.pos()).type;
195                         if (ch != Change::UNCHANGED)
196                                 return ch;
197                 }
198         }
199         return Change::UNCHANGED;
200 }
201
202 }
203
204 LyXFunc::LyXFunc(LyXView * lv)
205         : owner(lv),
206         encoded_last_key(0),
207         keyseq(toplevel_keymap.get(), toplevel_keymap.get()),
208         cancel_meta_seq(toplevel_keymap.get(), toplevel_keymap.get()),
209         meta_fake_bit(key_modifier::none)
210 {
211 }
212
213
214 void LyXFunc::handleKeyFunc(kb_action action)
215 {
216         char c = encoded_last_key;
217
218         if (keyseq.length()) {
219                 c = 0;
220         }
221
222         owner->getIntl().getTransManager()
223                 .deadkey(c, get_accent(action).accent, view()->getLyXText());
224         // Need to clear, in case the minibuffer calls these
225         // actions
226         keyseq.clear();
227         // copied verbatim from do_accent_char
228         view()->cursor().resetAnchor();
229         view()->update();
230 }
231
232
233 void LyXFunc::processKeySym(LyXKeySymPtr keysym, key_modifier::state state)
234 {
235         lyxerr[Debug::KEY] << "KeySym is " << keysym->getSymbolName() << endl;
236
237         // Do nothing if we have nothing (JMarc)
238         if (!keysym->isOK()) {
239                 lyxerr[Debug::KEY] << "Empty kbd action (probably composing)"
240                                    << endl;
241                 return;
242         }
243
244         if (keysym->isModifier()) {
245                 lyxerr[Debug::KEY] << "isModifier true" << endl;
246                 return;
247         }
248
249         Encoding const * encoding = view()->cursor().getEncoding();
250
251         encoded_last_key = keysym->getISOEncoded(encoding ? encoding->name() : "");
252
253         // Do a one-deep top-level lookup for
254         // cancel and meta-fake keys. RVDK_PATCH_5
255         cancel_meta_seq.reset();
256
257         FuncRequest func = cancel_meta_seq.addkey(keysym, state);
258         lyxerr[Debug::KEY] << BOOST_CURRENT_FUNCTION
259                            << " action first set to [" << func.action << ']'
260                            << endl;
261
262         // When not cancel or meta-fake, do the normal lookup.
263         // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
264         // Mostly, meta_fake_bit = key_modifier::none. RVDK_PATCH_5.
265         if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_PREFIX)) {
266                 // remove Caps Lock and Mod2 as a modifiers
267                 func = keyseq.addkey(keysym, (state | meta_fake_bit));
268                 lyxerr[Debug::KEY] << BOOST_CURRENT_FUNCTION
269                                    << "action now set to ["
270                                    << func.action << ']' << endl;
271         }
272
273         // Dont remove this unless you know what you are doing.
274         meta_fake_bit = key_modifier::none;
275
276         // Can this happen now ?
277         if (func.action == LFUN_NOACTION) {
278                 func = FuncRequest(LFUN_COMMAND_PREFIX);
279         }
280
281         if (lyxerr.debugging(Debug::KEY)) {
282                 lyxerr << BOOST_CURRENT_FUNCTION
283                        << " Key [action="
284                        << func.action << "]["
285                        << keyseq.print() << ']'
286                        << endl;
287         }
288
289         // already here we know if it any point in going further
290         // why not return already here if action == -1 and
291         // num_bytes == 0? (Lgb)
292
293         if (keyseq.length() > 1) {
294                 owner->message(keyseq.print());
295         }
296
297
298         // Maybe user can only reach the key via holding down shift.
299         // Let's see. But only if shift is the only modifier
300         if (func.action == LFUN_UNKNOWN_ACTION &&
301             state == key_modifier::shift) {
302                 lyxerr[Debug::KEY] << "Trying without shift" << endl;
303                 func = keyseq.addkey(keysym, key_modifier::none);
304                 lyxerr[Debug::KEY] << "Action now " << func.action << endl;
305         }
306
307         if (func.action == LFUN_UNKNOWN_ACTION) {
308                 // Hmm, we didn't match any of the keysequences. See
309                 // if it's normal insertable text not already covered
310                 // by a binding
311                 if (keysym->isText() && keyseq.length() == 1) {
312                         lyxerr[Debug::KEY] << "isText() is true, inserting." << endl;
313                         func = FuncRequest(LFUN_SELF_INSERT,
314                                            FuncRequest::KEYBOARD);
315                 } else {
316                         lyxerr[Debug::KEY] << "Unknown, !isText() - giving up" << endl;
317                         owner->message(_("Unknown function."));
318                         return;
319                 }
320         }
321
322         if (func.action == LFUN_SELF_INSERT) {
323                 if (encoded_last_key != 0) {
324                         string const arg(1, encoded_last_key);
325                         dispatch(FuncRequest(LFUN_SELF_INSERT, arg,
326                                              FuncRequest::KEYBOARD));
327                         lyxerr[Debug::KEY]
328                                 << "SelfInsert arg[`" << arg << "']" << endl;
329                 }
330         } else {
331                 dispatch(func);
332         }
333 }
334
335
336 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
337 {
338         //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
339         FuncStatus flag;
340         LCursor & cur = view()->cursor();
341
342         /* In LyX/Mac, when a dialog is open, the menus of the
343            application can still be accessed without giving focus to
344            the main window. In this case, we want to disable the menu
345            entries that are buffer-related.
346
347            Note that this code is not perfect, as bug 1941 attests:
348            http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
349         */
350         Buffer * buf;
351         if (cmd.origin == FuncRequest::UI && !owner->hasFocus())
352                 buf = 0;
353         else
354                 buf = owner->buffer();
355
356         if (cmd.action == LFUN_NOACTION) {
357                 flag.message(N_("Nothing to do"));
358                 flag.enabled(false);
359                 return flag;
360         }
361
362         switch (cmd.action) {
363         case LFUN_UNKNOWN_ACTION:
364 #ifndef HAVE_LIBAIKSAURUS
365         case LFUN_THESAURUS_ENTRY:
366 #endif
367                 flag.unknown(true);
368                 flag.enabled(false);
369                 break;
370         default:
371                 flag |= lyx_gui::getStatus(cmd);
372         }
373
374         if (flag.unknown()) {
375                 flag.message(N_("Unknown action"));
376                 return flag;
377         }
378
379         if (!flag.enabled()) {
380                 if (flag.message().empty())
381                         flag.message(N_("Command disabled"));
382                 return flag;
383         }
384
385         // Check whether we need a buffer
386         if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
387                 // no, exit directly
388                 flag.message(N_("Command not allowed with"
389                                     "out any document open"));
390                 flag.enabled(false);
391                 return flag;
392         }
393
394         // I would really like to avoid having this switch and rather try to
395         // encode this in the function itself.
396         // -- And I'd rather let an inset decide which LFUNs it is willing
397         // to handle (Andre')
398         bool enable = true;
399         switch (cmd.action) {
400         case LFUN_TOOLTIPS_TOGGLE:
401                 flag.setOnOff(owner->getDialogs().tooltipsEnabled());
402                 break;
403
404         case LFUN_BUFFER_TOGGLE_READ_ONLY:
405                 flag.setOnOff(buf->isReadonly());
406                 break;
407
408         case LFUN_BUFFER_SWITCH:
409                 // toggle on the current buffer, but do not toggle off
410                 // the other ones (is that a good idea?)
411                 if (cmd.argument == buf->fileName())
412                         flag.setOnOff(true);
413                 break;
414
415         case LFUN_BUFFER_EXPORT:
416                 enable = cmd.argument == "custom"
417                         || Exporter::isExportable(*buf, cmd.argument);
418                 break;
419
420         case LFUN_BUFFER_CHKTEX:
421                 enable = buf->isLatex() && lyxrc.chktex_command != "none";
422                 break;
423
424         case LFUN_BUILD_PROGRAM:
425                 enable = Exporter::isExportable(*buf, "program");
426                 break;
427
428         case LFUN_LAYOUT_TABULAR:
429                 enable = cur.innerInsetOfType(InsetBase::TABULAR_CODE);
430                 break;
431
432         case LFUN_LAYOUT:
433         case LFUN_LAYOUT_PARAGRAPH:
434                 enable = !cur.inset().forceDefaultParagraphs(cur.idx());
435                 break;
436
437         case LFUN_VC_REGISTER:
438                 enable = !buf->lyxvc().inUse();
439                 break;
440         case LFUN_VC_CHECK_IN:
441                 enable = buf->lyxvc().inUse() && !buf->isReadonly();
442                 break;
443         case LFUN_VC_CHECK_OUT:
444                 enable = buf->lyxvc().inUse() && buf->isReadonly();
445                 break;
446         case LFUN_VC_REVERT:
447         case LFUN_VC_UNDO_LAST:
448                 enable = buf->lyxvc().inUse();
449                 break;
450         case LFUN_BUFFER_RELOAD:
451                 enable = !buf->isUnnamed() && !buf->isClean();
452                 break;
453
454         case LFUN_INSET_SETTINGS: {
455                 enable = false;
456                 if (!cur)
457                         break;
458                 InsetBase::Code code = cur.inset().lyxCode();
459                 switch (code) {
460                         case InsetBase::TABULAR_CODE:
461                                 enable = cmd.argument == "tabular";
462                                 break;
463                         case InsetBase::ERT_CODE:
464                                 enable = cmd.argument == "ert";
465                                 break;
466                         case InsetBase::FLOAT_CODE:
467                                 enable = cmd.argument == "float";
468                                 break;
469                         case InsetBase::WRAP_CODE:
470                                 enable = cmd.argument == "wrap";
471                                 break;
472                         case InsetBase::NOTE_CODE:
473                                 enable = cmd.argument == "note";
474                                 break;
475                         case InsetBase::BRANCH_CODE:
476                                 enable = cmd.argument == "branch";
477                                 break;
478                         case InsetBase::BOX_CODE:
479                                 enable = cmd.argument == "box";
480                                 break;
481                         default:
482                                 break;
483                 }
484                 break;
485         }
486
487         case LFUN_INSET_APPLY: {
488                 string const name = cmd.getArg(0);
489                 InsetBase * inset = owner->getDialogs().getOpenInset(name);
490                 if (inset) {
491                         FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument);
492                         FuncStatus fs;
493                         bool const success = inset->getStatus(cur, fr, fs);
494                         // Every inset is supposed to handle this
495                         BOOST_ASSERT(success);
496                         flag |= fs;
497                 } else {
498                         FuncRequest fr(LFUN_INSET_INSERT, cmd.argument);
499                         flag |= getStatus(fr);
500                 }
501                 enable = flag.enabled();
502                 break;
503         }
504
505         case LFUN_DIALOG_SHOW: {
506                 string const name = cmd.getArg(0);
507                 if (!buf)
508                         enable = name == "aboutlyx"
509                                 || name == "file"
510                                 || name == "forks"
511                                 || name == "prefs"
512                                 || name == "texinfo";
513                 else if (name == "print")
514                         enable = Exporter::isExportable(*buf, "dvi")
515                                 && lyxrc.print_command != "none";
516                 else if (name == "character" || name == "mathpanel")
517                         enable = cur.inset().lyxCode() != InsetBase::ERT_CODE;
518                 else if (name == "latexlog")
519                         enable = isFileReadable(buf->getLogName().second);
520 #if !defined (USE_ASPELL) && !defined (USE_ISPELL) && !defined (USE_PSPELL)
521                 else if (name == "spellchecker")
522                         enable = false;
523 #endif
524                 else if (name == "vclog")
525                         enable = buf->lyxvc().inUse();
526                 else if (name == "view-source")
527                         enable = buf;
528                 break;
529         }
530
531         case LFUN_DIALOG_SHOW_NEW_INSET:
532                 enable = cur.inset().lyxCode() != InsetBase::ERT_CODE;
533                 break;
534
535         case LFUN_DIALOG_UPDATE: {
536                 string const name = cmd.getArg(0);
537                 if (!buf)
538                         enable = name == "prefs";
539                 break;
540         }
541
542         case LFUN_CITATION_INSERT: {
543                 FuncRequest fr(LFUN_INSET_INSERT, "citation");
544                 enable = getStatus(fr).enabled();
545                 break;
546         }
547
548         case LFUN_BUFFER_WRITE: {
549                 enable = view()->buffer()->isUnnamed()
550                         || !view()->buffer()->isClean();
551                 break;
552         }
553
554         // this one is difficult to get right. As a half-baked
555         // solution, we consider only the first action of the sequence
556         case LFUN_COMMAND_SEQUENCE: {
557                 // argument contains ';'-terminated commands
558                 string const firstcmd = token(cmd.argument, ';', 0);
559                 FuncRequest func(lyxaction.lookupFunc(firstcmd));
560                 func.origin = cmd.origin;
561                 flag = getStatus(func);
562         }
563
564         case LFUN_BUFFER_NEW:
565         case LFUN_BUFFER_NEW_TEMPLATE:
566         case LFUN_WORD_FIND_FORWARD:
567         case LFUN_WORD_FIND_BACKWARD:
568         case LFUN_COMMAND_PREFIX:
569         case LFUN_COMMAND_EXECUTE:
570         case LFUN_CANCEL:
571         case LFUN_META_PREFIX:
572         case LFUN_BUFFER_CLOSE:
573         case LFUN_BUFFER_WRITE_AS:
574         case LFUN_BUFFER_UPDATE:
575         case LFUN_BUFFER_VIEW:
576         case LFUN_BUFFER_IMPORT:
577         case LFUN_LYX_QUIT:
578         case LFUN_TOC_VIEW:
579         case LFUN_BUFFER_AUTO_SAVE:
580         case LFUN_RECONFIGURE:
581         case LFUN_HELP_OPEN:
582         case LFUN_FILE_NEW:
583         case LFUN_FILE_OPEN:
584         case LFUN_DROP_LAYOUTS_CHOICE:
585         case LFUN_MENU_OPEN:
586         case LFUN_SERVER_GET_NAME:
587         case LFUN_SERVER_NOTIFY:
588         case LFUN_SERVER_GOTO_FILE_ROW:
589         case LFUN_DIALOG_SHOW_NEXT_INSET:
590         case LFUN_DIALOG_HIDE:
591         case LFUN_DIALOG_DISCONNECT_INSET:
592         case LFUN_BUFFER_CHILD_OPEN:
593         case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
594         case LFUN_KEYMAP_OFF:
595         case LFUN_KEYMAP_PRIMARY:
596         case LFUN_KEYMAP_SECONDARY:
597         case LFUN_KEYMAP_TOGGLE:
598         case LFUN_REPEAT:
599         case LFUN_BUFFER_EXPORT_CUSTOM:
600         case LFUN_BUFFER_PRINT:
601         case LFUN_PREFERENCES_SAVE:
602         case LFUN_SCREEN_FONT_UPDATE:
603         case LFUN_SET_COLOR:
604         case LFUN_MESSAGE:
605         case LFUN_EXTERNAL_EDIT:
606         case LFUN_GRAPHICS_EDIT:
607         case LFUN_ALL_INSETS_TOGGLE:
608         case LFUN_BUFFER_LANGUAGE:
609         case LFUN_TEXTCLASS_APPLY:
610         case LFUN_TEXTCLASS_LOAD:
611         case LFUN_BUFFER_SAVE_AS_DEFAULT:
612         case LFUN_BUFFER_PARAMS_APPLY:
613         case LFUN_LYXRC_APPLY:
614         case LFUN_BUFFER_NEXT:
615         case LFUN_BUFFER_PREVIOUS:
616                 // these are handled in our dispatch()
617                 break;
618
619         default:
620
621                 if (!::getStatus(cur, cmd, flag))
622                         flag = view()->getStatus(cmd);
623         }
624
625         if (!enable)
626                 flag.enabled(false);
627
628         // Can we use a readonly buffer?
629         if (buf && buf->isReadonly()
630             && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
631             && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
632                 flag.message(N_("Document is read-only"));
633                 flag.enabled(false);
634         }
635
636         // Are we in a DELETED change-tracking region?
637         if (buf && buf->params().tracking_changes
638             && lookupChangeType(cur, true) == Change::DELETED
639             && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
640             && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
641                 flag.message(N_("This portion of the document is deleted."));
642                 flag.enabled(false);
643         }
644
645         // the default error message if we disable the command
646         if (!flag.enabled() && flag.message().empty())
647                 flag.message(N_("Command disabled"));
648
649         return flag;
650 }
651
652
653 namespace {
654
655 bool ensureBufferClean(BufferView * bv)
656 {
657         Buffer & buf = *bv->buffer();
658         if (buf.isClean())
659                 return true;
660
661         string const file = makeDisplayPath(buf.fileName(), 30);
662         string text = bformat(_("The document %1$s has unsaved "
663                                 "changes.\n\nDo you want to save "
664                                 "the document?"), file);
665         int const ret = Alert::prompt(_("Save changed document?"),
666                                       text, 0, 1, _("&Save"),
667                                       _("&Cancel"));
668
669         if (ret == 0)
670                 bv->owner()->dispatch(FuncRequest(LFUN_BUFFER_WRITE));
671
672         return buf.isClean();
673 }
674
675
676 void showPrintError(string const & name)
677 {
678         string str = bformat(_("Could not print the document %1$s.\n"
679                                "Check that your printer is set up correctly."),
680                              makeDisplayPath(name, 50));
681         Alert::error(_("Print document failed"), str);
682 }
683
684
685 void loadTextclass(string const & name)
686 {
687         std::pair<bool, lyx::textclass_type> const tc_pair =
688                 textclasslist.numberOfClass(name);
689
690         if (!tc_pair.first) {
691                 lyxerr << "Document class \"" << name
692                        << "\" does not exist."
693                        << std::endl;
694                 return;
695         }
696
697         lyx::textclass_type const tc = tc_pair.second;
698
699         if (!textclasslist[tc].load()) {
700                 string s = bformat(_("The document could not be converted\n"
701                                      "into the document class %1$s."),
702                                    textclasslist[tc].name());
703                 Alert::error(_("Could not change class"), s);
704         }
705 }
706
707
708 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
709
710 } //namespace anon
711
712
713 void LyXFunc::dispatch(FuncRequest const & cmd)
714 {
715         BOOST_ASSERT(view());
716         string const argument = cmd.argument;
717         kb_action const action = cmd.action;
718
719         lyxerr[Debug::ACTION] << "LyXFunc::dispatch: cmd: " << cmd << endl;
720         //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
721
722         // we have not done anything wrong yet.
723         errorstat = false;
724         dispatch_buffer.erase();
725
726         // redraw the screen at the end (first of the two drawing steps).
727         //This is done unless explicitely requested otherwise
728         bool update = true;
729         // also do the second redrawing step. Only done if requested.
730         bool updateforce = false;
731
732         FuncStatus const flag = getStatus(cmd);
733         if (!flag.enabled()) {
734                 // We cannot use this function here
735                 lyxerr[Debug::ACTION] << "LyXFunc::dispatch: "
736                        << lyxaction.getActionName(action)
737                        << " [" << action << "] is disabled at this location"
738                        << endl;
739                 setErrorMessage(flag.message());
740         } else {
741                 switch (action) {
742
743                 case LFUN_WORD_FIND_FORWARD:
744                 case LFUN_WORD_FIND_BACKWARD: {
745                         static string last_search;
746                         string searched_string;
747
748                         if (!argument.empty()) {
749                                 last_search = argument;
750                                 searched_string = argument;
751                         } else {
752                                 searched_string = last_search;
753                         }
754
755                         if (searched_string.empty())
756                                 break;
757
758                         bool const fw = action == LFUN_WORD_FIND_FORWARD;
759                         string const data =
760                                 lyx::find::find2string(searched_string, true, false, fw);
761                         lyx::find::find(view(), FuncRequest(LFUN_WORD_FIND, data));
762                         break;
763                 }
764
765                 case LFUN_COMMAND_PREFIX:
766                         owner->message(keyseq.printOptions());
767                         break;
768
769                 case LFUN_COMMAND_EXECUTE:
770                         owner->getToolbars().display("minibuffer", true);
771                         owner->focus_command_buffer();
772                         break;
773
774                 case LFUN_CANCEL:
775                         keyseq.reset();
776                         meta_fake_bit = key_modifier::none;
777                         if (view()->available())
778                                 // cancel any selection
779                                 dispatch(FuncRequest(LFUN_MARK_OFF));
780                         setMessage(N_("Cancel"));
781                         break;
782
783                 case LFUN_META_PREFIX:
784                         meta_fake_bit = key_modifier::alt;
785                         setMessage(keyseq.print());
786                         break;
787
788                 case LFUN_BUFFER_TOGGLE_READ_ONLY:
789                         if (owner->buffer()->lyxvc().inUse())
790                                 owner->buffer()->lyxvc().toggleReadOnly();
791                         else
792                                 owner->buffer()->setReadonly(
793                                         !owner->buffer()->isReadonly());
794                         break;
795
796                 // --- Menus -----------------------------------------------
797                 case LFUN_BUFFER_NEW:
798                         menuNew(argument, false);
799                         break;
800
801                 case LFUN_BUFFER_NEW_TEMPLATE:
802                         menuNew(argument, true);
803                         break;
804
805                 case LFUN_BUFFER_CLOSE:
806                         closeBuffer();
807                         break;
808
809                 case LFUN_BUFFER_WRITE:
810                         if (!owner->buffer()->isUnnamed()) {
811                                 string const str = bformat(_("Saving document %1$s..."),
812                                          makeDisplayPath(owner->buffer()->fileName()));
813                                 owner->message(str);
814                                 menuWrite(owner->buffer());
815                                 owner->message(str + _(" done."));
816                         } else
817                                 writeAs(owner->buffer());
818                         update = false;
819                         break;
820
821                 case LFUN_BUFFER_WRITE_AS:
822                         writeAs(owner->buffer(), argument);
823                         update = false;
824                         break;
825
826                 case LFUN_BUFFER_RELOAD: {
827                         string const file = makeDisplayPath(view()->buffer()->fileName(), 20);
828                         string text = bformat(_("Any changes will be lost. Are you sure "
829                                 "you want to revert to the saved version of the document %1$s?"), file);
830                         int const ret = Alert::prompt(_("Revert to saved document?"),
831                                 text, 0, 1, _("&Revert"), _("&Cancel"));
832
833                         if (ret == 0)
834                                 view()->reload();
835                         break;
836                 }
837
838                 case LFUN_BUFFER_UPDATE:
839                         Exporter::Export(owner->buffer(), argument, true);
840                         break;
841
842                 case LFUN_BUFFER_VIEW:
843                         Exporter::preview(owner->buffer(), argument);
844                         break;
845
846                 case LFUN_BUILD_PROGRAM:
847                         Exporter::Export(owner->buffer(), "program", true);
848                         break;
849
850                 case LFUN_BUFFER_CHKTEX:
851                         owner->buffer()->runChktex();
852                         break;
853
854                 case LFUN_BUFFER_EXPORT:
855                         if (argument == "custom")
856                                 owner->getDialogs().show("sendto");
857                         else {
858                                 Exporter::Export(owner->buffer(), argument, false);
859                         }
860                         break;
861
862                 case LFUN_BUFFER_EXPORT_CUSTOM: {
863                         string format_name;
864                         string command = split(argument, format_name, ' ');
865                         Format const * format = formats.getFormat(format_name);
866                         if (!format) {
867                                 lyxerr << "Format \"" << format_name
868                                        << "\" not recognized!"
869                                        << std::endl;
870                                 break;
871                         }
872
873                         Buffer * buffer = owner->buffer();
874
875                         // The name of the file created by the conversion process
876                         string filename;
877
878                         // Output to filename
879                         if (format->name() == "lyx") {
880                                 string const latexname =
881                                         buffer->getLatexName(false);
882                                 filename = changeExtension(latexname,
883                                                            format->extension());
884                                 filename = addName(buffer->temppath(), filename);
885
886                                 if (!buffer->writeFile(filename))
887                                         break;
888
889                         } else {
890                                 Exporter::Export(buffer, format_name, true, filename);
891                         }
892
893                         // Substitute $$FName for filename
894                         if (!contains(command, "$$FName"))
895                                 command = "( " + command + " ) < $$FName";
896                         command = subst(command, "$$FName", filename);
897
898                         // Execute the command in the background
899                         Systemcall call;
900                         call.startscript(Systemcall::DontWait, command);
901                         break;
902                 }
903
904                 case LFUN_BUFFER_PRINT: {
905                         string target;
906                         string target_name;
907                         string command = split(split(argument, target, ' '),
908                                                target_name, ' ');
909
910                         if (target.empty()
911                             || target_name.empty()
912                             || command.empty()) {
913                                 lyxerr << "Unable to parse \""
914                                        << argument << '"' << std::endl;
915                                 break;
916                         }
917                         if (target != "printer" && target != "file") {
918                                 lyxerr << "Unrecognized target \""
919                                        << target << '"' << std::endl;
920                                 break;
921                         }
922
923                         Buffer * buffer = owner->buffer();
924
925                         if (!Exporter::Export(buffer, "dvi", true)) {
926                                 showPrintError(buffer->fileName());
927                                 break;
928                         }
929
930                         // Push directory path.
931                         string const path = buffer->temppath();
932                         Path p(path);
933
934                         // there are three cases here:
935                         // 1. we print to a file
936                         // 2. we print directly to a printer
937                         // 3. we print using a spool command (print to file first)
938                         Systemcall one;
939                         int res = 0;
940                         string const dviname =
941                                 changeExtension(buffer->getLatexName(true),
942                                                 "dvi");
943
944                         if (target == "printer") {
945                                 if (!lyxrc.print_spool_command.empty()) {
946                                         // case 3: print using a spool
947                                         string const psname =
948                                                 changeExtension(dviname,".ps");
949                                         command += lyxrc.print_to_file
950                                                 + quoteName(psname)
951                                                 + ' '
952                                                 + quoteName(dviname);
953
954                                         string command2 =
955                                                 lyxrc.print_spool_command +' ';
956                                         if (target_name != "default") {
957                                                 command2 += lyxrc.print_spool_printerprefix
958                                                         + target_name
959                                                         + ' ';
960                                         }
961                                         command2 += quoteName(psname);
962                                         // First run dvips.
963                                         // If successful, then spool command
964                                         res = one.startscript(
965                                                 Systemcall::Wait,
966                                                 command);
967
968                                         if (res == 0)
969                                                 res = one.startscript(
970                                                         Systemcall::DontWait,
971                                                         command2);
972                                 } else {
973                                         // case 2: print directly to a printer
974                                         res = one.startscript(
975                                                 Systemcall::DontWait,
976                                                 command + quoteName(dviname));
977                                 }
978
979                         } else {
980                                 // case 1: print to a file
981                                 command += lyxrc.print_to_file
982                                         + quoteName(makeAbsPath(target_name,
983                                                                 path))
984                                         + ' '
985                                         + quoteName(dviname);
986                                 res = one.startscript(Systemcall::DontWait,
987                                                       command);
988                         }
989
990                         if (res != 0)
991                                 showPrintError(buffer->fileName());
992                         break;
993                 }
994
995                 case LFUN_BUFFER_IMPORT:
996                         doImport(argument);
997                         break;
998
999                 case LFUN_LYX_QUIT:
1000                         if (view()->available()) {
1001                                 // save cursor Position for opened files to .lyx/session
1002                                 LyX::ref().session().saveFilePosition(owner->buffer()->fileName(),
1003                                         boost::tie(view()->cursor().pit(), view()->cursor().pos()) );
1004                                 // save bookmarks to .lyx/session
1005                                 view()->saveSavedPositions();
1006                         }
1007                         quitLyX(argument == "force");
1008                         break;
1009
1010                 case LFUN_TOC_VIEW: {
1011                         InsetCommandParams p("tableofcontents");
1012                         string const data = InsetCommandMailer::params2string("toc", p);
1013                         owner->getDialogs().show("toc", data, 0);
1014                         break;
1015                 }
1016
1017                 case LFUN_BUFFER_AUTO_SAVE:
1018                         autoSave(view());
1019                         break;
1020
1021                 case LFUN_RECONFIGURE:
1022                         reconfigure(view());
1023                         break;
1024
1025                 case LFUN_HELP_OPEN: {
1026                         string const arg = argument;
1027                         if (arg.empty()) {
1028                                 setErrorMessage(N_("Missing argument"));
1029                                 break;
1030                         }
1031                         string const fname = i18nLibFileSearch("doc", arg, "lyx");
1032                         if (fname.empty()) {
1033                                 lyxerr << "LyX: unable to find documentation file `"
1034                                                          << arg << "'. Bad installation?" << endl;
1035                                 break;
1036                         }
1037                         owner->message(bformat(_("Opening help file %1$s..."),
1038                                 makeDisplayPath(fname)));
1039                         owner->loadLyXFile(fname, false);
1040                         break;
1041                 }
1042
1043                 // --- version control -------------------------------
1044                 case LFUN_VC_REGISTER:
1045                         if (!ensureBufferClean(view()))
1046                                 break;
1047                         if (!owner->buffer()->lyxvc().inUse()) {
1048                                 owner->buffer()->lyxvc().registrer();
1049                                 view()->reload();
1050                         }
1051                         break;
1052
1053                 case LFUN_VC_CHECK_IN:
1054                         if (!ensureBufferClean(view()))
1055                                 break;
1056                         if (owner->buffer()->lyxvc().inUse()
1057                                         && !owner->buffer()->isReadonly()) {
1058                                 owner->buffer()->lyxvc().checkIn();
1059                                 view()->reload();
1060                         }
1061                         break;
1062
1063                 case LFUN_VC_CHECK_OUT:
1064                         if (!ensureBufferClean(view()))
1065                                 break;
1066                         if (owner->buffer()->lyxvc().inUse()
1067                                         && owner->buffer()->isReadonly()) {
1068                                 owner->buffer()->lyxvc().checkOut();
1069                                 view()->reload();
1070                         }
1071                         break;
1072
1073                 case LFUN_VC_REVERT:
1074                         owner->buffer()->lyxvc().revert();
1075                         view()->reload();
1076                         break;
1077
1078                 case LFUN_VC_UNDO_LAST:
1079                         owner->buffer()->lyxvc().undoLast();
1080                         view()->reload();
1081                         break;
1082
1083                 // --- buffers ----------------------------------------
1084                 case LFUN_BUFFER_SWITCH:
1085                         owner->setBuffer(bufferlist.getBuffer(argument));
1086                         break;
1087
1088                 case LFUN_BUFFER_NEXT:
1089                         owner->setBuffer(bufferlist.next(view()->buffer()));
1090                         break;
1091
1092                 case LFUN_BUFFER_PREVIOUS:
1093                         owner->setBuffer(bufferlist.previous(view()->buffer()));
1094                         break;
1095
1096                 case LFUN_FILE_NEW:
1097                         newFile(view(), argument);
1098                         break;
1099
1100                 case LFUN_FILE_OPEN:
1101                         open(argument);
1102                         break;
1103
1104                 case LFUN_DROP_LAYOUTS_CHOICE:
1105                         owner->getToolbars().openLayoutList();
1106                         break;
1107
1108                 case LFUN_MENU_OPEN:
1109                         owner->getMenubar().openByName(argument);
1110                         break;
1111
1112                 // --- lyxserver commands ----------------------------
1113                 case LFUN_SERVER_GET_NAME:
1114                         setMessage(owner->buffer()->fileName());
1115                         lyxerr[Debug::INFO] << "FNAME["
1116                                                          << owner->buffer()->fileName()
1117                                                          << "] " << endl;
1118                         break;
1119
1120                 case LFUN_SERVER_NOTIFY:
1121                         dispatch_buffer = keyseq.print();
1122                         lyxserver->notifyClient(dispatch_buffer);
1123                         break;
1124
1125                 case LFUN_SERVER_GOTO_FILE_ROW: {
1126                         string file_name;
1127                         int row;
1128                         istringstream is(argument);
1129                         is >> file_name >> row;
1130                         if (prefixIs(file_name, package().temp_dir())) {
1131                                 // Needed by inverse dvi search. If it is a file
1132                                 // in tmpdir, call the apropriated function
1133                                 owner->setBuffer(bufferlist.getBufferFromTmp(file_name));
1134                         } else {
1135                                 // Must replace extension of the file to be .lyx
1136                                 // and get full path
1137                                 string const s = changeExtension(file_name, ".lyx");
1138                                 // Either change buffer or load the file
1139                                 if (bufferlist.exists(s)) {
1140                                         owner->setBuffer(bufferlist.getBuffer(s));
1141                                 } else {
1142                                         owner->loadLyXFile(s);
1143                                 }
1144                         }
1145
1146                         view()->setCursorFromRow(row);
1147
1148                         view()->center();
1149                         // see BufferView_pimpl::center()
1150                         break;
1151                 }
1152
1153                 case LFUN_DIALOG_SHOW: {
1154                         string const name = cmd.getArg(0);
1155                         string data = trim(cmd.argument.substr(name.size()));
1156
1157                         if (name == "character") {
1158                                 data = freefont2string();
1159                                 if (!data.empty())
1160                                         owner->getDialogs().show("character", data);
1161                         } else if (name == "latexlog") {
1162                                 pair<Buffer::LogType, string> const logfile =
1163                                         owner->buffer()->getLogName();
1164                                 switch (logfile.first) {
1165                                 case Buffer::latexlog:
1166                                         data = "latex ";
1167                                         break;
1168                                 case Buffer::buildlog:
1169                                         data = "literate ";
1170                                         break;
1171                                 }
1172                                 data += LyXLex::quoteString(logfile.second);
1173                                 owner->getDialogs().show("log", data);
1174                         } else if (name == "vclog") {
1175                                 string const data = "vc " +
1176                                         LyXLex::quoteString(owner->buffer()->lyxvc().getLogFile());
1177                                 owner->getDialogs().show("log", data);
1178                         } else
1179                                 owner->getDialogs().show(name, data);
1180                         break;
1181                 }
1182
1183                 case LFUN_DIALOG_SHOW_NEW_INSET: {
1184                         string const name = cmd.getArg(0);
1185                         string data = trim(cmd.argument.substr(name.size()));
1186                         if (name == "bibitem" ||
1187                             name == "bibtex" ||
1188                             name == "index" ||
1189                             name == "label" ||
1190                             name == "ref" ||
1191                             name == "toc" ||
1192                             name == "url") {
1193                                 InsetCommandParams p(name);
1194                                 data = InsetCommandMailer::params2string(name, p);
1195                         } else if (name == "include") {
1196                                 InsetCommandParams p(data);
1197                                 data = InsetIncludeMailer::params2string(p);
1198                         } else if (name == "box") {
1199                                 // \c data == "Boxed" || "Frameless" etc
1200                                 InsetBoxParams p(data);
1201                                 data = InsetBoxMailer::params2string(p);
1202                         } else if (name == "branch") {
1203                                 InsetBranchParams p;
1204                                 data = InsetBranchMailer::params2string(p);
1205                         } else if (name == "citation") {
1206                                 InsetCommandParams p("cite");
1207                                 data = InsetCommandMailer::params2string(name, p);
1208                         } else if (name == "ert") {
1209                                 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1210                         } else if (name == "external") {
1211                                 InsetExternalParams p;
1212                                 Buffer const & buffer = *owner->buffer();
1213                                 data = InsetExternalMailer::params2string(p, buffer);
1214                         } else if (name == "float") {
1215                                 InsetFloatParams p;
1216                                 data = InsetFloatMailer::params2string(p);
1217                         } else if (name == "graphics") {
1218                                 InsetGraphicsParams p;
1219                                 Buffer const & buffer = *owner->buffer();
1220                                 data = InsetGraphicsMailer::params2string(p, buffer);
1221                         } else if (name == "note") {
1222                                 InsetNoteParams p;
1223                                 data = InsetNoteMailer::params2string(p);
1224                         } else if (name == "vspace") {
1225                                 VSpace space;
1226                                 data = InsetVSpaceMailer::params2string(space);
1227                         } else if (name == "wrap") {
1228                                 InsetWrapParams p;
1229                                 data = InsetWrapMailer::params2string(p);
1230                         }
1231                         owner->getDialogs().show(name, data, 0);
1232                         break;
1233                 }
1234
1235                 case LFUN_DIALOG_SHOW_NEXT_INSET:
1236                         break;
1237
1238                 case LFUN_DIALOG_UPDATE: {
1239                         string const & name = argument;
1240                         // Can only update a dialog connected to an existing inset
1241                         InsetBase * inset = owner->getDialogs().getOpenInset(name);
1242                         if (inset) {
1243                                 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument);
1244                                 inset->dispatch(view()->cursor(), fr);
1245                         } else if (name == "paragraph") {
1246                                 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1247                         } else if (name == "prefs") {
1248                                 owner->getDialogs().update(name, string());
1249                         }
1250                         break;
1251                 }
1252
1253                 case LFUN_DIALOG_HIDE:
1254                         Dialogs::hide(argument, 0);
1255                         break;
1256
1257                 case LFUN_DIALOG_DISCONNECT_INSET:
1258                         owner->getDialogs().disconnect(argument);
1259                         break;
1260
1261
1262                 case LFUN_CITATION_INSERT: {
1263                         if (!argument.empty()) {
1264                                 // we can have one optional argument, delimited by '|'
1265                                 // citation-insert <key>|<text_before>
1266                                 // this should be enhanced to also support text_after
1267                                 // and citation style
1268                                 string arg = argument;
1269                                 string opt1;
1270                                 if (contains(argument, "|")) {
1271                                         arg = token(argument, '|', 0);
1272                                         opt1 = '[' + token(argument, '|', 1) + ']';
1273                                 }
1274                                 std::ostringstream os;
1275                                 os << "citation LatexCommand\n"
1276                                    << "\\cite" << opt1 << "{" << arg << "}\n"
1277                                    << "\\end_inset";
1278                                 FuncRequest fr(LFUN_INSET_INSERT, os.str());
1279                                 dispatch(fr);
1280                         } else
1281                                 dispatch(FuncRequest(LFUN_DIALOG_SHOW, "citation"));
1282                         break;
1283                 }
1284
1285                 case LFUN_BUFFER_CHILD_OPEN: {
1286                         string const filename =
1287                                 makeAbsPath(argument, owner->buffer()->filePath());
1288                         setMessage(N_("Opening child document ") +
1289                                          makeDisplayPath(filename) + "...");
1290                         view()->savePosition(0);
1291                         string const parentfilename = owner->buffer()->fileName();
1292                         if (bufferlist.exists(filename))
1293                                 owner->setBuffer(bufferlist.getBuffer(filename));
1294                         else
1295                                 owner->loadLyXFile(filename);
1296                         // Set the parent name of the child document.
1297                         // This makes insertion of citations and references in the child work,
1298                         // when the target is in the parent or another child document.
1299                         owner->buffer()->setParentName(parentfilename);
1300                         break;
1301                 }
1302
1303                 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1304                         lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1305                         break;
1306
1307                 case LFUN_KEYMAP_OFF:
1308                         owner->getIntl().keyMapOn(false);
1309                         break;
1310
1311                 case LFUN_KEYMAP_PRIMARY:
1312                         owner->getIntl().keyMapPrim();
1313                         break;
1314
1315                 case LFUN_KEYMAP_SECONDARY:
1316                         owner->getIntl().keyMapSec();
1317                         break;
1318
1319                 case LFUN_KEYMAP_TOGGLE:
1320                         owner->getIntl().toggleKeyMap();
1321                         break;
1322
1323                 case LFUN_REPEAT: {
1324                         // repeat command
1325                         string countstr;
1326                         string rest = split(argument, countstr, ' ');
1327                         istringstream is(countstr);
1328                         int count = 0;
1329                         is >> count;
1330                         lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1331                         for (int i = 0; i < count; ++i)
1332                                 dispatch(lyxaction.lookupFunc(rest));
1333                         break;
1334                 }
1335
1336                 case LFUN_COMMAND_SEQUENCE: {
1337                         // argument contains ';'-terminated commands
1338                         string arg = argument;
1339                         while (!arg.empty()) {
1340                                 string first;
1341                                 arg = split(arg, first, ';');
1342                                 FuncRequest func(lyxaction.lookupFunc(first));
1343                                 func.origin = cmd.origin;
1344                                 dispatch(func);
1345                         }
1346                         break;
1347                 }
1348
1349                 case LFUN_PREFERENCES_SAVE: {
1350                         Path p(package().user_support());
1351                         lyxrc.write("preferences", false);
1352                         break;
1353                 }
1354
1355                 case LFUN_SCREEN_FONT_UPDATE:
1356                         // handle the screen font changes.
1357                         lyxrc.set_font_norm_type();
1358                         lyx_gui::update_fonts();
1359                         // All visible buffers will need resize
1360                         view()->resize();
1361                         break;
1362
1363                 case LFUN_SET_COLOR: {
1364                         string lyx_name;
1365                         string const x11_name = split(argument, lyx_name, ' ');
1366                         if (lyx_name.empty() || x11_name.empty()) {
1367                                 setErrorMessage(N_("Syntax: set-color <lyx_name>"
1368                                                         " <x11_name>"));
1369                                 break;
1370                         }
1371
1372                         bool const graphicsbg_changed =
1373                                 (lyx_name == lcolor.getLyXName(LColor::graphicsbg) &&
1374                                  x11_name != lcolor.getX11Name(LColor::graphicsbg));
1375
1376                         if (!lcolor.setColor(lyx_name, x11_name)) {
1377                                 setErrorMessage(
1378                                         bformat(_("Set-color \"%1$s\" failed "
1379                                                                 "- color is undefined or "
1380                                                                 "may not be redefined"), lyx_name));
1381                                 break;
1382                         }
1383
1384                         lyx_gui::update_color(lcolor.getFromLyXName(lyx_name));
1385
1386                         if (graphicsbg_changed) {
1387 #ifdef WITH_WARNINGS
1388 #warning FIXME!! The graphics cache no longer has a changeDisplay method.
1389 #endif
1390 #if 0
1391                                 lyx::graphics::GCache::get().changeDisplay(true);
1392 #endif
1393                         }
1394                         break;
1395                 }
1396
1397                 case LFUN_MESSAGE:
1398                         owner->message(argument);
1399                         break;
1400
1401                 case LFUN_TOOLTIPS_TOGGLE:
1402                         owner->getDialogs().toggleTooltips();
1403                         break;
1404
1405                 case LFUN_EXTERNAL_EDIT: {
1406                         FuncRequest fr(action, argument);
1407                         InsetExternal().dispatch(view()->cursor(), fr);
1408                         break;
1409                 }
1410
1411                 case LFUN_GRAPHICS_EDIT: {
1412                         FuncRequest fr(action, argument);
1413                         InsetGraphics().dispatch(view()->cursor(), fr);
1414                         break;
1415                 }
1416
1417                 case LFUN_INSET_APPLY: {
1418                         string const name = cmd.getArg(0);
1419                         InsetBase * inset = owner->getDialogs().getOpenInset(name);
1420                         if (inset) {
1421                                 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1422                                 inset->dispatch(view()->cursor(), fr);
1423                         } else {
1424                                 FuncRequest fr(LFUN_INSET_INSERT, argument);
1425                                 dispatch(fr);
1426                         }
1427                         // ideally, the update flag should be set by the insets,
1428                         // but this is not possible currently
1429                         updateforce = true;
1430                         break;
1431                 }
1432
1433                 case LFUN_ALL_INSETS_TOGGLE: {
1434                         string action;
1435                         string const name = split(argument, action, ' ');
1436                         InsetBase::Code const inset_code =
1437                                 InsetBase::translate(name);
1438
1439                         LCursor & cur = view()->cursor();
1440                         FuncRequest fr(LFUN_INSET_TOGGLE, action);
1441
1442                         InsetBase & inset = owner->buffer()->inset();
1443                         InsetIterator it  = inset_iterator_begin(inset);
1444                         InsetIterator const end = inset_iterator_end(inset);
1445                         for (; it != end; ++it) {
1446                                 if (inset_code == InsetBase::NO_CODE
1447                                     || inset_code == it->lyxCode()) {
1448                                         LCursor tmpcur = cur;
1449                                         tmpcur.pushLeft(*it);
1450                                         it->dispatch(tmpcur, fr);
1451                                 }
1452                         }
1453                         updateforce = true;
1454                         break;
1455                 }
1456
1457                 case LFUN_BUFFER_LANGUAGE: {
1458                         Buffer & buffer = *owner->buffer();
1459                         Language const * oldL = buffer.params().language;
1460                         Language const * newL = languages.getLanguage(argument);
1461                         if (!newL || oldL == newL)
1462                                 break;
1463
1464                         if (oldL->rightToLeft() == newL->rightToLeft()
1465                             && !buffer.isMultiLingual())
1466                                 buffer.changeLanguage(oldL, newL);
1467                         else
1468                                 buffer.updateDocLang(newL);
1469                         break;
1470                 }
1471
1472                 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1473                         string const fname =
1474                                 addName(addPath(package().user_support(), "templates/"),
1475                                         "defaults.lyx");
1476                         Buffer defaults(fname);
1477
1478                         istringstream ss(argument);
1479                         LyXLex lex(0,0);
1480                         lex.setStream(ss);
1481                         int const unknown_tokens = defaults.readHeader(lex);
1482
1483                         if (unknown_tokens != 0) {
1484                                 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1485                                        << unknown_tokens << " unknown token"
1486                                        << (unknown_tokens == 1 ? "" : "s")
1487                                        << endl;
1488                         }
1489
1490                         if (defaults.writeFile(defaults.fileName()))
1491                                 setMessage(_("Document defaults saved in ")
1492                                            + makeDisplayPath(fname));
1493                         else
1494                                 setErrorMessage(_("Unable to save document defaults"));
1495                         break;
1496                 }
1497
1498                 case LFUN_BUFFER_PARAMS_APPLY: {
1499                         biblio::CiteEngine const engine =
1500                                 owner->buffer()->params().cite_engine;
1501
1502                         istringstream ss(argument);
1503                         LyXLex lex(0,0);
1504                         lex.setStream(ss);
1505                         int const unknown_tokens =
1506                                 owner->buffer()->readHeader(lex);
1507
1508                         if (unknown_tokens != 0) {
1509                                 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1510                                        << unknown_tokens << " unknown token"
1511                                        << (unknown_tokens == 1 ? "" : "s")
1512                                        << endl;
1513                         }
1514                         if (engine == owner->buffer()->params().cite_engine)
1515                                 break;
1516
1517                         LCursor & cur = view()->cursor();
1518                         FuncRequest fr(LFUN_INSET_REFRESH);
1519
1520                         InsetBase & inset = owner->buffer()->inset();
1521                         InsetIterator it  = inset_iterator_begin(inset);
1522                         InsetIterator const end = inset_iterator_end(inset);
1523                         for (; it != end; ++it)
1524                                 if (it->lyxCode() == InsetBase::CITE_CODE)
1525                                         it->dispatch(cur, fr);
1526                         break;
1527                 }
1528
1529                 case LFUN_TEXTCLASS_APPLY: {
1530                         Buffer * buffer = owner->buffer();
1531
1532                         lyx::textclass_type const old_class =
1533                                 buffer->params().textclass;
1534
1535                         loadTextclass(argument);
1536
1537                         std::pair<bool, lyx::textclass_type> const tc_pair =
1538                                 textclasslist.numberOfClass(argument);
1539
1540                         if (!tc_pair.first)
1541                                 break;
1542
1543                         lyx::textclass_type const new_class = tc_pair.second;
1544                         if (old_class == new_class)
1545                                 // nothing to do
1546                                 break;
1547
1548                         owner->message(_("Converting document to new document class..."));
1549                         recordUndoFullDocument(view());
1550                         buffer->params().textclass = new_class;
1551                         StableDocIterator backcur(view()->cursor());
1552                         ErrorList & el = buffer->errorList("Class Switch");
1553                         lyx::cap::switchBetweenClasses(
1554                                 old_class, new_class,
1555                                 static_cast<InsetText &>(buffer->inset()), el);
1556
1557                         view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
1558
1559                         buffer->errors("Class Switch");
1560                         updateLabels(*buffer);
1561                         updateforce = true;
1562                         break;
1563                 }
1564
1565                 case LFUN_TEXTCLASS_LOAD:
1566                         loadTextclass(argument);
1567                         break;
1568
1569                 case LFUN_LYXRC_APPLY: {
1570                         LyXRC const lyxrc_orig = lyxrc;
1571
1572                         istringstream ss(argument);
1573                         bool const success = lyxrc.read(ss) == 0;
1574
1575                         if (!success) {
1576                                 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1577                                        << "Unable to read lyxrc data"
1578                                        << endl;
1579                                 break;
1580                         }
1581
1582                         actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1583                         break;
1584                 }
1585
1586                 default: {
1587                         view()->cursor().dispatch(cmd);
1588                         updateforce |= view()->cursor().result().update();
1589                         if (!view()->cursor().result().dispatched())
1590                                 updateforce |= view()->dispatch(cmd);
1591                         break;
1592                 }
1593                 }
1594
1595                 if (view()->available()) {
1596                         // Redraw screen unless explicitly told otherwise.
1597                         // This also initializes the position cache for all insets
1598                         // in (at least partially) visible top-level paragraphs.
1599                         if (updateforce)
1600                                 view()->update(Update::FitCursor | Update::Force);
1601                         else if (update)
1602                                 view()->update(Update::FitCursor);
1603
1604                         owner->redrawWorkArea();
1605
1606                         // if we executed a mutating lfun, mark the buffer as dirty
1607                         if (flag.enabled()
1608                             && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)
1609                             && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly))
1610                                 view()->buffer()->markDirty();
1611                 }
1612
1613                 if (view()->cursor().inTexted()) {
1614                         view()->owner()->updateLayoutChoice();
1615                 }
1616         }
1617         sendDispatchMessage(_(getMessage()), cmd);
1618 }
1619
1620
1621 void LyXFunc::sendDispatchMessage(string const & msg, FuncRequest const & cmd)
1622 {
1623         /* When an action did not originate from the UI/kbd, it makes
1624          * sense to avoid updating the GUI. It turns out that this
1625          * fixes bug 1941, for reasons that are described here:
1626          * http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
1627          */
1628         if (cmd.origin != FuncRequest::INTERNAL) {
1629                 owner->updateMenubar();
1630                 owner->updateToolbars();
1631         }
1632
1633         const bool verbose = (cmd.origin == FuncRequest::UI
1634                               || cmd.origin == FuncRequest::COMMANDBUFFER);
1635
1636         if (cmd.action == LFUN_SELF_INSERT || !verbose) {
1637                 lyxerr[Debug::ACTION] << "dispatch msg is " << msg << endl;
1638                 if (!msg.empty())
1639                         owner->message(msg);
1640                 return;
1641         }
1642
1643         string dispatch_msg = msg;
1644         if (!dispatch_msg.empty())
1645                 dispatch_msg += ' ';
1646
1647         string comname = lyxaction.getActionName(cmd.action);
1648
1649         bool argsadded = false;
1650
1651         if (!cmd.argument.empty()) {
1652                 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1653                         comname += ' ' + cmd.argument;
1654                         argsadded = true;
1655                 }
1656         }
1657
1658         string const shortcuts = toplevel_keymap->printbindings(cmd);
1659
1660         if (!shortcuts.empty())
1661                 comname += ": " + shortcuts;
1662         else if (!argsadded && !cmd.argument.empty())
1663                 comname += ' ' + cmd.argument;
1664
1665         if (!comname.empty()) {
1666                 comname = rtrim(comname);
1667                 dispatch_msg += '(' + rtrim(comname) + ')';
1668         }
1669
1670         lyxerr[Debug::ACTION] << "verbose dispatch msg " << dispatch_msg << endl;
1671         if (!dispatch_msg.empty())
1672                 owner->message(dispatch_msg);
1673 }
1674
1675
1676 void LyXFunc::setupLocalKeymap()
1677 {
1678         keyseq.stdmap = toplevel_keymap.get();
1679         keyseq.curmap = toplevel_keymap.get();
1680         cancel_meta_seq.stdmap = toplevel_keymap.get();
1681         cancel_meta_seq.curmap = toplevel_keymap.get();
1682 }
1683
1684
1685 void LyXFunc::menuNew(string const & name, bool fromTemplate)
1686 {
1687         string initpath = lyxrc.document_path;
1688         string filename(name);
1689
1690         if (view()->available()) {
1691                 string const trypath = owner->buffer()->filePath();
1692                 // If directory is writeable, use this as default.
1693                 if (isDirWriteable(trypath))
1694                         initpath = trypath;
1695         }
1696
1697         static int newfile_number;
1698
1699         if (filename.empty()) {
1700                 filename = addName(lyxrc.document_path,
1701                             "newfile" + convert<string>(++newfile_number) + ".lyx");
1702                 while (bufferlist.exists(filename) || fs::is_readable(filename)) {
1703                         ++newfile_number;
1704                         filename = addName(lyxrc.document_path,
1705                                            "newfile" +  convert<string>(newfile_number) +
1706                                     ".lyx");
1707                 }
1708         }
1709
1710         // The template stuff
1711         string templname;
1712         if (fromTemplate) {
1713                 FileDialog fileDlg(_("Select template file"),
1714                         LFUN_SELECT_FILE_SYNC,
1715                         make_pair(string(_("Documents|#o#O")),
1716                                   string(lyxrc.document_path)),
1717                         make_pair(string(_("Templates|#T#t")),
1718                                   string(lyxrc.template_path)));
1719
1720                 FileDialog::Result result =
1721                         fileDlg.open(lyxrc.template_path,
1722                                      FileFilterList(_("LyX Documents (*.lyx)")),
1723                                      string());
1724
1725                 if (result.first == FileDialog::Later)
1726                         return;
1727                 if (result.second.empty())
1728                         return;
1729                 templname = result.second;
1730         }
1731
1732         Buffer * const b = newFile(filename, templname, !name.empty());
1733         if (b)
1734                 owner->setBuffer(b);
1735 }
1736
1737
1738 void LyXFunc::open(string const & fname)
1739 {
1740         string initpath = lyxrc.document_path;
1741
1742         if (view()->available()) {
1743                 string const trypath = owner->buffer()->filePath();
1744                 // If directory is writeable, use this as default.
1745                 if (isDirWriteable(trypath))
1746                         initpath = trypath;
1747         }
1748
1749         string filename;
1750
1751         if (fname.empty()) {
1752                 FileDialog fileDlg(_("Select document to open"),
1753                         LFUN_FILE_OPEN,
1754                         make_pair(string(_("Documents|#o#O")),
1755                                   string(lyxrc.document_path)),
1756                         make_pair(string(_("Examples|#E#e")),
1757                                   string(addPath(package().system_support(), "examples"))));
1758
1759                 FileDialog::Result result =
1760                         fileDlg.open(initpath,
1761                                      FileFilterList(_("LyX Documents (*.lyx)")),
1762                                      string());
1763
1764                 if (result.first == FileDialog::Later)
1765                         return;
1766
1767                 filename = result.second;
1768
1769                 // check selected filename
1770                 if (filename.empty()) {
1771                         owner->message(_("Canceled."));
1772                         return;
1773                 }
1774         } else
1775                 filename = fname;
1776
1777         // get absolute path of file and add ".lyx" to the filename if
1778         // necessary
1779         string const fullpath = fileSearch(string(), filename, "lyx");
1780         if (!fullpath.empty()) {
1781                 filename = fullpath;
1782         }
1783
1784         string const disp_fn(makeDisplayPath(filename));
1785
1786         // if the file doesn't exist, let the user create one
1787         if (!fs::exists(filename)) {
1788                 // the user specifically chose this name. Believe him.
1789                 Buffer * const b = newFile(filename, string(), true);
1790                 if (b)
1791                         owner->setBuffer(b);
1792                 return;
1793         }
1794
1795         owner->message(bformat(_("Opening document %1$s..."), disp_fn));
1796
1797         string str2;
1798         if (owner->loadLyXFile(filename)) {
1799                 str2 = bformat(_("Document %1$s opened."), disp_fn);
1800         } else {
1801                 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1802         }
1803         owner->message(str2);
1804 }
1805
1806
1807 void LyXFunc::doImport(string const & argument)
1808 {
1809         string format;
1810         string filename = split(argument, format, ' ');
1811
1812         lyxerr[Debug::INFO] << "LyXFunc::doImport: " << format
1813                             << " file: " << filename << endl;
1814
1815         // need user interaction
1816         if (filename.empty()) {
1817                 string initpath = lyxrc.document_path;
1818
1819                 if (view()->available()) {
1820                         string const trypath = owner->buffer()->filePath();
1821                         // If directory is writeable, use this as default.
1822                         if (isDirWriteable(trypath))
1823                                 initpath = trypath;
1824                 }
1825
1826                 string const text = bformat(_("Select %1$s file to import"),
1827                         formats.prettyName(format));
1828
1829                 FileDialog fileDlg(text,
1830                         LFUN_BUFFER_IMPORT,
1831                         make_pair(string(_("Documents|#o#O")),
1832                                   string(lyxrc.document_path)),
1833                         make_pair(string(_("Examples|#E#e")),
1834                                   string(addPath(package().system_support(), "examples"))));
1835
1836                 string const filter = formats.prettyName(format)
1837                         + " (*." + formats.extension(format) + ')';
1838
1839                 FileDialog::Result result =
1840                         fileDlg.open(initpath,
1841                                      FileFilterList(filter),
1842                                      string());
1843
1844                 if (result.first == FileDialog::Later)
1845                         return;
1846
1847                 filename = result.second;
1848
1849                 // check selected filename
1850                 if (filename.empty())
1851                         owner->message(_("Canceled."));
1852         }
1853
1854         if (filename.empty())
1855                 return;
1856
1857         // get absolute path of file
1858         filename = makeAbsPath(filename);
1859
1860         string const lyxfile = changeExtension(filename, ".lyx");
1861
1862         // Check if the document already is open
1863         if (lyx_gui::use_gui && bufferlist.exists(lyxfile)) {
1864                 if (!bufferlist.close(bufferlist.getBuffer(lyxfile), true)) {
1865                         owner->message(_("Canceled."));
1866                         return;
1867                 }
1868         }
1869
1870         // if the file exists already, and we didn't do
1871         // -i lyx thefile.lyx, warn
1872         if (fs::exists(lyxfile) && filename != lyxfile) {
1873                 string const file = makeDisplayPath(lyxfile, 30);
1874
1875                 string text = bformat(_("The document %1$s already exists.\n\n"
1876                         "Do you want to over-write that document?"), file);
1877                 int const ret = Alert::prompt(_("Over-write document?"),
1878                         text, 0, 1, _("&Over-write"), _("&Cancel"));
1879
1880                 if (ret == 1) {
1881                         owner->message(_("Canceled."));
1882                         return;
1883                 }
1884         }
1885
1886         ErrorList errorList;
1887         Importer::Import(owner, filename, format, errorList);
1888         // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1889 }
1890
1891
1892 void LyXFunc::closeBuffer()
1893 {
1894         // save current cursor position
1895         LyX::ref().session().saveFilePosition(owner->buffer()->fileName(),
1896                 boost::tie(view()->cursor().pit(), view()->cursor().pos()) );
1897         if (bufferlist.close(owner->buffer(), true) && !quitting) {
1898                 if (bufferlist.empty()) {
1899                         // need this otherwise SEGV may occur while
1900                         // trying to set variables that don't exist
1901                         // since there's no current buffer
1902                         owner->getDialogs().hideBufferDependent();
1903                 } else {
1904                         owner->setBuffer(bufferlist.first());
1905                 }
1906         }
1907 }
1908
1909
1910 // Each "owner" should have it's own message method. lyxview and
1911 // the minibuffer would use the minibuffer, but lyxserver would
1912 // send an ERROR signal to its client.  Alejandro 970603
1913 // This function is bit problematic when it comes to NLS, to make the
1914 // lyx servers client be language indepenent we must not translate
1915 // strings sent to this func.
1916 void LyXFunc::setErrorMessage(string const & m) const
1917 {
1918         dispatch_buffer = m;
1919         errorstat = true;
1920 }
1921
1922
1923 void LyXFunc::setMessage(string const & m) const
1924 {
1925         dispatch_buffer = m;
1926 }
1927
1928
1929 string const LyXFunc::viewStatusMessage()
1930 {
1931         // When meta-fake key is pressed, show the key sequence so far + "M-".
1932         if (wasMetaKey())
1933                 return keyseq.print() + "M-";
1934
1935         // Else, when a non-complete key sequence is pressed,
1936         // show the available options.
1937         if (keyseq.length() > 0 && !keyseq.deleted())
1938                 return keyseq.printOptions();
1939
1940         if (!view()->available())
1941                 return _("Welcome to LyX!");
1942
1943         return view()->cursor().currentState();
1944 }
1945
1946
1947 BufferView * LyXFunc::view() const
1948 {
1949         BOOST_ASSERT(owner);
1950         return owner->view();
1951 }
1952
1953
1954 bool LyXFunc::wasMetaKey() const
1955 {
1956         return (meta_fake_bit != key_modifier::none);
1957 }
1958
1959
1960 namespace {
1961
1962 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
1963 {
1964         // Why the switch you might ask. It is a trick to ensure that all
1965         // the elements in the LyXRCTags enum is handled. As you can see
1966         // there are no breaks at all. So it is just a huge fall-through.
1967         // The nice thing is that we will get a warning from the compiler
1968         // if we forget an element.
1969         LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
1970         switch (tag) {
1971         case LyXRC::RC_ACCEPT_COMPOUND:
1972         case LyXRC::RC_ALT_LANG:
1973         case LyXRC::RC_ASCIIROFF_COMMAND:
1974         case LyXRC::RC_ASCII_LINELEN:
1975         case LyXRC::RC_AUTOREGIONDELETE:
1976         case LyXRC::RC_AUTORESET_OPTIONS:
1977         case LyXRC::RC_AUTOSAVE:
1978         case LyXRC::RC_AUTO_NUMBER:
1979         case LyXRC::RC_BACKUPDIR_PATH:
1980         case LyXRC::RC_BIBTEX_COMMAND:
1981         case LyXRC::RC_BINDFILE:
1982         case LyXRC::RC_CHECKLASTFILES:
1983         case LyXRC::RC_USELASTFILEPOS:
1984         case LyXRC::RC_LOADSESSION:
1985         case LyXRC::RC_CHKTEX_COMMAND:
1986         case LyXRC::RC_CONVERTER:
1987         case LyXRC::RC_COPIER:
1988         case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
1989         case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
1990         case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
1991         case LyXRC::RC_DATE_INSERT_FORMAT:
1992         case LyXRC::RC_DEFAULT_LANGUAGE:
1993         case LyXRC::RC_DEFAULT_PAPERSIZE:
1994         case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
1995         case LyXRC::RC_DISPLAY_GRAPHICS:
1996         case LyXRC::RC_DOCUMENTPATH:
1997                 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
1998                         if (fs::exists(lyxrc_new.document_path) &&
1999                             fs::is_directory(lyxrc_new.document_path)) {
2000                                 using lyx::support::package;
2001                                 package().document_dir() = lyxrc.document_path;
2002                         }
2003                 }
2004         case LyXRC::RC_ESC_CHARS:
2005         case LyXRC::RC_FONT_ENCODING:
2006         case LyXRC::RC_FORMAT:
2007         case LyXRC::RC_INDEX_COMMAND:
2008         case LyXRC::RC_INPUT:
2009         case LyXRC::RC_KBMAP:
2010         case LyXRC::RC_KBMAP_PRIMARY:
2011         case LyXRC::RC_KBMAP_SECONDARY:
2012         case LyXRC::RC_LABEL_INIT_LENGTH:
2013         case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2014         case LyXRC::RC_LANGUAGE_AUTO_END:
2015         case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2016         case LyXRC::RC_LANGUAGE_COMMAND_END:
2017         case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2018         case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2019         case LyXRC::RC_LANGUAGE_PACKAGE:
2020         case LyXRC::RC_LANGUAGE_USE_BABEL:
2021         case LyXRC::RC_MAKE_BACKUP:
2022         case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2023         case LyXRC::RC_NUMLASTFILES:
2024         case LyXRC::RC_PATH_PREFIX:
2025                 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2026                         using lyx::support::prependEnvPath;
2027                         prependEnvPath("PATH", lyxrc.path_prefix);
2028                 }
2029         case LyXRC::RC_PERS_DICT:
2030         case LyXRC::RC_POPUP_BOLD_FONT:
2031         case LyXRC::RC_POPUP_FONT_ENCODING:
2032         case LyXRC::RC_POPUP_NORMAL_FONT:
2033         case LyXRC::RC_PREVIEW:
2034         case LyXRC::RC_PREVIEW_HASHED_LABELS:
2035         case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2036         case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2037         case LyXRC::RC_PRINTCOPIESFLAG:
2038         case LyXRC::RC_PRINTER:
2039         case LyXRC::RC_PRINTEVENPAGEFLAG:
2040         case LyXRC::RC_PRINTEXSTRAOPTIONS:
2041         case LyXRC::RC_PRINTFILEEXTENSION:
2042         case LyXRC::RC_PRINTLANDSCAPEFLAG:
2043         case LyXRC::RC_PRINTODDPAGEFLAG:
2044         case LyXRC::RC_PRINTPAGERANGEFLAG:
2045         case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2046         case LyXRC::RC_PRINTPAPERFLAG:
2047         case LyXRC::RC_PRINTREVERSEFLAG:
2048         case LyXRC::RC_PRINTSPOOL_COMMAND:
2049         case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2050         case LyXRC::RC_PRINTTOFILE:
2051         case LyXRC::RC_PRINTTOPRINTER:
2052         case LyXRC::RC_PRINT_ADAPTOUTPUT:
2053         case LyXRC::RC_PRINT_COMMAND:
2054         case LyXRC::RC_RTL_SUPPORT:
2055         case LyXRC::RC_SCREEN_DPI:
2056         case LyXRC::RC_SCREEN_FONT_ENCODING:
2057         case LyXRC::RC_SCREEN_FONT_ROMAN:
2058         case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2059         case LyXRC::RC_SCREEN_FONT_SANS:
2060         case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2061         case LyXRC::RC_SCREEN_FONT_SCALABLE:
2062         case LyXRC::RC_SCREEN_FONT_SIZES:
2063         case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2064         case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2065         case LyXRC::RC_SCREEN_GEOMETRY_HEIGHT:
2066         case LyXRC::RC_SCREEN_GEOMETRY_WIDTH:
2067         case LyXRC::RC_SCREEN_GEOMETRY_XYSAVED:
2068         case LyXRC::RC_SCREEN_ZOOM:
2069         case LyXRC::RC_SERVERPIPE:
2070         case LyXRC::RC_SET_COLOR:
2071         case LyXRC::RC_SHOW_BANNER:
2072         case LyXRC::RC_SPELL_COMMAND:
2073         case LyXRC::RC_TEMPDIRPATH:
2074         case LyXRC::RC_TEMPLATEPATH:
2075         case LyXRC::RC_TEX_ALLOWS_SPACES:
2076         case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2077                 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2078                         namespace os = lyx::support::os;
2079                         os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2080                 }
2081         case LyXRC::RC_UIFILE:
2082         case LyXRC::RC_USER_EMAIL:
2083         case LyXRC::RC_USER_NAME:
2084         case LyXRC::RC_USETEMPDIR:
2085         case LyXRC::RC_USE_ALT_LANG:
2086         case LyXRC::RC_USE_ESC_CHARS:
2087         case LyXRC::RC_USE_INP_ENC:
2088         case LyXRC::RC_USE_PERS_DICT:
2089         case LyXRC::RC_USE_SPELL_LIB:
2090         case LyXRC::RC_VIEWDVI_PAPEROPTION:
2091         case LyXRC::RC_VIEWER:
2092         case LyXRC::RC_LAST:
2093                 break;
2094         }
2095 }
2096
2097 } // namespace anon