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