]> git.lyx.org Git - lyx.git/blob - src/lyxfunc.C
* Gui.h: new closeAll() pure virtual method.
[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 (argument != "force") {
1026                                 if (!theApp->gui().closeAll())
1027                                         break;
1028                                 lyx_view_ = 0;
1029                         }
1030
1031                         // FIXME: this code needs to be transfered somewhere else
1032                         // as lyx_view_ will most certainly be null and a same buffer
1033                         // might be visible in more than one LyXView.
1034                         if (lyx_view_ && lyx_view_->view()->buffer()) {
1035                                 // save cursor Position for opened files to .lyx/session
1036                                 LyX::ref().session().saveFilePosition(lyx_view_->buffer()->fileName(),
1037                                         boost::tie(view()->cursor().pit(), view()->cursor().pos()) );
1038                                 // save bookmarks to .lyx/session
1039                                 view()->saveSavedPositions();
1040                         }
1041
1042                         LyX::ref().quit(argument == "force");
1043                         break;
1044
1045                 case LFUN_TOC_VIEW: {
1046                         BOOST_ASSERT(lyx_view_);
1047                         InsetCommandParams p("tableofcontents");
1048                         string const data = InsetCommandMailer::params2string("toc", p);
1049                         lyx_view_->getDialogs().show("toc", data, 0);
1050                         break;
1051                 }
1052
1053                 case LFUN_BUFFER_AUTO_SAVE:
1054                         autoSave(view());
1055                         break;
1056
1057                 case LFUN_RECONFIGURE:
1058                         reconfigure(view());
1059                         break;
1060
1061                 case LFUN_HELP_OPEN: {
1062                         BOOST_ASSERT(lyx_view_);
1063                         string const arg = argument;
1064                         if (arg.empty()) {
1065                                 setErrorMessage(_("Missing argument"));
1066                                 break;
1067                         }
1068                         string const fname = i18nLibFileSearch("doc", arg, "lyx");
1069                         if (fname.empty()) {
1070                                 lyxerr << "LyX: unable to find documentation file `"
1071                                                          << arg << "'. Bad installation?" << endl;
1072                                 break;
1073                         }
1074                         lyx_view_->message(bformat(_("Opening help file %1$s..."),
1075                                 makeDisplayPath(fname)));
1076                         lyx_view_->loadLyXFile(fname, false);
1077                         break;
1078                 }
1079
1080                 // --- version control -------------------------------
1081                 case LFUN_VC_REGISTER:
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()->lyxvc().registrer();
1087                                 view()->reload();
1088                         }
1089                         break;
1090
1091                 case LFUN_VC_CHECK_IN:
1092                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1093                         if (!ensureBufferClean(view()))
1094                                 break;
1095                         if (lyx_view_->buffer()->lyxvc().inUse()
1096                                         && !lyx_view_->buffer()->isReadonly()) {
1097                                 lyx_view_->buffer()->lyxvc().checkIn();
1098                                 view()->reload();
1099                         }
1100                         break;
1101
1102                 case LFUN_VC_CHECK_OUT:
1103                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1104                         if (!ensureBufferClean(view()))
1105                                 break;
1106                         if (lyx_view_->buffer()->lyxvc().inUse()
1107                                         && lyx_view_->buffer()->isReadonly()) {
1108                                 lyx_view_->buffer()->lyxvc().checkOut();
1109                                 view()->reload();
1110                         }
1111                         break;
1112
1113                 case LFUN_VC_REVERT:
1114                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1115                         lyx_view_->buffer()->lyxvc().revert();
1116                         view()->reload();
1117                         break;
1118
1119                 case LFUN_VC_UNDO_LAST:
1120                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1121                         lyx_view_->buffer()->lyxvc().undoLast();
1122                         view()->reload();
1123                         break;
1124
1125                 // --- buffers ----------------------------------------
1126                 case LFUN_BUFFER_SWITCH:
1127                         BOOST_ASSERT(lyx_view_);
1128                         lyx_view_->setBuffer(theBufferList().getBuffer(argument));
1129                         break;
1130
1131                 case LFUN_BUFFER_NEXT:
1132                         BOOST_ASSERT(lyx_view_);
1133                         lyx_view_->setBuffer(theBufferList().next(view()->buffer()));
1134                         break;
1135
1136                 case LFUN_BUFFER_PREVIOUS:
1137                         BOOST_ASSERT(lyx_view_);
1138                         lyx_view_->setBuffer(theBufferList().previous(view()->buffer()));
1139                         break;
1140
1141                 case LFUN_FILE_NEW:
1142                         BOOST_ASSERT(lyx_view_);
1143                         newFile(view(), argument);
1144                         break;
1145
1146                 case LFUN_FILE_OPEN:
1147                         BOOST_ASSERT(lyx_view_);
1148                         open(argument);
1149                         break;
1150
1151                 case LFUN_DROP_LAYOUTS_CHOICE:
1152                         BOOST_ASSERT(lyx_view_);
1153                         lyx_view_->getToolbars().openLayoutList();
1154                         break;
1155
1156                 case LFUN_MENU_OPEN:
1157                         BOOST_ASSERT(lyx_view_);
1158                         lyx_view_->getMenubar().openByName(from_utf8(argument));
1159                         break;
1160
1161                 // --- lyxserver commands ----------------------------
1162                 case LFUN_SERVER_GET_NAME:
1163                         BOOST_ASSERT(lyx_view_ && lyx_view_->buffer());
1164                         setMessage(from_utf8(lyx_view_->buffer()->fileName()));
1165                         lyxerr[Debug::INFO] << "FNAME["
1166                                                          << lyx_view_->buffer()->fileName()
1167                                                          << "] " << endl;
1168                         break;
1169
1170                 case LFUN_SERVER_NOTIFY:
1171                         dispatch_buffer = from_utf8(keyseq->print());
1172                         theLyXServer().notifyClient(to_utf8(dispatch_buffer));
1173                         break;
1174
1175                 case LFUN_SERVER_GOTO_FILE_ROW: {
1176                         BOOST_ASSERT(lyx_view_);
1177                         string file_name;
1178                         int row;
1179                         istringstream is(argument);
1180                         is >> file_name >> row;
1181                         if (prefixIs(file_name, package().temp_dir())) {
1182                                 // Needed by inverse dvi search. If it is a file
1183                                 // in tmpdir, call the apropriated function
1184                                 lyx_view_->setBuffer(theBufferList().getBufferFromTmp(file_name));
1185                         } else {
1186                                 // Must replace extension of the file to be .lyx
1187                                 // and get full path
1188                                 string const s = changeExtension(file_name, ".lyx");
1189                                 // Either change buffer or load the file
1190                                 if (theBufferList().exists(s)) {
1191                                         lyx_view_->setBuffer(theBufferList().getBuffer(s));
1192                                 } else {
1193                                         lyx_view_->loadLyXFile(s);
1194                                 }
1195                         }
1196
1197                         view()->setCursorFromRow(row);
1198
1199                         view()->center();
1200                         // see BufferView::center()
1201                         break;
1202                 }
1203
1204                 case LFUN_DIALOG_SHOW: {
1205                         BOOST_ASSERT(lyx_view_);
1206                         string const name = cmd.getArg(0);
1207                         string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1208
1209                         if (name == "character") {
1210                                 data = freefont2string();
1211                                 if (!data.empty())
1212                                         lyx_view_->getDialogs().show("character", data);
1213                         } else if (name == "latexlog") {
1214                                 pair<Buffer::LogType, string> const logfile =
1215                                         lyx_view_->buffer()->getLogName();
1216                                 switch (logfile.first) {
1217                                 case Buffer::latexlog:
1218                                         data = "latex ";
1219                                         break;
1220                                 case Buffer::buildlog:
1221                                         data = "literate ";
1222                                         break;
1223                                 }
1224                                 data += LyXLex::quoteString(logfile.second);
1225                                 lyx_view_->getDialogs().show("log", data);
1226                         } else if (name == "vclog") {
1227                                 string const data = "vc " +
1228                                         LyXLex::quoteString(lyx_view_->buffer()->lyxvc().getLogFile());
1229                                 lyx_view_->getDialogs().show("log", data);
1230                         } else
1231                                 lyx_view_->getDialogs().show(name, data);
1232                         break;
1233                 }
1234
1235                 case LFUN_DIALOG_SHOW_NEW_INSET: {
1236                         BOOST_ASSERT(lyx_view_);
1237                         string const name = cmd.getArg(0);
1238                         string data = trim(to_utf8(cmd.argument()).substr(name.size()));
1239                         if (name == "bibitem" ||
1240                             name == "bibtex" ||
1241                             name == "index" ||
1242                             name == "label" ||
1243                             name == "ref" ||
1244                             name == "toc" ||
1245                             name == "url") {
1246                                 InsetCommandParams p(name);
1247                                 data = InsetCommandMailer::params2string(name, p);
1248                         } else if (name == "include") {
1249                                 InsetCommandParams p(data);
1250                                 data = InsetIncludeMailer::params2string(p);
1251                         } else if (name == "box") {
1252                                 // \c data == "Boxed" || "Frameless" etc
1253                                 InsetBoxParams p(data);
1254                                 data = InsetBoxMailer::params2string(p);
1255                         } else if (name == "branch") {
1256                                 InsetBranchParams p;
1257                                 data = InsetBranchMailer::params2string(p);
1258                         } else if (name == "citation") {
1259                                 InsetCommandParams p("cite");
1260                                 data = InsetCommandMailer::params2string(name, p);
1261                         } else if (name == "ert") {
1262                                 data = InsetERTMailer::params2string(InsetCollapsable::Open);
1263                         } else if (name == "external") {
1264                                 InsetExternalParams p;
1265                                 Buffer const & buffer = *lyx_view_->buffer();
1266                                 data = InsetExternalMailer::params2string(p, buffer);
1267                         } else if (name == "float") {
1268                                 InsetFloatParams p;
1269                                 data = InsetFloatMailer::params2string(p);
1270                         } else if (name == "graphics") {
1271                                 InsetGraphicsParams p;
1272                                 Buffer const & buffer = *lyx_view_->buffer();
1273                                 data = InsetGraphicsMailer::params2string(p, buffer);
1274                         } else if (name == "note") {
1275                                 InsetNoteParams p;
1276                                 data = InsetNoteMailer::params2string(p);
1277                         } else if (name == "vspace") {
1278                                 VSpace space;
1279                                 data = InsetVSpaceMailer::params2string(space);
1280                         } else if (name == "wrap") {
1281                                 InsetWrapParams p;
1282                                 data = InsetWrapMailer::params2string(p);
1283                         }
1284                         lyx_view_->getDialogs().show(name, data, 0);
1285                         break;
1286                 }
1287
1288                 case LFUN_DIALOG_UPDATE: {
1289                         BOOST_ASSERT(lyx_view_);
1290                         string const & name = argument;
1291                         // Can only update a dialog connected to an existing inset
1292                         InsetBase * inset = lyx_view_->getDialogs().getOpenInset(name);
1293                         if (inset) {
1294                                 FuncRequest fr(LFUN_INSET_DIALOG_UPDATE, cmd.argument());
1295                                 inset->dispatch(view()->cursor(), fr);
1296                         } else if (name == "paragraph") {
1297                                 dispatch(FuncRequest(LFUN_PARAGRAPH_UPDATE));
1298                         } else if (name == "prefs") {
1299                                 lyx_view_->getDialogs().update(name, string());
1300                         }
1301                         break;
1302                 }
1303
1304                 case LFUN_DIALOG_HIDE:
1305                         Dialogs::hide(argument, 0);
1306                         break;
1307
1308                 case LFUN_DIALOG_DISCONNECT_INSET:
1309                         BOOST_ASSERT(lyx_view_);
1310                         lyx_view_->getDialogs().disconnect(argument);
1311                         break;
1312
1313
1314                 case LFUN_CITATION_INSERT: {
1315                         BOOST_ASSERT(lyx_view_);
1316                         if (!argument.empty()) {
1317                                 // we can have one optional argument, delimited by '|'
1318                                 // citation-insert <key>|<text_before>
1319                                 // this should be enhanced to also support text_after
1320                                 // and citation style
1321                                 string arg = argument;
1322                                 string opt1;
1323                                 if (contains(argument, "|")) {
1324                                         arg = token(argument, '|', 0);
1325                                         opt1 = '[' + token(argument, '|', 1) + ']';
1326                                 }
1327                                 std::ostringstream os;
1328                                 os << "citation LatexCommand\n"
1329                                    << "\\cite" << opt1 << "{" << arg << "}\n"
1330                                    << "\\end_inset";
1331                                 FuncRequest fr(LFUN_INSET_INSERT, os.str());
1332                                 dispatch(fr);
1333                         } else
1334                                 dispatch(FuncRequest(LFUN_DIALOG_SHOW, "citation"));
1335                         break;
1336                 }
1337
1338                 case LFUN_BUFFER_CHILD_OPEN: {
1339                         BOOST_ASSERT(lyx_view_);
1340                         string const filename =
1341                                 makeAbsPath(argument, lyx_view_->buffer()->filePath());
1342                         // FIXME Should use bformat
1343                         setMessage(_("Opening child document ") +
1344                                          makeDisplayPath(filename) + "...");
1345                         view()->savePosition(0);
1346                         string const parentfilename = lyx_view_->buffer()->fileName();
1347                         if (theBufferList().exists(filename))
1348                                 lyx_view_->setBuffer(theBufferList().getBuffer(filename));
1349                         else
1350                                 lyx_view_->loadLyXFile(filename);
1351                         // Set the parent name of the child document.
1352                         // This makes insertion of citations and references in the child work,
1353                         // when the target is in the parent or another child document.
1354                         lyx_view_->buffer()->setParentName(parentfilename);
1355                         break;
1356                 }
1357
1358                 case LFUN_TOGGLE_CURSOR_FOLLOWS_SCROLLBAR:
1359                         BOOST_ASSERT(lyx_view_);
1360                         lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1361                         break;
1362
1363                 case LFUN_KEYMAP_OFF:
1364                         BOOST_ASSERT(lyx_view_);
1365                         lyx_view_->view()->getIntl().keyMapOn(false);
1366                         break;
1367
1368                 case LFUN_KEYMAP_PRIMARY:
1369                         BOOST_ASSERT(lyx_view_);
1370                         lyx_view_->view()->getIntl().keyMapPrim();
1371                         break;
1372
1373                 case LFUN_KEYMAP_SECONDARY:
1374                         BOOST_ASSERT(lyx_view_);
1375                         lyx_view_->view()->getIntl().keyMapSec();
1376                         break;
1377
1378                 case LFUN_KEYMAP_TOGGLE:
1379                         BOOST_ASSERT(lyx_view_);
1380                         lyx_view_->view()->getIntl().toggleKeyMap();
1381                         break;
1382
1383                 case LFUN_REPEAT: {
1384                         // repeat command
1385                         string countstr;
1386                         string rest = split(argument, countstr, ' ');
1387                         istringstream is(countstr);
1388                         int count = 0;
1389                         is >> count;
1390                         lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
1391                         for (int i = 0; i < count; ++i)
1392                                 dispatch(lyxaction.lookupFunc(rest));
1393                         break;
1394                 }
1395
1396                 case LFUN_COMMAND_SEQUENCE: {
1397                         // argument contains ';'-terminated commands
1398                         string arg = argument;
1399                         while (!arg.empty()) {
1400                                 string first;
1401                                 arg = split(arg, first, ';');
1402                                 FuncRequest func(lyxaction.lookupFunc(first));
1403                                 func.origin = cmd.origin;
1404                                 dispatch(func);
1405                         }
1406                         break;
1407                 }
1408
1409                 case LFUN_PREFERENCES_SAVE: {
1410                         support::Path p(package().user_support());
1411                         lyxrc.write("preferences", false);
1412                         break;
1413                 }
1414
1415                 case LFUN_SCREEN_FONT_UPDATE:
1416                         BOOST_ASSERT(lyx_view_);
1417                         // handle the screen font changes.
1418                         lyxrc.set_font_norm_type();
1419                         theFontLoader().update();
1420                         // All visible buffers will need resize
1421                         view()->resize();
1422                         break;
1423
1424                 case LFUN_SET_COLOR: {
1425                         string lyx_name;
1426                         string const x11_name = split(argument, lyx_name, ' ');
1427                         if (lyx_name.empty() || x11_name.empty()) {
1428                                 setErrorMessage(_("Syntax: set-color <lyx_name>"
1429                                                         " <x11_name>"));
1430                                 break;
1431                         }
1432
1433                         bool const graphicsbg_changed =
1434                                 (lyx_name == lcolor.getLyXName(LColor::graphicsbg) &&
1435                                  x11_name != lcolor.getX11Name(LColor::graphicsbg));
1436
1437                         if (!lcolor.setColor(lyx_name, x11_name)) {
1438                                 setErrorMessage(
1439                                                 bformat(_("Set-color \"%1$s\" failed "
1440                                                                        "- color is undefined or "
1441                                                                        "may not be redefined"),
1442                                                                            from_utf8(lyx_name)));
1443                                 break;
1444                         }
1445
1446                         theApp->updateColor(lcolor.getFromLyXName(lyx_name));
1447
1448                         if (graphicsbg_changed) {
1449 #ifdef WITH_WARNINGS
1450 #warning FIXME!! The graphics cache no longer has a changeDisplay method.
1451 #endif
1452 #if 0
1453                                 graphics::GCache::get().changeDisplay(true);
1454 #endif
1455                         }
1456                         break;
1457                 }
1458
1459                 case LFUN_MESSAGE:
1460                         BOOST_ASSERT(lyx_view_);
1461                         lyx_view_->message(from_utf8(argument));
1462                         break;
1463
1464                 case LFUN_EXTERNAL_EDIT: {
1465                         BOOST_ASSERT(lyx_view_);
1466                         FuncRequest fr(action, argument);
1467                         InsetExternal().dispatch(view()->cursor(), fr);
1468                         break;
1469                 }
1470
1471                 case LFUN_GRAPHICS_EDIT: {
1472                         FuncRequest fr(action, argument);
1473                         InsetGraphics().dispatch(view()->cursor(), fr);
1474                         break;
1475                 }
1476
1477                 case LFUN_INSET_APPLY: {
1478                         BOOST_ASSERT(lyx_view_);
1479                         string const name = cmd.getArg(0);
1480                         InsetBase * inset = lyx_view_->getDialogs().getOpenInset(name);
1481                         if (inset) {
1482                                 FuncRequest fr(LFUN_INSET_MODIFY, argument);
1483                                 inset->dispatch(view()->cursor(), fr);
1484                         } else {
1485                                 FuncRequest fr(LFUN_INSET_INSERT, argument);
1486                                 dispatch(fr);
1487                         }
1488                         // ideally, the update flag should be set by the insets,
1489                         // but this is not possible currently
1490                         updateFlags = Update::Force | Update::FitCursor;
1491                         break;
1492                 }
1493
1494                 case LFUN_ALL_INSETS_TOGGLE: {
1495                         BOOST_ASSERT(lyx_view_);
1496                         string action;
1497                         string const name = split(argument, action, ' ');
1498                         InsetBase::Code const inset_code =
1499                                 InsetBase::translate(name);
1500
1501                         LCursor & cur = view()->cursor();
1502                         FuncRequest fr(LFUN_INSET_TOGGLE, action);
1503
1504                         InsetBase & inset = lyx_view_->buffer()->inset();
1505                         InsetIterator it  = inset_iterator_begin(inset);
1506                         InsetIterator const end = inset_iterator_end(inset);
1507                         for (; it != end; ++it) {
1508                                 if (inset_code == InsetBase::NO_CODE
1509                                     || inset_code == it->lyxCode()) {
1510                                         LCursor tmpcur = cur;
1511                                         tmpcur.pushLeft(*it);
1512                                         it->dispatch(tmpcur, fr);
1513                                 }
1514                         }
1515                         updateFlags = Update::Force | Update::FitCursor;
1516                         break;
1517                 }
1518
1519                 case LFUN_BUFFER_LANGUAGE: {
1520                         BOOST_ASSERT(lyx_view_);
1521                         Buffer & buffer = *lyx_view_->buffer();
1522                         Language const * oldL = buffer.params().language;
1523                         Language const * newL = languages.getLanguage(argument);
1524                         if (!newL || oldL == newL)
1525                                 break;
1526
1527                         if (oldL->rightToLeft() == newL->rightToLeft()
1528                             && !buffer.isMultiLingual())
1529                                 buffer.changeLanguage(oldL, newL);
1530                         else
1531                                 buffer.updateDocLang(newL);
1532                         break;
1533                 }
1534
1535                 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1536                         string const fname =
1537                                 addName(addPath(package().user_support(), "templates/"),
1538                                         "defaults.lyx");
1539                         Buffer defaults(fname);
1540
1541                         istringstream ss(argument);
1542                         LyXLex lex(0,0);
1543                         lex.setStream(ss);
1544                         int const unknown_tokens = defaults.readHeader(lex);
1545
1546                         if (unknown_tokens != 0) {
1547                                 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1548                                        << unknown_tokens << " unknown token"
1549                                        << (unknown_tokens == 1 ? "" : "s")
1550                                        << endl;
1551                         }
1552
1553                         if (defaults.writeFile(defaults.fileName()))
1554                                 // FIXME Should use bformat
1555                                 setMessage(_("Document defaults saved in ")
1556                                            + makeDisplayPath(fname));
1557                         else
1558                                 setErrorMessage(_("Unable to save document defaults"));
1559                         break;
1560                 }
1561
1562                 case LFUN_BUFFER_PARAMS_APPLY: {
1563                         BOOST_ASSERT(lyx_view_);
1564                         biblio::CiteEngine const engine =
1565                                 lyx_view_->buffer()->params().cite_engine;
1566
1567                         istringstream ss(argument);
1568                         LyXLex lex(0,0);
1569                         lex.setStream(ss);
1570                         int const unknown_tokens =
1571                                 lyx_view_->buffer()->readHeader(lex);
1572
1573                         if (unknown_tokens != 0) {
1574                                 lyxerr << "Warning in LFUN_BUFFER_PARAMS_APPLY!\n"
1575                                        << unknown_tokens << " unknown token"
1576                                        << (unknown_tokens == 1 ? "" : "s")
1577                                        << endl;
1578                         }
1579                         if (engine == lyx_view_->buffer()->params().cite_engine)
1580                                 break;
1581
1582                         LCursor & cur = view()->cursor();
1583                         FuncRequest fr(LFUN_INSET_REFRESH);
1584
1585                         InsetBase & inset = lyx_view_->buffer()->inset();
1586                         InsetIterator it  = inset_iterator_begin(inset);
1587                         InsetIterator const end = inset_iterator_end(inset);
1588                         for (; it != end; ++it)
1589                                 if (it->lyxCode() == InsetBase::CITE_CODE)
1590                                         it->dispatch(cur, fr);
1591                         break;
1592                 }
1593
1594                 case LFUN_TEXTCLASS_APPLY: {
1595                         BOOST_ASSERT(lyx_view_);
1596                         Buffer * buffer = lyx_view_->buffer();
1597
1598                         textclass_type const old_class =
1599                                 buffer->params().textclass;
1600
1601                         loadTextclass(argument);
1602
1603                         std::pair<bool, textclass_type> const tc_pair =
1604                                 textclasslist.numberOfClass(argument);
1605
1606                         if (!tc_pair.first)
1607                                 break;
1608
1609                         textclass_type const new_class = tc_pair.second;
1610                         if (old_class == new_class)
1611                                 // nothing to do
1612                                 break;
1613
1614                         lyx_view_->message(_("Converting document to new document class..."));
1615                         recordUndoFullDocument(view());
1616                         buffer->params().textclass = new_class;
1617                         StableDocIterator backcur(view()->cursor());
1618                         ErrorList & el = buffer->errorList("Class Switch");
1619                         cap::switchBetweenClasses(
1620                                 old_class, new_class,
1621                                 static_cast<InsetText &>(buffer->inset()), el);
1622
1623                         view()->setCursor(backcur.asDocIterator(&(buffer->inset())));
1624
1625                         buffer->errors("Class Switch");
1626                         updateLabels(*buffer);
1627                         updateFlags = Update::Force | Update::FitCursor;
1628                         break;
1629                 }
1630
1631                 case LFUN_TEXTCLASS_LOAD:
1632                         loadTextclass(argument);
1633                         break;
1634
1635                 case LFUN_LYXRC_APPLY: {
1636                         LyXRC const lyxrc_orig = lyxrc;
1637
1638                         istringstream ss(argument);
1639                         bool const success = lyxrc.read(ss) == 0;
1640
1641                         if (!success) {
1642                                 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1643                                        << "Unable to read lyxrc data"
1644                                        << endl;
1645                                 break;
1646                         }
1647
1648                         actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1649                         break;
1650                 }
1651
1652                 case LFUN_WINDOW_NEW:
1653                         LyX::ref().newLyXView();
1654                         break;
1655
1656                 case LFUN_WINDOW_CLOSE:
1657                         BOOST_ASSERT(lyx_view_);
1658                         BOOST_ASSERT(theApp);
1659                         lyx_view_->close();
1660                         // We return here because lyx_view does not exists anymore.
1661                         return;
1662
1663                 default: {
1664                         BOOST_ASSERT(lyx_view_);
1665                         view()->cursor().dispatch(cmd);
1666                         updateFlags = view()->cursor().result().update();
1667                         if (!view()->cursor().result().dispatched())
1668                                 if (view()->dispatch(cmd)) 
1669                                         updateFlags = Update::Force | Update::FitCursor;
1670                         break;
1671                 }
1672                 }
1673
1674                 if (lyx_view_ && view()->buffer()) {
1675                         // Redraw screen unless explicitly told otherwise.
1676                         // This also initializes the position cache for all insets
1677                         // in (at least partially) visible top-level paragraphs.
1678                         bool needSecondUpdate = false;
1679                         if (updateFlags != Update::None)
1680                                 view()->update(updateFlags);
1681                         else
1682                                 needSecondUpdate = view()->fitCursor();
1683
1684                         if (needSecondUpdate || updateFlags != Update::None) {
1685                                 view()->buffer()->changed();
1686                         }
1687                         lyx_view_->updateStatusBar();
1688
1689                         // if we executed a mutating lfun, mark the buffer as dirty
1690                         if (flag.enabled()
1691                             && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)
1692                             && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly))
1693                                 view()->buffer()->markDirty();
1694
1695                         if (view()->cursor().inTexted()) {
1696                                 lyx_view_->updateLayoutChoice();
1697                         }
1698                 }
1699         }
1700         if (!quitting)
1701                 // FIXME UNICODE: _() does not support anything but ascii.
1702                 // Do we need a to_ascii() method?
1703                 sendDispatchMessage(getMessage(), cmd);
1704 }
1705
1706
1707 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
1708 {
1709         /* When an action did not originate from the UI/kbd, it makes
1710          * sense to avoid updating the GUI. It turns out that this
1711          * fixes bug 1941, for reasons that are described here:
1712          * http://bugzilla.lyx.org/show_bug.cgi?id=1941#c4
1713          */
1714         if (cmd.origin != FuncRequest::INTERNAL) {
1715                 lyx_view_->updateMenubar();
1716                 lyx_view_->updateToolbars();
1717         }
1718
1719         const bool verbose = (cmd.origin == FuncRequest::UI
1720                               || cmd.origin == FuncRequest::COMMANDBUFFER);
1721
1722         if (cmd.action == LFUN_SELF_INSERT || !verbose) {
1723                 lyxerr[Debug::ACTION] << "dispatch msg is " << to_utf8(msg) << endl;
1724                 if (!msg.empty())
1725                         lyx_view_->message(msg);
1726                 return;
1727         }
1728
1729         docstring dispatch_msg = msg;
1730         if (!dispatch_msg.empty())
1731                 dispatch_msg += ' ';
1732
1733         string comname = lyxaction.getActionName(cmd.action);
1734
1735         bool argsadded = false;
1736
1737         if (!cmd.argument().empty()) {
1738                 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1739                         comname += ' ' + to_utf8(cmd.argument());
1740                         argsadded = true;
1741                 }
1742         }
1743
1744         string const shortcuts = theTopLevelKeymap().printbindings(cmd);
1745
1746         if (!shortcuts.empty())
1747                 comname += ": " + shortcuts;
1748         else if (!argsadded && !cmd.argument().empty())
1749                 comname += ' ' + to_utf8(cmd.argument());
1750
1751         if (!comname.empty()) {
1752                 comname = rtrim(comname);
1753                 dispatch_msg += from_utf8('(' + rtrim(comname) + ')');
1754         }
1755
1756         lyxerr[Debug::ACTION] << "verbose dispatch msg "
1757                 << to_utf8(dispatch_msg) << endl;
1758         if (!dispatch_msg.empty())
1759                 lyx_view_->message(dispatch_msg);
1760 }
1761
1762
1763 void LyXFunc::menuNew(string const & name, bool fromTemplate)
1764 {
1765         string initpath = lyxrc.document_path;
1766         string filename(name);
1767
1768         if (view()->buffer()) {
1769                 string const trypath = lyx_view_->buffer()->filePath();
1770                 // If directory is writeable, use this as default.
1771                 if (isDirWriteable(trypath))
1772                         initpath = trypath;
1773         }
1774
1775         static int newfile_number;
1776
1777         if (filename.empty()) {
1778                 filename = addName(lyxrc.document_path,
1779                             "newfile" + convert<string>(++newfile_number) + ".lyx");
1780                 while (theBufferList().exists(filename) || fs::is_readable(filename)) {
1781                         ++newfile_number;
1782                         filename = addName(lyxrc.document_path,
1783                                            "newfile" +  convert<string>(newfile_number) +
1784                                     ".lyx");
1785                 }
1786         }
1787
1788         // The template stuff
1789         string templname;
1790         if (fromTemplate) {
1791                 FileDialog fileDlg(_("Select template file"),
1792                         LFUN_SELECT_FILE_SYNC,
1793                         make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
1794                         make_pair(_("Templates|#T#t"), from_utf8(lyxrc.template_path)));
1795
1796                 FileDialog::Result result =
1797                         fileDlg.open(from_utf8(lyxrc.template_path),
1798                                      FileFilterList(_("LyX Documents (*.lyx)")),
1799                                      docstring());
1800
1801                 if (result.first == FileDialog::Later)
1802                         return;
1803                 if (result.second.empty())
1804                         return;
1805                 templname = to_utf8(result.second);
1806         }
1807
1808         Buffer * const b = newFile(filename, templname, !name.empty());
1809         if (b)
1810                 lyx_view_->setBuffer(b);
1811 }
1812
1813
1814 void LyXFunc::open(string const & fname)
1815 {
1816         string initpath = lyxrc.document_path;
1817
1818         if (view()->buffer()) {
1819                 string const trypath = lyx_view_->buffer()->filePath();
1820                 // If directory is writeable, use this as default.
1821                 if (isDirWriteable(trypath))
1822                         initpath = trypath;
1823         }
1824
1825         string filename;
1826
1827         if (fname.empty()) {
1828                 FileDialog fileDlg(_("Select document to open"),
1829                         LFUN_FILE_OPEN,
1830                         make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
1831                         make_pair(_("Examples|#E#e"), from_utf8(addPath(package().system_support(), "examples"))));
1832
1833                 FileDialog::Result result =
1834                         fileDlg.open(from_utf8(initpath),
1835                                      FileFilterList(_("LyX Documents (*.lyx)")),
1836                                      docstring());
1837
1838                 if (result.first == FileDialog::Later)
1839                         return;
1840
1841                 filename = to_utf8(result.second);
1842
1843                 // check selected filename
1844                 if (filename.empty()) {
1845                         lyx_view_->message(_("Canceled."));
1846                         return;
1847                 }
1848         } else
1849                 filename = fname;
1850
1851         // get absolute path of file and add ".lyx" to the filename if
1852         // necessary
1853         string const fullpath = fileSearch(string(), filename, "lyx");
1854         if (!fullpath.empty()) {
1855                 filename = fullpath;
1856         }
1857
1858         docstring const disp_fn = makeDisplayPath(filename);
1859
1860         // if the file doesn't exist, let the user create one
1861         if (!fs::exists(filename)) {
1862                 // the user specifically chose this name. Believe him.
1863                 Buffer * const b = newFile(filename, string(), true);
1864                 if (b)
1865                         lyx_view_->setBuffer(b);
1866                 return;
1867         }
1868
1869         lyx_view_->message(bformat(_("Opening document %1$s..."), disp_fn));
1870
1871         docstring str2;
1872         if (lyx_view_->loadLyXFile(filename)) {
1873                 str2 = bformat(_("Document %1$s opened."), disp_fn);
1874         } else {
1875                 str2 = bformat(_("Could not open document %1$s"), disp_fn);
1876         }
1877         lyx_view_->message(str2);
1878 }
1879
1880
1881 void LyXFunc::doImport(string const & argument)
1882 {
1883         string format;
1884         string filename = split(argument, format, ' ');
1885
1886         lyxerr[Debug::INFO] << "LyXFunc::doImport: " << format
1887                             << " file: " << filename << endl;
1888
1889         // need user interaction
1890         if (filename.empty()) {
1891                 string initpath = lyxrc.document_path;
1892
1893                 if (view()->buffer()) {
1894                         string const trypath = lyx_view_->buffer()->filePath();
1895                         // If directory is writeable, use this as default.
1896                         if (isDirWriteable(trypath))
1897                                 initpath = trypath;
1898                 }
1899
1900                 docstring const text = bformat(_("Select %1$s file to import"),
1901                         formats.prettyName(format));
1902
1903                 FileDialog fileDlg(text,
1904                         LFUN_BUFFER_IMPORT,
1905                         make_pair(_("Documents|#o#O"), from_utf8(lyxrc.document_path)),
1906                         make_pair(_("Examples|#E#e"),
1907                                   from_utf8(addPath(package().system_support(), "examples"))));
1908
1909                 docstring filter = formats.prettyName(format);
1910                 filter += " (*.";
1911                 // FIXME UNICODE
1912                 filter += from_utf8(formats.extension(format));
1913                 filter += ')';
1914
1915                 FileDialog::Result result =
1916                         fileDlg.open(from_utf8(initpath),
1917                                      FileFilterList(filter),
1918                                      docstring());
1919
1920                 if (result.first == FileDialog::Later)
1921                         return;
1922
1923                 filename = to_utf8(result.second);
1924
1925                 // check selected filename
1926                 if (filename.empty())
1927                         lyx_view_->message(_("Canceled."));
1928         }
1929
1930         if (filename.empty())
1931                 return;
1932
1933         // get absolute path of file
1934         filename = makeAbsPath(filename);
1935
1936         string const lyxfile = changeExtension(filename, ".lyx");
1937
1938         // Check if the document already is open
1939         if (use_gui && theBufferList().exists(lyxfile)) {
1940                 if (!theBufferList().close(theBufferList().getBuffer(lyxfile), true)) {
1941                         lyx_view_->message(_("Canceled."));
1942                         return;
1943                 }
1944         }
1945
1946         // if the file exists already, and we didn't do
1947         // -i lyx thefile.lyx, warn
1948         if (fs::exists(lyxfile) && filename != lyxfile) {
1949                 docstring const file = makeDisplayPath(lyxfile, 30);
1950
1951                 docstring text = bformat(_("The document %1$s already exists.\n\n"
1952                                                      "Do you want to over-write that document?"), file);
1953                 int const ret = Alert::prompt(_("Over-write document?"),
1954                         text, 0, 1, _("&Over-write"), _("&Cancel"));
1955
1956                 if (ret == 1) {
1957                         lyx_view_->message(_("Canceled."));
1958                         return;
1959                 }
1960         }
1961
1962         ErrorList errorList;
1963         Importer::Import(lyx_view_, filename, format, errorList);
1964         // FIXME (Abdel 12/08/06): Is there a need to display the error list here?
1965 }
1966
1967
1968 void LyXFunc::closeBuffer()
1969 {
1970         // save current cursor position
1971         LyX::ref().session().saveFilePosition(lyx_view_->buffer()->fileName(),
1972                 boost::tie(view()->cursor().pit(), view()->cursor().pos()) );
1973         if (theBufferList().close(lyx_view_->buffer(), true) && !quitting) {
1974                 if (theBufferList().empty()) {
1975                         // need this otherwise SEGV may occur while
1976                         // trying to set variables that don't exist
1977                         // since there's no current buffer
1978                         lyx_view_->getDialogs().hideBufferDependent();
1979                 } else {
1980                         lyx_view_->setBuffer(theBufferList().first());
1981                 }
1982         }
1983 }
1984
1985
1986 // Each "lyx_view_" should have it's own message method. lyxview and
1987 // the minibuffer would use the minibuffer, but lyxserver would
1988 // send an ERROR signal to its client.  Alejandro 970603
1989 // This function is bit problematic when it comes to NLS, to make the
1990 // lyx servers client be language indepenent we must not translate
1991 // strings sent to this func.
1992 void LyXFunc::setErrorMessage(docstring const & m) const
1993 {
1994         dispatch_buffer = m;
1995         errorstat = true;
1996 }
1997
1998
1999 void LyXFunc::setMessage(docstring const & m) const
2000 {
2001         dispatch_buffer = m;
2002 }
2003
2004
2005 string const LyXFunc::viewStatusMessage()
2006 {
2007         // When meta-fake key is pressed, show the key sequence so far + "M-".
2008         if (wasMetaKey())
2009                 return keyseq->print() + "M-";
2010
2011         // Else, when a non-complete key sequence is pressed,
2012         // show the available options.
2013         if (keyseq->length() > 0 && !keyseq->deleted())
2014                 return keyseq->printOptions();
2015
2016         if (!view()->buffer())
2017                 return to_utf8(_("Welcome to LyX!"));
2018
2019         return view()->cursor().currentState();
2020 }
2021
2022
2023 BufferView * LyXFunc::view() const
2024 {
2025         BOOST_ASSERT(lyx_view_);
2026         return lyx_view_->view();
2027 }
2028
2029
2030 bool LyXFunc::wasMetaKey() const
2031 {
2032         return (meta_fake_bit != key_modifier::none);
2033 }
2034
2035
2036 namespace {
2037
2038 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
2039 {
2040         // Why the switch you might ask. It is a trick to ensure that all
2041         // the elements in the LyXRCTags enum is handled. As you can see
2042         // there are no breaks at all. So it is just a huge fall-through.
2043         // The nice thing is that we will get a warning from the compiler
2044         // if we forget an element.
2045         LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
2046         switch (tag) {
2047         case LyXRC::RC_ACCEPT_COMPOUND:
2048         case LyXRC::RC_ALT_LANG:
2049         case LyXRC::RC_ASCIIROFF_COMMAND:
2050         case LyXRC::RC_ASCII_LINELEN:
2051         case LyXRC::RC_AUTOREGIONDELETE:
2052         case LyXRC::RC_AUTORESET_OPTIONS:
2053         case LyXRC::RC_AUTOSAVE:
2054         case LyXRC::RC_AUTO_NUMBER:
2055         case LyXRC::RC_BACKUPDIR_PATH:
2056         case LyXRC::RC_BIBTEX_COMMAND:
2057         case LyXRC::RC_BINDFILE:
2058         case LyXRC::RC_CHECKLASTFILES:
2059         case LyXRC::RC_USELASTFILEPOS:
2060         case LyXRC::RC_LOADSESSION:
2061         case LyXRC::RC_CHKTEX_COMMAND:
2062         case LyXRC::RC_CONVERTER:
2063         case LyXRC::RC_COPIER:
2064         case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
2065         case LyXRC::RC_CUSTOM_EXPORT_COMMAND:
2066         case LyXRC::RC_CUSTOM_EXPORT_FORMAT:
2067         case LyXRC::RC_DATE_INSERT_FORMAT:
2068         case LyXRC::RC_DEFAULT_LANGUAGE:
2069         case LyXRC::RC_DEFAULT_PAPERSIZE:
2070         case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
2071         case LyXRC::RC_DISPLAY_GRAPHICS:
2072         case LyXRC::RC_DOCUMENTPATH:
2073                 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
2074                         if (fs::exists(lyxrc_new.document_path) &&
2075                             fs::is_directory(lyxrc_new.document_path)) {
2076                                 support::package().document_dir() = lyxrc.document_path;
2077                         }
2078                 }
2079         case LyXRC::RC_ESC_CHARS:
2080         case LyXRC::RC_FONT_ENCODING:
2081         case LyXRC::RC_FORMAT:
2082         case LyXRC::RC_INDEX_COMMAND:
2083         case LyXRC::RC_INPUT:
2084         case LyXRC::RC_KBMAP:
2085         case LyXRC::RC_KBMAP_PRIMARY:
2086         case LyXRC::RC_KBMAP_SECONDARY:
2087         case LyXRC::RC_LABEL_INIT_LENGTH:
2088         case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
2089         case LyXRC::RC_LANGUAGE_AUTO_END:
2090         case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
2091         case LyXRC::RC_LANGUAGE_COMMAND_END:
2092         case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
2093         case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
2094         case LyXRC::RC_LANGUAGE_PACKAGE:
2095         case LyXRC::RC_LANGUAGE_USE_BABEL:
2096         case LyXRC::RC_MAKE_BACKUP:
2097         case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
2098         case LyXRC::RC_NUMLASTFILES:
2099         case LyXRC::RC_PATH_PREFIX:
2100                 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
2101                         support::prependEnvPath("PATH", lyxrc.path_prefix);
2102                 }
2103         case LyXRC::RC_PERS_DICT:
2104         case LyXRC::RC_POPUP_BOLD_FONT:
2105         case LyXRC::RC_POPUP_FONT_ENCODING:
2106         case LyXRC::RC_POPUP_NORMAL_FONT:
2107         case LyXRC::RC_PREVIEW:
2108         case LyXRC::RC_PREVIEW_HASHED_LABELS:
2109         case LyXRC::RC_PREVIEW_SCALE_FACTOR:
2110         case LyXRC::RC_PRINTCOLLCOPIESFLAG:
2111         case LyXRC::RC_PRINTCOPIESFLAG:
2112         case LyXRC::RC_PRINTER:
2113         case LyXRC::RC_PRINTEVENPAGEFLAG:
2114         case LyXRC::RC_PRINTEXSTRAOPTIONS:
2115         case LyXRC::RC_PRINTFILEEXTENSION:
2116         case LyXRC::RC_PRINTLANDSCAPEFLAG:
2117         case LyXRC::RC_PRINTODDPAGEFLAG:
2118         case LyXRC::RC_PRINTPAGERANGEFLAG:
2119         case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
2120         case LyXRC::RC_PRINTPAPERFLAG:
2121         case LyXRC::RC_PRINTREVERSEFLAG:
2122         case LyXRC::RC_PRINTSPOOL_COMMAND:
2123         case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
2124         case LyXRC::RC_PRINTTOFILE:
2125         case LyXRC::RC_PRINTTOPRINTER:
2126         case LyXRC::RC_PRINT_ADAPTOUTPUT:
2127         case LyXRC::RC_PRINT_COMMAND:
2128         case LyXRC::RC_RTL_SUPPORT:
2129         case LyXRC::RC_SCREEN_DPI:
2130         case LyXRC::RC_SCREEN_FONT_ENCODING:
2131         case LyXRC::RC_SCREEN_FONT_ROMAN:
2132         case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
2133         case LyXRC::RC_SCREEN_FONT_SANS:
2134         case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
2135         case LyXRC::RC_SCREEN_FONT_SCALABLE:
2136         case LyXRC::RC_SCREEN_FONT_SIZES:
2137         case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
2138         case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
2139         case LyXRC::RC_SCREEN_GEOMETRY_HEIGHT:
2140         case LyXRC::RC_SCREEN_GEOMETRY_WIDTH:
2141         case LyXRC::RC_SCREEN_GEOMETRY_XYSAVED:
2142         case LyXRC::RC_SCREEN_ZOOM:
2143         case LyXRC::RC_SERVERPIPE:
2144         case LyXRC::RC_SET_COLOR:
2145         case LyXRC::RC_SHOW_BANNER:
2146         case LyXRC::RC_SPELL_COMMAND:
2147         case LyXRC::RC_TEMPDIRPATH:
2148         case LyXRC::RC_TEMPLATEPATH:
2149         case LyXRC::RC_TEX_ALLOWS_SPACES:
2150         case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
2151                 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
2152                         support::os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
2153                 }
2154         case LyXRC::RC_UIFILE:
2155         case LyXRC::RC_USER_EMAIL:
2156         case LyXRC::RC_USER_NAME:
2157         case LyXRC::RC_USETEMPDIR:
2158         case LyXRC::RC_USE_ALT_LANG:
2159         case LyXRC::RC_USE_ESC_CHARS:
2160         case LyXRC::RC_USE_INP_ENC:
2161         case LyXRC::RC_USE_PERS_DICT:
2162         case LyXRC::RC_USE_SPELL_LIB:
2163         case LyXRC::RC_VIEWDVI_PAPEROPTION:
2164         case LyXRC::RC_VIEWER:
2165         case LyXRC::RC_LAST:
2166                 break;
2167         }
2168 }
2169
2170 } // namespace anon
2171
2172
2173 } // namespace lyx