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