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