]> git.lyx.org Git - lyx.git/blob - src/LyXFunc.cpp
move LFUN_BUFFER_PARAMS_APPLY to BufferView. I needed to make LyXFunc::updateLayout...
[lyx.git] / src / LyXFunc.cpp
1 /**
2  * \file LyXFunc.cpp
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 "LayoutFile.h"
25 #include "BranchList.h"
26 #include "buffer_funcs.h"
27 #include "Buffer.h"
28 #include "BufferList.h"
29 #include "BufferParams.h"
30 #include "BufferView.h"
31 #include "CmdDef.h"
32 #include "Color.h"
33 #include "Converter.h"
34 #include "Cursor.h"
35 #include "CutAndPaste.h"
36 #include "DispatchResult.h"
37 #include "Encoding.h"
38 #include "ErrorList.h"
39 #include "Format.h"
40 #include "FuncRequest.h"
41 #include "FuncStatus.h"
42 #include "InsetIterator.h"
43 #include "Intl.h"
44 #include "KeyMap.h"
45 #include "Language.h"
46 #include "Lexer.h"
47 #include "LyXAction.h"
48 #include "lyxfind.h"
49 #include "LyX.h"
50 #include "LyXRC.h"
51 #include "LyXVC.h"
52 #include "Paragraph.h"
53 #include "ParagraphParameters.h"
54 #include "ParIterator.h"
55 #include "Row.h"
56 #include "Server.h"
57 #include "Session.h"
58 #include "SpellChecker.h"
59
60 #include "insets/InsetBox.h"
61 #include "insets/InsetBranch.h"
62 #include "insets/InsetCommand.h"
63 #include "insets/InsetERT.h"
64 #include "insets/InsetExternal.h"
65 #include "insets/InsetFloat.h"
66 #include "insets/InsetGraphics.h"
67 #include "insets/InsetInclude.h"
68 #include "insets/InsetListings.h"
69 #include "insets/InsetNote.h"
70 #include "insets/InsetPhantom.h"
71 #include "insets/InsetSpace.h"
72 #include "insets/InsetTabular.h"
73 #include "insets/InsetVSpace.h"
74 #include "insets/InsetWrap.h"
75
76 #include "frontends/alert.h"
77 #include "frontends/Application.h"
78 #include "frontends/KeySymbol.h"
79 #include "frontends/LyXView.h"
80 #include "frontends/Selection.h"
81
82 #include "support/debug.h"
83 #include "support/environment.h"
84 #include "support/FileName.h"
85 #include "support/filetools.h"
86 #include "support/gettext.h"
87 #include "support/lstrings.h"
88 #include "support/Path.h"
89 #include "support/Package.h"
90 #include "support/Systemcall.h"
91 #include "support/convert.h"
92 #include "support/os.h"
93
94 #include <sstream>
95 #include <vector>
96
97 using namespace std;
98 using namespace lyx::support;
99
100 namespace lyx {
101
102 using frontend::LyXView;
103
104 namespace Alert = frontend::Alert;
105
106 namespace {
107
108
109 // This function runs "configure" and then rereads lyx.defaults to
110 // reconfigure the automatic settings.
111 void reconfigure(LyXView * lv, string const & option)
112 {
113         // emit message signal.
114         if (lv)
115                 lv->message(_("Running configure..."));
116
117         // Run configure in user lyx directory
118         PathChanger p(package().user_support());
119         string configure_command = package().configure_command();
120         configure_command += option;
121         Systemcall one;
122         int ret = one.startscript(Systemcall::Wait, configure_command);
123         p.pop();
124         // emit message signal.
125         if (lv)
126                 lv->message(_("Reloading configuration..."));
127         lyxrc.read(libFileSearch(string(), "lyxrc.defaults"));
128         // Re-read packages.lst
129         LaTeXFeatures::getAvailable();
130
131         if (ret)
132                 Alert::information(_("System reconfiguration failed"),
133                            _("The system reconfiguration has failed.\n"
134                                   "Default textclass is used but LyX may "
135                                   "not be able to work properly.\n"
136                                   "Please reconfigure again if needed."));
137         else
138
139                 Alert::information(_("System reconfigured"),
140                            _("The system has been reconfigured.\n"
141                              "You need to restart LyX to make use of any\n"
142                              "updated document class specifications."));
143 }
144
145
146 bool getLocalStatus(Cursor cursor, FuncRequest const & cmd, FuncStatus & status)
147 {
148         // Try to fix cursor in case it is broken.
149         cursor.fixIfBroken();
150
151         // This is, of course, a mess. Better create a new doc iterator and use
152         // this in Inset::getStatus. This might require an additional
153         // BufferView * arg, though (which should be avoided)
154         //Cursor safe = *this;
155         bool res = false;
156         for ( ; cursor.depth(); cursor.pop()) {
157                 //lyxerr << "\nCursor::getStatus: cmd: " << cmd << endl << *this << endl;
158                 LASSERT(cursor.idx() <= cursor.lastidx(), /**/);
159                 LASSERT(cursor.pit() <= cursor.lastpit(), /**/);
160                 LASSERT(cursor.pos() <= cursor.lastpos(), /**/);
161
162                 // The inset's getStatus() will return 'true' if it made
163                 // a definitive decision on whether it want to handle the
164                 // request or not. The result of this decision is put into
165                 // the 'status' parameter.
166                 if (cursor.inset().getStatus(cursor, cmd, status)) {
167                         res = true;
168                         break;
169                 }
170         }
171         return res;
172 }
173
174
175 /** Return the change status at cursor position, taking in account the
176  * status at each level of the document iterator (a table in a deleted
177  * footnote is deleted).
178  * When \param outer is true, the top slice is not looked at.
179  */
180 Change::Type lookupChangeType(DocIterator const & dit, bool outer = false)
181 {
182         size_t const depth = dit.depth() - (outer ? 1 : 0);
183
184         for (size_t i = 0 ; i < depth ; ++i) {
185                 CursorSlice const & slice = dit[i];
186                 if (!slice.inset().inMathed()
187                     && slice.pos() < slice.paragraph().size()) {
188                         Change::Type const ch = slice.paragraph().lookupChange(slice.pos()).type;
189                         if (ch != Change::UNCHANGED)
190                                 return ch;
191                 }
192         }
193         return Change::UNCHANGED;
194 }
195
196 }
197
198
199 LyXFunc::LyXFunc()
200         : lyx_view_(0), encoded_last_key(0), meta_fake_bit(NoModifier)
201 {
202 }
203
204
205 void LyXFunc::initKeySequences(KeyMap * kb)
206 {
207         keyseq = KeySequence(kb, kb);
208         cancel_meta_seq = KeySequence(kb, kb);
209 }
210
211
212 void LyXFunc::setLyXView(LyXView * lv)
213 {
214         if (lyx_view_ && lyx_view_->currentBufferView() && lyx_view_ != lv)
215                 // save current selection to the selection buffer to allow
216                 // middle-button paste in another window
217                 cap::saveSelection(lyx_view_->currentBufferView()->cursor());
218         lyx_view_ = lv;
219 }
220
221
222 void LyXFunc::handleKeyFunc(FuncCode action)
223 {
224         char_type c = encoded_last_key;
225
226         if (keyseq.length())
227                 c = 0;
228
229         LASSERT(lyx_view_ && lyx_view_->currentBufferView(), /**/);
230         BufferView * bv = lyx_view_->currentBufferView();
231         bv->getIntl().getTransManager().deadkey(
232                 c, get_accent(action).accent, bv->cursor().innerText(),
233                 bv->cursor());
234         // Need to clear, in case the minibuffer calls these
235         // actions
236         keyseq.clear();
237         // copied verbatim from do_accent_char
238         bv->cursor().resetAnchor();
239         bv->processUpdateFlags(Update::FitCursor);
240 }
241
242 //FIXME: bookmark handling is a frontend issue. This code should be transferred
243 // to GuiView and be GuiView and be window dependent.
244 void LyXFunc::gotoBookmark(unsigned int idx, bool openFile, bool switchToBuffer)
245 {
246         LASSERT(lyx_view_, /**/);
247         if (!theSession().bookmarks().isValid(idx))
248                 return;
249         BookmarksSection::Bookmark const & bm = theSession().bookmarks().bookmark(idx);
250         LASSERT(!bm.filename.empty(), /**/);
251         string const file = bm.filename.absFilename();
252         // if the file is not opened, open it.
253         if (!theBufferList().exists(bm.filename)) {
254                 if (openFile)
255                         dispatch(FuncRequest(LFUN_FILE_OPEN, file));
256                 else
257                         return;
258         }
259         // open may fail, so we need to test it again
260         if (!theBufferList().exists(bm.filename))
261                 return;
262
263         // bm can be changed when saving
264         BookmarksSection::Bookmark tmp = bm;
265
266         // Special case idx == 0 used for back-from-back jump navigation
267         if (idx == 0)
268                 dispatch(FuncRequest(LFUN_BOOKMARK_SAVE, "0"));
269
270         // if the current buffer is not that one, switch to it.
271         if (!lyx_view_->documentBufferView()
272                 || lyx_view_->documentBufferView()->buffer().fileName() != tmp.filename) {
273                 if (!switchToBuffer)
274                         return;
275                 dispatch(FuncRequest(LFUN_BUFFER_SWITCH, file));
276         }
277
278         // moveToPosition try paragraph id first and then paragraph (pit, pos).
279         if (!lyx_view_->documentBufferView()->moveToPosition(
280                 tmp.bottom_pit, tmp.bottom_pos, tmp.top_id, tmp.top_pos))
281                 return;
282
283         // bm changed
284         if (idx == 0)
285                 return;
286
287         // Cursor jump succeeded!
288         Cursor const & cur = lyx_view_->documentBufferView()->cursor();
289         pit_type new_pit = cur.pit();
290         pos_type new_pos = cur.pos();
291         int new_id = cur.paragraph().id();
292
293         // if bottom_pit, bottom_pos or top_id has been changed, update bookmark
294         // see http://bugzilla.lyx.org/show_bug.cgi?id=3092
295         if (bm.bottom_pit != new_pit || bm.bottom_pos != new_pos 
296                 || bm.top_id != new_id) {
297                 const_cast<BookmarksSection::Bookmark &>(bm).updatePos(
298                         new_pit, new_pos, new_id);
299         }
300 }
301
302
303 void LyXFunc::processKeySym(KeySymbol const & keysym, KeyModifier state)
304 {
305         LYXERR(Debug::KEY, "KeySym is " << keysym.getSymbolName());
306
307         // Do nothing if we have nothing (JMarc)
308         if (!keysym.isOK()) {
309                 LYXERR(Debug::KEY, "Empty kbd action (probably composing)");
310                 lyx_view_->restartCursor();
311                 return;
312         }
313
314         if (keysym.isModifier()) {
315                 LYXERR(Debug::KEY, "isModifier true");
316                 if (lyx_view_)
317                         lyx_view_->restartCursor();
318                 return;
319         }
320
321         //Encoding const * encoding = lyx_view_->documentBufferView()->cursor().getEncoding();
322         //encoded_last_key = keysym.getISOEncoded(encoding ? encoding->name() : "");
323         // FIXME: encoded_last_key shadows the member variable of the same
324         // name. Is that intended?
325         char_type encoded_last_key = keysym.getUCSEncoded();
326
327         // Do a one-deep top-level lookup for
328         // cancel and meta-fake keys. RVDK_PATCH_5
329         cancel_meta_seq.reset();
330
331         FuncRequest func = cancel_meta_seq.addkey(keysym, state);
332         LYXERR(Debug::KEY, "action first set to [" << func.action << ']');
333
334         // When not cancel or meta-fake, do the normal lookup.
335         // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
336         // Mostly, meta_fake_bit = NoModifier. RVDK_PATCH_5.
337         if ((func.action != LFUN_CANCEL) && (func.action != LFUN_META_PREFIX)) {
338                 // remove Caps Lock and Mod2 as a modifiers
339                 func = keyseq.addkey(keysym, (state | meta_fake_bit));
340                 LYXERR(Debug::KEY, "action now set to [" << func.action << ']');
341         }
342
343         // Dont remove this unless you know what you are doing.
344         meta_fake_bit = NoModifier;
345
346         // Can this happen now ?
347         if (func.action == LFUN_NOACTION)
348                 func = FuncRequest(LFUN_COMMAND_PREFIX);
349
350         LYXERR(Debug::KEY, " Key [action=" << func.action << "]["
351                 << keyseq.print(KeySequence::Portable) << ']');
352
353         // already here we know if it any point in going further
354         // why not return already here if action == -1 and
355         // num_bytes == 0? (Lgb)
356
357         if (keyseq.length() > 1)
358                 lyx_view_->message(keyseq.print(KeySequence::ForGui));
359
360
361         // Maybe user can only reach the key via holding down shift.
362         // Let's see. But only if shift is the only modifier
363         if (func.action == LFUN_UNKNOWN_ACTION && state == ShiftModifier) {
364                 LYXERR(Debug::KEY, "Trying without shift");
365                 func = keyseq.addkey(keysym, NoModifier);
366                 LYXERR(Debug::KEY, "Action now " << func.action);
367         }
368
369         if (func.action == LFUN_UNKNOWN_ACTION) {
370                 // Hmm, we didn't match any of the keysequences. See
371                 // if it's normal insertable text not already covered
372                 // by a binding
373                 if (keysym.isText() && keyseq.length() == 1) {
374                         LYXERR(Debug::KEY, "isText() is true, inserting.");
375                         func = FuncRequest(LFUN_SELF_INSERT,
376                                            FuncRequest::KEYBOARD);
377                 } else {
378                         LYXERR(Debug::KEY, "Unknown, !isText() - giving up");
379                         lyx_view_->message(_("Unknown function."));
380                         lyx_view_->restartCursor();
381                         return;
382                 }
383         }
384
385         if (func.action == LFUN_SELF_INSERT) {
386                 if (encoded_last_key != 0) {
387                         docstring const arg(1, encoded_last_key);
388                         dispatch(FuncRequest(LFUN_SELF_INSERT, arg,
389                                              FuncRequest::KEYBOARD));
390                         LYXERR(Debug::KEY, "SelfInsert arg[`" << to_utf8(arg) << "']");
391                 }
392         } else {
393                 dispatch(func);
394                 if (!lyx_view_)
395                         return;
396         }
397 }
398
399
400 FuncStatus LyXFunc::getStatus(FuncRequest const & cmd) const
401 {
402         //lyxerr << "LyXFunc::getStatus: cmd: " << cmd << endl;
403         FuncStatus flag;
404
405         /* In LyX/Mac, when a dialog is open, the menus of the
406            application can still be accessed without giving focus to
407            the main window. In this case, we want to disable the menu
408            entries that are buffer or view-related.
409
410            If this code is moved somewhere else (like in
411            GuiView::getStatus), then several functions will not be
412            handled correctly.
413         */
414         frontend::LyXView * lv = 0;
415         Buffer * buf = 0;
416         if (lyx_view_ 
417             && (cmd.origin != FuncRequest::MENU || lyx_view_->hasFocus())) {
418                 lv = lyx_view_;
419                 if (lyx_view_->documentBufferView())
420                         buf = &lyx_view_->documentBufferView()->buffer();
421         }
422
423         if (cmd.action == LFUN_NOACTION) {
424                 flag.message(from_utf8(N_("Nothing to do")));
425                 flag.setEnabled(false);
426                 return flag;
427         }
428
429         switch (cmd.action) {
430         case LFUN_UNKNOWN_ACTION:
431                 flag.unknown(true);
432                 flag.setEnabled(false);
433                 break;
434
435         default:
436                 break;
437         }
438
439         if (flag.unknown()) {
440                 flag.message(from_utf8(N_("Unknown action")));
441                 return flag;
442         }
443
444         if (!flag.enabled()) {
445                 if (flag.message().empty())
446                         flag.message(from_utf8(N_("Command disabled")));
447                 return flag;
448         }
449
450         // Check whether we need a buffer
451         if (!lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer) && !buf) {
452                 // no, exit directly
453                 flag.message(from_utf8(N_("Command not allowed with"
454                                     "out any document open")));
455                 flag.setEnabled(false);
456                 return flag;
457         }
458
459         // I would really like to avoid having this switch and rather try to
460         // encode this in the function itself.
461         // -- And I'd rather let an inset decide which LFUNs it is willing
462         // to handle (Andre')
463         bool enable = true;
464         switch (cmd.action) {
465
466         case LFUN_CITATION_INSERT: {
467                 FuncRequest fr(LFUN_INSET_INSERT, "citation");
468                 enable = getStatus(fr).enabled();
469                 break;
470         }
471         
472         // This could be used for the no-GUI version. The GUI version is handled in
473         // LyXView::getStatus(). See above.
474         /*
475         case LFUN_BUFFER_WRITE:
476         case LFUN_BUFFER_WRITE_AS: {
477                 Buffer * b = theBufferList().getBuffer(FileName(cmd.getArg(0)));
478                 enable = b && (b->isUnnamed() || !b->isClean());
479                 break;
480         }
481         */
482
483         case LFUN_BUFFER_WRITE_ALL: {
484                 // We enable the command only if there are some modified buffers
485                 Buffer * first = theBufferList().first();
486                 enable = false;
487                 if (!first)
488                         break;
489                 Buffer * b = first;
490                 // We cannot use a for loop as the buffer list is a cycle.
491                 do {
492                         if (!b->isClean()) {
493                                 enable = true;
494                                 break;
495                         }
496                         b = theBufferList().next(b);
497                 } while (b != first); 
498                 break;
499         }
500
501         case LFUN_BOOKMARK_GOTO: {
502                 const unsigned int num = convert<unsigned int>(to_utf8(cmd.argument()));
503                 enable = theSession().bookmarks().isValid(num);
504                 break;
505         }
506
507         case LFUN_BOOKMARK_CLEAR:
508                 enable = theSession().bookmarks().hasValid();
509                 break;
510
511         // this one is difficult to get right. As a half-baked
512         // solution, we consider only the first action of the sequence
513         case LFUN_COMMAND_SEQUENCE: {
514                 // argument contains ';'-terminated commands
515                 string const firstcmd = token(to_utf8(cmd.argument()), ';', 0);
516                 FuncRequest func(lyxaction.lookupFunc(firstcmd));
517                 func.origin = cmd.origin;
518                 flag = getStatus(func);
519                 break;
520         }
521
522         // we want to check if at least one of these is enabled
523         case LFUN_COMMAND_ALTERNATIVES: {
524                 // argument contains ';'-terminated commands
525                 string arg = to_utf8(cmd.argument());
526                 while (!arg.empty()) {
527                         string first;
528                         arg = split(arg, first, ';');
529                         FuncRequest func(lyxaction.lookupFunc(first));
530                         func.origin = cmd.origin;
531                         flag = getStatus(func);
532                         // if this one is enabled, the whole thing is
533                         if (flag.enabled())
534                                 break;
535                 }
536                 break;
537         }
538
539         case LFUN_CALL: {
540                 FuncRequest func;
541                 string name = to_utf8(cmd.argument());
542                 if (theTopLevelCmdDef().lock(name, func)) {
543                         func.origin = cmd.origin;
544                         flag = getStatus(func);
545                         theTopLevelCmdDef().release(name);
546                 } else {
547                         // catch recursion or unknown command
548                         // definition. all operations until the
549                         // recursion or unknown command definition
550                         // occurs are performed, so set the state to
551                         // enabled
552                         enable = true;
553                 }
554                 break;
555         }
556
557         case LFUN_COMMAND_PREFIX:
558         case LFUN_CANCEL:
559         case LFUN_META_PREFIX:
560         case LFUN_RECONFIGURE:
561         case LFUN_HELP_OPEN:
562         case LFUN_DROP_LAYOUTS_CHOICE:
563         case LFUN_SERVER_GET_FILENAME:
564         case LFUN_SERVER_NOTIFY:
565         case LFUN_SERVER_GOTO_FILE_ROW:
566         case LFUN_CURSOR_FOLLOWS_SCROLLBAR_TOGGLE:
567         case LFUN_REPEAT:
568         case LFUN_PREFERENCES_SAVE:
569         case LFUN_INSET_EDIT:
570         case LFUN_TEXTCLASS_APPLY:
571         case LFUN_TEXTCLASS_LOAD:
572         case LFUN_BUFFER_SAVE_AS_DEFAULT:
573         case LFUN_LAYOUT_MODULES_CLEAR:
574         case LFUN_LAYOUT_MODULE_ADD:
575         case LFUN_LAYOUT_RELOAD:
576         case LFUN_LYXRC_APPLY:
577                 // these are handled in our dispatch()
578                 break;
579
580         default:
581                 if (!theApp()) {
582                         enable = false;
583                         break;
584                 }
585                 if (theApp()->getStatus(cmd, flag))
586                         break;
587
588                 // Does the view know something?
589                 if (!lv) {
590                         enable = false;
591                         break;
592                 }
593                 if (lv->getStatus(cmd, flag))
594                         break;
595
596                 BufferView * bv = lv->currentBufferView();
597                 BufferView * doc_bv = lv->documentBufferView();
598                 // If we do not have a BufferView, then other functions are disabled
599                 if (!bv) {
600                         enable = false;
601                         break;
602                 }
603                 // Is this a function that acts on inset at point?
604                 Inset * inset = bv->cursor().nextInset();
605                 if (lyxaction.funcHasFlag(cmd.action, LyXAction::AtPoint)
606                     && inset && inset->getStatus(bv->cursor(), cmd, flag))
607                         break;
608
609                 bool decided = getLocalStatus(bv->cursor(), cmd, flag);
610                 if (!decided)
611                         // try the BufferView
612                         decided = bv->getStatus(cmd, flag);
613                 if (!decided)
614                         // try the Buffer
615                         decided = bv->buffer().getStatus(cmd, flag);
616                 if (!decided && doc_bv)
617                         // try the Document Buffer
618                         decided = doc_bv->buffer().getStatus(cmd, flag);
619         }
620
621         if (!enable)
622                 flag.setEnabled(false);
623
624         // Can we use a readonly buffer?
625         if (buf && buf->isReadonly()
626             && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
627             && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
628                 flag.message(from_utf8(N_("Document is read-only")));
629                 flag.setEnabled(false);
630         }
631
632         // Are we in a DELETED change-tracking region?
633         if (lyx_view_ && lyx_view_->documentBufferView()
634                 && (lookupChangeType(lyx_view_->documentBufferView()->cursor(), true)
635                     == Change::DELETED)
636             && !lyxaction.funcHasFlag(cmd.action, LyXAction::ReadOnly)
637             && !lyxaction.funcHasFlag(cmd.action, LyXAction::NoBuffer)) {
638                 flag.message(from_utf8(N_("This portion of the document is deleted.")));
639                 flag.setEnabled(false);
640         }
641
642         // the default error message if we disable the command
643         if (!flag.enabled() && flag.message().empty())
644                 flag.message(from_utf8(N_("Command disabled")));
645
646         return flag;
647 }
648
649
650 namespace {
651
652 bool loadLayoutFile(string const & name, string const & buf_path)
653 {
654         if (!LayoutFileList::get().haveClass(name)) {
655                 lyxerr << "Document class \"" << name
656                        << "\" does not exist."
657                        << endl;
658                 return false;
659         }
660
661         LayoutFile & tc = LayoutFileList::get()[name];
662         if (!tc.load(buf_path)) {
663                 docstring s = bformat(_("The document class %1$s "
664                                    "could not be loaded."), from_utf8(name));
665                 Alert::error(_("Could not load class"), s);
666                 return false;
667         }
668         return true;
669 }
670
671
672 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new);
673
674 } //namespace anon
675
676
677 void LyXFunc::dispatch(FuncRequest const & cmd)
678 {
679         string const argument = to_utf8(cmd.argument());
680         FuncCode const action = cmd.action;
681
682         LYXERR(Debug::ACTION, "\nLyXFunc::dispatch: cmd: " << cmd);
683         //lyxerr << "LyXFunc::dispatch: cmd: " << cmd << endl;
684
685         // we have not done anything wrong yet.
686         errorstat = false;
687         dispatch_buffer.erase();
688
689         // redraw the screen at the end (first of the two drawing steps).
690         //This is done unless explicitely requested otherwise
691         Update::flags updateFlags = Update::FitCursor;
692
693         FuncStatus const flag = getStatus(cmd);
694         if (!flag.enabled()) {
695                 // We cannot use this function here
696                 LYXERR(Debug::ACTION, "LyXFunc::dispatch: "
697                        << lyxaction.getActionName(action)
698                        << " [" << action << "] is disabled at this location");
699                 setErrorMessage(flag.message());
700                 if (lyx_view_)
701                         lyx_view_->restartCursor();
702         } else {
703                 Buffer * buffer = 0;
704                 if (lyx_view_ && lyx_view_->currentBufferView())
705                         buffer = &lyx_view_->currentBufferView()->buffer();
706                 switch (action) {
707
708                 case LFUN_COMMAND_PREFIX:
709                         LASSERT(lyx_view_, /**/);
710                         lyx_view_->message(keyseq.printOptions(true));
711                         break;
712
713                 case LFUN_CANCEL:
714                         LASSERT(lyx_view_ && lyx_view_->currentBufferView(), /**/);
715                         keyseq.reset();
716                         meta_fake_bit = NoModifier;
717                         if (buffer)
718                                 // cancel any selection
719                                 dispatch(FuncRequest(LFUN_MARK_OFF));
720                         setMessage(from_ascii(N_("Cancel")));
721                         break;
722
723                 case LFUN_META_PREFIX:
724                         meta_fake_bit = AltModifier;
725                         setMessage(keyseq.print(KeySequence::ForGui));
726                         break;
727
728                 // --- Menus -----------------------------------------------
729                 case LFUN_RECONFIGURE:
730                         // argument is any additional parameter to the configure.py command
731                         reconfigure(lyx_view_, argument);
732                         break;
733
734                 case LFUN_HELP_OPEN: {
735                         if (lyx_view_ == 0)
736                                 theApp()->dispatch(FuncRequest(LFUN_WINDOW_NEW));
737                         string const arg = argument;
738                         if (arg.empty()) {
739                                 setErrorMessage(from_utf8(N_("Missing argument")));
740                                 break;
741                         }
742                         FileName fname = i18nLibFileSearch("doc", arg, "lyx");
743                         if (fname.empty()) 
744                                 fname = i18nLibFileSearch("examples", arg, "lyx");
745
746                         if (fname.empty()) {
747                                 lyxerr << "LyX: unable to find documentation file `"
748                                                          << arg << "'. Bad installation?" << endl;
749                                 break;
750                         }
751                         lyx_view_->message(bformat(_("Opening help file %1$s..."),
752                                 makeDisplayPath(fname.absFilename())));
753                         Buffer * buf = lyx_view_->loadDocument(fname, false);
754                         if (buf) {
755                                 buf->updateLabels();
756                                 lyx_view_->setBuffer(buf);
757                                 buf->errors("Parse");
758                         }
759                         updateFlags = Update::None;
760                         break;
761                 }
762
763                 // --- lyxserver commands ----------------------------
764                 case LFUN_SERVER_GET_FILENAME:
765                         LASSERT(lyx_view_ && buffer, /**/);
766                         setMessage(from_utf8(buffer->absFileName()));
767                         LYXERR(Debug::INFO, "FNAME["
768                                 << buffer->absFileName() << ']');
769                         break;
770
771                 case LFUN_SERVER_NOTIFY:
772                         dispatch_buffer = keyseq.print(KeySequence::Portable);
773                         theServer().notifyClient(to_utf8(dispatch_buffer));
774                         break;
775
776                 case LFUN_SERVER_GOTO_FILE_ROW: {
777                         LASSERT(lyx_view_, /**/);
778                         string file_name;
779                         int row;
780                         istringstream is(argument);
781                         is >> file_name >> row;
782                         file_name = os::internal_path(file_name);
783                         Buffer * buf = 0;
784                         bool loaded = false;
785                         string const abstmp = package().temp_dir().absFilename();
786                         string const realtmp = package().temp_dir().realPath();
787                         // We have to use os::path_prefix_is() here, instead of
788                         // simply prefixIs(), because the file name comes from
789                         // an external application and may need case adjustment.
790                         if (os::path_prefix_is(file_name, abstmp, os::CASE_ADJUSTED)
791                             || os::path_prefix_is(file_name, realtmp, os::CASE_ADJUSTED)) {
792                                 // Needed by inverse dvi search. If it is a file
793                                 // in tmpdir, call the apropriated function.
794                                 // If tmpdir is a symlink, we may have the real
795                                 // path passed back, so we correct for that.
796                                 if (!prefixIs(file_name, abstmp))
797                                         file_name = subst(file_name, realtmp, abstmp);
798                                 buf = theBufferList().getBufferFromTmp(file_name);
799                         } else {
800                                 // Must replace extension of the file to be .lyx
801                                 // and get full path
802                                 FileName const s = fileSearch(string(), changeExtension(file_name, ".lyx"), "lyx");
803                                 // Either change buffer or load the file
804                                 if (theBufferList().exists(s))
805                                         buf = theBufferList().getBuffer(s);
806                                 else if (s.exists()) {
807                                         buf = lyx_view_->loadDocument(s);
808                                         loaded = true;
809                                 } else
810                                         lyx_view_->message(bformat(
811                                                 _("File does not exist: %1$s"),
812                                                 makeDisplayPath(file_name)));
813                         }
814
815                         if (!buf) {
816                                 updateFlags = Update::None;
817                                 break;
818                         }
819
820                         buf->updateLabels();
821                         lyx_view_->setBuffer(buf);
822                         lyx_view_->documentBufferView()->setCursorFromRow(row);
823                         if (loaded)
824                                 buf->errors("Parse");
825                         updateFlags = Update::FitCursor;
826                         break;
827                 }
828
829
830                 case LFUN_DIALOG_SHOW_NEW_INSET: {
831                         LASSERT(lyx_view_, /**/);
832                         string const name = cmd.getArg(0);
833                         InsetCode code = insetCode(name);
834                         string data = trim(to_utf8(cmd.argument()).substr(name.size()));
835                         bool insetCodeOK = true;
836                         switch (code) {
837                         case BIBITEM_CODE:
838                         case BIBTEX_CODE:
839                         case INDEX_CODE:
840                         case LABEL_CODE:
841                         case NOMENCL_CODE:
842                         case NOMENCL_PRINT_CODE:
843                         case REF_CODE:
844                         case TOC_CODE:
845                         case HYPERLINK_CODE: {
846                                 InsetCommandParams p(code);
847                                 data = InsetCommand::params2string(name, p);
848                                 break;
849                         }
850                         case INCLUDE_CODE: {
851                                 // data is the include type: one of "include",
852                                 // "input", "verbatiminput" or "verbatiminput*"
853                                 if (data.empty())
854                                         // default type is requested
855                                         data = "include";
856                                 InsetCommandParams p(INCLUDE_CODE, data);
857                                 data = InsetCommand::params2string("include", p);
858                                 break;
859                         }
860                         case BOX_CODE: {
861                                 // \c data == "Boxed" || "Frameless" etc
862                                 InsetBoxParams p(data);
863                                 data = InsetBox::params2string(p);
864                                 break;
865                         }
866                         case BRANCH_CODE: {
867                                 InsetBranchParams p;
868                                 data = InsetBranch::params2string(p);
869                                 break;
870                         }
871                         case CITE_CODE: {
872                                 InsetCommandParams p(CITE_CODE);
873                                 data = InsetCommand::params2string(name, p);
874                                 break;
875                         }
876                         case ERT_CODE: {
877                                 data = InsetERT::params2string(InsetCollapsable::Open);
878                                 break;
879                         }
880                         case EXTERNAL_CODE: {
881                                 InsetExternalParams p;
882                                 data = InsetExternal::params2string(p, *buffer);
883                                 break;
884                         }
885                         case FLOAT_CODE:  {
886                                 InsetFloatParams p;
887                                 data = InsetFloat::params2string(p);
888                                 break;
889                         }
890                         case LISTINGS_CODE: {
891                                 InsetListingsParams p;
892                                 data = InsetListings::params2string(p);
893                                 break;
894                         }
895                         case GRAPHICS_CODE: {
896                                 InsetGraphicsParams p;
897                                 data = InsetGraphics::params2string(p, *buffer);
898                                 break;
899                         }
900                         case NOTE_CODE: {
901                                 InsetNoteParams p;
902                                 data = InsetNote::params2string(p);
903                                 break;
904                         }
905                         case PHANTOM_CODE: {
906                                 InsetPhantomParams p;
907                                 data = InsetPhantom::params2string(p);
908                                 break;
909                         }
910                         case SPACE_CODE: {
911                                 InsetSpaceParams p;
912                                 data = InsetSpace::params2string(p);
913                                 break;
914                         }
915                         case VSPACE_CODE: {
916                                 VSpace space;
917                                 data = InsetVSpace::params2string(space);
918                                 break;
919                         }
920                         case WRAP_CODE: {
921                                 InsetWrapParams p;
922                                 data = InsetWrap::params2string(p);
923                                 break;
924                         }
925                         default:
926                                 lyxerr << "Inset type '" << name << 
927                                         "' not recognized in LFUN_DIALOG_SHOW_NEW_INSET" <<  endl;
928                                 insetCodeOK = false;
929                                 break;
930                         } // end switch(code)
931                         if (insetCodeOK)
932                                 dispatch(FuncRequest(LFUN_DIALOG_SHOW, name + " " + data));
933                         break;
934                 }
935
936                 case LFUN_CITATION_INSERT: {
937                         LASSERT(lyx_view_, /**/);
938                         if (!argument.empty()) {
939                                 // we can have one optional argument, delimited by '|'
940                                 // citation-insert <key>|<text_before>
941                                 // this should be enhanced to also support text_after
942                                 // and citation style
943                                 string arg = argument;
944                                 string opt1;
945                                 if (contains(argument, "|")) {
946                                         arg = token(argument, '|', 0);
947                                         opt1 = token(argument, '|', 1);
948                                 }
949                                 InsetCommandParams icp(CITE_CODE);
950                                 icp["key"] = from_utf8(arg);
951                                 if (!opt1.empty())
952                                         icp["before"] = from_utf8(opt1);
953                                 string icstr = InsetCommand::params2string("citation", icp);
954                                 FuncRequest fr(LFUN_INSET_INSERT, icstr);
955                                 dispatch(fr);
956                         } else
957                                 dispatch(FuncRequest(LFUN_DIALOG_SHOW_NEW_INSET, "citation"));
958                         break;
959                 }
960
961                 case LFUN_CURSOR_FOLLOWS_SCROLLBAR_TOGGLE:
962                         LASSERT(lyx_view_, /**/);
963                         lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
964                         break;
965
966                 case LFUN_REPEAT: {
967                         // repeat command
968                         string countstr;
969                         string rest = split(argument, countstr, ' ');
970                         istringstream is(countstr);
971                         int count = 0;
972                         is >> count;
973                         //lyxerr << "repeat: count: " << count << " cmd: " << rest << endl;
974                         for (int i = 0; i < count; ++i)
975                                 dispatch(lyxaction.lookupFunc(rest));
976                         break;
977                 }
978
979                 case LFUN_COMMAND_SEQUENCE: {
980                         // argument contains ';'-terminated commands
981                         string arg = argument;
982                         if (theBufferList().isLoaded(buffer))
983                                 buffer->undo().beginUndoGroup();
984                         while (!arg.empty()) {
985                                 string first;
986                                 arg = split(arg, first, ';');
987                                 FuncRequest func(lyxaction.lookupFunc(first));
988                                 func.origin = cmd.origin;
989                                 dispatch(func);
990                         }
991                         if (theBufferList().isLoaded(buffer))
992                                 buffer->undo().endUndoGroup();
993                         break;
994                 }
995
996                 case LFUN_COMMAND_ALTERNATIVES: {
997                         // argument contains ';'-terminated commands
998                         string arg = argument;
999                         while (!arg.empty()) {
1000                                 string first;
1001                                 arg = split(arg, first, ';');
1002                                 FuncRequest func(lyxaction.lookupFunc(first));
1003                                 func.origin = cmd.origin;
1004                                 FuncStatus stat = getStatus(func);
1005                                 if (stat.enabled()) {
1006                                         dispatch(func);
1007                                         break;
1008                                 }
1009                         }
1010                         break;
1011                 }
1012
1013                 case LFUN_CALL: {
1014                         FuncRequest func;
1015                         if (theTopLevelCmdDef().lock(argument, func)) {
1016                                 func.origin = cmd.origin;
1017                                 dispatch(func);
1018                                 theTopLevelCmdDef().release(argument);
1019                         } else {
1020                                 if (func.action == LFUN_UNKNOWN_ACTION) {
1021                                         // unknown command definition
1022                                         lyxerr << "Warning: unknown command definition `"
1023                                                    << argument << "'"
1024                                                    << endl;
1025                                 } else {
1026                                         // recursion detected
1027                                         lyxerr << "Warning: Recursion in the command definition `"
1028                                                    << argument << "' detected"
1029                                                    << endl;
1030                                 }
1031                         }
1032                         break;
1033                 }
1034
1035                 case LFUN_PREFERENCES_SAVE: {
1036                         lyxrc.write(makeAbsPath("preferences",
1037                                                 package().user_support().absFilename()),
1038                                     false);
1039                         break;
1040                 }
1041
1042                 case LFUN_BUFFER_SAVE_AS_DEFAULT: {
1043                         string const fname =
1044                                 addName(addPath(package().user_support().absFilename(), "templates/"),
1045                                         "defaults.lyx");
1046                         Buffer defaults(fname);
1047
1048                         istringstream ss(argument);
1049                         Lexer lex;
1050                         lex.setStream(ss);
1051                         int const unknown_tokens = defaults.readHeader(lex);
1052
1053                         if (unknown_tokens != 0) {
1054                                 lyxerr << "Warning in LFUN_BUFFER_SAVE_AS_DEFAULT!\n"
1055                                        << unknown_tokens << " unknown token"
1056                                        << (unknown_tokens == 1 ? "" : "s")
1057                                        << endl;
1058                         }
1059
1060                         if (defaults.writeFile(FileName(defaults.absFileName())))
1061                                 setMessage(bformat(_("Document defaults saved in %1$s"),
1062                                                    makeDisplayPath(fname)));
1063                         else
1064                                 setErrorMessage(from_ascii(N_("Unable to save document defaults")));
1065                         break;
1066                 }
1067
1068                 case LFUN_LAYOUT_MODULES_CLEAR: {
1069                         LASSERT(lyx_view_ && lyx_view_->documentBufferView(), /**/);
1070                         DocumentClass const * const oldClass = buffer->params().documentClassPtr();
1071                         lyx_view_->documentBufferView()->cursor().recordUndoFullDocument();
1072                         buffer->params().clearLayoutModules();
1073                         buffer->params().makeDocumentClass();
1074                         updateLayout(oldClass, buffer);
1075                         updateFlags = Update::Force | Update::FitCursor;
1076                         break;
1077                 }
1078                 
1079                 case LFUN_LAYOUT_MODULE_ADD: {
1080                         LASSERT(lyx_view_ && lyx_view_->documentBufferView(), /**/);
1081                         BufferParams const & params = buffer->params();
1082                         if (!params.moduleCanBeAdded(argument)) {
1083                                 LYXERR0("Module `" << argument << 
1084                                                 "' cannot be added due to failed requirements or "
1085                                                 "conflicts with installed modules.");
1086                                 break;
1087                         }
1088                         DocumentClass const * const oldClass = params.documentClassPtr();
1089                         lyx_view_->documentBufferView()->cursor().recordUndoFullDocument();
1090                         buffer->params().addLayoutModule(argument);
1091                         buffer->params().makeDocumentClass();
1092                         updateLayout(oldClass, buffer);
1093                         updateFlags = Update::Force | Update::FitCursor;
1094                         break;
1095                 }
1096
1097                 case LFUN_TEXTCLASS_APPLY: {
1098                         LASSERT(lyx_view_ && lyx_view_->documentBufferView(), /**/);
1099
1100                         if (!loadLayoutFile(argument, buffer->temppath()) &&
1101                                 !loadLayoutFile(argument, buffer->filePath()))
1102                                 break;
1103
1104                         LayoutFile const * old_layout = buffer->params().baseClass();
1105                         LayoutFile const * new_layout = &(LayoutFileList::get()[argument]);
1106
1107                         if (old_layout == new_layout)
1108                                 // nothing to do
1109                                 break;
1110
1111                         //Save the old, possibly modular, layout for use in conversion.
1112                         DocumentClass const * const oldDocClass =
1113                                 buffer->params().documentClassPtr();
1114                         lyx_view_->documentBufferView()->cursor().recordUndoFullDocument();
1115                         buffer->params().setBaseClass(argument);
1116                         buffer->params().makeDocumentClass();
1117                         updateLayout(oldDocClass, buffer);
1118                         updateFlags = Update::Force | Update::FitCursor;
1119                         break;
1120                 }
1121                 
1122                 case LFUN_LAYOUT_RELOAD: {
1123                         LASSERT(lyx_view_, /**/);
1124                         DocumentClass const * const oldClass = buffer->params().documentClassPtr();
1125                         LayoutFileIndex bc = buffer->params().baseClassID();
1126                         LayoutFileList::get().reset(bc);
1127                         buffer->params().setBaseClass(bc);
1128                         buffer->params().makeDocumentClass();
1129                         updateLayout(oldClass, buffer);
1130                         updateFlags = Update::Force | Update::FitCursor;
1131                         break;
1132                 }
1133
1134                 case LFUN_TEXTCLASS_LOAD:
1135                         loadLayoutFile(argument, buffer->temppath()) ||
1136                         loadLayoutFile(argument, buffer->filePath());
1137                         break;
1138
1139                 case LFUN_LYXRC_APPLY: {
1140                         // reset active key sequences, since the bindings
1141                         // are updated (bug 6064)
1142                         keyseq.reset();
1143                         LyXRC const lyxrc_orig = lyxrc;
1144
1145                         istringstream ss(argument);
1146                         bool const success = lyxrc.read(ss) == 0;
1147
1148                         if (!success) {
1149                                 lyxerr << "Warning in LFUN_LYXRC_APPLY!\n"
1150                                        << "Unable to read lyxrc data"
1151                                        << endl;
1152                                 break;
1153                         }
1154
1155                         actOnUpdatedPrefs(lyxrc_orig, lyxrc);
1156
1157                         setSpellChecker();
1158
1159                         theApp()->resetGui();
1160
1161                         /// We force the redraw in any case because there might be
1162                         /// some screen font changes.
1163                         /// FIXME: only the current view will be updated. the Gui
1164                         /// class is able to furnish the list of views.
1165                         updateFlags = Update::Force;
1166                         break;
1167                 }
1168
1169                 case LFUN_BOOKMARK_GOTO:
1170                         // go to bookmark, open unopened file and switch to buffer if necessary
1171                         gotoBookmark(convert<unsigned int>(to_utf8(cmd.argument())), true, true);
1172                         updateFlags = Update::FitCursor;
1173                         break;
1174
1175                 case LFUN_BOOKMARK_CLEAR:
1176                         theSession().bookmarks().clear();
1177                         break;
1178
1179                 default:
1180                         LASSERT(theApp(), /**/);
1181                         // Let the frontend dispatch its own actions.
1182                         if (theApp()->dispatch(cmd))
1183                                 // Nothing more to do.
1184                                 return;
1185
1186                         // Everything below is only for active lyx_view_
1187                         if (lyx_view_ == 0)
1188                                 break;
1189
1190                         // Start an undo group. This may be needed for
1191                         // some stuff like inset-apply on labels.
1192                         if (theBufferList().isLoaded(buffer))
1193                                 buffer->undo().beginUndoGroup();
1194                                 
1195                         // Let the current LyXView dispatch its own actions.
1196                         if (lyx_view_->dispatch(cmd)) {
1197                                 if (lyx_view_->currentBufferView()) {
1198                                         updateFlags = lyx_view_->currentBufferView()->cursor().result().update();
1199                                         if (theBufferList().isLoaded(buffer))
1200                                                 buffer->undo().endUndoGroup();
1201                                 }
1202                                 break;
1203                         }
1204
1205                         LASSERT(lyx_view_->currentBufferView(), /**/);
1206
1207                         // Let the current BufferView dispatch its own actions.
1208                         if (lyx_view_->currentBufferView()->dispatch(cmd)) {
1209                                 // The BufferView took care of its own updates if needed.
1210                                 updateFlags = Update::None;
1211                                 if (theBufferList().isLoaded(buffer))
1212                                         buffer->undo().endUndoGroup();
1213                                 break;
1214                         }
1215
1216                         // OK, so try the Buffer itself
1217                         DispatchResult dr;
1218                         BufferView * bv = lyx_view_->currentBufferView();
1219                         bv->buffer().dispatch(cmd, dr);
1220                         if (dr.dispatched()) {
1221                                 updateFlags = dr.update();
1222                                 break;
1223                         }
1224                         // OK, so try with the document Buffer.
1225                         BufferView * doc_bv = lyx_view_->documentBufferView();
1226                         if (doc_bv) {
1227                                 buffer = &(doc_bv->buffer());
1228                                 buffer->dispatch(cmd, dr);
1229                                 if (dr.dispatched()) {
1230                                         updateFlags = dr.update();
1231                                         break;
1232                                 }
1233                         }
1234
1235                         // Is this a function that acts on inset at point?
1236                         Inset * inset = bv->cursor().nextInset();
1237                         if (lyxaction.funcHasFlag(action, LyXAction::AtPoint)
1238                             && inset) {
1239                                 bv->cursor().result().dispatched(true);
1240                                 bv->cursor().result().update(Update::FitCursor | Update::Force);
1241                                 FuncRequest tmpcmd = cmd;
1242                                 inset->dispatch(bv->cursor(), tmpcmd);
1243                                 if (bv->cursor().result().dispatched()) {
1244                                         updateFlags = bv->cursor().result().update();
1245                                         break;
1246                                 }
1247                         }
1248
1249                         // Let the current Cursor dispatch its own actions.
1250                         Cursor old = bv->cursor();
1251                         bv->cursor().getPos(cursorPosBeforeDispatchX_,
1252                                                 cursorPosBeforeDispatchY_);
1253                         bv->cursor().dispatch(cmd);
1254
1255                         // notify insets we just left
1256                         if (bv->cursor() != old) {
1257                                 old.fixIfBroken();
1258                                 bool badcursor = notifyCursorLeavesOrEnters(old, bv->cursor());
1259                                 if (badcursor)
1260                                         bv->cursor().fixIfBroken();
1261                         }
1262
1263                         if (theBufferList().isLoaded(buffer))
1264                                 buffer->undo().endUndoGroup();
1265
1266                         // update completion. We do it here and not in
1267                         // processKeySym to avoid another redraw just for a
1268                         // changed inline completion
1269                         if (cmd.origin == FuncRequest::KEYBOARD) {
1270                                 if (cmd.action == LFUN_SELF_INSERT
1271                                     || (cmd.action == LFUN_ERT_INSERT && bv->cursor().inMathed()))
1272                                         lyx_view_->updateCompletion(bv->cursor(), true, true);
1273                                 else if (cmd.action == LFUN_CHAR_DELETE_BACKWARD)
1274                                         lyx_view_->updateCompletion(bv->cursor(), false, true);
1275                                 else
1276                                         lyx_view_->updateCompletion(bv->cursor(), false, false);
1277                         }
1278
1279                         updateFlags = bv->cursor().result().update();
1280                 }
1281
1282                 // if we executed a mutating lfun, mark the buffer as dirty
1283                 if (theBufferList().isLoaded(buffer) && flag.enabled()
1284                     && !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
1285                     && !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
1286                         buffer->markDirty();                    
1287
1288                 if (lyx_view_ && lyx_view_->currentBufferView()) {
1289                         // BufferView::update() updates the ViewMetricsInfo and
1290                         // also initializes the position cache for all insets in
1291                         // (at least partially) visible top-level paragraphs.
1292                         // We will redraw the screen only if needed.
1293                         lyx_view_->currentBufferView()->processUpdateFlags(updateFlags);
1294
1295                         // Do we have a selection?
1296                         theSelection().haveSelection(
1297                                 lyx_view_->currentBufferView()->cursor().selection());
1298                         
1299                         // update gui
1300                         lyx_view_->restartCursor();
1301                 }
1302         }
1303         if (lyx_view_) {
1304                 // Some messages may already be translated, so we cannot use _()
1305                 sendDispatchMessage(translateIfPossible(getMessage()), cmd);
1306         }
1307 }
1308
1309
1310 void LyXFunc::sendDispatchMessage(docstring const & msg, FuncRequest const & cmd)
1311 {
1312         const bool verbose = (cmd.origin == FuncRequest::MENU
1313                               || cmd.origin == FuncRequest::TOOLBAR
1314                               || cmd.origin == FuncRequest::COMMANDBUFFER);
1315
1316         if (cmd.action == LFUN_SELF_INSERT || !verbose) {
1317                 LYXERR(Debug::ACTION, "dispatch msg is " << to_utf8(msg));
1318                 if (!msg.empty())
1319                         lyx_view_->message(msg);
1320                 return;
1321         }
1322
1323         docstring dispatch_msg = msg;
1324         if (!dispatch_msg.empty())
1325                 dispatch_msg += ' ';
1326
1327         docstring comname = from_utf8(lyxaction.getActionName(cmd.action));
1328
1329         bool argsadded = false;
1330
1331         if (!cmd.argument().empty()) {
1332                 if (cmd.action != LFUN_UNKNOWN_ACTION) {
1333                         comname += ' ' + cmd.argument();
1334                         argsadded = true;
1335                 }
1336         }
1337
1338         docstring const shortcuts = theTopLevelKeymap().printBindings(cmd, KeySequence::ForGui);
1339
1340         if (!shortcuts.empty())
1341                 comname += ": " + shortcuts;
1342         else if (!argsadded && !cmd.argument().empty())
1343                 comname += ' ' + cmd.argument();
1344
1345         if (!comname.empty()) {
1346                 comname = rtrim(comname);
1347                 dispatch_msg += '(' + rtrim(comname) + ')';
1348         }
1349
1350         LYXERR(Debug::ACTION, "verbose dispatch msg " << to_utf8(dispatch_msg));
1351         if (!dispatch_msg.empty())
1352                 lyx_view_->message(dispatch_msg);
1353 }
1354
1355
1356 // Each "lyx_view_" should have it's own message method. lyxview and
1357 // the minibuffer would use the minibuffer, but lyxserver would
1358 // send an ERROR signal to its client.  Alejandro 970603
1359 // This function is bit problematic when it comes to NLS, to make the
1360 // lyx servers client be language indepenent we must not translate
1361 // strings sent to this func.
1362 void LyXFunc::setErrorMessage(docstring const & m) const
1363 {
1364         dispatch_buffer = m;
1365         errorstat = true;
1366 }
1367
1368
1369 void LyXFunc::setMessage(docstring const & m) const
1370 {
1371         dispatch_buffer = m;
1372 }
1373
1374
1375 docstring LyXFunc::viewStatusMessage()
1376 {
1377         // When meta-fake key is pressed, show the key sequence so far + "M-".
1378         if (wasMetaKey())
1379                 return keyseq.print(KeySequence::ForGui) + "M-";
1380
1381         // Else, when a non-complete key sequence is pressed,
1382         // show the available options.
1383         if (keyseq.length() > 0 && !keyseq.deleted())
1384                 return keyseq.printOptions(true);
1385
1386         LASSERT(lyx_view_, /**/);
1387         if (!lyx_view_->currentBufferView())
1388                 return _("Welcome to LyX!");
1389
1390         return lyx_view_->currentBufferView()->cursor().currentState();
1391 }
1392
1393
1394 bool LyXFunc::wasMetaKey() const
1395 {
1396         return (meta_fake_bit != NoModifier);
1397 }
1398
1399
1400 void LyXFunc::updateLayout(DocumentClass const * const oldlayout, Buffer * buf)
1401 {
1402         lyx_view_->message(_("Converting document to new document class..."));
1403         
1404         StableDocIterator backcur(lyx_view_->currentBufferView()->cursor());
1405         ErrorList & el = buf->errorList("Class Switch");
1406         cap::switchBetweenClasses(
1407                         oldlayout, buf->params().documentClassPtr(),
1408                         static_cast<InsetText &>(buf->inset()), el);
1409
1410         lyx_view_->currentBufferView()->setCursor(backcur.asDocIterator(buf));
1411
1412         buf->errors("Class Switch");
1413         buf->updateLabels();
1414 }
1415
1416
1417 namespace {
1418
1419 void actOnUpdatedPrefs(LyXRC const & lyxrc_orig, LyXRC const & lyxrc_new)
1420 {
1421         // Why the switch you might ask. It is a trick to ensure that all
1422         // the elements in the LyXRCTags enum is handled. As you can see
1423         // there are no breaks at all. So it is just a huge fall-through.
1424         // The nice thing is that we will get a warning from the compiler
1425         // if we forget an element.
1426         LyXRC::LyXRCTags tag = LyXRC::RC_LAST;
1427         switch (tag) {
1428         case LyXRC::RC_ACCEPT_COMPOUND:
1429         case LyXRC::RC_ALT_LANG:
1430         case LyXRC::RC_PLAINTEXT_LINELEN:
1431         case LyXRC::RC_PLAINTEXT_ROFF_COMMAND:
1432         case LyXRC::RC_AUTOCORRECTION_MATH:
1433         case LyXRC::RC_AUTOREGIONDELETE:
1434         case LyXRC::RC_AUTORESET_OPTIONS:
1435         case LyXRC::RC_AUTOSAVE:
1436         case LyXRC::RC_AUTO_NUMBER:
1437         case LyXRC::RC_BACKUPDIR_PATH:
1438         case LyXRC::RC_BIBTEX_ALTERNATIVES:
1439         case LyXRC::RC_BIBTEX_COMMAND:
1440         case LyXRC::RC_BINDFILE:
1441         case LyXRC::RC_CHECKLASTFILES:
1442         case LyXRC::RC_COMPLETION_CURSOR_TEXT:
1443         case LyXRC::RC_COMPLETION_INLINE_DELAY:
1444         case LyXRC::RC_COMPLETION_INLINE_DOTS:
1445         case LyXRC::RC_COMPLETION_INLINE_MATH:
1446         case LyXRC::RC_COMPLETION_INLINE_TEXT:
1447         case LyXRC::RC_COMPLETION_POPUP_AFTER_COMPLETE:
1448         case LyXRC::RC_COMPLETION_POPUP_DELAY:
1449         case LyXRC::RC_COMPLETION_POPUP_MATH:
1450         case LyXRC::RC_COMPLETION_POPUP_TEXT:
1451         case LyXRC::RC_USELASTFILEPOS:
1452         case LyXRC::RC_LOADSESSION:
1453         case LyXRC::RC_CHKTEX_COMMAND:
1454         case LyXRC::RC_CONVERTER:
1455         case LyXRC::RC_CONVERTER_CACHE_MAXAGE:
1456         case LyXRC::RC_COPIER:
1457         case LyXRC::RC_CURSOR_FOLLOWS_SCROLLBAR:
1458         case LyXRC::RC_SCROLL_BELOW_DOCUMENT:
1459         case LyXRC::RC_DATE_INSERT_FORMAT:
1460         case LyXRC::RC_DEFAULT_LANGUAGE:
1461         case LyXRC::RC_GUI_LANGUAGE:
1462         case LyXRC::RC_DEFAULT_PAPERSIZE:
1463         case LyXRC::RC_DEFAULT_VIEW_FORMAT:
1464         case LyXRC::RC_DEFFILE:
1465         case LyXRC::RC_DIALOGS_ICONIFY_WITH_MAIN:
1466         case LyXRC::RC_DISPLAY_GRAPHICS:
1467         case LyXRC::RC_DOCUMENTPATH:
1468                 if (lyxrc_orig.document_path != lyxrc_new.document_path) {
1469                         FileName path(lyxrc_new.document_path);
1470                         if (path.exists() && path.isDirectory())
1471                                 package().document_dir() = FileName(lyxrc.document_path);
1472                 }
1473         case LyXRC::RC_EDITOR_ALTERNATIVES:
1474         case LyXRC::RC_ESC_CHARS:
1475         case LyXRC::RC_EXAMPLEPATH:
1476         case LyXRC::RC_FONT_ENCODING:
1477         case LyXRC::RC_FORMAT:
1478         case LyXRC::RC_GROUP_LAYOUTS:
1479         case LyXRC::RC_HUNSPELLDIR_PATH:
1480         case LyXRC::RC_INDEX_ALTERNATIVES:
1481         case LyXRC::RC_INDEX_COMMAND:
1482         case LyXRC::RC_JBIBTEX_COMMAND:
1483         case LyXRC::RC_JINDEX_COMMAND:
1484         case LyXRC::RC_NOMENCL_COMMAND:
1485         case LyXRC::RC_INPUT:
1486         case LyXRC::RC_KBMAP:
1487         case LyXRC::RC_KBMAP_PRIMARY:
1488         case LyXRC::RC_KBMAP_SECONDARY:
1489         case LyXRC::RC_LABEL_INIT_LENGTH:
1490         case LyXRC::RC_LANGUAGE_AUTO_BEGIN:
1491         case LyXRC::RC_LANGUAGE_AUTO_END:
1492         case LyXRC::RC_LANGUAGE_COMMAND_BEGIN:
1493         case LyXRC::RC_LANGUAGE_COMMAND_END:
1494         case LyXRC::RC_LANGUAGE_COMMAND_LOCAL:
1495         case LyXRC::RC_LANGUAGE_GLOBAL_OPTIONS:
1496         case LyXRC::RC_LANGUAGE_PACKAGE:
1497         case LyXRC::RC_LANGUAGE_USE_BABEL:
1498         case LyXRC::RC_MAC_LIKE_WORD_MOVEMENT:
1499         case LyXRC::RC_MACRO_EDIT_STYLE:
1500         case LyXRC::RC_MAKE_BACKUP:
1501         case LyXRC::RC_MARK_FOREIGN_LANGUAGE:
1502         case LyXRC::RC_MOUSE_WHEEL_SPEED:
1503         case LyXRC::RC_NUMLASTFILES:
1504         case LyXRC::RC_PARAGRAPH_MARKERS:
1505         case LyXRC::RC_PATH_PREFIX:
1506                 if (lyxrc_orig.path_prefix != lyxrc_new.path_prefix) {
1507                         prependEnvPath("PATH", lyxrc.path_prefix);
1508                 }
1509         case LyXRC::RC_PERS_DICT:
1510         case LyXRC::RC_PREVIEW:
1511         case LyXRC::RC_PREVIEW_HASHED_LABELS:
1512         case LyXRC::RC_PREVIEW_SCALE_FACTOR:
1513         case LyXRC::RC_PRINTCOLLCOPIESFLAG:
1514         case LyXRC::RC_PRINTCOPIESFLAG:
1515         case LyXRC::RC_PRINTER:
1516         case LyXRC::RC_PRINTEVENPAGEFLAG:
1517         case LyXRC::RC_PRINTEXSTRAOPTIONS:
1518         case LyXRC::RC_PRINTFILEEXTENSION:
1519         case LyXRC::RC_PRINTLANDSCAPEFLAG:
1520         case LyXRC::RC_PRINTODDPAGEFLAG:
1521         case LyXRC::RC_PRINTPAGERANGEFLAG:
1522         case LyXRC::RC_PRINTPAPERDIMENSIONFLAG:
1523         case LyXRC::RC_PRINTPAPERFLAG:
1524         case LyXRC::RC_PRINTREVERSEFLAG:
1525         case LyXRC::RC_PRINTSPOOL_COMMAND:
1526         case LyXRC::RC_PRINTSPOOL_PRINTERPREFIX:
1527         case LyXRC::RC_PRINTTOFILE:
1528         case LyXRC::RC_PRINTTOPRINTER:
1529         case LyXRC::RC_PRINT_ADAPTOUTPUT:
1530         case LyXRC::RC_PRINT_COMMAND:
1531         case LyXRC::RC_RTL_SUPPORT:
1532         case LyXRC::RC_SCREEN_DPI:
1533         case LyXRC::RC_SCREEN_FONT_ROMAN:
1534         case LyXRC::RC_SCREEN_FONT_ROMAN_FOUNDRY:
1535         case LyXRC::RC_SCREEN_FONT_SANS:
1536         case LyXRC::RC_SCREEN_FONT_SANS_FOUNDRY:
1537         case LyXRC::RC_SCREEN_FONT_SCALABLE:
1538         case LyXRC::RC_SCREEN_FONT_SIZES:
1539         case LyXRC::RC_SCREEN_FONT_TYPEWRITER:
1540         case LyXRC::RC_SCREEN_FONT_TYPEWRITER_FOUNDRY:
1541         case LyXRC::RC_GEOMETRY_SESSION:
1542         case LyXRC::RC_SCREEN_ZOOM:
1543         case LyXRC::RC_SERVERPIPE:
1544         case LyXRC::RC_SET_COLOR:
1545         case LyXRC::RC_SHOW_BANNER:
1546         case LyXRC::RC_OPEN_BUFFERS_IN_TABS:
1547         case LyXRC::RC_SPELL_COMMAND:
1548         case LyXRC::RC_SPELLCHECKER:
1549         case LyXRC::RC_SPELLCHECK_CONTINUOUSLY:
1550         case LyXRC::RC_SPLITINDEX_COMMAND:
1551         case LyXRC::RC_TEMPDIRPATH:
1552         case LyXRC::RC_TEMPLATEPATH:
1553         case LyXRC::RC_TEX_ALLOWS_SPACES:
1554         case LyXRC::RC_TEX_EXPECTS_WINDOWS_PATHS:
1555                 if (lyxrc_orig.windows_style_tex_paths != lyxrc_new.windows_style_tex_paths) {
1556                         os::windows_style_tex_paths(lyxrc_new.windows_style_tex_paths);
1557                 }
1558         case LyXRC::RC_THESAURUSDIRPATH:
1559         case LyXRC::RC_UIFILE:
1560         case LyXRC::RC_USER_EMAIL:
1561         case LyXRC::RC_USER_NAME:
1562         case LyXRC::RC_USETEMPDIR:
1563         case LyXRC::RC_USE_ALT_LANG:
1564         case LyXRC::RC_USE_CONVERTER_CACHE:
1565         case LyXRC::RC_USE_ESC_CHARS:
1566         case LyXRC::RC_USE_INP_ENC:
1567         case LyXRC::RC_USE_PERS_DICT:
1568         case LyXRC::RC_USE_TOOLTIP:
1569         case LyXRC::RC_USE_PIXMAP_CACHE:
1570         case LyXRC::RC_USE_SPELL_LIB:
1571         case LyXRC::RC_VIEWDVI_PAPEROPTION:
1572         case LyXRC::RC_SORT_LAYOUTS:
1573         case LyXRC::RC_FULL_SCREEN_LIMIT:
1574         case LyXRC::RC_FULL_SCREEN_SCROLLBAR:
1575         case LyXRC::RC_FULL_SCREEN_MENUBAR:
1576         case LyXRC::RC_FULL_SCREEN_TABBAR:
1577         case LyXRC::RC_FULL_SCREEN_TOOLBARS:
1578         case LyXRC::RC_FULL_SCREEN_WIDTH:
1579         case LyXRC::RC_VISUAL_CURSOR:
1580         case LyXRC::RC_VIEWER:
1581         case LyXRC::RC_VIEWER_ALTERNATIVES:
1582         case LyXRC::RC_LAST:
1583                 break;
1584         }
1585 }
1586
1587 } // namespace anon
1588 } // namespace lyx