]> git.lyx.org Git - lyx.git/blob - src/lyxfunc.C
remove inconsistency del/backspace
[lyx.git] / src / lyxfunc.C
1 /* This file is part of
2  * ====================================================== 
3  * 
4  *           LyX, The Document Processor
5  *       
6  *          Copyright 1995 Matthias Ettrich
7  *          Copyright 1995-2001 The LyX Team.
8  *
9  * ====================================================== */
10
11 #include <config.h>
12
13 #include "Lsstream.h"
14
15 #include <ctime>
16 #include <clocale>
17
18 #include <utility> 
19 #include <algorithm> 
20
21 #include <cstdlib>
22 #include <cctype>
23
24 #ifdef __GNUG__
25 #pragma implementation
26 #endif
27
28 #include "support/lyxalgo.h"
29 #include "support/LAssert.h"
30 #include "version.h"
31 #include "kbmap.h"
32 #include "lyxfunc.h"
33 #include "bufferlist.h"
34 #include "BufferView.h"
35 #include "ColorHandler.h"
36 #include "lyxserver.h"
37 #include "intl.h"
38 #include "lyx_main.h"
39 #include "lyx_cb.h"
40 #include "LyXAction.h"
41 #include "insets/inseturl.h"
42 #include "insets/insetlatexaccent.h"
43 #include "insets/insettoc.h"
44 #include "insets/insetref.h"
45 #include "insets/insetparent.h"
46 #include "insets/insetindex.h"
47 #include "insets/insetinclude.h"
48 #include "insets/insetbib.h"
49 #include "insets/insetcite.h"
50 #include "insets/insettext.h"
51 #include "insets/insetert.h"
52 #include "insets/insetexternal.h"
53 #include "insets/insetgraphics.h"
54 #include "insets/insetfoot.h"
55 #include "insets/insetmarginal.h"
56 #include "insets/insetminipage.h"
57 #include "insets/insetfloat.h"
58 #if 0
59 #include "insets/insetlist.h"
60 #include "insets/insettheorem.h"
61 #endif
62 #include "insets/insettabular.h"
63 #include "insets/insetcaption.h"
64 #include "mathed/formulamacro.h"
65 #include "mathed/math_cursor.h"
66 #include "mathed/math_inset.h"
67 #include "minibuffer.h"
68 #include "vspace.h"
69 #include "LyXView.h"
70 #include "lyx_gui_misc.h"
71 #include "support/filetools.h"
72 #include "support/FileInfo.h"
73 #include "support/syscall.h"
74 #include "support/lstrings.h"
75 #include "support/path.h"
76 #include "support/lyxfunctional.h"
77 #include "debug.h"
78 #include "lyxrc.h"
79 #include "lyxtext.h"
80 #include "gettext.h"
81 #include "trans_mgr.h"
82 #include "layout.h"
83 #include "WorkArea.h"
84 #include "bufferview_funcs.h"
85 #include "frontends/FileDialog.h"
86 #include "frontends/Dialogs.h"
87 #include "frontends/Toolbar.h"
88 #include "frontends/Menubar.h"
89 #include "FloatList.h"
90 #include "converter.h"
91 #include "exporter.h"
92 #include "importer.h"
93 #include "FontLoader.h"
94 #include "TextCache.h"
95 #include "lyxfind.h"
96 #include "undo_funcs.h"
97 #include "ParagraphParameters.h"
98 #include "figureForm.h"
99
100 using std::pair;
101 using std::make_pair; 
102 using std::endl;
103 using std::find_if;
104
105 extern BufferList bufferlist;
106 extern LyXServer * lyxserver;
107 extern bool selection_possible;
108 extern void MenuSendto();
109
110 extern boost::scoped_ptr<kb_keymap> toplevel_keymap;
111
112 extern void show_symbols_form(LyXFunc *);
113
114 extern LyXAction lyxaction;
115 // (alkis)
116 extern tex_accent_struct get_accent(kb_action action);
117
118 extern LyXTextClass::size_type current_layout;
119
120 extern void ShowLatexLog();
121
122
123 #if 0
124
125 ///
126 class MiniBufferController : public SigC::Object {
127 public:
128         ///
129         MiniBufferController() {
130                 minibuffer
131                         .cmdReady
132                         .connect(slot(this,
133                                       &MiniBufferController::receiveCommand));
134                 minibuffer
135                         .argReady
136                         .connect(slot(this,
137                                       &MiniBufferController::receiveArg));
138         }
139         ///
140         void receiveCmd(string const & cmd) {}
141         ///
142         void receiveArg(string const & arg) {}
143         
144         
145 private:
146 };
147
148 namespace {
149
150 MiniBufferController mb_ctrl;
151
152 }
153 #endif
154
155
156 /* === globals =========================================================== */
157
158 // Initialization of static member var
159 bool LyXFunc::show_sc = true;
160
161
162 LyXFunc::LyXFunc(LyXView * o)
163         : owner(o)
164 {
165         meta_fake_bit = 0;
166         lyx_dead_action = LFUN_NOACTION;
167         lyx_calling_dead_action = LFUN_NOACTION;
168         setupLocalKeymap();
169 }
170
171
172 inline
173 LyXText * LyXFunc::TEXT(bool flag = true) const
174 {
175         if (flag)
176                 return owner->view()->text;
177         return owner->view()->getLyXText();
178 }
179
180
181 // I changed this func slightly. I commented out the ...FinishUndo(),
182 // this means that all places that used to have a moveCursorUpdate, now
183 // have a ...FinishUndo() as the preceeding statement. I have also added
184 // a moveCursorUpdate to some of the functions that updated the cursor, but
185 // that did not show its new position.
186 inline
187 void LyXFunc::moveCursorUpdate(bool flag, bool selecting)
188 {
189         if (selecting || TEXT(flag)->selection.mark()) {
190                 TEXT(flag)->setSelection(owner->view());
191                 if (TEXT(flag)->bv_owner)
192                     owner->view()->toggleToggle();
193         }
194         owner->view()->update(TEXT(flag), BufferView::SELECT|BufferView::FITCUR);
195         owner->view()->showCursor();
196         
197         /* ---> Everytime the cursor is moved, show the current font state. */
198         // should this too me moved out of this func?
199         owner->view()->setState();
200 }
201
202
203 void LyXFunc::handleKeyFunc(kb_action action)
204 {
205         char c = keyseq.getiso();
206
207         if (keyseq.length != -1) c = 0;
208         
209         owner->getIntl()->getTrans()
210                 .deadkey(c, get_accent(action).accent, TEXT(false));
211         // Need to reset, in case the minibuffer calls these
212         // actions
213         keyseq.reset();
214         keyseq.length = 0;
215         // copied verbatim from do_accent_char
216         owner->view()->update(TEXT(false),
217                BufferView::SELECT|BufferView::FITCUR|BufferView::CHANGE);
218         TEXT(false)->selection.cursor = TEXT(false)->cursor;
219 }
220
221
222 void LyXFunc::processKeySym(KeySym keysym, unsigned int state) 
223 {
224         string argument;
225         
226         if (lyxerr.debugging(Debug::KEY)) {
227                 char const * tmp = XKeysymToString(keysym);
228                 string const stm = (tmp ? tmp : "");
229                 lyxerr << "KeySym is "
230                        << stm
231                        << "["
232                        << keysym << "] State is ["
233                        << state << "]"
234                        << endl;
235         }
236         // Do nothing if we have nothing (JMarc)
237         if (keysym == NoSymbol) {
238                 lyxerr[Debug::KEY] << "Empty kbd action (probably composing)"
239                                    << endl;
240                 return;
241         }
242
243         // Can we be sure that this will work for all X Window
244         // implementations? (Lgb)
245         // This code snippet makes lyx ignore some keys. Perhaps
246         // all of them should be explictly mentioned?
247         if ((keysym >= XK_Shift_L && keysym <= XK_Hyper_R)
248             || keysym == XK_Mode_switch || keysym == 0x0) {
249                 return;
250         }
251         
252         // Do a one-deep top-level lookup for
253         // cancel and meta-fake keys. RVDK_PATCH_5
254         cancel_meta_seq.reset();
255
256         int action = cancel_meta_seq.addkey(keysym, state
257                                             &(ShiftMask|ControlMask
258                                               |Mod1Mask)); 
259         if (lyxerr.debugging(Debug::KEY)) {
260                 lyxerr << "action first set to [" << action << "]" << endl;
261         }
262         
263         // When not cancel or meta-fake, do the normal lookup. 
264         // Note how the meta_fake Mod1 bit is OR-ed in and reset afterwards.
265         // Mostly, meta_fake_bit = 0. RVDK_PATCH_5.
266         if ((action != LFUN_CANCEL) && (action != LFUN_META_FAKE)) {
267                 if (lyxerr.debugging(Debug::KEY)) {
268                         lyxerr << "meta_fake_bit is ["
269                                << meta_fake_bit << "]" << endl;
270                 }
271                 // remove Caps Lock and Mod2 as a modifiers
272                 action = keyseq.addkey(keysym,
273                                        (state | meta_fake_bit)
274                                        &(ShiftMask|ControlMask
275                                          |Mod1Mask));
276                 if (lyxerr.debugging(Debug::KEY)) {
277                         lyxerr << "action now set to ["
278                                << action << "]" << endl;
279                 }
280         }
281         // Dont remove this unless you know what you are doing.
282         meta_fake_bit = 0;
283                 
284         if (action == 0) action = LFUN_PREFIX;
285
286         if (lyxerr.debugging(Debug::KEY)) {
287                 string buf;
288                 keyseq.print(buf);
289                 lyxerr << "Key [action="
290                        << action << "]["
291                        << buf << "]"
292                        << endl;
293         }
294
295         // already here we know if it any point in going further
296         // why not return already here if action == -1 and
297         // num_bytes == 0? (Lgb)
298
299         if (keyseq.length > 1 || keyseq.length < -1) {
300                 string buf;
301                 keyseq.print(buf);
302                 owner->message(buf);
303         }
304
305         if (action == -1) {
306                 // It is unknown, but what if we remove all
307                 // the modifiers? (Lgb)
308                 action = keyseq.addkey(keysym, 0);
309
310                 if (lyxerr.debugging(Debug::KEY)) {
311                         lyxerr << "Removing modifiers...\n"
312                                << "Action now set to ["
313                                << action << "]" << endl;
314                 }
315                 if (action == -1) {
316                         owner->message(_("Unknown function."));
317                         return;
318                 }
319         }
320
321         if (action == LFUN_SELFINSERT) {
322                 // This is very X dependant.
323                 unsigned int c = keysym;
324                 
325                 switch (c & 0x0000FF00) {
326                         // latin 1 byte 3 = 0
327                 case 0x00000000: break;
328                         // latin 2 byte 3 = 1
329                 case 0x00000100:
330                         // latin 3 byte 3 = 2
331                 case 0x00000200:
332                         // latin 4 byte 3 = 3
333                 case 0x00000300:
334                         // latin 8 byte 3 = 18 (0x12)
335                 case 0x00001200:
336                         // latin 9 byte 3 = 19 (0x13)
337                 case 0x00001300:
338                         c &= 0x000000FF;
339                         break;
340                 default:
341                         c = 0;
342                         break;
343                 }
344                 if (c > 0)
345                         argument = static_cast<char>(c);
346                 lyxerr[Debug::KEY] << "SelfInsert arg[`"
347                                    << argument << "']" << endl;
348         }
349         
350         bool tmp_sc = show_sc;
351         show_sc = false;
352         dispatch(action, argument);
353         show_sc = tmp_sc;
354         
355         //return 0;
356
357
358
359 func_status::value_type LyXFunc::getStatus(int ac) const
360 {
361         return getStatus(ac, string());
362 }
363
364
365 func_status::value_type LyXFunc::getStatus(int ac,
366                                            string const & not_to_use_arg) const
367 {
368         kb_action action;
369         func_status::value_type flag = func_status::OK;
370         string argument;
371         Buffer * buf = owner->buffer();
372         
373         if (lyxaction.isPseudoAction(ac)) 
374                 action = lyxaction.retrieveActionArg(ac, argument);
375         else {
376                 action = static_cast<kb_action>(ac);
377                 if (!not_to_use_arg.empty())
378                         argument = not_to_use_arg; // exept here
379         }
380         
381         if (action == LFUN_UNKNOWN_ACTION) {
382                 setErrorMessage(N_("Unknown action"));
383                 return func_status::Unknown;
384         }
385         
386         // Check whether we need a buffer
387         if (!lyxaction.funcHasFlag(action, LyXAction::NoBuffer)) {
388                 // Yes we need a buffer, do we have one?
389                 if (buf) {
390                         // yes
391                         // Can we use a readonly buffer?
392                         if (buf->isReadonly() && 
393                             !lyxaction.funcHasFlag(action,
394                                                    LyXAction::ReadOnly)) {
395                                 // no
396                                 setErrorMessage(N_("Document is read-only"));
397                                 flag |= func_status::Disabled;
398                         }
399                 } else {
400                         // no
401                         setErrorMessage(N_("Command not allowed with"
402                                            "out any document open"));
403                         flag |= func_status::Disabled;
404                         return flag;
405                 }
406         }
407
408         // I would really like to avoid having this switch and rather try to
409         // encode this in the function itself.
410         bool disable = false;
411         switch (action) {
412         case LFUN_MENUPRINT:
413                 disable = !Exporter::IsExportable(buf, "dvi")
414                         || lyxrc.print_command == "none";
415                 break;
416         case LFUN_EXPORT:
417                 disable = argument == "fax" &&
418                         !Exporter::IsExportable(buf, argument);
419                 break;
420         case LFUN_UNDO:
421                 disable = buf->undostack.empty();
422                 break;
423         case LFUN_REDO:
424                 disable = buf->redostack.empty();
425                 break;
426         case LFUN_SPELLCHECK:
427                 disable = lyxrc.isp_command == "none";
428                 break;
429         case LFUN_RUNCHKTEX:
430                 disable = lyxrc.chktex_command == "none";
431                 break;
432         case LFUN_BUILDPROG:
433                 disable = !Exporter::IsExportable(buf, "program");
434                 break;
435
436         case LFUN_LAYOUT_TABULAR:
437                 disable = true;
438                 if (owner->view()->theLockingInset()) {
439                         disable = (owner->view()->theLockingInset()->lyxCode() != Inset::TABULAR_CODE) &&
440                                 !owner->view()->theLockingInset()->getFirstLockingInsetOfType(Inset::TABULAR_CODE);
441                 }
442                 break;
443
444         case LFUN_TABULAR_FEATURE:
445                 disable = true;
446                 if (owner->view()->theLockingInset()) {
447                         func_status::value_type ret = func_status::Disabled;
448                         if (owner->view()->theLockingInset()->lyxCode() == Inset::TABULAR_CODE) {
449                                 ret = static_cast<InsetTabular *>
450                                         (owner->view()->theLockingInset())->
451                                         getStatus(argument);
452                         } else if (owner->view()->theLockingInset()->getFirstLockingInsetOfType(Inset::TABULAR_CODE)) {
453                                 ret = static_cast<InsetTabular *>
454                                         (owner->view()->theLockingInset()->
455                                          getFirstLockingInsetOfType(Inset::TABULAR_CODE))->
456                                         getStatus(argument);
457                         }
458                         flag |= ret;
459                         disable = false;
460                 } else {
461                         static InsetTabular inset(*owner->buffer(), 1, 1);
462                         func_status::value_type ret;
463
464                         disable = true;
465                         ret = inset.getStatus(argument);
466                         if ((ret & func_status::ToggleOn) ||
467                             (ret & func_status::ToggleOff))
468                                 flag |= func_status::ToggleOff;
469                 }
470                 break;
471
472         case LFUN_VC_REGISTER:
473                 disable = buf->lyxvc.inUse();
474                 break;
475         case LFUN_VC_CHECKIN:
476                 disable = !buf->lyxvc.inUse() || buf->isReadonly();
477                 break;
478         case LFUN_VC_CHECKOUT:
479                 disable = !buf->lyxvc.inUse() || !buf->isReadonly();
480                 break;
481         case LFUN_VC_REVERT:
482         case LFUN_VC_UNDO:
483         case LFUN_VC_HISTORY:
484                 disable = !buf->lyxvc.inUse();
485                 break;
486         case LFUN_BOOKMARK_GOTO:
487                 disable =  !owner->view()->
488                         isSavedPosition(strToUnsignedInt(argument));
489                 break;
490
491
492         case LFUN_INSET_TOGGLE:
493                 disable = (TEXT(false)->getInset() == 0);
494                 break;
495
496         case LFUN_MATH_VALIGN: {
497     // I think this test can be simplified (Andre')
498                 // mathcursor is != 0  iff we are in math mode
499                 //Inset * tli = owner->view()->theLockingInset();
500                 //if (tli && (tli->lyxCode() == Inset::MATH_CODE 
501                 //          || tli->lyxCode() == Inset::MATHMACRO_CODE)) {
502                 //
503                 if (mathcursor) {
504                         char align = mathcursor->valign();
505                         if (align == '\0') {
506                                 disable = true;
507                                 break;
508                         }
509                         if (argument.empty()) {
510                                 flag = func_status::OK;
511                                 break;
512                         }
513                         if (!contains("tcb", argument[0])) {
514                                 disable = true;
515                                 break;
516                         }
517                         if (argument[0] == align) 
518                                 flag |= func_status::ToggleOn;
519                         else
520                                 flag |= func_status::ToggleOff;
521                 } else
522                         disable = true;
523                 break;
524         }
525         case LFUN_MATH_HALIGN: {
526                 //Inset * tli = owner->view()->theLockingInset();
527                 //if (tli && (tli->lyxCode() == Inset::MATH_CODE 
528                 //          || tli->lyxCode() == Inset::MATHMACRO_CODE)) {
529                 if (mathcursor) {
530                         char align = mathcursor->halign();
531                         if (align == '\0') {
532                                 disable = true;
533                                 break;
534                         }
535                         if (argument.empty()) {
536                                 flag = func_status::OK;
537                                 break;
538                         }
539                         if (!contains("lcr", argument[0])) {
540                                 disable = true;
541                                 break;
542                         }
543                         if (argument[0] == align) 
544                                 flag |= func_status::ToggleOn;
545                         else
546                                 flag |= func_status::ToggleOff;
547                 } else
548                         disable = true;
549                 break;
550         }
551         case LFUN_MATH_MUTATE: {
552                 Inset * tli = owner->view()->theLockingInset();
553                 if (tli && (tli->lyxCode() == Inset::MATH_CODE)) {
554                         MathInsetTypes type = mathcursor->formula()->getType();
555                         func_status::value_type box = func_status::ToggleOff;
556                         if (argument == "inline") {
557                                 if (type == LM_OT_SIMPLE)
558                                         box = func_status::ToggleOn;
559                         } else if (argument == "display") {
560                                 if (type == LM_OT_EQUATION)
561                                         box = func_status::ToggleOn;
562                         } else if (argument == "eqnarray") {
563                                 if (type == LM_OT_EQNARRAY)
564                                         box = func_status::ToggleOn;
565                         } else if (argument == "align") {
566                                 if (type == LM_OT_ALIGN)
567                                         box = func_status::ToggleOn;
568                         } else {
569                                 box = func_status::OK;
570                                 disable = true;
571                         }
572                         flag |= box;
573                 } else
574                         disable = true;
575                 break;
576         }
577
578         // we just need to be in math mode to enable that
579         case LFUN_MATH_SIZE: 
580         case LFUN_MATH_SPACE:
581         case LFUN_MATH_LIMITS: 
582         case LFUN_MATH_NONUMBER: 
583         case LFUN_MATH_NUMBER:
584                 disable = !mathcursor;
585                 break;
586
587         // we need to be math mode and a math array for that
588         // Hack: halign produces non-zero result iff we are in a math array
589         case LFUN_MATH_ROW_INSERT: 
590         case LFUN_MATH_ROW_DELETE: 
591         case LFUN_MATH_COLUMN_INSERT: 
592         case LFUN_MATH_COLUMN_DELETE: 
593                 disable = !mathcursor || !mathcursor->halign();
594                 break;
595
596         default:
597                 break;
598         }
599
600         // the functions which insert insets
601         Inset::Code code = Inset::NO_CODE;
602         switch (action) {
603         case LFUN_INSET_TEXT:
604                 code = Inset::TEXT_CODE;
605                 break;
606         case LFUN_INSET_ERT:
607                 code = Inset::ERT_CODE;         
608                 break;
609         case LFUN_FIGURE:
610         case LFUN_INSET_GRAPHICS:
611                 code = Inset::GRAPHICS_CODE;
612                 break;
613         case LFUN_INSET_FOOTNOTE:
614                 code = Inset::FOOT_CODE;
615                 break;
616         case LFUN_DIALOG_TABULAR_INSERT:
617         case LFUN_INSET_TABULAR:
618                 code = Inset::TABULAR_CODE;
619                 break;
620         case LFUN_INSET_EXTERNAL:
621                 code = Inset::EXTERNAL_CODE;
622                 break;
623         case LFUN_INSET_MARGINAL:
624                 code = Inset::MARGIN_CODE;
625                 break;
626         case LFUN_INSET_MINIPAGE:
627                 code = Inset::MINIPAGE_CODE;
628                 break;
629         case LFUN_INSET_FLOAT:
630         case LFUN_INSET_WIDE_FLOAT:
631                 code = Inset::FLOAT_CODE;
632                 break;
633         case LFUN_FLOAT_LIST:
634                 code = Inset::FLOAT_LIST_CODE;
635                 break;
636 #if 0
637         case LFUN_INSET_LIST:
638                 code = Inset::LIST_CODE;
639                 break;
640         case LFUN_INSET_THEOREM:
641                 code = Inset::THEOREM_CODE;
642                 break;
643 #endif
644         case LFUN_INSET_CAPTION:
645                 code = Inset::CAPTION_CODE;
646                 break;
647         case LFUN_INSERT_NOTE:
648                 code = Inset::IGNORE_CODE;
649                 break;
650         case LFUN_INSERT_LABEL:
651                 code = Inset::LABEL_CODE;
652                 break;
653         case LFUN_REF_INSERT:
654                 code = Inset::REF_CODE;
655                 break;
656         case LFUN_CITATION_CREATE:
657         case LFUN_CITATION_INSERT:
658                 code = Inset::CITE_CODE;
659                 break;
660         case LFUN_INSERT_BIBTEX:
661                 code = Inset::BIBTEX_CODE;
662                 break;
663         case LFUN_INDEX_INSERT:
664         case LFUN_INDEX_INSERT_LAST:
665         case LFUN_INDEX_CREATE:
666                 code = Inset::INDEX_CODE;
667                 break;
668         case LFUN_INDEX_PRINT:
669                 code = Inset::INDEX_PRINT_CODE;
670                 break;
671         case LFUN_CHILD_INSERT:
672                 code = Inset::INCLUDE_CODE;
673                 break;
674         case LFUN_TOC_INSERT:
675                 code = Inset::TOC_CODE;
676                 break;
677         case LFUN_PARENTINSERT:
678                 code = Inset::PARENT_CODE;
679                 break;
680         case LFUN_HTMLURL:
681         case LFUN_URL:
682         case LFUN_INSERT_URL:
683                 code = Inset::URL_CODE;
684                 break;
685         case LFUN_QUOTE:
686                 // always allow this, since we will inset a raw quote
687                 // if an inset is not allowed.
688                 break;
689         case LFUN_HYPHENATION:
690         case LFUN_LIGATURE_BREAK:
691         case LFUN_HFILL:
692         case LFUN_MENU_SEPARATOR:
693         case LFUN_LDOTS:
694         case LFUN_END_OF_SENTENCE:
695         case LFUN_PROTECTEDSPACE:
696                 code = Inset::SPECIALCHAR_CODE;
697                 break;
698         default:
699                 break;
700         }
701         if (code != Inset::NO_CODE 
702             && owner->view()->theLockingInset()
703             && !owner->view()->theLockingInset()->insetAllowed(code)) {
704                 disable = true;
705         }
706
707         if (disable)
708                 flag |= func_status::Disabled;
709         
710         // the font related functions (and a few others)
711         func_status::value_type box = func_status::ToggleOff;
712         LyXFont const & font =
713                 TEXT(false)->real_current_font;
714         switch (action) {
715         case LFUN_EMPH:
716                 if (font.emph() == LyXFont::ON)
717                         box = func_status::ToggleOn;
718                 break;
719         case LFUN_NOUN:
720                 if (font.noun() == LyXFont::ON)
721                         box = func_status::ToggleOn;
722                 break;
723         case LFUN_BOLD:
724                 if (font.series() == LyXFont::BOLD_SERIES)
725                         box = func_status::ToggleOn;
726                 break;
727         case LFUN_READ_ONLY_TOGGLE:
728                 if (buf->isReadonly())
729                         box = func_status::ToggleOn;
730                 break;
731         case LFUN_APPENDIX:
732                 if (TEXT(false)->cursor.par()->params().startOfAppendix())
733                         box = func_status::ToggleOn;
734                 break;
735         default:
736                 box = func_status::OK;
737                 break;
738         }
739         flag |= box;
740
741         return flag;
742 }
743
744
745 // temporary dispatch method
746 void LyXFunc::miniDispatch(string const & s) 
747 {
748         if (!s.empty()) {
749                 dispatch(s);
750         }
751 }
752
753
754 string const LyXFunc::dispatch(string const & s) 
755 {
756         // Split command string into command and argument
757         string cmd;
758         string line = frontStrip(s);
759         string const arg = strip(frontStrip(split(line, cmd, ' ')));
760
761         return dispatch(lyxaction.LookupFunc(cmd), arg);
762 }
763
764
765 string const LyXFunc::dispatch(int ac,
766                                string const & do_not_use_this_arg)
767 {
768         lyxerr[Debug::ACTION] << "LyXFunc::Dispatch: action[" << ac
769                               <<"] arg[" << do_not_use_this_arg << "]" << endl;
770         
771         string argument;
772         kb_action action;
773         
774         // we have not done anything wrong yet.
775         errorstat = false;
776         dispatch_buffer.erase();
777         
778         // if action is a pseudo-action, we need the real action
779         if (lyxaction.isPseudoAction(ac)) {
780                 string tmparg;
781                 action = static_cast<kb_action>
782                         (lyxaction.retrieveActionArg(ac, tmparg));
783                 if (!tmparg.empty())
784                         argument = tmparg;
785         } else {
786                 action = static_cast<kb_action>(ac);
787                 if (!do_not_use_this_arg.empty())
788                         argument = do_not_use_this_arg; // except here
789         }
790
791 #ifdef NEW_DISPATCHER
792         // We try do call the most specific dispatcher first:
793         //  1. the lockinginset's dispatch
794         //  2. the bufferview's dispatch
795         //  3. the lyxview's dispatch
796 #endif
797         
798         selection_possible = false;
799         
800         if (owner->view()->available())
801                 owner->view()->hideCursor();
802
803         // We cannot use this function here
804         if (getStatus(ac, do_not_use_this_arg) & func_status::Disabled) {
805                 lyxerr << "LyXFunc::Dispatch: "
806                        << lyxaction.getActionName(ac)
807                        << " [" << ac << "] is disabled at this location"
808                        << endl;
809                 goto exit_with_message;
810         }
811
812         if (owner->view()->available() && owner->view()->theLockingInset()) {
813                 UpdatableInset::RESULT result;
814                 if ((action > 1) || ((action == LFUN_UNKNOWN_ACTION) &&
815                                      (keyseq.length >= -1)))
816                 {
817                         if ((action==LFUN_UNKNOWN_ACTION) && argument.empty()){
818                                 argument = keyseq.getiso();
819                         }
820                         // Undo/Redo is a bit tricky for insets.
821                         if (action == LFUN_UNDO) {
822 #ifdef RETHINK_THIS_FOR_NOW_WE_LEAVE_ALL_UNLOCKED
823                                 int slx;
824                                 int sly;
825                                 UpdatableInset * inset = 
826                                         owner->view()->theLockingInset()->getLockingInset();
827                                 int inset_id = inset->id();
828                                 inset->getCursorPos(owner->view(), slx, sly);
829                                 owner->view()->unlockInset(inset);
830 #else
831                                 owner->view()->unlockInset(owner->view()->theLockingInset());
832 #endif
833                                 owner->view()->menuUndo();
834 #ifdef RETHINK_THIS_FOR_NOW_WE_LEAVE_ALL_UNLOCKED
835 #if 0
836                                 if (TEXT()->cursor.par()->
837                                     isInset(TEXT()->cursor.pos())) {
838                                         inset = static_cast<UpdatableInset*>(
839                                                 TEXT()->cursor.par()->
840                                                 getInset(TEXT()->
841                                                          cursor.pos()));
842                                 } else {
843                                         inset = 0;
844                                 }
845 #else
846                                 inset = static_cast<UpdatableInset *>(owner->view()->buffer()->getInsetFromID(inset_id));
847 #endif
848                                 if (inset)
849                                         inset->edit(owner->view(),slx,sly,0);
850 #endif
851                                 return string();
852                         } else if (action == LFUN_REDO) {
853                                 int slx;
854                                 int sly;
855                                 UpdatableInset * inset = owner->view()->
856                                         theLockingInset();
857                                 inset->getCursorPos(owner->view(), slx, sly);
858                                 owner->view()->unlockInset(inset);
859                                 owner->view()->menuRedo();
860                                 inset = static_cast<UpdatableInset*>(
861                                         TEXT()->cursor.par()->
862                                         getInset(TEXT()->
863                                                  cursor.pos()));
864                                 if (inset)
865                                         inset->edit(owner->view(),slx,sly,0); 
866                                 return string();
867                         } else if (((result=owner->view()->theLockingInset()->
868                                      localDispatch(owner->view(), action, argument)) ==
869                                     UpdatableInset::DISPATCHED) ||
870                                    (result == UpdatableInset::DISPATCHED_NOUPDATE))
871                                 return string();
872                         else if (result == UpdatableInset::FINISHED) {
873                                         if (TEXT()->cursor.par()->isRightToLeftPar(owner->buffer()->params)) {
874                                                 TEXT()->cursorRight(owner->view());
875                                                 moveCursorUpdate(true, false);
876                                                 owner->showState();
877                                         }
878                                         return string();
879                         } else if (result == UpdatableInset::FINISHED_RIGHT) {
880                                 if (!TEXT()->cursor.par()->isRightToLeftPar(owner->buffer()->params)) {
881                                         TEXT()->cursorRight(owner->view());
882                                         moveCursorUpdate(true, false);
883                                         owner->showState();
884                                 }
885                                 return string();
886                         } else if (result == UpdatableInset::FINISHED_UP) {
887                                 if (TEXT()->cursor.row()->previous()) {
888                                         TEXT()->cursorUp(owner->view());
889                                         moveCursorUpdate(true, false);
890                                         owner->showState();
891                                 }
892                                 return string();
893                         } else if (result == UpdatableInset::FINISHED_DOWN) {
894                                 if (TEXT()->cursor.row()->next())
895                                         TEXT()->cursorDown(owner->view());
896                                 else
897                                         TEXT()->cursorRight(owner->view());
898                                 moveCursorUpdate(true, false);
899                                 owner->showState();
900                                 return string();
901                         } else {
902                                 //setMessage(N_("Text mode"));
903                                 switch (action) {
904                                 case LFUN_UNKNOWN_ACTION:
905                                 case LFUN_BREAKPARAGRAPH:
906                                 case LFUN_BREAKLINE:
907                                         TEXT()->cursorRight(owner->view());
908                                         owner->view()->setState();
909                                         owner->showState();
910                                         break;
911                                 case LFUN_RIGHT:
912                                         if (!TEXT()->cursor.par()->isRightToLeftPar(owner->buffer()->params)) {
913                                                 TEXT()->cursorRight(owner->view());
914                                                 moveCursorUpdate(true, false);
915                                                 owner->showState();
916                                         }
917                                         return string();
918                                 case LFUN_LEFT: 
919                                         if (TEXT()->cursor.par()->isRightToLeftPar(owner->buffer()->params)) {
920                                                 TEXT()->cursorRight(owner->view());
921                                                 moveCursorUpdate(true, false);
922                                                 owner->showState();
923                                         }
924                                         return string();
925                                 case LFUN_DOWN:
926                                         if (TEXT()->cursor.row()->next())
927                                                 TEXT()->cursorDown(owner->view());
928                                         else
929                                                 TEXT()->cursorRight(owner->view());
930                                         moveCursorUpdate(true, false);
931                                         owner->showState();
932                                         return string();
933                                 default:
934                                         break;
935                                 }
936                         }
937                 }
938         }
939
940         switch (action) {
941                 
942         case LFUN_ESCAPE:
943         {
944                 if (!owner->view()->available()) break;
945                 
946                 // this function should be used always [asierra060396]
947                 UpdatableInset * tli =
948                         owner->view()->theLockingInset();
949                 if (tli) {
950                         UpdatableInset * lock = tli->getLockingInset();
951                         
952                         if (tli == lock) {
953                                 owner->view()->unlockInset(tli);
954                                 TEXT()->cursorRight(owner->view());
955                                 moveCursorUpdate(true, false);
956                                 owner->showState();
957                         } else {
958                                 tli->unlockInsetInInset(owner->view(),
959                                                         lock,
960                                                         true);
961                         }
962                 }
963         }
964         break;
965                         
966                 // --- Misc -------------------------------------------
967         case LFUN_WORDFINDFORWARD  : 
968         case LFUN_WORDFINDBACKWARD : {
969                 static string last_search;
970                 string searched_string;
971             
972                 if (!argument.empty()) {
973                         last_search = argument;
974                         searched_string = argument;
975                 } else {
976                         searched_string = last_search;
977                 }
978                 bool fw = (action == LFUN_WORDFINDBACKWARD);
979                 if (!searched_string.empty()) {
980                         LyXFind(owner->view(), searched_string, fw);
981                 }
982 //              owner->view()->showCursor();
983         }
984         break;
985                 
986         case LFUN_PREFIX:
987         {
988                 if (owner->view()->available() && !owner->view()->theLockingInset()) {
989                         owner->view()->update(TEXT(),
990                                               BufferView::SELECT|BufferView::FITCUR);
991                 }
992                 string buf;
993                 keyseq.print(buf, true);
994                 owner->message(buf);
995         }
996         break;
997
998         // --- Misc -------------------------------------------
999         case LFUN_EXEC_COMMAND:
1000         {
1001                 std::vector<string> allCmds;
1002                 std::transform(lyxaction.func_begin(), lyxaction.func_end(),
1003                                std::back_inserter(allCmds), lyx::firster());
1004                 static std::vector<string> hist;
1005                 owner->getMiniBuffer()->getString(MiniBuffer::spaces,
1006                                                   allCmds, hist);
1007         }
1008         break;
1009                 
1010         case LFUN_CANCEL:                   // RVDK_PATCH_5
1011                 keyseq.reset();
1012                 meta_fake_bit = 0;
1013                 if (owner->view()->available())
1014                         // cancel any selection
1015                         dispatch(LFUN_MARK_OFF);
1016                 setMessage(N_("Cancel"));
1017                 break;
1018
1019         case LFUN_META_FAKE:                                 // RVDK_PATCH_5
1020         {
1021                 meta_fake_bit = Mod1Mask;
1022                 string buf;
1023                 keyseq.print(buf, true);
1024                 setMessage(buf); // RVDK_PATCH_5
1025         }
1026         break;  
1027
1028         case LFUN_READ_ONLY_TOGGLE:
1029                 if (owner->buffer()->lyxvc.inUse()) {
1030                         owner->buffer()->lyxvc.toggleReadOnly();
1031                 } else {
1032                         owner->buffer()->setReadonly(
1033                                 !owner->buffer()->isReadonly());
1034                 }
1035                 break;
1036                 
1037         case LFUN_CENTER: // this is center and redraw.
1038                 owner->view()->center();
1039                 break;
1040                 
1041                 // --- Menus -----------------------------------------------
1042         case LFUN_MENUNEW:
1043                 menuNew(false);
1044                 break;
1045                 
1046         case LFUN_MENUNEWTMPLT:
1047                 menuNew(true);
1048                 break;
1049                 
1050         case LFUN_CLOSEBUFFER:
1051                 closeBuffer();
1052                 break;
1053                 
1054         case LFUN_MENUWRITE:
1055                 if (!owner->buffer()->isUnnamed()) {
1056                         ostringstream s1;
1057                         s1 << _("Saving document") << ' '
1058                            << MakeDisplayPath(owner->buffer()->fileName() + "...");
1059                         owner->message(s1.str().c_str());
1060                         MenuWrite(owner->view(), owner->buffer());
1061                 } else
1062                         WriteAs(owner->view(), owner->buffer());
1063                 break;
1064                 
1065         case LFUN_WRITEAS:
1066                 WriteAs(owner->view(), owner->buffer(), argument);
1067                 break;
1068                 
1069         case LFUN_MENURELOAD:
1070                 reloadBuffer();
1071                 break;
1072                 
1073         case LFUN_UPDATE:
1074                 Exporter::Export(owner->buffer(), argument, true);
1075                 break;
1076
1077         case LFUN_PREVIEW:
1078                 Exporter::Preview(owner->buffer(), argument);
1079                 break;
1080                 
1081         case LFUN_BUILDPROG:
1082                 Exporter::Export(owner->buffer(), "program", true);
1083                 break;
1084                 
1085         case LFUN_RUNCHKTEX:
1086                 MenuRunChktex(owner->buffer());
1087                 break;
1088                                 
1089         case LFUN_MENUPRINT:
1090                 owner->getDialogs()->showPrint();
1091                 break;
1092
1093         case LFUN_EXPORT:
1094                 if (argument == "custom")
1095                         MenuSendto();
1096                 else
1097                         Exporter::Export(owner->buffer(), argument, false);
1098                 break;
1099
1100         case LFUN_IMPORT:
1101                 doImport(argument);
1102                 break;
1103                 
1104         case LFUN_QUIT:
1105                 QuitLyX();
1106                 break;
1107                 
1108         case LFUN_TOCVIEW:
1109 #if 0
1110         case LFUN_LOFVIEW:
1111         case LFUN_LOTVIEW:
1112         case LFUN_LOAVIEW:
1113 #endif
1114         {
1115                 InsetCommandParams p;
1116
1117 #if 0
1118                 if (action == LFUN_TOCVIEW)
1119 #endif
1120                         p.setCmdName("tableofcontents");
1121 #if 0
1122                 else if (action == LFUN_LOAVIEW )
1123                         p.setCmdName("listof{algorithm}{List of Algorithms}");
1124                 else if (action == LFUN_LOFVIEW)
1125                         p.setCmdName("listoffigures");
1126                 else
1127                         p.setCmdName("listoftables");
1128 #endif
1129                 owner->getDialogs()->createTOC(p.getAsString());
1130                 break;
1131         }       
1132
1133         case LFUN_DIALOG_TABULAR_INSERT:
1134                 owner->getDialogs()->showTabularCreate();
1135                 break;
1136                 
1137         case LFUN_FIGURE:
1138                 Figure();
1139                 break;
1140
1141         case LFUN_AUTOSAVE:
1142                 AutoSave(owner->view());
1143                 break;
1144                 
1145         case LFUN_UNDO:
1146                 owner->view()->menuUndo();
1147                 break;
1148                 
1149         case LFUN_REDO:
1150                 owner->view()->menuRedo();
1151                 break;
1152                 
1153         case LFUN_MENUSEARCH:
1154                 owner->getDialogs()->showSearch();
1155                 break;
1156                 
1157         case LFUN_REMOVEERRORS:
1158                 if (owner->view()->removeAutoInsets()) {
1159                         owner->view()->redraw();
1160                         owner->view()->fitCursor();
1161                 }
1162                 break;
1163
1164         case LFUN_DEPTH:
1165                 changeDepth(owner->view(), TEXT(false), 0);
1166                 break;
1167                 
1168         case LFUN_DEPTH_MIN:
1169                 changeDepth(owner->view(), TEXT(false), -1);
1170                 break;
1171                 
1172         case LFUN_DEPTH_PLUS:
1173                 changeDepth(owner->view(), TEXT(false), 1);
1174                 break;
1175                 
1176         case LFUN_FREE:
1177                 owner->getDialogs()->setUserFreeFont();
1178                 break;
1179
1180         case LFUN_RECONFIGURE:
1181                 Reconfigure(owner->view());
1182                 break;
1183
1184 #if 0
1185         case LFUN_FLOATSOPERATE:
1186                 if (argument == "openfoot")
1187                         owner->view()->allFloats(1,0);
1188                 else if (argument == "closefoot")
1189                         owner->view()->allFloats(0,0);
1190                 else if (argument == "openfig")
1191                         owner->view()->allFloats(1,1);
1192                 else if (argument == "closefig")
1193                         owner->view()->allFloats(0,1);
1194                 break;
1195 #else
1196 #ifdef WITH_WARNINGS
1197 //#warning Find another implementation here (or another lyxfunc)!
1198 #endif
1199 #endif
1200         case LFUN_HELP_ABOUTLYX:
1201                 owner->getDialogs()->showAboutlyx();
1202                 break;
1203
1204         case LFUN_HELP_TEXINFO:
1205                 owner->getDialogs()->showTexinfo();
1206                 break;
1207
1208         case LFUN_HELP_OPEN:
1209         {
1210                 string const arg = argument;
1211                 if (arg.empty()) {
1212                         setErrorMessage(N_("Missing argument"));
1213                         break;
1214                 }
1215                 owner->prohibitInput();
1216                 string const fname = i18nLibFileSearch("doc", arg, "lyx");
1217                 if (fname.empty()) {
1218                         lyxerr << "LyX: unable to find documentation file `"
1219                                << arg << "'. Bad installation?" << endl;
1220                         owner->allowInput();
1221                         break;
1222                 }
1223                 ostringstream str;
1224                 str << _("Opening help file") << ' '
1225                     << MakeDisplayPath(fname) << "...";
1226                 owner->message(str.str().c_str());
1227                 owner->view()->buffer(bufferlist.loadLyXFile(fname, false));
1228                 owner->allowInput();
1229                 break;
1230         }
1231
1232                 // --- version control -------------------------------
1233         case LFUN_VC_REGISTER:
1234         {
1235                 if (!owner->buffer()->lyxvc.inUse())
1236                         owner->buffer()->lyxvc.registrer();
1237         }
1238         break;
1239                 
1240         case LFUN_VC_CHECKIN:
1241         {
1242                 if (owner->buffer()->lyxvc.inUse()
1243                     && !owner->buffer()->isReadonly())
1244                         owner->buffer()->lyxvc.checkIn();
1245         }
1246         break;
1247                 
1248         case LFUN_VC_CHECKOUT:
1249         {
1250                 if (owner->buffer()->lyxvc.inUse()
1251                     && owner->buffer()->isReadonly())
1252                         owner->buffer()->lyxvc.checkOut();
1253         }
1254         break;
1255         
1256         case LFUN_VC_REVERT:
1257         {
1258                 owner->buffer()->lyxvc.revert();
1259         }
1260         break;
1261                 
1262         case LFUN_VC_UNDO:
1263         {
1264                 owner->buffer()->lyxvc.undoLast();
1265         }
1266         break;
1267                 
1268         case LFUN_VC_HISTORY:
1269         {
1270                 owner->getDialogs()->showVCLogFile();
1271                 break;
1272         }
1273         
1274         // --- buffers ----------------------------------------
1275
1276         case LFUN_SWITCHBUFFER:
1277                 owner->view()->buffer(bufferlist.getBuffer(argument));
1278                 break;
1279
1280         case LFUN_FILE_NEW:
1281         {
1282                 // servercmd: argument must be <file>:<template>
1283                 Buffer * tmpbuf = NewLyxFile(argument);
1284                 if (tmpbuf)
1285                         owner->view()->buffer(tmpbuf);
1286         }
1287         break;
1288                         
1289         case LFUN_FILE_OPEN:
1290                 open(argument);
1291                 break;
1292
1293         case LFUN_LATEX_LOG:
1294                 owner->getDialogs()->showLogFile();
1295                 break;
1296                 
1297         case LFUN_LAYOUTNO:
1298         {
1299                 lyxerr[Debug::INFO] << "LFUN_LAYOUTNO: (arg) " << argument << endl;
1300                 int sel = strToInt(argument);
1301                 lyxerr[Debug::INFO] << "LFUN_LAYOUTNO: (sel) "<< sel << endl;
1302                 
1303                 // Should this give a setMessage instead?
1304                 if (sel == 0) 
1305                         return string(); // illegal argument
1306
1307                 --sel; // sel 1..., but layout 0...
1308
1309                 // Pretend we got the name instead.
1310                 dispatch(int(LFUN_LAYOUT), 
1311                          textclasslist.NameOfLayout(owner->view()
1312                                                     ->buffer()->params.textclass,
1313                                                     sel));
1314                 return string();
1315         }
1316                 
1317         case LFUN_LAYOUT_DOCUMENT:
1318                 owner->getDialogs()->showDocument();
1319                 break;
1320                 
1321         case LFUN_LAYOUT_PARAGRAPH:
1322                 owner->getDialogs()->showParagraph();
1323                 break;
1324                 
1325         case LFUN_LAYOUT_CHARACTER:
1326                 owner->getDialogs()->showCharacter();
1327                 break;
1328
1329         case LFUN_LAYOUT_TABULAR:
1330             if (owner->view()->theLockingInset()) {
1331                 if (owner->view()->theLockingInset()->lyxCode()==Inset::TABULAR_CODE) {
1332                     InsetTabular * inset = static_cast<InsetTabular *>
1333                         (owner->view()->theLockingInset());
1334                     inset->openLayoutDialog(owner->view());
1335                 } else if (owner->view()->theLockingInset()->
1336                            getFirstLockingInsetOfType(Inset::TABULAR_CODE)!=0) {
1337                     InsetTabular * inset = static_cast<InsetTabular *>(
1338                         owner->view()->theLockingInset()->getFirstLockingInsetOfType(Inset::TABULAR_CODE));
1339                     inset->openLayoutDialog(owner->view());
1340                 }
1341             }
1342             break;
1343
1344         case LFUN_LAYOUT_PREAMBLE:
1345                 owner->getDialogs()->showPreamble();
1346                 break;
1347                 
1348         case LFUN_LAYOUT_SAVE_DEFAULT:
1349                 MenuLayoutSave(owner->view());
1350                 break;
1351                 
1352         case LFUN_DROP_LAYOUTS_CHOICE:
1353                 owner->getToolbar()->openLayoutList();
1354                 break;
1355
1356         case LFUN_MENU_OPEN_BY_NAME:
1357                 owner->getMenubar()->openByName(argument);
1358                 break; // RVDK_PATCH_5
1359                 
1360         case LFUN_SPELLCHECK:
1361                 if (lyxrc.isp_command != "none")
1362                         owner->getDialogs()->showSpellchecker();
1363                 break;
1364                 
1365         // --- lyxserver commands ----------------------------
1366
1367
1368         case LFUN_GETNAME:
1369                 setMessage(owner->buffer()->fileName());
1370                 lyxerr[Debug::INFO] << "FNAME["
1371                                << owner->buffer()->fileName()
1372                                << "] " << endl;
1373                 break;
1374                 
1375         case LFUN_NOTIFY:
1376         {
1377                 string buf;
1378                 keyseq.print(buf);
1379                 dispatch_buffer = buf;
1380                 lyxserver->notifyClient(dispatch_buffer);
1381         }
1382         break;
1383
1384         case LFUN_GOTOFILEROW:
1385         {
1386                 string file_name;
1387                 int row;
1388                 istringstream istr(argument.c_str());
1389                 istr >> file_name >> row;
1390                 // Must replace extension of the file to be .lyx and get full path
1391                 string const s(ChangeExtension(file_name, ".lyx"));
1392
1393                 // Either change buffer or load the file
1394                 if (bufferlist.exists(s)) {
1395                         owner->view()->buffer(bufferlist.getBuffer(s));
1396                 } else {
1397                         owner->view()->buffer(bufferlist.loadLyXFile(s));
1398                 }
1399                 
1400                 // Set the cursor  
1401                 owner->view()->setCursorFromRow(row);
1402
1403                 // Recenter screen
1404                 owner->view()->center();
1405         }
1406         break;
1407
1408         case LFUN_GOTO_PARAGRAPH:
1409         {
1410                 istringstream istr(argument.c_str());
1411
1412                 int id;
1413                 istr >> id;
1414                 Paragraph * par = owner->buffer()->getParFromID(id);
1415                 if (par == 0) {
1416                         lyxerr[Debug::INFO] << "No matching paragraph found! ["
1417                                             << id << "]" << std::endl;
1418                         break;
1419                 } else {
1420                         lyxerr << "Paragraph " << par->id()
1421                                << " found." << endl;
1422                 }
1423
1424                 // Set the cursor
1425                 owner->view()->text->setCursor(owner->view(), par, 0);
1426                 owner->view()->setState();
1427                 owner->showState();
1428
1429                 // Recenter screen
1430                 owner->view()->center();
1431         }
1432         break;
1433
1434         case LFUN_APROPOS:
1435         case LFUN_GETTIP:
1436         {
1437                 int const qa = lyxaction.LookupFunc(argument);
1438                 setMessage(lyxaction.helpText(static_cast<kb_action>(qa)));
1439         }
1440         break;
1441
1442         // --- toolbar ----------------------------------
1443         case LFUN_PUSH_TOOLBAR:
1444         {
1445                 int nth = strToInt(argument);
1446                 if (nth <= 0) {
1447                         setErrorMessage(N_("Push-toolbar needs argument > 0"));
1448                 } else {
1449                         owner->getToolbar()->push(nth);
1450                 }
1451         }
1452         break;
1453         
1454         case LFUN_ADD_TO_TOOLBAR:
1455         {
1456                 if (lyxerr.debugging(Debug::GUI)) {
1457                         lyxerr << "LFUN_ADD_TO_TOOLBAR:"
1458                                 "argument = `" << argument << '\'' << endl;
1459                 }
1460                 string tmp(argument);
1461                 //lyxerr <<string("Argument: ") + argument);
1462                 //lyxerr <<string("Tmp     : ") + tmp);
1463                 if (tmp.empty()) {
1464                         setErrorMessage(N_("Usage: toolbar-add-to <LyX command>"));
1465                 } else {
1466                         owner->getToolbar()->add(argument, false);
1467                         owner->getToolbar()->set();
1468                 }
1469         }
1470         break;
1471         
1472         // --- insert characters ----------------------------------------
1473
1474         // ---  Mathed stuff. If we are here, there is no locked inset yet.
1475         case LFUN_MATH_EXTERN:
1476         case LFUN_MATH_NUMBER:
1477         case LFUN_MATH_NONUMBER:
1478         case LFUN_MATH_LIMITS:
1479         {
1480                 setErrorMessage(N_("This is only allowed in math mode!"));
1481         }
1482         break;
1483
1484         case LFUN_MATH_PANEL:
1485                 owner->getDialogs()->showMathPanel();
1486                 break;
1487         
1488         case LFUN_CITATION_CREATE:
1489         {
1490                 InsetCommandParams p( "cite" );
1491                 
1492                 if (!argument.empty()) {
1493                         // This should be set at source, ie when typing
1494                         // "citation-insert foo" in the minibuffer.
1495                         // Question: would pybibliographer also need to be
1496                         // changed. Suspect so. Leave as-is therefore.
1497                         if (contains(argument, "|")) {
1498                                 p.setContents( token(argument, '|', 0) );
1499                                 p.setOptions(  token(argument, '|', 1) );
1500                         } else {
1501                                 p.setContents( argument );
1502                         }
1503                         dispatch(LFUN_CITATION_INSERT, p.getAsString());
1504                 } else
1505                         owner->getDialogs()->createCitation( p.getAsString() );
1506         }
1507         break;
1508                     
1509         case LFUN_CHILDOPEN:
1510         {
1511                 string const filename =
1512                         MakeAbsPath(argument, 
1513                                     OnlyPath(owner->buffer()->fileName()));
1514                 setMessage(N_("Opening child document ") +
1515                            MakeDisplayPath(filename) + "...");
1516                 owner->view()->savePosition(0);
1517                 if (bufferlist.exists(filename))
1518                         owner->view()->buffer(bufferlist.getBuffer(filename));
1519                 else
1520                         owner->view()->buffer(bufferlist.loadLyXFile(filename));
1521         }
1522         break;
1523
1524         case LFUN_TOGGLECURSORFOLLOW:
1525                 lyxrc.cursor_follows_scrollbar = !lyxrc.cursor_follows_scrollbar;
1526                 break;
1527                 
1528         case LFUN_KMAP_OFF:             // keymap off
1529                 owner->getIntl()->KeyMapOn(false);
1530                 break;
1531                 
1532         case LFUN_KMAP_PRIM:    // primary keymap
1533                 owner->getIntl()->KeyMapPrim();
1534                 break;
1535                 
1536         case LFUN_KMAP_SEC:             // secondary keymap
1537                 owner->getIntl()->KeyMapSec();
1538                 break;
1539                 
1540         case LFUN_KMAP_TOGGLE:  // toggle keymap
1541                 owner->getIntl()->ToggleKeyMap();
1542                 break;
1543
1544         case LFUN_SEQUENCE: 
1545         {
1546                 // argument contains ';'-terminated commands
1547                 while (argument.find(';') != string::npos) {
1548                         string first;
1549                         argument = split(argument, first, ';');
1550                         dispatch(first);
1551                 }
1552         }
1553         break;
1554
1555         case LFUN_DIALOG_PREFERENCES:
1556                 owner->getDialogs()->showPreferences();
1557                 break;
1558                 
1559         case LFUN_SAVEPREFERENCES:
1560         {
1561                 Path p(user_lyxdir);
1562                 lyxrc.write("preferences");
1563         }
1564         break;
1565
1566         case LFUN_SCREEN_FONT_UPDATE:
1567         {
1568                 // handle the screen font changes.
1569                 // 
1570                 lyxrc.set_font_norm_type();
1571                 fontloader.update();
1572                 // Of course we should only do the resize and the textcache.clear
1573                 // if values really changed...but not very important right now. (Lgb)
1574                 // All visible buffers will need resize
1575                 owner->resize();
1576                 // We also need to empty the textcache so that
1577                 // the buffer will be formatted correctly after
1578                 // a zoom change.
1579                 textcache.clear();
1580         }
1581         break;
1582
1583         case LFUN_SET_COLOR:
1584         {
1585                 string lyx_name;
1586                 string const x11_name = split(argument, lyx_name, ' ');
1587                 if (lyx_name.empty() || x11_name.empty()) {
1588                         setErrorMessage(N_("Syntax: set-color <lyx_name>"
1589                                                 " <x11_name>"));
1590                         break;
1591                         }
1592
1593                 if (!lcolor.setColor(lyx_name, x11_name)) {
1594                         static string const err1 (N_("Set-color \""));
1595                         static string const err2 (
1596                                 N_("\" failed - color is undefined "
1597                                    "or may not be redefined"));
1598                         setErrorMessage(_(err1) + lyx_name + _(err2));
1599                         break;
1600                 }
1601                 lyxColorHandler->updateColor(lcolor.getFromLyXName(lyx_name));
1602                 owner->view()->redraw();
1603                 break;
1604         }
1605
1606         case LFUN_MESSAGE:
1607                 owner->message(argument);
1608                 break;
1609
1610         case LFUN_MESSAGE_PUSH:
1611                 owner->messagePush(argument);
1612                 break;
1613
1614         case LFUN_MESSAGE_POP:
1615                 owner->messagePop();
1616                 break;
1617
1618         default:
1619                 // Then if it was none of the above
1620                 if (!owner->view()->Dispatch(action, argument))
1621                         lyxerr << "A truly unknown func ["
1622                                << lyxaction.getActionName(action) << "]!"
1623                                << endl;
1624                 break;
1625         } // end of switch
1626
1627 exit_with_message:
1628
1629         commandshortcut.erase();
1630         
1631         if (lyxrc.display_shortcuts && show_sc) {
1632                 if (action != LFUN_SELFINSERT) {
1633                         // Put name of command and list of shortcuts
1634                         // for it in minibuffer
1635                         string comname = lyxaction.getActionName(action);
1636
1637                         int pseudoaction = action;
1638                         bool argsadded = false;
1639
1640                         if (!argument.empty()) {
1641                                 // If we have the command with argument, 
1642                                 // this is better
1643                                 pseudoaction = 
1644                                         lyxaction.searchActionArg(action,
1645                                                                   argument);
1646
1647                                 if (pseudoaction == -1) {
1648                                         pseudoaction = action;
1649                                 } else {
1650                                         comname += " " + argument;
1651                                         argsadded = true;
1652                                 }
1653                         }
1654
1655                         string const shortcuts =
1656                                 toplevel_keymap->findbinding(pseudoaction);
1657
1658                         if (!shortcuts.empty()) {
1659                                 comname += ": " + shortcuts;
1660                         } else if (!argsadded) {
1661                                 comname += " " + argument;
1662                         }
1663
1664                         if (!comname.empty()) {
1665                                 comname = strip(comname);
1666                                 commandshortcut = "(" + comname + ')';
1667
1668                                 // Here we could even add a small pause,
1669                                 // to annoy the user and make him learn
1670                                 // the shortcuts.
1671                                 // No! That will just annoy, not teach
1672                                 // anything. The user will read the messages
1673                                 // if they are interested. (Asger)
1674                         }
1675                 }
1676         }
1677
1678         string const res = getMessage();
1679
1680         if (res.empty()) {
1681                 if (!commandshortcut.empty()) {
1682                         owner->getMiniBuffer()->addSet(commandshortcut);
1683                 }
1684         } else {
1685                 string const msg(_(res) + ' ' + commandshortcut);
1686                 owner->message(msg);
1687         }
1688
1689         return res;
1690 }
1691
1692
1693 void LyXFunc::setupLocalKeymap()
1694 {
1695         keyseq.stdmap = keyseq.curmap = toplevel_keymap.get();
1696         cancel_meta_seq.stdmap = cancel_meta_seq.curmap = toplevel_keymap.get();
1697 }
1698
1699
1700 void LyXFunc::menuNew(bool fromTemplate)
1701 {
1702         string initpath = lyxrc.document_path;
1703
1704         if (owner->view()->available()) {
1705                 string const trypath = owner->buffer()->filepath;
1706                 // If directory is writeable, use this as default.
1707                 if (IsDirWriteable(trypath))
1708                         initpath = trypath;
1709         }
1710
1711         static int newfile_number;
1712         string s;
1713         
1714         if (lyxrc.new_ask_filename) {
1715                 FileDialog fileDlg(owner, _("Enter filename for new document"),
1716                                    LFUN_SELECT_FILE_SYNC,
1717                         make_pair(string(_("Documents")),
1718                                   string(lyxrc.document_path)),
1719                         make_pair(string(_("Templates")),
1720                                   string(lyxrc.template_path)));
1721
1722                 FileDialog::Result result =
1723                         fileDlg.Select(initpath,
1724                                        _("*.lyx|LyX Documents (*.lyx)"),
1725                                        _("newfile"));
1726         
1727                 if (result.second.empty()) {
1728                         owner->message(_("Canceled."));
1729                         lyxerr[Debug::INFO] << "New Document Cancelled." << endl;
1730                         return;
1731                 }
1732         
1733                 // get absolute path of file and make sure the filename ends
1734                 // with .lyx
1735                 s = MakeAbsPath(result.second);
1736                 if (!IsLyXFilename(s))
1737                         s += ".lyx";
1738
1739                 // Check if the document already is open
1740                 if (bufferlist.exists(s)) {
1741                         switch (AskConfirmation(_("Document is already open:"),
1742                                                 MakeDisplayPath(s, 50),
1743                                                 _("Do you want to close that document now?\n"
1744                                                   "('No' will just switch to the open version)")))
1745                         {
1746                         case 1: // Yes: close the document
1747                                 if (!bufferlist.close(bufferlist.getBuffer(s)))
1748                                 // If close is canceled, we cancel here too.
1749                                         return;
1750                                 break;
1751                         case 2: // No: switch to the open document
1752                                 owner->view()->buffer(bufferlist.getBuffer(s));
1753                                 return;
1754                         case 3: // Cancel: Do nothing
1755                                 owner->message(_("Canceled."));
1756                                 return;
1757                         }
1758                 }
1759                 // Check whether the file already exists
1760                 FileInfo fi(s);
1761                 if (fi.readable() &&
1762                     AskQuestion(_("File already exists:"), 
1763                                 MakeDisplayPath(s, 50),
1764                                 _("Do you want to open the document?"))) {
1765                                 // loads document
1766                         string const disp_fn(MakeDisplayPath(s));
1767                         
1768                         ostringstream str;
1769                         str << _("Opening  document") << ' '
1770                             << disp_fn << "...";
1771                         
1772                         owner->message(str.str().c_str());
1773                         //XFlush(fl_get_display());
1774                         owner->view()->buffer(bufferlist.loadLyXFile(s));
1775                         ostringstream str2;
1776                         str2 << _("Document") << ' '
1777                              << disp_fn << ' ' << _("opened.");
1778                         
1779                         owner->message(str2.str().c_str());
1780                         
1781                         return;
1782                 }
1783         } else {
1784                 s = AddName(lyxrc.document_path,
1785                             "newfile" + tostr(++newfile_number) + ".lyx");
1786                 FileInfo fi(s);
1787                 while (bufferlist.exists(s) || fi.readable()) {
1788                         ++newfile_number;
1789                         s = AddName(lyxrc.document_path,
1790                                     "newfile" + tostr(newfile_number) +
1791                                     ".lyx");
1792                         fi.newFile(s);
1793                 }
1794         }
1795
1796         // The template stuff
1797         string templname;
1798         if (fromTemplate) {
1799                 FileDialog fileDlg(owner, _("Select template file"),
1800                         LFUN_SELECT_FILE_SYNC,
1801                         make_pair(string(_("Documents")),
1802                                   string(lyxrc.document_path)),
1803                         make_pair(string(_("Templates")),
1804                                   string(lyxrc.template_path)));
1805
1806                 FileDialog::Result result =
1807                         fileDlg.Select(lyxrc.template_path,
1808                                        _("*.lyx|LyX Documents (*.lyx)"));
1809         
1810                 if (result.first == FileDialog::Later)
1811                         return;
1812
1813                 string const fname = result.second;
1814
1815                 if (fname.empty()) 
1816                         return;
1817                 templname = fname;
1818         }
1819   
1820         // find a free buffer
1821         lyxerr[Debug::INFO] << "Find a free buffer." << endl;
1822         owner->view()->buffer(bufferlist.newFile(s, templname));
1823 }
1824
1825
1826 void LyXFunc::open(string const & fname)
1827 {
1828         string initpath = lyxrc.document_path;
1829   
1830         if (owner->view()->available()) {
1831                 string const trypath = owner->buffer()->filepath;
1832                 // If directory is writeable, use this as default.
1833                 if (IsDirWriteable(trypath))
1834                         initpath = trypath;
1835         }
1836
1837         string filename;
1838  
1839         if (fname.empty()) {
1840                 FileDialog fileDlg(owner, _("Select document to open"),
1841                         LFUN_FILE_OPEN,
1842                         make_pair(string(_("Documents")),
1843                                   string(lyxrc.document_path)),
1844                         make_pair(string(_("Examples")),
1845                                   string(AddPath(system_lyxdir, "examples"))));
1846
1847                 FileDialog::Result result =
1848                         fileDlg.Select(initpath,
1849                                        "*.lyx|LyX Documents (*.lyx)");
1850         
1851                 if (result.first == FileDialog::Later)
1852                         return;
1853
1854                 filename = result.second;
1855  
1856                 // check selected filename
1857                 if (filename.empty()) {
1858                         owner->message(_("Canceled."));
1859                         return;
1860                 }
1861         } else
1862                 filename = fname;
1863
1864         // get absolute path of file and add ".lyx" to the filename if
1865         // necessary
1866         string const fullpath = FileSearch(string(), filename, "lyx");
1867         if (fullpath.empty()) {
1868                 WriteAlert(_("Error"), _("Could not find file"), filename);
1869                 return;
1870         }
1871
1872         filename = fullpath;
1873  
1874         // loads document
1875         string const disp_fn(MakeDisplayPath(filename));
1876
1877         ostringstream str;
1878         str << _("Opening document") << ' ' << disp_fn << "...";
1879         
1880         owner->message(str.str().c_str());
1881
1882         Buffer * openbuf = bufferlist.loadLyXFile(filename);
1883         if (openbuf) {
1884                 owner->view()->buffer(openbuf);
1885                 ostringstream str;
1886                 str << _("Document") << ' ' << disp_fn << ' ' << _("opened.");
1887                 owner->message(str.str().c_str());
1888         } else {
1889                 ostringstream str;
1890                 str << _("Could not open document") << ' ' << disp_fn;
1891                 owner->message(str.str().c_str());
1892         }
1893 }
1894
1895
1896 // checks for running without gui are missing.
1897 void LyXFunc::doImport(string const & argument)
1898 {
1899         string format;
1900         string filename = split(argument, format, ' ');
1901         lyxerr[Debug::INFO] << "LyXFunc::doImport: " << format 
1902                             << " file: " << filename << endl;
1903
1904         if (filename.empty()) { // need user interaction
1905                 string initpath = lyxrc.document_path;
1906                 
1907                 if (owner->view()->available()) {
1908                         string const trypath = owner->buffer()->filepath;
1909                         // If directory is writeable, use this as default.
1910                         if (IsDirWriteable(trypath))
1911                                 initpath = trypath;
1912                 }
1913
1914                 string const text = _("Select ") + formats.prettyName(format)
1915                         + _(" file to import");
1916
1917                 FileDialog fileDlg(owner, text, 
1918                         LFUN_IMPORT,
1919                         make_pair(string(_("Documents")),
1920                                   string(lyxrc.document_path)),
1921                         make_pair(string(_("Examples")),
1922                                   string(AddPath(system_lyxdir, "examples"))));
1923                         
1924                 string const extension = "*." + formats.extension(format)
1925                         + "| " + formats.prettyName(format)
1926                         + " (*." + formats.extension(format) + ")";
1927
1928                 FileDialog::Result result = fileDlg.Select(initpath,
1929                                                            extension);
1930
1931                 if (result.first == FileDialog::Later)
1932                         return;
1933
1934                 filename = result.second;
1935  
1936                 // check selected filename
1937                 if (filename.empty())
1938                         owner->message(_("Canceled."));
1939         }
1940
1941         // still no filename? abort
1942         if (filename.empty()) 
1943                 return;
1944
1945         // get absolute path of file
1946         filename = MakeAbsPath(filename);
1947
1948         string const lyxfile = ChangeExtension(filename, ".lyx");
1949
1950         // Check if the document already is open
1951         if (bufferlist.exists(lyxfile)) {
1952                 switch (AskConfirmation(_("Document is already open:"), 
1953                                         MakeDisplayPath(lyxfile, 50),
1954                                         _("Do you want to close that document now?\n"
1955                                           "('No' will just switch to the open version)")))
1956                         {
1957                         case 1: // Yes: close the document
1958                                 if (!bufferlist.close(bufferlist.getBuffer(lyxfile)))
1959                                 // If close is canceled, we cancel here too.
1960                                         return;
1961                                 break;
1962                         case 2: // No: switch to the open document
1963                                 owner->view()->buffer(bufferlist.getBuffer(lyxfile));
1964                                 return;
1965                         case 3: // Cancel: Do nothing
1966                                 owner->message(_("Canceled."));
1967                                 return;
1968                         }
1969         }
1970
1971         // Check if a LyX document by the same root exists in filesystem
1972         FileInfo const f(lyxfile, true);
1973         if (f.exist() && !AskQuestion(_("A document by the name"), 
1974                                       MakeDisplayPath(lyxfile),
1975                                       _("already exists. Overwrite?"))) {
1976                 owner->message(_("Canceled"));
1977                 return;
1978         }
1979         // filename should be valid now
1980         
1981         Importer::Import(owner, filename, format);
1982 }
1983
1984
1985 void LyXFunc::reloadBuffer()
1986 {
1987         string const fn = owner->buffer()->fileName();
1988         if (bufferlist.close(owner->buffer()))
1989                 owner->view()->buffer(bufferlist.loadLyXFile(fn));
1990 }
1991
1992
1993 void LyXFunc::closeBuffer()
1994 {
1995         if (bufferlist.close(owner->buffer()) && !quitting) {
1996                 if (bufferlist.empty()) {
1997                         // need this otherwise SEGV may occur while trying to
1998                         // set variables that don't exist
1999                         // since there's no current buffer
2000                         owner->getDialogs()->hideBufferDependent();
2001                 } else {
2002                         owner->view()->buffer(bufferlist.first());
2003                 }
2004         }
2005 }
2006
2007
2008 // Each "owner" should have it's own message method. lyxview and
2009 // the minibuffer would use the minibuffer, but lyxserver would
2010 // send an ERROR signal to its client.  Alejandro 970603
2011 // This func is bit problematic when it comes to NLS, to make the
2012 // lyx servers client be language indepenent we must not translate
2013 // strings sent to this func.
2014 void LyXFunc::setErrorMessage(string const & m) const
2015 {
2016         dispatch_buffer = m;
2017         errorstat = true;
2018 }
2019
2020
2021 void LyXFunc::setMessage(string const & m)
2022 {
2023         dispatch_buffer = m;
2024 }
2025
2026
2027 void LyXFunc::initMiniBuffer() 
2028 {
2029         string text = _("Welcome to LyX!");
2030         
2031         // When meta-fake key is pressed, show the key sequence so far + "M-".
2032         if (wasMetaKey()) {
2033                 keyseqStr();
2034                 text += "M-";
2035         }
2036
2037         // Else, when a non-complete key sequence is pressed,
2038         // show the available options.
2039         else if (keyseqUncomplete()) 
2040                 text = keyseqOptions();
2041    
2042         // Else, show the buffer state.
2043         else if (owner->view()->available()) {
2044                 Buffer * tmpbuf = owner->buffer();
2045                 
2046                 string const nicename = 
2047                         MakeDisplayPath(tmpbuf->fileName());
2048                 // Should we do this instead? (kindo like emacs)
2049                 // leaves more room for other information
2050                 text = "LyX: ";
2051                 text += nicename;
2052                 if (tmpbuf->lyxvc.inUse()) {
2053                         text += " [";
2054                         text += tmpbuf->lyxvc.versionString();
2055                         text += ' ';
2056                         text += tmpbuf->lyxvc.locker();
2057                         if (tmpbuf->isReadonly())
2058                                 text += " (RO)";
2059                         text += ']';
2060                 } else if (tmpbuf->isReadonly())
2061                         text += " [RO]";
2062                 if (!tmpbuf->isLyxClean())
2063                         text += _(" (Changed)");
2064         } else {
2065                 if (text != _("Welcome to LyX!")) // this is a hack
2066                         text = _("* No document open *");
2067         }
2068         
2069         owner->message(text);
2070 }
2071