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