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