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