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