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