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