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