]> git.lyx.org Git - lyx.git/blob - src/lyxfunc.C
bug 2298: cursorTop/Bottom/Home/End does not redraw after dEPM
[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()->isClean();
545                 break;
546         }
547
548         // this one is difficult to get right. As a half-baked
549         // solution, we consider only the first action of the sequence
550         case LFUN_SEQUENCE: {
551                 // argument contains ';'-terminated commands
552                 string const firstcmd = token(cmd.argument, ';', 0);
553                 FuncRequest func(lyxaction.lookupFunc(firstcmd));
554                 func.origin = cmd.origin;
555                 flag = getStatus(func);
556         }
557
558         case LFUN_MENUNEW:
559         case LFUN_MENUNEWTMPLT:
560         case LFUN_WORDFINDFORWARD:
561         case LFUN_WORDFINDBACKWARD:
562         case LFUN_PREFIX:
563         case LFUN_EXEC_COMMAND:
564         case LFUN_CANCEL:
565         case LFUN_META_FAKE:
566         case LFUN_CLOSEBUFFER:
567         case LFUN_WRITEAS:
568         case LFUN_UPDATE:
569         case LFUN_PREVIEW:
570         case LFUN_IMPORT:
571         case LFUN_QUIT:
572         case LFUN_TOCVIEW:
573         case LFUN_AUTOSAVE:
574         case LFUN_RECONFIGURE:
575         case LFUN_HELP_OPEN:
576         case LFUN_FILE_NEW:
577         case LFUN_FILE_OPEN:
578         case LFUN_DROP_LAYOUTS_CHOICE:
579         case LFUN_MENU_OPEN_BY_NAME:
580         case LFUN_GETNAME:
581         case LFUN_NOTIFY:
582         case LFUN_GOTOFILEROW:
583         case LFUN_DIALOG_SHOW_NEXT_INSET:
584         case LFUN_DIALOG_HIDE:
585         case LFUN_DIALOG_DISCONNECT_INSET:
586         case LFUN_CHILDOPEN:
587         case LFUN_TOGGLECURSORFOLLOW:
588         case LFUN_KMAP_OFF:
589         case LFUN_KMAP_PRIM:
590         case LFUN_KMAP_SEC:
591         case LFUN_KMAP_TOGGLE:
592         case LFUN_REPEAT:
593         case LFUN_EXPORT_CUSTOM:
594         case LFUN_PRINT:
595         case LFUN_SAVEPREFERENCES:
596         case LFUN_SCREEN_FONT_UPDATE:
597         case LFUN_SET_COLOR:
598         case LFUN_MESSAGE:
599         case LFUN_EXTERNAL_EDIT:
600         case LFUN_GRAPHICS_EDIT:
601         case LFUN_ALL_INSETS_TOGGLE:
602         case LFUN_LANGUAGE_BUFFER:
603         case LFUN_TEXTCLASS_APPLY:
604         case LFUN_TEXTCLASS_LOAD:
605         case LFUN_SAVE_AS_DEFAULT:
606         case LFUN_BUFFERPARAMS_APPLY:
607         case LFUN_LYXRC_APPLY:
608         case LFUN_NEXTBUFFER:
609         case LFUN_PREVIOUSBUFFER:
610                 // these are handled in our dispatch()
611                 break;
612
613         default:
614
615                 if (!::getStatus(cur, cmd, flag))
616                         flag = view()->getStatus(cmd);
617         }
618
619         if (!enable)
620                 flag.enabled(false);
621
622         // Can we use a readonly buffer?
623         if (buf && buf->isReadonly()
624             && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
625             && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
626                 flag.message(N_("Document is read-only"));
627                 flag.enabled(false);
628         }
629
630         // Are we in a DELETED change-tracking region?
631         if (buf && buf->params().tracking_changes
632             && lookupChange(cur, true) == Change::DELETED
633             && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
634             && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
635                 flag.message(N_("This portion of the document is deleted."));
636                 flag.enabled(false);
637         }
638
639         // the default error message if we disable the command
640         if (!flag.enabled() && flag.message().empty())
641                 flag.message(N_("Command disabled"));
642
643         return flag;
644 }
645
646
647 namespace {
648
649 bool ensureBufferClean(BufferView * bv)
650 {
651         Buffer & buf = *bv->buffer();
652         if (buf.isClean())
653                 return true;
654
655         string const file = MakeDisplayPath(buf.fileName(), 30);
656         string text = bformat(_("The document %1$s has unsaved "
657                                 "changes.\n\nDo you want to save "
658                                 "the document?"), file);
659         int const ret = Alert::prompt(_("Save changed document?"),
660                                       text, 0, 1, _("&Save"),
661                                       _("&Cancel"));
662
663         if (ret == 0)
664                 bv->owner()->dispatch(FuncRequest(LFUN_MENUWRITE));
665
666         return buf.isClean();
667 }
668
669
670 void showPrintError(string const & name)
671 {
672         string str = bformat(_("Could not print the document %1$s.\n"
673                                "Check that your printer is set up correctly."),
674                              MakeDisplayPath(name, 50));
675         Alert::error(_("Print document failed"), str);
676 }
677
678
679 void loadTextclass(string const & name)
680 {
681         std::pair<bool, lyx::textclass_type> const tc_pair =
682                 textclasslist.NumberOfClass(name);
683
684         if (!tc_pair.first) {
685                 lyxerr << "Document class \"" << name
686                        << "\" does not exist."
687                        << std::endl;
688                 return;
689         }
690
691         lyx::textclass_type const tc = tc_pair.second;
692
693         if (!textclasslist[tc].load()) {
694                 string s = bformat(_("The document could not be converted\n"
695                                      "into the document class %1$s."),
696                                    textclasslist[tc].name());
697                 Alert::error(_("Could not change class"), s);
698         }
699 }
700
701
702 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
703
704 } //namespace anon
705
706
707 void LyXFunc::dispatch(FuncRequest const & cmd)
708 {
709         BOOST_ASSERT(view());
710         string const argument = cmd.argument;
711         kb_action const action = cmd.action;
712
713         lyxerr[Debug::ACTION] << "LyXFunc::dispatch: cmd: " << cmd << endl;
714         //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
715
716         // we have not done anything wrong yet.
717         errorstat = false;
718         dispatch_buffer.erase();
719
720         bool update = false;
721
722         FuncStatus const flag = getStatus(cmd);
723         if (!flag.enabled()) {
724                 // We cannot use this function here
725                 lyxerr[Debug::ACTION] << "LyXFunc::dispatch: "
726                        << lyxaction.getActionName(action)
727                        << " [" << action << "] is disabled at this location"
728                        << endl;
729                 setErrorMessage(flag.message());
730         } else {
731
732                 if (view()->available())
733                         view()->hideCursor();
734
735                 switch (action) {
736
737                 case LFUN_WORDFINDFORWARD:
738                 case LFUN_WORDFINDBACKWARD: {
739                         static string last_search;
740                         string searched_string;
741
742                         if (!argument.empty()) {
743                                 last_search = argument;
744                                 searched_string = argument;
745                         } else {
746                                 searched_string = last_search;
747                         }
748
749                         if (searched_string.empty())
750                                 break;
751
752                         bool const fw = action == LFUN_WORDFINDFORWARD;
753                         string const data =
754                                 lyx::find::find2string(searched_string, true, false, fw);
755                         lyx::find::find(view(), FuncRequest(LFUN_WORD_FIND, data));
756                         break;
757                 }
758
759                 case LFUN_PREFIX:
760                         owner->message(keyseq.printOptions());
761                         break;
762
763                 case LFUN_EXEC_COMMAND:
764                         owner->getToolbars().display("minibuffer", true);
765                         owner->focus_command_buffer();
766                         break;
767
768                 case LFUN_CANCEL:
769                         keyseq.reset();
770                         meta_fake_bit = key_modifier::none;
771                         if (view()->available())
772                                 // cancel any selection
773                                 dispatch(FuncRequest(LFUN_MARK_OFF));
774                         setMessage(N_("Cancel"));
775                         break;
776
777                 case LFUN_META_FAKE:
778                         meta_fake_bit = key_modifier::alt;
779                         setMessage(keyseq.print());
780                         break;
781
782                 case LFUN_READ_ONLY_TOGGLE:
783                         if (owner->buffer()->lyxvc().inUse())
784                                 owner->buffer()->lyxvc().toggleReadOnly();
785                         else
786                                 owner->buffer()->setReadonly(
787                                         !owner->buffer()->isReadonly());
788                         break;
789
790                 // --- Menus -----------------------------------------------
791                 case LFUN_MENUNEW:
792                         menuNew(argument, false);
793                         break;
794
795                 case LFUN_MENUNEWTMPLT:
796                         menuNew(argument, true);
797                         break;
798
799                 case LFUN_CLOSEBUFFER:
800                         closeBuffer();
801                         break;
802
803                 case LFUN_MENUWRITE:
804                         if (!owner->buffer()->isUnnamed()) {
805                                 string const str = bformat(_("Saving document %1$s..."),
806                                          MakeDisplayPath(owner->buffer()->fileName()));
807                                 owner->message(str);
808                                 MenuWrite(owner->buffer());
809                                 owner->message(str + _(" done."));
810                         } else
811                                 WriteAs(owner->buffer());
812                         break;
813
814                 case LFUN_WRITEAS:
815                         WriteAs(owner->buffer(), argument);
816                         break;
817
818                 case LFUN_MENURELOAD: {
819                         string const file = MakeDisplayPath(view()->buffer()->fileName(), 20);
820                         string text = bformat(_("Any changes will be lost. Are you sure "
821                                 "you want to revert to the saved version of the document %1$s?"), file);
822                         int const ret = Alert::prompt(_("Revert to saved document?"),
823                                 text, 0, 1, _("&Revert"), _("&Cancel"));
824
825                         if (ret == 0)
826                                 view()->reload();
827                         break;
828                 }
829
830                 case LFUN_UPDATE:
831                         Exporter::Export(owner->buffer(), argument, true);
832                         view()->showErrorList(BufferFormat(*owner->buffer()));
833                         break;
834
835                 case LFUN_PREVIEW:
836                         Exporter::Preview(owner->buffer(), argument);
837                         view()->showErrorList(BufferFormat(*owner->buffer()));
838                         break;
839
840                 case LFUN_BUILDPROG:
841                         Exporter::Export(owner->buffer(), "program", true);
842                         view()->showErrorList(_("Build"));
843                         break;
844
845                 case LFUN_RUNCHKTEX:
846                         owner->buffer()->runChktex();
847                         view()->showErrorList(_("ChkTeX"));
848                         break;
849
850                 case LFUN_EXPORT:
851                         if (argument == "custom")
852                                 owner->getDialogs().show("sendto");
853                         else {
854                                 Exporter::Export(owner->buffer(), argument, false);
855                                 view()->showErrorList(BufferFormat(*owner->buffer()));
856                         }
857                         break;
858
859                 case LFUN_EXPORT_CUSTOM: {
860                         string format_name;
861                         string command = split(argument, format_name, ' ');
862                         Format const * format = formats.getFormat(format_name);
863                         if (!format) {
864                                 lyxerr << "Format \"" << format_name
865                                        << "\" not recognized!"
866                                        << std::endl;
867                                 break;
868                         }
869
870                         Buffer * buffer = owner->buffer();
871
872                         // The name of the file created by the conversion process
873                         string filename;
874
875                         // Output to filename
876                         if (format->name() == "lyx") {
877                                 string const latexname =
878                                         buffer->getLatexName(false);
879                                 filename = ChangeExtension(latexname,
880                                                            format->extension());
881                                 filename = AddName(buffer->temppath(), filename);
882
883                                 if (!buffer->writeFile(filename))
884                                         break;
885
886                         } else {
887                                 Exporter::Export(buffer, format_name, true,
888                                                  filename);
889                         }
890
891                         // Substitute $$FName for filename
892                         if (!contains(command, "$$FName"))
893                                 command = "( " + command + " ) < $$FName";
894                         command = subst(command, "$$FName", filename);
895
896                         // Execute the command in the background
897                         Systemcall call;
898                         call.startscript(Systemcall::DontWait, command);
899                         break;
900                 }
901
902                 case LFUN_PRINT: {
903                         string target;
904                         string target_name;
905                         string command = split(split(argument, target, ' '),
906                                                target_name, ' ');
907
908                         if (target.empty()
909                             || target_name.empty()
910                             || command.empty()) {
911                                 lyxerr << "Unable to parse \""
912                                        << argument << '"' << std::endl;
913                                 break;
914                         }
915                         if (target != "printer" && target != "file") {
916                                 lyxerr << "Unrecognized target \""
917                                        << target << '"' << std::endl;
918                                 break;
919                         }
920
921                         Buffer * buffer = owner->buffer();
922
923                         if (!Exporter::Export(buffer, "dvi", true)) {
924                                 showPrintError(buffer->fileName());
925                                 break;
926                         }
927
928                         // Push directory path.
929                         string const path = buffer->temppath();
930                         Path p(path);
931
932                         // there are three cases here:
933                         // 1. we print to a file
934                         // 2. we print directly to a printer
935                         // 3. we print using a spool command (print to file first)
936                         Systemcall one;
937                         int res = 0;
938                         string const dviname =
939                                 ChangeExtension(buffer->getLatexName(true),
940                                                 "dvi");
941
942                         if (target == "printer") {
943                                 if (!lyxrc.print_spool_command.empty()) {
944                                         // case 3: print using a spool
945                                         string const psname =
946                                                 ChangeExtension(dviname,".ps");
947                                         command += lyxrc.print_to_file
948                                                 + QuoteName(psname)
949                                                 + ' '
950                                                 + QuoteName(dviname);
951
952                                         string command2 =
953                                                 lyxrc.print_spool_command +' ';
954                                         if (target_name != "default") {
955                                                 command2 += lyxrc.print_spool_printerprefix
956                                                         + target_name
957                                                         + ' ';
958                                         }
959                                         command2 += QuoteName(psname);
960                                         // First run dvips.
961                                         // If successful, then spool command
962                                         res = one.startscript(
963                                                 Systemcall::Wait,
964                                                 command);
965
966                                         if (res == 0)
967                                                 res = one.startscript(
968                                                         Systemcall::DontWait,
969                                                         command2);
970                                 } else {
971                                         // case 2: print directly to a printer
972                                         res = one.startscript(
973                                                 Systemcall::DontWait,
974                                                 command + QuoteName(dviname));
975                                 }
976
977                         } else {
978                                 // case 1: print to a file
979                                 command += lyxrc.print_to_file
980                                         + QuoteName(MakeAbsPath(target_name,
981                                                                 path))
982                                         + ' '
983                                         + QuoteName(dviname);
984                                 res = one.startscript(Systemcall::DontWait,
985                                                       command);
986                         }
987
988                         if (res != 0)
989                                 showPrintError(buffer->fileName());
990                         break;
991                 }
992
993                 case LFUN_IMPORT:
994                         doImport(argument);
995                         break;
996
997                 case LFUN_QUIT:
998                         QuitLyX(argument == "force");
999                         break;
1000
1001                 case LFUN_TOCVIEW: {
1002                         InsetCommandParams p("tableofcontents");
1003                         string const data = InsetCommandMailer::params2string("toc", p);
1004                         owner->getDialogs().show("toc", data, 0);
1005                         break;
1006                 }
1007
1008                 case LFUN_AUTOSAVE:
1009                         AutoSave(view());
1010                         break;
1011
1012                 case LFUN_RECONFIGURE:
1013                         Reconfigure(view());
1014                         break;
1015
1016                 case LFUN_HELP_OPEN: {
1017                         string const arg = argument;
1018                         if (arg.empty()) {
1019                                 setErrorMessage(N_("Missing argument"));
1020                                 break;
1021                         }
1022                         string const fname = i18nLibFileSearch("doc", arg, "lyx");
1023                         if (fname.empty()) {
1024                                 lyxerr << "LyX: unable to find documentation file `"
1025                                                          << arg << "'. Bad installation?" << endl;
1026                                 break;
1027                         }
1028                         owner->message(bformat(_("Opening help file %1$s..."),
1029                                 MakeDisplayPath(fname)));
1030                         view()->loadLyXFile(fname, false);
1031                         break;
1032                 }
1033
1034                 // --- version control -------------------------------
1035                 case LFUN_VC_REGISTER:
1036                         if (!ensureBufferClean(view()))
1037                                 break;
1038                         if (!owner->buffer()->lyxvc().inUse()) {
1039                                 owner->buffer()->lyxvc().registrer();
1040                                 view()->reload();
1041                         }
1042                         break;
1043
1044                 case LFUN_VC_CHECKIN:
1045                         if (!ensureBufferClean(view()))
1046                                 break;
1047                         if (owner->buffer()->lyxvc().inUse()
1048                                         && !owner->buffer()->isReadonly()) {
1049                                 owner->buffer()->lyxvc().checkIn();
1050                                 view()->reload();
1051                         }
1052                         break;
1053
1054                 case LFUN_VC_CHECKOUT:
1055                         if (!ensureBufferClean(view()))
1056                                 break;
1057                         if (owner->buffer()->lyxvc().inUse()
1058                                         && owner->buffer()->isReadonly()) {
1059                                 owner->buffer()->lyxvc().checkOut();
1060                                 view()->reload();
1061                         }
1062                         break;
1063
1064                 case LFUN_VC_REVERT:
1065                         owner->buffer()->lyxvc().revert();
1066                         view()->reload();
1067                         break;
1068
1069                 case LFUN_VC_UNDO:
1070                         owner->buffer()->lyxvc().undoLast();
1071                         view()->reload();
1072                         break;
1073
1074                 // --- buffers ----------------------------------------
1075                 case LFUN_SWITCHBUFFER:
1076                         view()->setBuffer(bufferlist.getBuffer(argument));
1077                         break;
1078
1079                 case LFUN_NEXTBUFFER:
1080                         view()->setBuffer(bufferlist.next(view()->buffer()));
1081                         break;
1082
1083                 case LFUN_PREVIOUSBUFFER:
1084                         view()->setBuffer(bufferlist.previous(view()->buffer()));
1085                         break;
1086
1087                 case LFUN_FILE_NEW:
1088                         NewFile(view(), argument);
1089                         break;
1090
1091                 case LFUN_FILE_OPEN:
1092                         open(argument);
1093                         break;
1094
1095                 case LFUN_DROP_LAYOUTS_CHOICE:
1096                         owner->getToolbars().openLayoutList();
1097                         break;
1098
1099                 case LFUN_MENU_OPEN_BY_NAME:
1100                         owner->getMenubar().openByName(argument);
1101                         break;
1102
1103                 // --- lyxserver commands ----------------------------
1104                 case LFUN_GETNAME:
1105                         setMessage(owner->buffer()->fileName());
1106                         lyxerr[Debug::INFO] << "FNAME["
1107                                                          << owner->buffer()->fileName()
1108                                                          << "] " << endl;
1109                         break;
1110
1111                 case LFUN_NOTIFY:
1112                         dispatch_buffer = keyseq.print();
1113                         lyxserver->notifyClient(dispatch_buffer);
1114                         break;
1115
1116                 case LFUN_GOTOFILEROW: {
1117                         string file_name;
1118                         int row;
1119                         istringstream is(argument);
1120                         is >> file_name >> row;
1121                         if (prefixIs(file_name, package().temp_dir())) {
1122                                 // Needed by inverse dvi search. If it is a file
1123                                 // in tmpdir, call the apropriated function
1124                                 view()->setBuffer(bufferlist.getBufferFromTmp(file_name));
1125                         } else {
1126                                 // Must replace extension of the file to be .lyx
1127                                 // and get full path
1128                                 string const s = ChangeExtension(file_name, ".lyx");
1129                                 // Either change buffer or load the file
1130                                 if (bufferlist.exists(s)) {
1131                                         view()->setBuffer(bufferlist.getBuffer(s));
1132                                 } else {
1133                                         view()->loadLyXFile(s);
1134                                 }
1135                         }
1136
1137                         view()->setCursorFromRow(row);
1138
1139                         view()->center();
1140                         // see BufferView_pimpl::center()
1141                         view()->updateScrollbar();
1142                         break;
1143                 }
1144
1145                 case LFUN_DIALOG_SHOW: {
1146                         string const name = cmd.getArg(0);
1147                         string data = trim(cmd.argument.substr(name.size()));
1148
1149                         if (name == "character") {
1150                                 data = freefont2string();
1151                                 if (!data.empty())
1152                                         owner->getDialogs().show("character", data);
1153                         }
1154
1155                         else if (name == "latexlog") {
1156                                 pair<Buffer::LogType, string> const logfile =
1157                                         owner->buffer()->getLogName();
1158                                 switch (logfile.first) {
1159                                 case Buffer::latexlog:
1160                                         data = "latex ";
1161                                         break;
1162                                 case Buffer::buildlog:
1163                                         data = "literate ";
1164                                         break;
1165                                 }
1166                                 data += logfile.second;
1167                                 owner->getDialogs().show("log", data);
1168                         }
1169                         else if (name == "vclog") {
1170                                 string const data = "vc " +
1171                                         owner->buffer()->lyxvc().getLogFile();
1172                                 owner->getDialogs().show("log", data);
1173                         }
1174                         else
1175                                 owner->getDialogs().show(name, data);
1176                         break;
1177                 }
1178
1179                 case LFUN_DIALOG_SHOW_NEW_INSET: {
1180                         string const name = cmd.getArg(0);
1181                         string data = trim(cmd.argument.substr(name.size()));
1182                         if (name == "bibitem" ||
1183                             name == "bibtex" ||
1184                             name == "index" ||
1185                             name == "label" ||
1186                             name == "ref" ||
1187                             name == "toc" ||
1188                             name == "url") {
1189                                 InsetCommandParams p(name);
1190                                 data = InsetCommandMailer::params2string(name, p);
1191                         } else if (name == "include") {
1192                                 InsetCommandParams p(data);
1193                                 data = InsetIncludeMailer::params2string(p);
1194                         } else if (name == "box") {
1195                                 // \c data == "Boxed" || "Frameless" etc
1196                                 InsetBoxParams p(data);
1197                                 data = InsetBoxMailer::params2string(p);
1198                         } else if (name == "branch") {
1199                                 InsetBranchParams p;
1200                                 data = InsetBranchMailer::params2string(p);
1201                         } else if (name == "citation") {
1202                                 InsetCommandParams p("cite");
1203                                 data = InsetCommandMailer::params2string(name, p);
1204                         } else if (name == "ert") {
1205                                 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1206                         } else if (name == "external") {
1207                                 InsetExternalParams p;
1208                                 Buffer const & buffer = *owner->buffer();
1209                                 data = InsetExternalMailer::params2string(p, buffer);
1210                         } else if (name == "float") {
1211                                 InsetFloatParams p;
1212                                 data = InsetFloatMailer::params2string(p);
1213                         } else if (name == "graphics") {
1214                                 InsetGraphicsParams p;
1215                                 Buffer const & buffer = *owner->buffer();
1216                                 data = InsetGraphicsMailer::params2string(p, buffer);
1217                         } else if (name == "note") {
1218                                 InsetNoteParams p;
1219                                 data = InsetNoteMailer::params2string(p);
1220                         } else if (name == "vspace") {
1221                                 VSpace space;
1222                                 data = InsetVSpaceMailer::params2string(space);
1223                         } else if (name == "wrap") {
1224                                 InsetWrapParams p;
1225                                 data = InsetWrapMailer::params2string(p);
1226                         }
1227                         owner->getDialogs().show(name, data, 0);
1228                         break;
1229                 }
1230
1231                 case LFUN_DIALOG_SHOW_NEXT_INSET:
1232                         break;
1233
1234                 case LFUN_DIALOG_UPDATE: {
1235                         string const & name = argument;
1236                         // Can only update a dialog connected to an existing inset
1237                         InsetBase * inset = owner->getDialogs().getOpenInset(name);
1238                         if (inset) {
1239                                 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument);
1240                                 inset->dispatch(view()->cursor(), fr);
1241                         } else if (name == "paragraph") {
1242                                 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1243                         } else if (name == "prefs") {
1244                                 owner->getDialogs().update(name, string());
1245                         }
1246                         break;
1247                 }
1248
1249                 case LFUN_DIALOG_HIDE:
1250                         Dialogs::hide(argument, 0);
1251                         break;
1252
1253                 case LFUN_DIALOG_DISCONNECT_INSET:
1254                         owner->getDialogs().disconnect(argument);
1255                         break;
1256
1257                 
1258                 case LFUN_INSERT_CITATION: {
1259                         if (!argument.empty()) {
1260                                 // we can have one optional argument, delimited by '|'
1261                                 // citation-insert <key>|<text_before>
1262                                 // this should be enhanced to also support text_after 
1263                                 // and citation style
1264                                 string arg = argument;
1265                                 string opt1;
1266                                 if (contains(argument, "|")) {
1267                                         arg = token(argument, '|', 0);
1268                                         opt1 = '[' + token(argument, '|', 1) + ']';
1269                                 }
1270                                 std::ostringstream os;
1271                                 os << "citation LatexCommand\n"
1272                                    << "\\cite" << opt1 << "{" << arg << "}\n"
1273                                    << "\\end_inset";
1274                                 FuncRequest fr(LFUN_INSET_INSERT, os.str());
1275                                 dispatch(fr);
1276                         } else
1277                                 dispatch(FuncRequest(LFUN_DIALOG_SHOW, "citation"));
1278                         break;
1279                 }
1280
1281                 case LFUN_CHILDOPEN: {
1282                         string const filename =
1283                                 MakeAbsPath(argument, owner->buffer()->filePath());
1284                         setMessage(N_("Opening child document ") +
1285                                          MakeDisplayPath(filename) + "...");
1286                         view()->savePosition(0);
1287                         string const parentfilename = owner->buffer()->fileName();
1288                         if (bufferlist.exists(filename))
1289                                 view()->setBuffer(bufferlist.getBuffer(filename));
1290                         else
1291                                 view()->loadLyXFile(filename);
1292                         // Set the parent name of the child document.
1293                         // This makes insertion of citations and references in the child work,
1294                         // when the target is in the parent or another child document.
1295                         owner->buffer()->setParentName(parentfilename);
1296                         break;
1297                 }
1298
1299                 case LFUN_TOGGLECURSORFOLLOW:
1300                         lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1301                         break;
1302
1303                 case LFUN_KMAP_OFF:
1304                         owner->getIntl().KeyMapOn(false);
1305                         break;
1306
1307                 case LFUN_KMAP_PRIM:
1308                         owner->getIntl().KeyMapPrim();
1309                         break;
1310
1311                 case LFUN_KMAP_SEC:
1312                         owner->getIntl().KeyMapSec();
1313                         break;
1314
1315                 case LFUN_KMAP_TOGGLE:
1316                         owner->getIntl().ToggleKeyMap();
1317                         break;
1318
1319                 case LFUN_REPEAT: {
1320                         // repeat command
1321                         string countstr;
1322                         string rest = split(argument, countstr, ' ');
1323                         istringstream is(countstr);
1324                         int count = 0;
1325                         is >> count;
1326                         lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1327                         for (int i = 0; i < count; ++i)
1328                                 dispatch(lyxaction.lookupFunc(rest));
1329                         break;
1330                 }
1331
1332                 case LFUN_SEQUENCE: {
1333                         // argument contains ';'-terminated commands
1334                         string arg = argument;
1335                         while (!arg.empty()) {
1336                                 string first;
1337                                 arg = split(arg, first, ';');
1338                                 FuncRequest func(lyxaction.lookupFunc(first));
1339                                 func.origin = cmd.origin;
1340                                 dispatch(func);
1341                         }
1342                         break;
1343                 }
1344
1345                 case LFUN_SAVEPREFERENCES: {
1346                         Path p(package().user_support());
1347                         lyxrc.write("preferences", false);
1348                         break;
1349                 }
1350
1351                 case LFUN_SCREEN_FONT_UPDATE:
1352                         // handle the screen font changes.
1353                         lyxrc.set_font_norm_type();
1354                         lyx_gui::update_fonts();
1355                         // All visible buffers will need resize
1356                         view()->resize();
1357                         break;
1358
1359                 case LFUN_SET_COLOR: {
1360                         string lyx_name;
1361                         string const x11_name = split(argument, lyx_name, ' ');
1362                         if (lyx_name.empty() || x11_name.empty()) {
1363                                 setErrorMessage(N_("Syntax: set-color <lyx_name>"
1364                                                         " <x11_name>"));
1365                                 break;
1366                         }
1367
1368                         bool const graphicsbg_changed =
1369                                 (lyx_name == lcolor.getLyXName(LColor::graphicsbg) &&
1370                                  x11_name != lcolor.getX11Name(LColor::graphicsbg));
1371
1372                         if (!lcolor.setColor(lyx_name, x11_name)) {
1373                                 setErrorMessage(
1374                                         bformat(_("Set-color \"%1$s\" failed "
1375                                                                 "- color is undefined or "
1376                                                                 "may not be redefined"), lyx_name));
1377                                 break;
1378                         }
1379
1380                         lyx_gui::update_color(lcolor.getFromLyXName(lyx_name));
1381
1382                         if (graphicsbg_changed) {
1383 #ifdef WITH_WARNINGS
1384 #warning FIXME!! The graphics cache no longer has a changeDisplay method.
1385 #endif
1386 #if 0
1387                                 lyx::graphics::GCache::get().changeDisplay(true);
1388 #endif
1389                         }
1390                         break;
1391                 }
1392
1393                 case LFUN_MESSAGE:
1394                         owner->message(argument);
1395                         break;
1396
1397                 case LFUN_TOOLTIPS_TOGGLE:
1398                         owner->getDialogs().toggleTooltips();
1399                         break;
1400
1401                 case LFUN_EXTERNAL_EDIT: {
1402                         FuncRequest fr(action, argument);
1403                         InsetExternal().dispatch(view()->cursor(), fr);
1404                         break;
1405                 }
1406
1407                 case LFUN_GRAPHICS_EDIT: {
1408                         FuncRequest fr(action, argument);
1409                         InsetGraphics().dispatch(view()->cursor(), fr);
1410                         break;
1411                 }
1412
1413                 case LFUN_INSET_APPLY: {
1414                         string const name = cmd.getArg(0);
1415                         InsetBase * inset = owner->getDialogs().getOpenInset(name);
1416                         if (inset) {
1417                                 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1418                                 inset->dispatch(view()->cursor(), fr);
1419                         } else {
1420                                 FuncRequest fr(LFUN_INSET_INSERT, argument);
1421                                 dispatch(fr);
1422                         }
1423                         // ideally, the update flag should be set by the insets,
1424                         // but this is not possible currently
1425                         update = true;
1426                         break;
1427                 }
1428
1429                 case LFUN_ALL_INSETS_TOGGLE: {
1430                         string action;
1431                         string const name = split(argument, action, ' ');
1432                         InsetBase::Code const inset_code =
1433                                 InsetBase::translate(name);
1434
1435                         LCursor & cur = view()->cursor();
1436                         FuncRequest fr(LFUN_INSET_TOGGLE, action);
1437
1438                         InsetBase & inset = owner->buffer()->inset();
1439                         InsetIterator it  = inset_iterator_begin(inset);
1440                         InsetIterator const end = inset_iterator_end(inset);
1441                         for (; it != end; ++it) {
1442                                 if (inset_code == InsetBase::NO_CODE
1443                                     || inset_code == it->lyxCode()) {
1444                                         LCursor tmpcur = cur;
1445                                         tmpcur.pushLeft(*it);
1446                                         it->dispatch(tmpcur, fr);
1447                                 }
1448                         }
1449                         update = true;
1450                         break;
1451                 }
1452
1453                 case LFUN_LANGUAGE_BUFFER: {
1454                         Buffer & buffer = *owner->buffer();
1455                         Language const * oldL = buffer.params().language;
1456                         Language const * newL = languages.getLanguage(argument);
1457                         if (!newL || oldL == newL)
1458                                 break;
1459
1460                         if (oldL->RightToLeft() == newL->RightToLeft()
1461                             && !buffer.isMultiLingual())
1462                                 buffer.changeLanguage(oldL, newL);
1463                         else
1464                                 buffer.updateDocLang(newL);
1465                         break;
1466                 }
1467
1468                 case LFUN_SAVE_AS_DEFAULT: {
1469                         string const fname =
1470                                 AddName(AddPath(package().user_support(), "templates/"),
1471                                         "defaults.lyx");
1472                         Buffer defaults(fname);
1473
1474                         istringstream ss(argument);
1475                         LyXLex lex(0,0);
1476                         lex.setStream(ss);
1477                         int const unknown_tokens = defaults.readHeader(lex);
1478
1479                         if (unknown_tokens != 0) {
1480                                 lyxerr << "Warning in LFUN_SAVE_AS_DEFAULT!\n"
1481                                        << unknown_tokens << " unknown token"
1482                                        << (unknown_tokens == 1 ? "" : "s")
1483                                        << endl;
1484                         }
1485
1486                         if (defaults.writeFile(defaults.fileName()))
1487                                 setMessage(_("Document defaults saved in ")
1488                                            + MakeDisplayPath(fname));
1489                         else
1490                                 setErrorMessage(_("Unable to save document defaults"));
1491                         break;
1492                 }
1493
1494                 case LFUN_BUFFERPARAMS_APPLY: {
1495                         biblio::CiteEngine const engine =
1496                                 owner->buffer()->params().cite_engine;
1497
1498                         istringstream ss(argument);
1499                         LyXLex lex(0,0);
1500                         lex.setStream(ss);
1501                         int const unknown_tokens =
1502                                 owner->buffer()->readHeader(lex);
1503
1504                         if (unknown_tokens != 0) {
1505                                 lyxerr << "Warning in LFUN_BUFFERPARAMS_APPLY!\n"
1506                                        << unknown_tokens << " unknown token"
1507                                        << (unknown_tokens == 1 ? "" : "s")
1508                                        << endl;
1509                         }
1510                         if (engine == owner->buffer()->params().cite_engine)
1511                                 break;
1512
1513                         LCursor & cur = view()->cursor();
1514                         FuncRequest fr(LFUN_INSET_REFRESH);
1515
1516                         InsetBase & inset = owner->buffer()->inset();
1517                         InsetIterator it  = inset_iterator_begin(inset);
1518                         InsetIterator const end = inset_iterator_end(inset);
1519                         for (; it != end; ++it)
1520                                 if (it->lyxCode() == InsetBase::CITE_CODE)
1521                                         it->dispatch(cur, fr);
1522                         break;
1523                 }
1524
1525                 case LFUN_TEXTCLASS_APPLY: {
1526                         Buffer * buffer = owner->buffer();
1527
1528                         lyx::textclass_type const old_class =
1529                                 buffer->params().textclass;
1530
1531                         loadTextclass(argument);
1532
1533                         std::pair<bool, lyx::textclass_type> const tc_pair =
1534                                 textclasslist.NumberOfClass(argument);
1535
1536                         if (!tc_pair.first)
1537                                 break;
1538
1539                         lyx::textclass_type const new_class = tc_pair.second;
1540                         if (old_class == new_class)
1541                                 // nothing to do
1542                                 break;
1543
1544                         owner->message(_("Converting document to new document class..."));
1545                         recordUndoFullDocument(view());
1546                         buffer->params().textclass = new_class;
1547                         StableDocIterator backcur(view()->cursor());
1548                         ErrorList el;
1549                         lyx::cap::SwitchBetweenClasses(
1550                                 old_class, new_class,
1551                                 buffer->paragraphs(), el);
1552
1553                         view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
1554                         bufferErrors(*buffer, el);
1555                         view()->showErrorList(_("Class switch"));
1556                         updateCounters(*buffer);
1557                         update = true;
1558                         break;
1559                 }
1560
1561                 case LFUN_TEXTCLASS_LOAD:
1562                         loadTextclass(argument);
1563                         break;
1564
1565                 case LFUN_LYXRC_APPLY: {
1566                         LyXRC const lyxrc_orig = lyxrc;
1567
1568                         istringstream ss(argument);
1569                         bool const success = lyxrc.read(ss) == 0;
1570
1571                         if (!success) {
1572                                 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1573                                        << "Unable to read lyxrc data"
1574                                        << endl;
1575                                 break;
1576                         }
1577
1578                         actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1579                         break;
1580                 }
1581
1582                 default: {
1583                         view()->cursor().dispatch(cmd);
1584                         update |= view()->cursor().result().update();
1585                         if (!view()->cursor().result().dispatched())
1586                                 update |= view()->dispatch(cmd);
1587                         break;
1588                 }
1589                 }
1590
1591                 if (view()->available()) {
1592                         // Redraw screen unless explicitly told otherwise.
1593                         // This also initializes the position cache for all insets
1594                         // in (at least partially) visible top-level paragraphs.
1595                         if (update)
1596                                 view()->update(Update::FitCursor | Update::Force);
1597                         else
1598                                 view()->update(Update::FitCursor);
1599
1600                         // if we executed a mutating lfun, mark the buffer as dirty
1601                         if (flag.enabled()
1602                             && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)
1603                             && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly))
1604                                 view()->buffer()->markDirty();
1605                 }
1606
1607                 if (view()->cursor().inTexted()) {
1608                         view()->owner()->updateLayoutChoice();
1609                 }
1610         }
1611         sendDispatchMessage(_(getMessage()), cmd);
1612 }
1613
1614
1615 void LyXFunc::sendDispatchMessage(string const & msg, FuncRequest const & cmd)
1616 {
1617         /* When an action did not originate from the UI/kbd, it makes
1618          * sense to avoid updating the GUI. It turns out that this
1619          * fixes bug 1941, for reasons that are described here:
1620          * http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4 
1621          */
1622         if (cmd.origin != FuncRequest::INTERNAL) {
1623                 owner->updateMenubar();
1624                 owner->updateToolbars();
1625         }
1626
1627         const bool verbose = (cmd.origin == FuncRequest::UI
1628                               || cmd.origin == FuncRequest::COMMANDBUFFER);
1629
1630         if (cmd.action == LFUN_SELFINSERT || !verbose) {
1631                 lyxerr[Debug::ACTION] << "dispatch msg is " << msg << endl;
1632                 if (!msg.empty())
1633                         owner->message(msg);
1634                 return;
1635         }
1636
1637         string dispatch_msg = msg;
1638         if (!dispatch_msg.empty())
1639                 dispatch_msg += ' ';
1640
1641         string comname = lyxaction.getActionName(cmd.action);
1642
1643         bool argsadded = false;
1644
1645         if (!cmd.argument.empty()) {
1646                 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1647                         comname += ' ' + cmd.argument;
1648                         argsadded = true;
1649                 }
1650         }
1651
1652         string const shortcuts = toplevel_keymap->printbindings(cmd);
1653
1654         if (!shortcuts.empty())
1655                 comname += ": " + shortcuts;
1656         else if (!argsadded && !cmd.argument.empty())
1657                 comname += ' ' + cmd.argument;
1658
1659         if (!comname.empty()) {
1660                 comname = rtrim(comname);
1661                 dispatch_msg += '(' + rtrim(comname) + ')';
1662         }
1663
1664         lyxerr[Debug::ACTION] << "verbose dispatch msg " << dispatch_msg << endl;
1665         if (!dispatch_msg.empty())
1666                 owner->message(dispatch_msg);
1667 }
1668
1669
1670 void LyXFunc::setupLocalKeymap()
1671 {
1672         keyseq.stdmap = toplevel_keymap.get();
1673         keyseq.curmap = toplevel_keymap.get();
1674         cancel_meta_seq.stdmap = toplevel_keymap.get();
1675         cancel_meta_seq.curmap = toplevel_keymap.get();
1676 }
1677
1678
1679 void LyXFunc::menuNew(string const & name, bool fromTemplate)
1680 {
1681         string initpath = lyxrc.document_path;
1682         string filename(name);
1683
1684         if (view()->available()) {
1685                 string const trypath = owner->buffer()->filePath();
1686                 // If directory is writeable, use this as default.
1687                 if (IsDirWriteable(trypath))
1688                         initpath = trypath;
1689         }
1690
1691         static int newfile_number;
1692
1693         if (filename.empty()) {
1694                 filename = AddName(lyxrc.document_path,
1695                             "newfile" + convert<string>(++newfile_number) + ".lyx");
1696                 while (bufferlist.exists(filename) || fs::is_readable(filename)) {
1697                         ++newfile_number;
1698                         filename = AddName(lyxrc.document_path,
1699                                            "newfile" +  convert<string>(newfile_number) +
1700                                     ".lyx");
1701                 }
1702         }
1703
1704         // The template stuff
1705         string templname;
1706         if (fromTemplate) {
1707                 FileDialog fileDlg(_("Select template file"),
1708                         LFUN_SELECT_FILE_SYNC,
1709                         make_pair(string(_("Documents|#o#O")),
1710                                   string(lyxrc.document_path)),
1711                         make_pair(string(_("Templates|#T#t")),
1712                                   string(lyxrc.template_path)));
1713
1714                 FileDialog::Result result =
1715                         fileDlg.open(lyxrc.template_path,
1716                                      FileFilterList(_("LyX Documents (*.lyx)")),
1717                                      string());
1718
1719                 if (result.first == FileDialog::Later)
1720                         return;
1721                 if (result.second.empty())
1722                         return;
1723                 templname = result.second;
1724         }
1725
1726         view()->newFile(filename, templname, !name.empty());
1727 }
1728
1729
1730 void LyXFunc::open(string const & fname)
1731 {
1732         string initpath = lyxrc.document_path;
1733
1734         if (view()->available()) {
1735                 string const trypath = owner->buffer()->filePath();
1736                 // If directory is writeable, use this as default.
1737                 if (IsDirWriteable(trypath))
1738                         initpath = trypath;
1739         }
1740
1741         string filename;
1742
1743         if (fname.empty()) {
1744                 FileDialog fileDlg(_("Select document to open"),
1745                         LFUN_FILE_OPEN,
1746                         make_pair(string(_("Documents|#o#O")),
1747                                   string(lyxrc.document_path)),
1748                         make_pair(string(_("Examples|#E#e")),
1749                                   string(AddPath(package().system_support(), "examples"))));
1750
1751                 FileDialog::Result result =
1752                         fileDlg.open(initpath,
1753                                      FileFilterList(_("LyX Documents (*.lyx)")),
1754                                      string());
1755
1756                 if (result.first == FileDialog::Later)
1757                         return;
1758
1759                 filename = result.second;
1760
1761                 // check selected filename
1762                 if (filename.empty()) {
1763                         owner->message(_("Canceled."));
1764                         return;
1765                 }
1766         } else
1767                 filename = fname;
1768
1769         // get absolute path of file and add ".lyx" to the filename if
1770         // necessary
1771         string const fullpath = FileSearch(string(), filename, "lyx");
1772         if (!fullpath.empty()) {
1773                 filename = fullpath;
1774         }
1775
1776         string const disp_fn(MakeDisplayPath(filename));
1777
1778         // if the file doesn't exist, let the user create one
1779         if (!fs::exists(filename)) {
1780                 // the user specifically chose this name. Believe them.
1781                 view()->newFile(filename, "", true);
1782                 return;
1783         }
1784
1785         owner->message(bformat(_("Opening document %1$s..."), disp_fn));
1786
1787         string str2;
1788         if (view()->loadLyXFile(filename)) {
1789                 str2 = bformat(_("Document %1$s opened."), disp_fn);
1790         } else {
1791                 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1792         }
1793         owner->message(str2);
1794 }
1795
1796
1797 void LyXFunc::doImport(string const & argument)
1798 {
1799         string format;
1800         string filename = split(argument, format, ' ');
1801
1802         lyxerr[Debug::INFO] << "LyXFunc::doImport: " << format
1803                             << " file: " << filename << endl;
1804
1805         // need user interaction
1806         if (filename.empty()) {
1807                 string initpath = lyxrc.document_path;
1808
1809                 if (view()->available()) {
1810                         string const trypath = owner->buffer()->filePath();
1811                         // If directory is writeable, use this as default.
1812                         if (IsDirWriteable(trypath))
1813                                 initpath = trypath;
1814                 }
1815
1816                 string const text = bformat(_("Select %1$s file to import"),
1817                         formats.prettyName(format));
1818
1819                 FileDialog fileDlg(text,
1820                         LFUN_IMPORT,
1821                         make_pair(string(_("Documents|#o#O")),
1822                                   string(lyxrc.document_path)),
1823                         make_pair(string(_("Examples|#E#e")),
1824                                   string(AddPath(package().system_support(), "examples"))));
1825
1826                 string const filter = formats.prettyName(format)
1827                         + " (*." + formats.extension(format) + ')';
1828
1829                 FileDialog::Result result =
1830                         fileDlg.open(initpath,
1831                                      FileFilterList(filter),
1832                                      string());
1833
1834                 if (result.first == FileDialog::Later)
1835                         return;
1836
1837                 filename = result.second;
1838
1839                 // check selected filename
1840                 if (filename.empty())
1841                         owner->message(_("Canceled."));
1842         }
1843
1844         if (filename.empty())
1845                 return;
1846
1847         // get absolute path of file
1848         filename = MakeAbsPath(filename);
1849
1850         string const lyxfile = ChangeExtension(filename, ".lyx");
1851
1852         // Check if the document already is open
1853         if (lyx_gui::use_gui && bufferlist.exists(lyxfile)) {
1854                 if (!bufferlist.close(bufferlist.getBuffer(lyxfile), true)) {
1855                         owner->message(_("Canceled."));
1856                         return;
1857                 }
1858         }
1859
1860         // if the file exists already, and we didn't do
1861         // -i lyx thefile.lyx, warn
1862         if (fs::exists(lyxfile) && filename != lyxfile) {
1863                 string const file = MakeDisplayPath(lyxfile, 30);
1864
1865                 string text = bformat(_("The document %1$s already exists.\n\n"
1866                         "Do you want to over-write that document?"), file);
1867                 int const ret = Alert::prompt(_("Over-write document?"),
1868                         text, 0, 1, _("&Over-write"), _("&Cancel"));
1869
1870                 if (ret == 1) {
1871                         owner->message(_("Canceled."));
1872                         return;
1873                 }
1874         }
1875
1876         Importer::Import(owner, filename, format);
1877 }
1878
1879
1880 void LyXFunc::closeBuffer()
1881 {
1882         if (bufferlist.close(owner->buffer(), true) && !quitting) {
1883                 if (bufferlist.empty()) {
1884                         // need this otherwise SEGV may occur while
1885                         // trying to set variables that don't exist
1886                         // since there's no current buffer
1887                         owner->getDialogs().hideBufferDependent();
1888                 } else {
1889                         view()->setBuffer(bufferlist.first());
1890                 }
1891         }
1892 }
1893
1894
1895 // Each "owner" should have it's own message method. lyxview and
1896 // the minibuffer would use the minibuffer, but lyxserver would
1897 // send an ERROR signal to its client.  Alejandro 970603
1898 // This function is bit problematic when it comes to NLS, to make the
1899 // lyx servers client be language indepenent we must not translate
1900 // strings sent to this func.
1901 void LyXFunc::setErrorMessage(string const & m) const
1902 {
1903         dispatch_buffer = m;
1904         errorstat = true;
1905 }
1906
1907
1908 void LyXFunc::setMessage(string const & m) const
1909 {
1910         dispatch_buffer = m;
1911 }
1912
1913
1914 string const LyXFunc::viewStatusMessage()
1915 {
1916         // When meta-fake key is pressed, show the key sequence so far + "M-".
1917         if (wasMetaKey())
1918                 return keyseq.print() + "M-";
1919
1920         // Else, when a non-complete key sequence is pressed,
1921         // show the available options.
1922         if (keyseq.length() > 0 && !keyseq.deleted())
1923                 return keyseq.printOptions();
1924
1925         if (!view()->available())
1926                 return _("Welcome to LyX!");
1927
1928         return view()->cursor().currentState();
1929 }
1930
1931
1932 BufferView * LyXFunc::view() const
1933 {
1934         BOOST_ASSERT(owner);
1935         return owner->view().get();
1936 }
1937
1938
1939 bool LyXFunc::wasMetaKey() const
1940 {
1941         return (meta_fake_bit != key_modifier::none);
1942 }
1943
1944
1945 namespace {
1946
1947 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
1948 {
1949         // Why the switch you might ask. It is a trick to ensure that all
1950         // the elements in the LyXRCTags enum is handled. As you can see
1951         // there are no breaks at all. So it is just a huge fall-through.
1952         // The nice thing is that we will get a warning from the compiler
1953         // if we forget an element.
1954         LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
1955         switch (tag) {
1956         case LyXRC::RC_ACCEPT_COMPOUND:
1957         case LyXRC::RC_ALT_LANG:
1958         case LyXRC::RC_ASCIIROFF_COMMAND:
1959         case LyXRC::RC_ASCII_LINELEN:
1960         case LyXRC::RC_AUTOREGIONDELETE:
1961         case LyXRC::RC_AUTORESET_OPTIONS:
1962         case LyXRC::RC_AUTOSAVE:
1963         case LyXRC::RC_AUTO_NUMBER:
1964         case LyXRC::RC_BACKUPDIR_PATH:
1965         case LyXRC::RC_BIBTEX_COMMAND:
1966         case LyXRC::RC_BINDFILE:
1967         case LyXRC::RC_CHECKLASTFILES:
1968         case LyXRC::RC_CHKTEX_COMMAND:
1969         case LyXRC::RC_CONVERTER:
1970         case LyXRC::RC_COPIER:
1971         case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
1972         case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
1973         case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
1974         case LyXRC::RC_CYGWIN_PATH_FIX:
1975                 if (lyxrc_orig.cygwin_path_fix != lyxrc_new.cygwin_path_fix) {
1976                         namespace os = lyx::support::os;
1977                         os::cygwin_path_fix(lyxrc_new.cygwin_path_fix);
1978                 }
1979         case LyXRC::RC_DATE_INSERT_FORMAT:
1980         case LyXRC::RC_DEFAULT_LANGUAGE:
1981         case LyXRC::RC_DEFAULT_PAPERSIZE:
1982         case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
1983         case LyXRC::RC_DISPLAY_GRAPHICS:
1984         case LyXRC::RC_DOCUMENTPATH:
1985                 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
1986                         if (fs::exists(lyxrc_new.document_path) &&
1987                             fs::is_directory(lyxrc_new.document_path)) {
1988                                 using lyx::support::package;
1989                                 package().document_dir() = lyxrc.document_path;
1990                         }
1991                 }
1992         case LyXRC::RC_ESC_CHARS:
1993         case LyXRC::RC_FONT_ENCODING:
1994         case LyXRC::RC_FORMAT:
1995         case LyXRC::RC_INDEX_COMMAND:
1996         case LyXRC::RC_INPUT:
1997         case LyXRC::RC_KBMAP:
1998         case LyXRC::RC_KBMAP_PRIMARY:
1999         case LyXRC::RC_KBMAP_SECONDARY:
2000         case LyXRC::RC_LABEL_INIT_LENGTH:
2001         case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2002         case LyXRC::RC_LANGUAGE_AUTO_END:
2003         case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2004         case LyXRC::RC_LANGUAGE_COMMAND_END:
2005         case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2006         case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2007         case LyXRC::RC_LANGUAGE_PACKAGE:
2008         case LyXRC::RC_LANGUAGE_USE_BABEL:
2009         case LyXRC::RC_LASTFILES:
2010         case LyXRC::RC_MAKE_BACKUP:
2011         case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2012         case LyXRC::RC_NUMLASTFILES:
2013         case LyXRC::RC_PATH_PREFIX:
2014                 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2015                         using lyx::support::prependEnvPath;
2016                         prependEnvPath("PATH", lyxrc.path_prefix);
2017                 }
2018         case LyXRC::RC_PERS_DICT:
2019         case LyXRC::RC_POPUP_BOLD_FONT:
2020         case LyXRC::RC_POPUP_FONT_ENCODING:
2021         case LyXRC::RC_POPUP_NORMAL_FONT:
2022         case LyXRC::RC_PREVIEW:
2023         case LyXRC::RC_PREVIEW_HASHED_LABELS:
2024         case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2025         case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2026         case LyXRC::RC_PRINTCOPIESFLAG:
2027         case LyXRC::RC_PRINTER:
2028         case LyXRC::RC_PRINTEVENPAGEFLAG:
2029         case LyXRC::RC_PRINTEXSTRAOPTIONS:
2030         case LyXRC::RC_PRINTFILEEXTENSION:
2031         case LyXRC::RC_PRINTLANDSCAPEFLAG:
2032         case LyXRC::RC_PRINTODDPAGEFLAG:
2033         case LyXRC::RC_PRINTPAGERANGEFLAG:
2034         case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2035         case LyXRC::RC_PRINTPAPERFLAG:
2036         case LyXRC::RC_PRINTREVERSEFLAG:
2037         case LyXRC::RC_PRINTSPOOL_COMMAND:
2038         case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2039         case LyXRC::RC_PRINTTOFILE:
2040         case LyXRC::RC_PRINTTOPRINTER:
2041         case LyXRC::RC_PRINT_ADAPTOUTPUT:
2042         case LyXRC::RC_PRINT_COMMAND:
2043         case LyXRC::RC_RTL_SUPPORT:
2044         case LyXRC::RC_SCREEN_DPI:
2045         case LyXRC::RC_SCREEN_FONT_ENCODING:
2046         case LyXRC::RC_SCREEN_FONT_ROMAN:
2047         case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2048         case LyXRC::RC_SCREEN_FONT_SANS:
2049         case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2050         case LyXRC::RC_SCREEN_FONT_SCALABLE:
2051         case LyXRC::RC_SCREEN_FONT_SIZES:
2052         case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2053         case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2054         case LyXRC::RC_SCREEN_ZOOM:
2055         case LyXRC::RC_SERVERPIPE:
2056         case LyXRC::RC_SET_COLOR:
2057         case LyXRC::RC_SHOW_BANNER:
2058         case LyXRC::RC_SPELL_COMMAND:
2059         case LyXRC::RC_TEMPDIRPATH:
2060         case LyXRC::RC_TEMPLATEPATH:
2061         case LyXRC::RC_TEX_ALLOWS_SPACES:
2062         case LyXRC::RC_UIFILE:
2063         case LyXRC::RC_USER_EMAIL:
2064         case LyXRC::RC_USER_NAME:
2065         case LyXRC::RC_USETEMPDIR:
2066         case LyXRC::RC_USE_ALT_LANG:
2067         case LyXRC::RC_USE_ESC_CHARS:
2068         case LyXRC::RC_USE_INP_ENC:
2069         case LyXRC::RC_USE_PERS_DICT:
2070         case LyXRC::RC_USE_SPELL_LIB:
2071         case LyXRC::RC_VIEWDVI_PAPEROPTION:
2072         case LyXRC::RC_VIEWER:
2073         case LyXRC::RC_WHEEL_JUMP:
2074         case LyXRC::RC_LAST:
2075                 break;
2076         }
2077 }
2078
2079 } // namespace anon