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