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