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