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