]> git.lyx.org Git - lyx.git/blob - src/lyxfunc.C
Extracted from r14281
[lyx.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                         view()->showErrorList(bufferFormat(*owner->buffer()));
841                         break;
842
843                 case LFUN_BUFFER_VIEW:
844                         Exporter::preview(owner->buffer(), argument);
845                         view()->showErrorList(bufferFormat(*owner->buffer()));
846                         break;
847
848                 case LFUN_BUILD_PROGRAM:
849                         Exporter::Export(owner->buffer(), "program", true);
850                         view()->showErrorList(_("Build"));
851                         break;
852
853                 case LFUN_BUFFER_CHKTEX:
854                         owner->buffer()->runChktex();
855                         view()->showErrorList(_("ChkTeX"));
856                         break;
857
858                 case LFUN_BUFFER_EXPORT:
859                         if (argument == "custom")
860                                 owner->getDialogs().show("sendto");
861                         else {
862                                 Exporter::Export(owner->buffer(), argument, false);
863                                 view()->showErrorList(bufferFormat(*owner->buffer()));
864                         }
865                         break;
866
867                 case LFUN_BUFFER_EXPORT_CUSTOM: {
868                         string format_name;
869                         string command = split(argument, format_name, ' ');
870                         Format const * format = formats.getFormat(format_name);
871                         if (!format) {
872                                 lyxerr << "Format \"" << format_name
873                                        << "\" not recognized!"
874                                        << std::endl;
875                                 break;
876                         }
877
878                         Buffer * buffer = owner->buffer();
879
880                         // The name of the file created by the conversion process
881                         string filename;
882
883                         // Output to filename
884                         if (format->name() == "lyx") {
885                                 string const latexname =
886                                         buffer->getLatexName(false);
887                                 filename = changeExtension(latexname,
888                                                            format->extension());
889                                 filename = addName(buffer->temppath(), filename);
890
891                                 if (!buffer->writeFile(filename))
892                                         break;
893
894                         } else {
895                                 Exporter::Export(buffer, format_name, true,
896                                                  filename);
897                         }
898
899                         // Substitute $$FName for filename
900                         if (!contains(command, "$$FName"))
901                                 command = "( " + command + " ) < $$FName";
902                         command = subst(command, "$$FName", filename);
903
904                         // Execute the command in the background
905                         Systemcall call;
906                         call.startscript(Systemcall::DontWait, command);
907                         break;
908                 }
909
910                 case LFUN_BUFFER_PRINT: {
911                         string target;
912                         string target_name;
913                         string command = split(split(argument, target, ' '),
914                                                target_name, ' ');
915
916                         if (target.empty()
917                             || target_name.empty()
918                             || command.empty()) {
919                                 lyxerr << "Unable to parse \""
920                                        << argument << '"' << std::endl;
921                                 break;
922                         }
923                         if (target != "printer" && target != "file") {
924                                 lyxerr << "Unrecognized target \""
925                                        << target << '"' << std::endl;
926                                 break;
927                         }
928
929                         Buffer * buffer = owner->buffer();
930
931                         if (!Exporter::Export(buffer, "dvi", true)) {
932                                 showPrintError(buffer->fileName());
933                                 break;
934                         }
935
936                         // Push directory path.
937                         string const path = buffer->temppath();
938                         Path p(path);
939
940                         // there are three cases here:
941                         // 1. we print to a file
942                         // 2. we print directly to a printer
943                         // 3. we print using a spool command (print to file first)
944                         Systemcall one;
945                         int res = 0;
946                         string const dviname =
947                                 changeExtension(buffer->getLatexName(true),
948                                                 "dvi");
949
950                         if (target == "printer") {
951                                 if (!lyxrc.print_spool_command.empty()) {
952                                         // case 3: print using a spool
953                                         string const psname =
954                                                 changeExtension(dviname,".ps");
955                                         command += lyxrc.print_to_file
956                                                 + quoteName(psname)
957                                                 + ' '
958                                                 + quoteName(dviname);
959
960                                         string command2 =
961                                                 lyxrc.print_spool_command +' ';
962                                         if (target_name != "default") {
963                                                 command2 += lyxrc.print_spool_printerprefix
964                                                         + target_name
965                                                         + ' ';
966                                         }
967                                         command2 += quoteName(psname);
968                                         // First run dvips.
969                                         // If successful, then spool command
970                                         res = one.startscript(
971                                                 Systemcall::Wait,
972                                                 command);
973
974                                         if (res == 0)
975                                                 res = one.startscript(
976                                                         Systemcall::DontWait,
977                                                         command2);
978                                 } else {
979                                         // case 2: print directly to a printer
980                                         res = one.startscript(
981                                                 Systemcall::DontWait,
982                                                 command + quoteName(dviname));
983                                 }
984
985                         } else {
986                                 // case 1: print to a file
987                                 command += lyxrc.print_to_file
988                                         + quoteName(makeAbsPath(target_name,
989                                                                 path))
990                                         + ' '
991                                         + quoteName(dviname);
992                                 res = one.startscript(Systemcall::DontWait,
993                                                       command);
994                         }
995
996                         if (res != 0)
997                                 showPrintError(buffer->fileName());
998                         break;
999                 }
1000
1001                 case LFUN_BUFFER_IMPORT:
1002                         doImport(argument);
1003                         break;
1004
1005                 case LFUN_LYX_QUIT:
1006                         if (view()->available()) {
1007                                 // save cursor Position for opened files to .lyx/session
1008                                 LyX::ref().session().saveFilePosition(owner->buffer()->fileName(),
1009                                         boost::tie(view()->cursor().pit(), view()->cursor().pos()) );
1010                                 // save bookmarks to .lyx/session
1011                                 view()->saveSavedPositions();
1012                         }
1013                         quitLyX(argument == "force");
1014                         break;
1015
1016                 case LFUN_TOC_VIEW: {
1017                         InsetCommandParams p("tableofcontents");
1018                         string const data = InsetCommandMailer::params2string("toc", p);
1019                         owner->getDialogs().show("toc", data, 0);
1020                         break;
1021                 }
1022
1023                 case LFUN_BUFFER_AUTO_SAVE:
1024                         autoSave(view());
1025                         break;
1026
1027                 case LFUN_RECONFIGURE:
1028                         reconfigure(view());
1029                         break;
1030
1031                 case LFUN_HELP_OPEN: {
1032                         string const arg = argument;
1033                         if (arg.empty()) {
1034                                 setErrorMessage(N_("Missing argument"));
1035                                 break;
1036                         }
1037                         string const fname = i18nLibFileSearch("doc", arg, "lyx");
1038                         if (fname.empty()) {
1039                                 lyxerr << "LyX: unable to find documentation file `"
1040                                                          << arg << "'. Bad installation?" << endl;
1041                                 break;
1042                         }
1043                         owner->message(bformat(_("Opening help file %1$s..."),
1044                                 makeDisplayPath(fname)));
1045                         view()->loadLyXFile(fname, false);
1046                         break;
1047                 }
1048
1049                 // --- version control -------------------------------
1050                 case LFUN_VC_REGISTER:
1051                         if (!ensureBufferClean(view()))
1052                                 break;
1053                         if (!owner->buffer()->lyxvc().inUse()) {
1054                                 owner->buffer()->lyxvc().registrer();
1055                                 view()->reload();
1056                         }
1057                         break;
1058
1059                 case LFUN_VC_CHECK_IN:
1060                         if (!ensureBufferClean(view()))
1061                                 break;
1062                         if (owner->buffer()->lyxvc().inUse()
1063                                         && !owner->buffer()->isReadonly()) {
1064                                 owner->buffer()->lyxvc().checkIn();
1065                                 view()->reload();
1066                         }
1067                         break;
1068
1069                 case LFUN_VC_CHECK_OUT:
1070                         if (!ensureBufferClean(view()))
1071                                 break;
1072                         if (owner->buffer()->lyxvc().inUse()
1073                                         && owner->buffer()->isReadonly()) {
1074                                 owner->buffer()->lyxvc().checkOut();
1075                                 view()->reload();
1076                         }
1077                         break;
1078
1079                 case LFUN_VC_REVERT:
1080                         owner->buffer()->lyxvc().revert();
1081                         view()->reload();
1082                         break;
1083
1084                 case LFUN_VC_UNDO_LAST:
1085                         owner->buffer()->lyxvc().undoLast();
1086                         view()->reload();
1087                         break;
1088
1089                 // --- buffers ----------------------------------------
1090                 case LFUN_BUFFER_SWITCH:
1091                         view()->setBuffer(bufferlist.getBuffer(argument));
1092                         break;
1093
1094                 case LFUN_BUFFER_NEXT:
1095                         view()->setBuffer(bufferlist.next(view()->buffer()));
1096                         break;
1097
1098                 case LFUN_BUFFER_PREVIOUS:
1099                         view()->setBuffer(bufferlist.previous(view()->buffer()));
1100                         break;
1101
1102                 case LFUN_FILE_NEW:
1103                         newFile(view(), argument);
1104                         break;
1105
1106                 case LFUN_FILE_OPEN:
1107                         open(argument);
1108                         break;
1109
1110                 case LFUN_DROP_LAYOUTS_CHOICE:
1111                         owner->getToolbars().openLayoutList();
1112                         break;
1113
1114                 case LFUN_MENU_OPEN:
1115                         owner->getMenubar().openByName(argument);
1116                         break;
1117
1118                 // --- lyxserver commands ----------------------------
1119                 case LFUN_SERVER_GET_NAME:
1120                         setMessage(owner->buffer()->fileName());
1121                         lyxerr[Debug::INFO] << "FNAME["
1122                                                          << owner->buffer()->fileName()
1123                                                          << "] " << endl;
1124                         break;
1125
1126                 case LFUN_SERVER_NOTIFY:
1127                         dispatch_buffer = keyseq.print();
1128                         lyxserver->notifyClient(dispatch_buffer);
1129                         break;
1130
1131                 case LFUN_SERVER_GOTO_FILE_ROW: {
1132                         string file_name;
1133                         int row;
1134                         istringstream is(argument);
1135                         is >> file_name >> row;
1136                         if (prefixIs(file_name, package().temp_dir())) {
1137                                 // Needed by inverse dvi search. If it is a file
1138                                 // in tmpdir, call the apropriated function
1139                                 view()->setBuffer(bufferlist.getBufferFromTmp(file_name));
1140                         } else {
1141                                 // Must replace extension of the file to be .lyx
1142                                 // and get full path
1143                                 string const s = changeExtension(file_name, ".lyx");
1144                                 // Either change buffer or load the file
1145                                 if (bufferlist.exists(s)) {
1146                                         view()->setBuffer(bufferlist.getBuffer(s));
1147                                 } else {
1148                                         view()->loadLyXFile(s);
1149                                 }
1150                         }
1151
1152                         view()->setCursorFromRow(row);
1153
1154                         view()->center();
1155                         // see BufferView_pimpl::center()
1156                         break;
1157                 }
1158
1159                 case LFUN_DIALOG_SHOW: {
1160                         string const name = cmd.getArg(0);
1161                         string data = trim(cmd.argument.substr(name.size()));
1162
1163                         if (name == "character") {
1164                                 data = freefont2string();
1165                                 if (!data.empty())
1166                                         owner->getDialogs().show("character", data);
1167                         } else if (name == "latexlog") {
1168                                 pair<Buffer::LogType, string> const logfile =
1169                                         owner->buffer()->getLogName();
1170                                 switch (logfile.first) {
1171                                 case Buffer::latexlog:
1172                                         data = "latex ";
1173                                         break;
1174                                 case Buffer::buildlog:
1175                                         data = "literate ";
1176                                         break;
1177                                 }
1178                                 data += logfile.second;
1179                                 owner->getDialogs().show("log", data);
1180                         } else if (name == "vclog") {
1181                                 string const data = "vc " +
1182                                         owner->buffer()->lyxvc().getLogFile();
1183                                 owner->getDialogs().show("log", data);
1184                         } else
1185                                 owner->getDialogs().show(name, data);
1186                         break;
1187                 }
1188
1189                 case LFUN_DIALOG_SHOW_NEW_INSET: {
1190                         string const name = cmd.getArg(0);
1191                         string data = trim(cmd.argument.substr(name.size()));
1192                         if (name == "bibitem" ||
1193                             name == "bibtex" ||
1194                             name == "index" ||
1195                             name == "label" ||
1196                             name == "ref" ||
1197                             name == "toc" ||
1198                             name == "url") {
1199                                 InsetCommandParams p(name);
1200                                 data = InsetCommandMailer::params2string(name, p);
1201                         } else if (name == "include") {
1202                                 InsetCommandParams p(data);
1203                                 data = InsetIncludeMailer::params2string(p);
1204                         } else if (name == "box") {
1205                                 // \c data == "Boxed" || "Frameless" etc
1206                                 InsetBoxParams p(data);
1207                                 data = InsetBoxMailer::params2string(p);
1208                         } else if (name == "branch") {
1209                                 InsetBranchParams p;
1210                                 data = InsetBranchMailer::params2string(p);
1211                         } else if (name == "citation") {
1212                                 InsetCommandParams p("cite");
1213                                 data = InsetCommandMailer::params2string(name, p);
1214                         } else if (name == "ert") {
1215                                 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1216                         } else if (name == "external") {
1217                                 InsetExternalParams p;
1218                                 Buffer const & buffer = *owner->buffer();
1219                                 data = InsetExternalMailer::params2string(p, buffer);
1220                         } else if (name == "float") {
1221                                 InsetFloatParams p;
1222                                 data = InsetFloatMailer::params2string(p);
1223                         } else if (name == "graphics") {
1224                                 InsetGraphicsParams p;
1225                                 Buffer const & buffer = *owner->buffer();
1226                                 data = InsetGraphicsMailer::params2string(p, buffer);
1227                         } else if (name == "note") {
1228                                 InsetNoteParams p;
1229                                 data = InsetNoteMailer::params2string(p);
1230                         } else if (name == "vspace") {
1231                                 VSpace space;
1232                                 data = InsetVSpaceMailer::params2string(space);
1233                         } else if (name == "wrap") {
1234                                 InsetWrapParams p;
1235                                 data = InsetWrapMailer::params2string(p);
1236                         }
1237                         owner->getDialogs().show(name, data, 0);
1238                         break;
1239                 }
1240
1241                 case LFUN_DIALOG_SHOW_NEXT_INSET:
1242                         break;
1243
1244                 case LFUN_DIALOG_UPDATE: {
1245                         string const & name = argument;
1246                         // Can only update a dialog connected to an existing inset
1247                         InsetBase * inset = owner->getDialogs().getOpenInset(name);
1248                         if (inset) {
1249                                 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument);
1250                                 inset->dispatch(view()->cursor(), fr);
1251                         } else if (name == "paragraph") {
1252                                 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1253                         } else if (name == "prefs") {
1254                                 owner->getDialogs().update(name, string());
1255                         }
1256                         break;
1257                 }
1258
1259                 case LFUN_DIALOG_HIDE:
1260                         Dialogs::hide(argument, 0);
1261                         break;
1262
1263                 case LFUN_DIALOG_DISCONNECT_INSET:
1264                         owner->getDialogs().disconnect(argument);
1265                         break;
1266
1267
1268                 case LFUN_CITATION_INSERT: {
1269                         if (!argument.empty()) {
1270                                 // we can have one optional argument, delimited by '|'
1271                                 // citation-insert <key>|<text_before>
1272                                 // this should be enhanced to also support text_after
1273                                 // and citation style
1274                                 string arg = argument;
1275                                 string opt1;
1276                                 if (contains(argument, "|")) {
1277                                         arg = token(argument, '|', 0);
1278                                         opt1 = '[' + token(argument, '|', 1) + ']';
1279                                 }
1280                                 std::ostringstream os;
1281                                 os << "citation LatexCommand\n"
1282                                    << "\\cite" << opt1 << "{" << arg << "}\n"
1283                                    << "\\end_inset";
1284                                 FuncRequest fr(LFUN_INSET_INSERT, os.str());
1285                                 dispatch(fr);
1286                         } else
1287                                 dispatch(FuncRequest(LFUN_DIALOG_SHOW, "citation"));
1288                         break;
1289                 }
1290
1291                 case LFUN_BUFFER_CHILD_OPEN: {
1292                         string const filename =
1293                                 makeAbsPath(argument, owner->buffer()->filePath());
1294                         setMessage(N_("Opening child document ") +
1295                                          makeDisplayPath(filename) + "...");
1296                         view()->savePosition(0);
1297                         string const parentfilename = owner->buffer()->fileName();
1298                         if (bufferlist.exists(filename))
1299                                 view()->setBuffer(bufferlist.getBuffer(filename));
1300                         else
1301                                 view()->loadLyXFile(filename);
1302                         // Set the parent name of the child document.
1303                         // This makes insertion of citations and references in the child work,
1304                         // when the target is in the parent or another child document.
1305                         owner->buffer()->setParentName(parentfilename);
1306                         break;
1307                 }
1308
1309                 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1310                         lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1311                         break;
1312
1313                 case LFUN_KEYMAP_OFF:
1314                         owner->getIntl().keyMapOn(false);
1315                         break;
1316
1317                 case LFUN_KEYMAP_PRIMARY:
1318                         owner->getIntl().keyMapPrim();
1319                         break;
1320
1321                 case LFUN_KEYMAP_SECONDARY:
1322                         owner->getIntl().keyMapSec();
1323                         break;
1324
1325                 case LFUN_KEYMAP_TOGGLE:
1326                         owner->getIntl().toggleKeyMap();
1327                         break;
1328
1329                 case LFUN_REPEAT: {
1330                         // repeat command
1331                         string countstr;
1332                         string rest = split(argument, countstr, ' ');
1333                         istringstream is(countstr);
1334                         int count = 0;
1335                         is >> count;
1336                         lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1337                         for (int i = 0; i < count; ++i)
1338                                 dispatch(lyxaction.lookupFunc(rest));
1339                         break;
1340                 }
1341
1342                 case LFUN_COMMAND_SEQUENCE: {
1343                         // argument contains ';'-terminated commands
1344                         string arg = argument;
1345                         while (!arg.empty()) {
1346                                 string first;
1347                                 arg = split(arg, first, ';');
1348                                 FuncRequest func(lyxaction.lookupFunc(first));
1349                                 func.origin = cmd.origin;
1350                                 dispatch(func);
1351                         }
1352                         break;
1353                 }
1354
1355                 case LFUN_PREFERENCES_SAVE: {
1356                         Path p(package().user_support());
1357                         lyxrc.write("preferences", false);
1358                         break;
1359                 }
1360
1361                 case LFUN_SCREEN_FONT_UPDATE:
1362                         // handle the screen font changes.
1363                         lyxrc.set_font_norm_type();
1364                         lyx_gui::update_fonts();
1365                         // All visible buffers will need resize
1366                         view()->resize();
1367                         break;
1368
1369                 case LFUN_SET_COLOR: {
1370                         string lyx_name;
1371                         string const x11_name = split(argument, lyx_name, ' ');
1372                         if (lyx_name.empty() || x11_name.empty()) {
1373                                 setErrorMessage(N_("Syntax: set-color <lyx_name>"
1374                                                         " <x11_name>"));
1375                                 break;
1376                         }
1377
1378                         bool const graphicsbg_changed =
1379                                 (lyx_name == lcolor.getLyXName(LColor::graphicsbg) &&
1380                                  x11_name != lcolor.getX11Name(LColor::graphicsbg));
1381
1382                         if (!lcolor.setColor(lyx_name, x11_name)) {
1383                                 setErrorMessage(
1384                                         bformat(_("Set-color \"%1$s\" failed "
1385                                                                 "- color is undefined or "
1386                                                                 "may not be redefined"), lyx_name));
1387                                 break;
1388                         }
1389
1390                         lyx_gui::update_color(lcolor.getFromLyXName(lyx_name));
1391
1392                         if (graphicsbg_changed) {
1393 #ifdef WITH_WARNINGS
1394 #warning FIXME!! The graphics cache no longer has a changeDisplay method.
1395 #endif
1396 #if 0
1397                                 lyx::graphics::GCache::get().changeDisplay(true);
1398 #endif
1399                         }
1400                         break;
1401                 }
1402
1403                 case LFUN_MESSAGE:
1404                         owner->message(argument);
1405                         break;
1406
1407                 case LFUN_TOOLTIPS_TOGGLE:
1408                         owner->getDialogs().toggleTooltips();
1409                         break;
1410
1411                 case LFUN_EXTERNAL_EDIT: {
1412                         FuncRequest fr(action, argument);
1413                         InsetExternal().dispatch(view()->cursor(), fr);
1414                         break;
1415                 }
1416
1417                 case LFUN_GRAPHICS_EDIT: {
1418                         FuncRequest fr(action, argument);
1419                         InsetGraphics().dispatch(view()->cursor(), fr);
1420                         break;
1421                 }
1422
1423                 case LFUN_INSET_APPLY: {
1424                         string const name = cmd.getArg(0);
1425                         InsetBase * inset = owner->getDialogs().getOpenInset(name);
1426                         if (inset) {
1427                                 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1428                                 inset->dispatch(view()->cursor(), fr);
1429                         } else {
1430                                 FuncRequest fr(LFUN_INSET_INSERT, argument);
1431                                 dispatch(fr);
1432                         }
1433                         // ideally, the update flag should be set by the insets,
1434                         // but this is not possible currently
1435                         updateforce = true;
1436                         break;
1437                 }
1438
1439                 case LFUN_ALL_INSETS_TOGGLE: {
1440                         string action;
1441                         string const name = split(argument, action, ' ');
1442                         InsetBase::Code const inset_code =
1443                                 InsetBase::translate(name);
1444
1445                         LCursor & cur = view()->cursor();
1446                         FuncRequest fr(LFUN_INSET_TOGGLE, action);
1447
1448                         InsetBase & inset = owner->buffer()->inset();
1449                         InsetIterator it  = inset_iterator_begin(inset);
1450                         InsetIterator const end = inset_iterator_end(inset);
1451                         for (; it != end; ++it) {
1452                                 if (inset_code == InsetBase::NO_CODE
1453                                     || inset_code == it->lyxCode()) {
1454                                         LCursor tmpcur = cur;
1455                                         tmpcur.pushLeft(*it);
1456                                         it->dispatch(tmpcur, fr);
1457                                 }
1458                         }
1459                         updateforce = true;
1460                         break;
1461                 }
1462
1463                 case LFUN_BUFFER_LANGUAGE: {
1464                         Buffer & buffer = *owner->buffer();
1465                         Language const * oldL = buffer.params().language;
1466                         Language const * newL = languages.getLanguage(argument);
1467                         if (!newL || oldL == newL)
1468                                 break;
1469
1470                         if (oldL->rightToLeft() == newL->rightToLeft()
1471                             && !buffer.isMultiLingual())
1472                                 buffer.changeLanguage(oldL, newL);
1473                         else
1474                                 buffer.updateDocLang(newL);
1475                         break;
1476                 }
1477
1478                 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1479                         string const fname =
1480                                 addName(addPath(package().user_support(), "templates/"),
1481                                         "defaults.lyx");
1482                         Buffer defaults(fname);
1483
1484                         istringstream ss(argument);
1485                         LyXLex lex(0,0);
1486                         lex.setStream(ss);
1487                         int const unknown_tokens = defaults.readHeader(lex);
1488
1489                         if (unknown_tokens != 0) {
1490                                 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1491                                        << unknown_tokens << " unknown token"
1492                                        << (unknown_tokens == 1 ? "" : "s")
1493                                        << endl;
1494                         }
1495
1496                         if (defaults.writeFile(defaults.fileName()))
1497                                 setMessage(_("Document defaults saved in ")
1498                                            + makeDisplayPath(fname));
1499                         else
1500                                 setErrorMessage(_("Unable to save document defaults"));
1501                         break;
1502                 }
1503
1504                 case LFUN_BUFFER_PARAMS_APPLY: {
1505                         biblio::CiteEngine const engine =
1506                                 owner->buffer()->params().cite_engine;
1507
1508                         istringstream ss(argument);
1509                         LyXLex lex(0,0);
1510                         lex.setStream(ss);
1511                         int const unknown_tokens =
1512                                 owner->buffer()->readHeader(lex);
1513
1514                         if (unknown_tokens != 0) {
1515                                 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1516                                        << unknown_tokens << " unknown token"
1517                                        << (unknown_tokens == 1 ? "" : "s")
1518                                        << endl;
1519                         }
1520                         if (engine == owner->buffer()->params().cite_engine)
1521                                 break;
1522
1523                         LCursor & cur = view()->cursor();
1524                         FuncRequest fr(LFUN_INSET_REFRESH);
1525
1526                         InsetBase & inset = owner->buffer()->inset();
1527                         InsetIterator it  = inset_iterator_begin(inset);
1528                         InsetIterator const end = inset_iterator_end(inset);
1529                         for (; it != end; ++it)
1530                                 if (it->lyxCode() == InsetBase::CITE_CODE)
1531                                         it->dispatch(cur, fr);
1532                         break;
1533                 }
1534
1535                 case LFUN_TEXTCLASS_APPLY: {
1536                         Buffer * buffer = owner->buffer();
1537
1538                         lyx::textclass_type const old_class =
1539                                 buffer->params().textclass;
1540
1541                         loadTextclass(argument);
1542
1543                         std::pair<bool, lyx::textclass_type> const tc_pair =
1544                                 textclasslist.numberOfClass(argument);
1545
1546                         if (!tc_pair.first)
1547                                 break;
1548
1549                         lyx::textclass_type const new_class = tc_pair.second;
1550                         if (old_class == new_class)
1551                                 // nothing to do
1552                                 break;
1553
1554                         owner->message(_("Converting document to new document class..."));
1555                         recordUndoFullDocument(view());
1556                         buffer->params().textclass = new_class;
1557                         StableDocIterator backcur(view()->cursor());
1558                         ErrorList el;
1559                         lyx::cap::switchBetweenClasses(
1560                                 old_class, new_class,
1561                                 static_cast<InsetText &>(buffer->inset()), el);
1562
1563                         view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
1564                         bufferErrors(*buffer, el);
1565                         view()->showErrorList(_("Class switch"));
1566                         updateLabels(*buffer);
1567                         updateforce = true;
1568                         break;
1569                 }
1570
1571                 case LFUN_TEXTCLASS_LOAD:
1572                         loadTextclass(argument);
1573                         break;
1574
1575                 case LFUN_LYXRC_APPLY: {
1576                         LyXRC const lyxrc_orig = lyxrc;
1577
1578                         istringstream ss(argument);
1579                         bool const success = lyxrc.read(ss) == 0;
1580
1581                         if (!success) {
1582                                 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1583                                        << "Unable to read lyxrc data"
1584                                        << endl;
1585                                 break;
1586                         }
1587
1588                         actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1589                         break;
1590                 }
1591
1592                 default: {
1593                         view()->cursor().dispatch(cmd);
1594                         updateforce |= view()->cursor().result().update();
1595                         if (!view()->cursor().result().dispatched())
1596                                 updateforce |= view()->dispatch(cmd);
1597                         break;
1598                 }
1599                 }
1600
1601                 if (view()->available()) {
1602                         // Redraw screen unless explicitly told otherwise.
1603                         // This also initializes the position cache for all insets
1604                         // in (at least partially) visible top-level paragraphs.
1605                         if (updateforce)
1606                                 view()->update(Update::FitCursor | Update::Force);
1607                         else if (update)
1608                                 view()->update(Update::FitCursor);
1609
1610                         // if we executed a mutating lfun, mark the buffer as dirty
1611                         if (flag.enabled()
1612                             && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)
1613                             && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly))
1614                                 view()->buffer()->markDirty();
1615                 }
1616
1617                 if (view()->cursor().inTexted()) {
1618                         view()->owner()->updateLayoutChoice();
1619                 }
1620         }
1621         sendDispatchMessage(_(getMessage()), cmd);
1622 }
1623
1624
1625 void LyXFunc::sendDispatchMessage(string const & msg, FuncRequest const & cmd)
1626 {
1627         /* When an action did not originate from the UI/kbd, it makes
1628          * sense to avoid updating the GUI. It turns out that this
1629          * fixes bug 1941, for reasons that are described here:
1630          * http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
1631          */
1632         if (cmd.origin != FuncRequest::INTERNAL) {
1633                 owner->updateMenubar();
1634                 owner->updateToolbars();
1635         }
1636
1637         const bool verbose = (cmd.origin == FuncRequest::UI
1638                               || cmd.origin == FuncRequest::COMMANDBUFFER);
1639
1640         if (cmd.action == LFUN_SELF_INSERT || !verbose) {
1641                 lyxerr[Debug::ACTION] << "dispatch msg is " << msg << endl;
1642                 if (!msg.empty())
1643                         owner->message(msg);
1644                 return;
1645         }
1646
1647         string dispatch_msg = msg;
1648         if (!dispatch_msg.empty())
1649                 dispatch_msg += ' ';
1650
1651         string comname = lyxaction.getActionName(cmd.action);
1652
1653         bool argsadded = false;
1654
1655         if (!cmd.argument.empty()) {
1656                 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1657                         comname += ' ' + cmd.argument;
1658                         argsadded = true;
1659                 }
1660         }
1661
1662         string const shortcuts = toplevel_keymap->printbindings(cmd);
1663
1664         if (!shortcuts.empty())
1665                 comname += ": " + shortcuts;
1666         else if (!argsadded && !cmd.argument.empty())
1667                 comname += ' ' + cmd.argument;
1668
1669         if (!comname.empty()) {
1670                 comname = rtrim(comname);
1671                 dispatch_msg += '(' + rtrim(comname) + ')';
1672         }
1673
1674         lyxerr[Debug::ACTION] << "verbose dispatch msg " << dispatch_msg << endl;
1675         if (!dispatch_msg.empty())
1676                 owner->message(dispatch_msg);
1677 }
1678
1679
1680 void LyXFunc::setupLocalKeymap()
1681 {
1682         keyseq.stdmap = toplevel_keymap.get();
1683         keyseq.curmap = toplevel_keymap.get();
1684         cancel_meta_seq.stdmap = toplevel_keymap.get();
1685         cancel_meta_seq.curmap = toplevel_keymap.get();
1686 }
1687
1688
1689 void LyXFunc::menuNew(string const & name, bool fromTemplate)
1690 {
1691         string initpath = lyxrc.document_path;
1692         string filename(name);
1693
1694         if (view()->available()) {
1695                 string const trypath = owner->buffer()->filePath();
1696                 // If directory is writeable, use this as default.
1697                 if (isDirWriteable(trypath))
1698                         initpath = trypath;
1699         }
1700
1701         static int newfile_number;
1702
1703         if (filename.empty()) {
1704                 filename = addName(lyxrc.document_path,
1705                             "newfile" + convert<string>(++newfile_number) + ".lyx");
1706                 while (bufferlist.exists(filename) || fs::is_readable(filename)) {
1707                         ++newfile_number;
1708                         filename = addName(lyxrc.document_path,
1709                                            "newfile" +  convert<string>(newfile_number) +
1710                                     ".lyx");
1711                 }
1712         }
1713
1714         // The template stuff
1715         string templname;
1716         if (fromTemplate) {
1717                 FileDialog fileDlg(_("Select template file"),
1718                         LFUN_SELECT_FILE_SYNC,
1719                         make_pair(string(_("Documents|#o#O")),
1720                                   string(lyxrc.document_path)),
1721                         make_pair(string(_("Templates|#T#t")),
1722                                   string(lyxrc.template_path)));
1723
1724                 FileDialog::Result result =
1725                         fileDlg.open(lyxrc.template_path,
1726                                      FileFilterList(_("LyX Documents (*.lyx)")),
1727                                      string());
1728
1729                 if (result.first == FileDialog::Later)
1730                         return;
1731                 if (result.second.empty())
1732                         return;
1733                 templname = result.second;
1734         }
1735
1736         view()->newFile(filename, templname, !name.empty());
1737 }
1738
1739
1740 void LyXFunc::open(string const & fname)
1741 {
1742         string initpath = lyxrc.document_path;
1743
1744         if (view()->available()) {
1745                 string const trypath = owner->buffer()->filePath();
1746                 // If directory is writeable, use this as default.
1747                 if (isDirWriteable(trypath))
1748                         initpath = trypath;
1749         }
1750
1751         string filename;
1752
1753         if (fname.empty()) {
1754                 FileDialog fileDlg(_("Select document to open"),
1755                         LFUN_FILE_OPEN,
1756                         make_pair(string(_("Documents|#o#O")),
1757                                   string(lyxrc.document_path)),
1758                         make_pair(string(_("Examples|#E#e")),
1759                                   string(addPath(package().system_support(), "examples"))));
1760
1761                 FileDialog::Result result =
1762                         fileDlg.open(initpath,
1763                                      FileFilterList(_("LyX Documents (*.lyx)")),
1764                                      string());
1765
1766                 if (result.first == FileDialog::Later)
1767                         return;
1768
1769                 filename = result.second;
1770
1771                 // check selected filename
1772                 if (filename.empty()) {
1773                         owner->message(_("Canceled."));
1774                         return;
1775                 }
1776         } else
1777                 filename = fname;
1778
1779         // get absolute path of file and add ".lyx" to the filename if
1780         // necessary
1781         string const fullpath = fileSearch(string(), filename, "lyx");
1782         if (!fullpath.empty()) {
1783                 filename = fullpath;
1784         }
1785
1786         string const disp_fn(makeDisplayPath(filename));
1787
1788         // if the file doesn't exist, let the user create one
1789         if (!fs::exists(filename)) {
1790                 // the user specifically chose this name. Believe them.
1791                 view()->newFile(filename, "", true);
1792                 return;
1793         }
1794
1795         owner->message(bformat(_("Opening document %1$s..."), disp_fn));
1796
1797         string str2;
1798         if (view()->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         Importer::Import(owner, filename, format);
1887 }
1888
1889
1890 void LyXFunc::closeBuffer()
1891 {
1892         // save current cursor position
1893         LyX::ref().session().saveFilePosition(owner->buffer()->fileName(),
1894                 boost::tie(view()->cursor().pit(), view()->cursor().pos()) );
1895         if (bufferlist.close(owner->buffer(), true) && !quitting) {
1896                 if (bufferlist.empty()) {
1897                         // need this otherwise SEGV may occur while
1898                         // trying to set variables that don't exist
1899                         // since there's no current buffer
1900                         owner->getDialogs().hideBufferDependent();
1901                 } else {
1902                         view()->setBuffer(bufferlist.first());
1903                 }
1904         }
1905 }
1906
1907
1908 // Each "owner" should have it's own message method. lyxview and
1909 // the minibuffer would use the minibuffer, but lyxserver would
1910 // send an ERROR signal to its client.  Alejandro 970603
1911 // This function is bit problematic when it comes to NLS, to make the
1912 // lyx servers client be language indepenent we must not translate
1913 // strings sent to this func.
1914 void LyXFunc::setErrorMessage(string const & m) const
1915 {
1916         dispatch_buffer = m;
1917         errorstat = true;
1918 }
1919
1920
1921 void LyXFunc::setMessage(string const & m) const
1922 {
1923         dispatch_buffer = m;
1924 }
1925
1926
1927 string const LyXFunc::viewStatusMessage()
1928 {
1929         // When meta-fake key is pressed, show the key sequence so far + "M-".
1930         if (wasMetaKey())
1931                 return keyseq.print() + "M-";
1932
1933         // Else, when a non-complete key sequence is pressed,
1934         // show the available options.
1935         if (keyseq.length() > 0 && !keyseq.deleted())
1936                 return keyseq.printOptions();
1937
1938         if (!view()->available())
1939                 return _("Welcome to LyX!");
1940
1941         return view()->cursor().currentState();
1942 }
1943
1944
1945 BufferView * LyXFunc::view() const
1946 {
1947         BOOST_ASSERT(owner);
1948         return owner->view();
1949 }
1950
1951
1952 bool LyXFunc::wasMetaKey() const
1953 {
1954         return (meta_fake_bit != key_modifier::none);
1955 }
1956
1957
1958 namespace {
1959
1960 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
1961 {
1962         // Why the switch you might ask. It is a trick to ensure that all
1963         // the elements in the LyXRCTags enum is handled. As you can see
1964         // there are no breaks at all. So it is just a huge fall-through.
1965         // The nice thing is that we will get a warning from the compiler
1966         // if we forget an element.
1967         LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
1968         switch (tag) {
1969         case LyXRC::RC_ACCEPT_COMPOUND:
1970         case LyXRC::RC_ALT_LANG:
1971         case LyXRC::RC_ASCIIROFF_COMMAND:
1972         case LyXRC::RC_ASCII_LINELEN:
1973         case LyXRC::RC_AUTOREGIONDELETE:
1974         case LyXRC::RC_AUTORESET_OPTIONS:
1975         case LyXRC::RC_AUTOSAVE:
1976         case LyXRC::RC_AUTO_NUMBER:
1977         case LyXRC::RC_BACKUPDIR_PATH:
1978         case LyXRC::RC_BIBTEX_COMMAND:
1979         case LyXRC::RC_BINDFILE:
1980         case LyXRC::RC_CHECKLASTFILES:
1981         case LyXRC::RC_USELASTFILEPOS:
1982         case LyXRC::RC_LOADSESSION:
1983         case LyXRC::RC_CHKTEX_COMMAND:
1984         case LyXRC::RC_CONVERTER:
1985         case LyXRC::RC_COPIER:
1986         case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
1987         case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
1988         case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
1989         case LyXRC::RC_DATE_INSERT_FORMAT:
1990         case LyXRC::RC_DEFAULT_LANGUAGE:
1991         case LyXRC::RC_DEFAULT_PAPERSIZE:
1992         case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
1993         case LyXRC::RC_DISPLAY_GRAPHICS:
1994         case LyXRC::RC_DOCUMENTPATH:
1995                 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
1996                         if (fs::exists(lyxrc_new.document_path) &&
1997                             fs::is_directory(lyxrc_new.document_path)) {
1998                                 using lyx::support::package;
1999                                 package().document_dir() = lyxrc.document_path;
2000                         }
2001                 }
2002         case LyXRC::RC_ESC_CHARS:
2003         case LyXRC::RC_FONT_ENCODING:
2004         case LyXRC::RC_FORMAT:
2005         case LyXRC::RC_INDEX_COMMAND:
2006         case LyXRC::RC_INPUT:
2007         case LyXRC::RC_KBMAP:
2008         case LyXRC::RC_KBMAP_PRIMARY:
2009         case LyXRC::RC_KBMAP_SECONDARY:
2010         case LyXRC::RC_LABEL_INIT_LENGTH:
2011         case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2012         case LyXRC::RC_LANGUAGE_AUTO_END:
2013         case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2014         case LyXRC::RC_LANGUAGE_COMMAND_END:
2015         case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2016         case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2017         case LyXRC::RC_LANGUAGE_PACKAGE:
2018         case LyXRC::RC_LANGUAGE_USE_BABEL:
2019         case LyXRC::RC_MAKE_BACKUP:
2020         case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2021         case LyXRC::RC_NUMLASTFILES:
2022         case LyXRC::RC_PATH_PREFIX:
2023                 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2024                         using lyx::support::prependEnvPath;
2025                         prependEnvPath("PATH", lyxrc.path_prefix);
2026                 }
2027         case LyXRC::RC_PERS_DICT:
2028         case LyXRC::RC_POPUP_BOLD_FONT:
2029         case LyXRC::RC_POPUP_FONT_ENCODING:
2030         case LyXRC::RC_POPUP_NORMAL_FONT:
2031         case LyXRC::RC_PREVIEW:
2032         case LyXRC::RC_PREVIEW_HASHED_LABELS:
2033         case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2034         case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2035         case LyXRC::RC_PRINTCOPIESFLAG:
2036         case LyXRC::RC_PRINTER:
2037         case LyXRC::RC_PRINTEVENPAGEFLAG:
2038         case LyXRC::RC_PRINTEXSTRAOPTIONS:
2039         case LyXRC::RC_PRINTFILEEXTENSION:
2040         case LyXRC::RC_PRINTLANDSCAPEFLAG:
2041         case LyXRC::RC_PRINTODDPAGEFLAG:
2042         case LyXRC::RC_PRINTPAGERANGEFLAG:
2043         case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2044         case LyXRC::RC_PRINTPAPERFLAG:
2045         case LyXRC::RC_PRINTREVERSEFLAG:
2046         case LyXRC::RC_PRINTSPOOL_COMMAND:
2047         case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2048         case LyXRC::RC_PRINTTOFILE:
2049         case LyXRC::RC_PRINTTOPRINTER:
2050         case LyXRC::RC_PRINT_ADAPTOUTPUT:
2051         case LyXRC::RC_PRINT_COMMAND:
2052         case LyXRC::RC_RTL_SUPPORT:
2053         case LyXRC::RC_SCREEN_DPI:
2054         case LyXRC::RC_SCREEN_FONT_ENCODING:
2055         case LyXRC::RC_SCREEN_FONT_ROMAN:
2056         case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2057         case LyXRC::RC_SCREEN_FONT_SANS:
2058         case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2059         case LyXRC::RC_SCREEN_FONT_SCALABLE:
2060         case LyXRC::RC_SCREEN_FONT_SIZES:
2061         case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2062         case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2063         case LyXRC::RC_SCREEN_GEOMETRY_HEIGHT:
2064         case LyXRC::RC_SCREEN_GEOMETRY_WIDTH:
2065         case LyXRC::RC_SCREEN_GEOMETRY_XYSAVED:
2066         case LyXRC::RC_SCREEN_ZOOM:
2067         case LyXRC::RC_SERVERPIPE:
2068         case LyXRC::RC_SET_COLOR:
2069         case LyXRC::RC_SHOW_BANNER:
2070         case LyXRC::RC_SPELL_COMMAND:
2071         case LyXRC::RC_TEMPDIRPATH:
2072         case LyXRC::RC_TEMPLATEPATH:
2073         case LyXRC::RC_TEX_ALLOWS_SPACES:
2074         case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2075                 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2076                         namespace os = lyx::support::os;
2077                         os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2078                 }
2079         case LyXRC::RC_UIFILE:
2080         case LyXRC::RC_USER_EMAIL:
2081         case LyXRC::RC_USER_NAME:
2082         case LyXRC::RC_USETEMPDIR:
2083         case LyXRC::RC_USE_ALT_LANG:
2084         case LyXRC::RC_USE_ESC_CHARS:
2085         case LyXRC::RC_USE_INP_ENC:
2086         case LyXRC::RC_USE_PERS_DICT:
2087         case LyXRC::RC_USE_SPELL_LIB:
2088         case LyXRC::RC_VIEWDVI_PAPEROPTION:
2089         case LyXRC::RC_VIEWER:
2090         case LyXRC::RC_WHEEL_JUMP:
2091         case LyXRC::RC_LAST:
2092                 break;
2093         }
2094 }
2095
2096 } // namespace anon