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