]> git.lyx.org Git - lyx.git/blob - src/mathed/formulabase.C
Changes due to the removal of using directives from support/std_sstream.h.
[lyx.git] / src / mathed / formulabase.C
1 /**
2  * \file formulabase.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Alejandro Aguilar Sierra
7  * \author André Pönitz
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include "formulabase.h"
15 #include "support/std_sstream.h"
16 #include "support/LAssert.h"
17 #include "formula.h"
18 #include "formulamacro.h"
19 #include "funcrequest.h"
20 #include "BufferView.h"
21 #include "lyxtext.h"
22 #include "gettext.h"
23 #include "debug.h"
24 #include "math_support.h"
25 #include "support/lstrings.h"
26 #include "support/lyxlib.h"
27 #include "frontends/LyXView.h"
28 #include "math_arrayinset.h"
29 #include "math_deliminset.h"
30 #include "math_cursor.h"
31 #include "math_factory.h"
32 #include "math_hullinset.h"
33 #include "math_parser.h"
34 #include "math_spaceinset.h"
35 #include "undo_funcs.h"
36 #include "frontends/Dialogs.h"
37 #include "ref_inset.h"
38
39
40 using namespace lyx::support;
41
42 using std::endl;
43 using std::istringstream;
44 using std::ostream;
45 using std::ostringstream;
46 using std::vector;
47 using std::abs;
48 using std::max;
49
50
51 MathCursor * mathcursor = 0;
52
53 namespace {
54
55 // local global
56 int first_x;
57 int first_y;
58
59 bool openNewInset(BufferView * bv, UpdatableInset * new_inset)
60 {
61         if (!bv->insertInset(new_inset)) {
62                 delete new_inset;
63                 return false;
64         }
65         new_inset->localDispatch(FuncRequest(bv, LFUN_INSET_EDIT, "left"));
66         return true;
67 }
68
69
70 } // namespace anon
71
72
73
74 InsetFormulaBase::InsetFormulaBase()
75         : view_(0), xo_(0), yo_(0)
76 {
77         // This is needed as long the math parser is not re-entrant
78         initMath();
79         //lyxerr << "sizeof MathInset: " << sizeof(MathInset) << endl;
80         //lyxerr << "sizeof MetricsInfo: " << sizeof(MetricsInfo) << endl;
81         //lyxerr << "sizeof MathCharInset: " << sizeof(MathCharInset) << endl;
82         //lyxerr << "sizeof LyXFont: " << sizeof(LyXFont) << endl;
83 }
84
85
86 // simply scrap this function if you want
87 void InsetFormulaBase::mutateToText()
88 {
89 #if 0
90         // translate to latex
91         ostringstream os;
92         latex(NULL, os, false, false);
93         string str = os.str();
94
95         // insert this text
96         LyXText * lt = view_->getLyXText();
97         string::const_iterator cit = str.begin();
98         string::const_iterator end = str.end();
99         for (; cit != end; ++cit)
100                 view_->owner()->getIntl()->getTransManager().TranslateAndInsert(*cit, lt);
101
102         // remove ourselves
103         //view_->owner()->dispatch(LFUN_ESCAPE);
104 #endif
105 }
106
107
108 void InsetFormulaBase::handleFont
109         (BufferView * bv, string const & arg, string const & font)
110 {
111         // this whole function is a hack and won't work for incremental font
112         // changes...
113         recordUndo(bv, Undo::ATOMIC);
114
115         if (mathcursor->inset()->name() == font)
116                 mathcursor->handleFont(font);
117         else {
118                 mathcursor->handleNest(createMathInset(font));
119                 mathcursor->insert(arg);
120         }
121 }
122
123
124 BufferView * InsetFormulaBase::view() const
125 {
126         return view_;
127 }
128
129
130 void InsetFormulaBase::validate(LaTeXFeatures &) const
131 {}
132
133
134 string const InsetFormulaBase::editMessage() const
135 {
136         return _("Math editor mode");
137 }
138
139
140 void InsetFormulaBase::insetUnlock(BufferView * bv)
141 {
142         if (mathcursor) {
143                 if (mathcursor->inMacroMode()) {
144                         mathcursor->macroModeClose();
145                         bv->updateInset(this);
146                 }
147                 releaseMathCursor(bv);
148         }
149         generatePreview();
150         bv->updateInset(this);
151 }
152
153
154 void InsetFormulaBase::getCursor(BufferView &, int & x, int & y) const
155 {
156         mathcursor->getPos(x, y);
157 }
158
159
160 void InsetFormulaBase::getCursorPos(BufferView *, int & x, int & y) const
161 {
162         // calling metrics here destroys the cached xo,yo positions e.g. in
163         // MathParboxinset. And it would be too expensive anyway...
164         //metrics(bv);
165         if (!mathcursor) {
166                 lyxerr << "getCursorPos - should not happen";
167                 x = y = 0;
168                 return;
169         }
170         mathcursor->getPos(x, y);
171         x = mathcursor->targetX();
172         x -= xo_;
173         y -= yo_;
174         //lyxerr << "getCursorPos: " << x << ' ' << y << endl;
175 }
176
177
178 void InsetFormulaBase::fitInsetCursor(BufferView * bv) const
179 {
180         if (!mathcursor)
181                 return;
182         int x, y, asc, des;
183         asc = 10;
184         des = 2;
185         //math_font_max_dim(font_, asc, des);
186         getCursorPos(bv, x, y);
187         //y += yo_;
188         //lyxerr << "fitInsetCursor: x: " << x << " y: " << y << " yo: " << yo_ << endl;
189         bv->fitLockedInsetCursor(x, y, asc, des);
190 }
191
192
193 void InsetFormulaBase::toggleInsetSelection(BufferView * bv)
194 {
195         if (mathcursor)
196                 bv->updateInset(this);
197 }
198
199
200 dispatch_result InsetFormulaBase::lfunMouseRelease(FuncRequest const & cmd)
201 {
202         if (!mathcursor)
203                 return UNDISPATCHED;
204
205         BufferView * bv = cmd.view();
206         bv->updateInset(this);
207         //lyxerr << "lfunMouseRelease: buttons: " << cmd.button() << endl;
208
209         if (cmd.button() == mouse_button::button3) {
210                 // try to dispatch to enclosed insets first
211                 if (mathcursor->dispatch(cmd) == UNDISPATCHED) {
212                         // launch math panel for right mouse button
213                         lyxerr << "lfunMouseRelease: undispatched: " << cmd.button() << endl;
214                         bv->owner()->getDialogs().show("mathpanel");
215                 }
216                 return DISPATCHED;
217         }
218
219         if (cmd.button() == mouse_button::button2) {
220                 MathArray ar;
221                 asArray(bv->getClipboard(), ar);
222                 mathcursor->selClear();
223                 mathcursor->setPos(cmd.x + xo_, cmd.y + yo_);
224                 mathcursor->insert(ar);
225                 bv->updateInset(this);
226                 return DISPATCHED;
227         }
228
229         if (cmd.button() == mouse_button::button1) {
230                 // try to dispatch to enclosed insets first
231                 mathcursor->dispatch(cmd);
232                 cmd.view()->stuffClipboard(mathcursor->grabSelection());
233                 // try to set the cursor
234                 //delete mathcursor;
235                 //mathcursor = new MathCursor(this, x == 0);
236                 //metrics(bv);
237                 //mathcursor->setPos(x + xo_, y + yo_);
238                 return DISPATCHED;
239         }
240
241         return UNDISPATCHED;
242 }
243
244
245 dispatch_result InsetFormulaBase::lfunMousePress(FuncRequest const & cmd)
246 {
247         BufferView * bv = cmd.view();
248         //lyxerr << "lfunMousePress: buttons: " << cmd.button() << endl;
249
250         if (!mathcursor || mathcursor->formula() != this) {
251                 lyxerr[Debug::MATHED] << "re-create cursor" << endl;
252                 releaseMathCursor(bv);
253                 mathcursor = new MathCursor(this, cmd.x == 0);
254                 //metrics(bv);
255                 mathcursor->setPos(cmd.x + xo_, cmd.y + yo_);
256         }
257
258         if (cmd.button() == mouse_button::button3) {
259                 mathcursor->dispatch(cmd);
260                 return DISPATCHED;
261         }
262
263         if (cmd.button() == mouse_button::button1) {
264                 first_x = cmd.x;
265                 first_y = cmd.y;
266                 mathcursor->selClear();
267                 mathcursor->setPos(cmd.x + xo_, cmd.y + yo_);
268                 mathcursor->dispatch(cmd);
269                 return DISPATCHED;
270         }
271
272         bv->updateInset(this);
273         return DISPATCHED;
274 }
275
276
277 dispatch_result InsetFormulaBase::lfunMouseMotion(FuncRequest const & cmd)
278 {
279         if (!mathcursor)
280                 return DISPATCHED;
281
282         if (mathcursor->dispatch(FuncRequest(cmd)) != UNDISPATCHED)
283                 return DISPATCHED;
284
285         // only select with button 1
286         if (cmd.button() != mouse_button::button1)
287                 return DISPATCHED;
288
289         if (abs(cmd.x - first_x) < 2 && abs(cmd.y - first_y) < 2)
290                 return DISPATCHED;
291
292         first_x = cmd.x;
293         first_y = cmd.y;
294
295         if (!mathcursor->selection())
296                 mathcursor->selStart();
297
298         BufferView * bv = cmd.view();
299         mathcursor->setPos(cmd.x + xo_, cmd.y + yo_);
300         bv->updateInset(this);
301         return DISPATCHED;
302 }
303
304
305 dispatch_result InsetFormulaBase::localDispatch(FuncRequest const & cmd)
306 {
307         //lyxerr << "InsetFormulaBase::localDispatch: act: " << cmd.action
308         //      << " arg: '" << cmd.argument
309         //      << " x: '" << cmd.x
310         //      << " y: '" << cmd.y
311         //      << "' button: " << cmd.button() << endl;
312
313         BufferView * bv = cmd.view();
314
315         // delete empty mathbox (LFUN_BACKSPACE and LFUN_DELETE)
316         bool remove_inset = false;
317
318         switch (cmd.action) {
319                 case LFUN_INSET_EDIT:
320                         lyxerr << "Called EDIT with '" << cmd.argument << "'" << endl;
321                         if (!bv->lockInset(this))
322                                 lyxerr << "Cannot lock math inset in edit call!" << endl;
323                         releaseMathCursor(bv);
324                         if (!cmd.argument.empty()) {
325                                 mathcursor = new MathCursor(this, cmd.argument == "left");
326                                 //metrics(bv);
327                         } else {
328                                 mathcursor = new MathCursor(this, true);
329                                 //metrics(bv);
330                                 mathcursor->setPos(cmd.x + xo_, cmd.y + yo_);
331                         }
332                         // if that is removed, we won't get the magenta box when entering an
333                         // inset for the first time
334                         bv->updateInset(this);
335                         return DISPATCHED;
336
337                 case LFUN_MOUSE_PRESS:
338                         //lyxerr << "Mouse single press" << endl;
339                         return lfunMousePress(cmd);
340                 case LFUN_MOUSE_MOTION:
341                         //lyxerr << "Mouse motion" << endl;
342                         return lfunMouseMotion(cmd);
343                 case LFUN_MOUSE_RELEASE:
344                         //lyxerr << "Mouse single release" << endl;
345                         return lfunMouseRelease(cmd);
346                 case LFUN_MOUSE_DOUBLE:
347                         //lyxerr << "Mouse double" << endl;
348                         return localDispatch(FuncRequest(LFUN_WORDSEL));
349                 default:
350                         break;
351         }
352
353         if (!mathcursor)
354                 return UNDISPATCHED;
355
356         string argument    = cmd.argument;
357         RESULT result      = DISPATCHED;
358         bool sel           = false;
359         bool was_macro     = mathcursor->inMacroMode();
360         bool was_selection = mathcursor->selection();
361
362         mathcursor->normalize();
363         mathcursor->touch();
364
365         switch (cmd.action) {
366
367         case LFUN_MATH_MUTATE:
368         case LFUN_MATH_DISPLAY:
369         case LFUN_MATH_NUMBER:
370         case LFUN_MATH_NONUMBER:
371         case LFUN_CELL_SPLIT:
372         case LFUN_BREAKLINE:
373         case LFUN_DELETE_LINE_FORWARD:
374         case LFUN_INSERT_LABEL:
375         case LFUN_MATH_EXTERN:
376         case LFUN_TABULAR_FEATURE:
377         case LFUN_PASTESELECTION:
378         case LFUN_MATH_LIMITS:
379                 recordUndo(bv, Undo::ATOMIC);
380                 mathcursor->dispatch(cmd);
381                 break;
382
383         case LFUN_RIGHTSEL:
384                 sel = true; // fall through...
385         case LFUN_RIGHT:
386                 result = mathcursor->right(sel) ? DISPATCHED : FINISHED_RIGHT;
387                 //lyxerr << "calling scroll 20" << endl;
388                 //scroll(bv, 20);
389                 // write something to the minibuffer
390                 //bv->owner()->message(mathcursor->info());
391                 break;
392
393         case LFUN_LEFTSEL:
394                 sel = true; // fall through
395         case LFUN_LEFT:
396                 result = mathcursor->left(sel) ? DISPATCHED : FINISHED;
397                 break;
398
399         case LFUN_UPSEL:
400                 sel = true; // fall through
401         case LFUN_UP:
402                 result = mathcursor->up(sel) ? DISPATCHED : FINISHED_UP;
403                 break;
404
405         case LFUN_DOWNSEL:
406                 sel = true; // fall through
407         case LFUN_DOWN:
408                 result = mathcursor->down(sel) ? DISPATCHED : FINISHED_DOWN;
409                 break;
410
411         case LFUN_WORDSEL:
412                 mathcursor->home(false);
413                 mathcursor->end(true);
414                 break;
415
416         case LFUN_UP_PARAGRAPHSEL:
417         case LFUN_UP_PARAGRAPH:
418         case LFUN_DOWN_PARAGRAPHSEL:
419         case LFUN_DOWN_PARAGRAPH:
420                 result = FINISHED;
421                 break;
422
423         case LFUN_HOMESEL:
424         case LFUN_WORDLEFTSEL:
425                 sel = true; // fall through
426         case LFUN_HOME:
427         case LFUN_WORDLEFT:
428                 result = mathcursor->home(sel) ? DISPATCHED : FINISHED;
429                 break;
430
431         case LFUN_ENDSEL:
432         case LFUN_WORDRIGHTSEL:
433                 sel = true; // fall through
434         case LFUN_END:
435         case LFUN_WORDRIGHT:
436                 result = mathcursor->end(sel) ? DISPATCHED : FINISHED_RIGHT;
437                 break;
438
439         case LFUN_PRIORSEL:
440         case LFUN_PRIOR:
441         case LFUN_BEGINNINGBUFSEL:
442         case LFUN_BEGINNINGBUF:
443                 result = FINISHED;
444                 break;
445
446         case LFUN_NEXTSEL:
447         case LFUN_NEXT:
448         case LFUN_ENDBUFSEL:
449         case LFUN_ENDBUF:
450                 result = FINISHED_RIGHT;
451                 break;
452
453         case LFUN_CELL_FORWARD:
454                 mathcursor->idxNext();
455                 break;
456
457         case LFUN_CELL_BACKWARD:
458                 mathcursor->idxPrev();
459                 break;
460
461         case LFUN_DELETE_WORD_BACKWARD:
462         case LFUN_BACKSPACE:
463                 recordUndo(bv, Undo::ATOMIC);
464                 if (!mathcursor->backspace()) {
465                         result = FINISHED;
466                         remove_inset = true;
467                 }
468                 break;
469
470         case LFUN_DELETE_WORD_FORWARD:
471         case LFUN_DELETE:
472                 recordUndo(bv, Undo::ATOMIC);
473                 if (!mathcursor->erase()) {
474                         result = FINISHED;
475                         remove_inset = true;
476                 }
477                 break;
478
479         //    case LFUN_GETXY:
480         //      sprintf(dispatch_buffer, "%d %d",);
481         //      dispatch_result = dispatch_buffer;
482         //      break;
483         case LFUN_SETXY: {
484                 lyxerr << "LFUN_SETXY broken!" << endl;
485                 int x = 0;
486                 int y = 0;
487                 istringstream is(cmd.argument.c_str());
488                 is >> x >> y;
489                 mathcursor->setPos(x, y);
490                 break;
491         }
492
493         case LFUN_PASTE: {
494                 size_t n = 0;
495                 istringstream is(cmd.argument.c_str());
496                 is >> n;
497                 if (was_macro)
498                         mathcursor->macroModeClose();
499                 recordUndo(bv, Undo::ATOMIC);
500                 mathcursor->selPaste(n);
501                 break;
502         }
503
504         case LFUN_CUT:
505                 recordUndo(bv, Undo::DELETE);
506                 mathcursor->selCut();
507                 break;
508
509         case LFUN_COPY:
510                 mathcursor->selCopy();
511                 break;
512
513
514         // Special casing for superscript in case of LyX handling
515         // dead-keys:
516         case LFUN_CIRCUMFLEX:
517                 if (cmd.argument.empty()) {
518                         // do superscript if LyX handles
519                         // deadkeys
520                         recordUndo(bv, Undo::ATOMIC);
521                         mathcursor->script(true);
522                 }
523                 break;
524
525         case LFUN_UMLAUT:
526         case LFUN_ACUTE:
527         case LFUN_GRAVE:
528         case LFUN_BREVE:
529         case LFUN_DOT:
530         case LFUN_MACRON:
531         case LFUN_CARON:
532         case LFUN_TILDE:
533         case LFUN_CEDILLA:
534         case LFUN_CIRCLE:
535         case LFUN_UNDERDOT:
536         case LFUN_TIE:
537         case LFUN_OGONEK:
538         case LFUN_HUNG_UMLAUT:
539                 break;
540
541         //  Math fonts
542         case LFUN_BOLD:         handleFont(bv, cmd.argument, "mathbf"); break;
543         case LFUN_SANS:         handleFont(bv, cmd.argument, "mathsf"); break;
544         case LFUN_EMPH:         handleFont(bv, cmd.argument, "mathcal"); break;
545         case LFUN_ROMAN:        handleFont(bv, cmd.argument, "mathrm"); break;
546         case LFUN_CODE:         handleFont(bv, cmd.argument, "texttt"); break;
547         case LFUN_FRAK:         handleFont(bv, cmd.argument, "mathfrak"); break;
548         case LFUN_ITAL:         handleFont(bv, cmd.argument, "mathit"); break;
549         case LFUN_NOUN:         handleFont(bv, cmd.argument, "mathbb"); break;
550         case LFUN_FREEFONT_APPLY:  handleFont(bv, cmd.argument, "textrm"); break;
551         case LFUN_DEFAULT:      handleFont(bv, cmd.argument, "textnormal"); break;
552
553         case LFUN_MATH_MODE:
554                 if (mathcursor->currentMode() == MathInset::TEXT_MODE)
555                         mathcursor->niceInsert(MathAtom(new MathHullInset("simple")));
556                 else
557                         handleFont(bv, cmd.argument, "textrm");
558                 //bv->owner()->message(_("math text mode toggled"));
559                 break;
560
561         case LFUN_MATH_SIZE:
562 #if 0
563                 if (!arg.empty()) {
564                         recordUndo(bv, Undo::ATOMIC);
565                         mathcursor->setSize(arg);
566                 }
567 #endif
568                 break;
569
570         case LFUN_INSERT_MATRIX: {
571                 recordUndo(bv, Undo::ATOMIC);
572                 unsigned int m = 1;
573                 unsigned int n = 1;
574                 string v_align;
575                 string h_align;
576                 istringstream is(STRCONV(argument));
577                 is >> m >> n >> v_align >> h_align;
578                 m = max(1u, m);
579                 n = max(1u, n);
580                 v_align += 'c';
581                 mathcursor->niceInsert(
582                         MathAtom(new MathArrayInset("array", m, n, v_align[0], h_align)));
583                 break;
584         }
585
586         case LFUN_SUPERSCRIPT:
587         case LFUN_SUBSCRIPT:
588         {
589                 recordUndo(bv, Undo::ATOMIC);
590                 mathcursor->script(cmd.action == LFUN_SUPERSCRIPT);
591                 break;
592         }
593
594         case LFUN_MATH_DELIM:
595         {
596                 //lyxerr << "formulabase::LFUN_MATH_DELIM, arg: '" << arg << "'" << endl;
597                 string ls;
598                 string rs = split(cmd.argument, ls, ' ');
599                 // Reasonable default values
600                 if (ls.empty())
601                         ls = '(';
602                 if (rs.empty())
603                         rs = ')';
604
605                 recordUndo(bv, Undo::ATOMIC);
606                 mathcursor->handleNest(MathAtom(new MathDelimInset(ls, rs)));
607                 break;
608         }
609
610         case LFUN_SPACE_INSERT:
611         case LFUN_MATH_SPACE:
612                 recordUndo(bv, Undo::ATOMIC);
613                 mathcursor->insert(MathAtom(new MathSpaceInset(",")));
614                 break;
615
616         case LFUN_UNDO:
617                 bv->owner()->message(_("Invalid action in math mode!"));
618                 break;
619
620
621         case LFUN_EXEC_COMMAND:
622                 result = UNDISPATCHED;
623                 break;
624
625         case LFUN_INSET_ERT:
626                 // interpret this as if a backslash was typed
627                 recordUndo(bv, Undo::ATOMIC);
628                 mathcursor->interpret('\\');
629                 break;
630
631         case LFUN_BREAKPARAGRAPH:
632         case LFUN_BREAKPARAGRAPHKEEPLAYOUT:
633         case LFUN_BREAKPARAGRAPH_SKIP:
634                 argument = "\n";
635                 // fall through
636
637 // FIXME: We probably should swap parts of "math-insert" and "self-insert"
638 // handling such that "self-insert" works on "arbitrary stuff" too, and
639 // math-insert only handles special math things like "matrix".
640         case LFUN_INSERT_MATH:
641                 recordUndo(bv, Undo::ATOMIC);
642                 mathcursor->niceInsert(argument);
643                 break;
644
645         case -1:
646         case LFUN_SELFINSERT:
647                 if (!argument.empty()) {
648                         recordUndo(bv, Undo::ATOMIC);
649                         if (argument.size() == 1)
650                                 result = mathcursor->interpret(argument[0]) ? DISPATCHED : FINISHED_RIGHT;
651                         else
652                                 mathcursor->insert(argument);
653                 }
654                 break;
655
656         case LFUN_ESCAPE:
657                 if (mathcursor->selection())
658                         mathcursor->selClear();
659                 else
660                         result = UNDISPATCHED;
661                 break;
662
663         case LFUN_INSET_TOGGLE:
664                 mathcursor->insetToggle();
665                 break;
666
667         case LFUN_DIALOG_SHOW:
668                 result = UNDISPATCHED;
669                 break;
670
671         case LFUN_DIALOG_SHOW_NEW_INSET: {
672                 string const & name = argument;
673                 string data;
674                 if (name == "ref") {
675                         RefInset tmp(name);
676                         data = tmp.createDialogStr(name);
677                 }
678
679                 if (data.empty())
680                         result = UNDISPATCHED;
681                 else {
682                         bv->owner()->getDialogs().show(name, data, 0);
683                 }
684         }
685         break;
686
687         case LFUN_INSET_APPLY: {
688                 string const name = cmd.getArg(0);
689                 InsetBase * base =
690                         bv->owner()->getDialogs().getOpenInset(name);
691
692                 if (base) {
693                         FuncRequest fr(bv, LFUN_INSET_MODIFY, cmd.argument);
694                         result = base->localDispatch(fr);
695                 } else {
696                         MathArray ar;
697                         if (createMathInset_fromDialogStr(cmd.argument, ar)) {
698                                 mathcursor->insert(ar);
699                                 result = DISPATCHED;
700                         } else {
701                                 result = UNDISPATCHED;
702                         }
703                 }
704         }
705         break;
706
707         default:
708                 result = UNDISPATCHED;
709         }
710
711         if (result == DISPATCHED)
712                 bv->updateInset(this);
713
714         mathcursor->normalize();
715         mathcursor->touch();
716
717         Assert(mathcursor);
718
719         if (mathcursor->selection() || was_selection)
720                 toggleInsetSelection(bv);
721
722         if (result == DISPATCHED || result == DISPATCHED_NOUPDATE ||
723             result == UNDISPATCHED) {
724                 fitInsetCursor(bv);
725                 revealCodes(bv);
726                 cmd.view()->stuffClipboard(mathcursor->grabSelection());
727         } else {
728                 releaseMathCursor(bv);
729                 bv->unlockInset(this);
730                 if (remove_inset)
731                         bv->owner()->dispatch(FuncRequest(LFUN_DELETE));
732         }
733
734         return result;  // original version
735 }
736
737
738 void InsetFormulaBase::revealCodes(BufferView * bv) const
739 {
740         if (!mathcursor)
741                 return;
742         bv->owner()->message(mathcursor->info());
743
744 #if 0
745         // write something to the minibuffer
746         // translate to latex
747         mathcursor->markInsert();
748         ostringstream os;
749         write(NULL, os);
750         string str = os.str();
751         mathcursor->markErase();
752         string::size_type pos = 0;
753         string res;
754         for (string::iterator it = str.begin(); it != str.end(); ++it) {
755                 if (*it == '\n')
756                         res += ' ';
757                 else if (*it == '\0') {
758                         res += "  -X-  ";
759                         pos = it - str.begin();
760                 }
761                 else
762                         res += *it;
763         }
764         if (pos > 30)
765                 res = res.substr(pos - 30);
766         if (res.size() > 60)
767                 res = res.substr(0, 60);
768         bv->owner()->message(res);
769 #endif
770 }
771
772
773 InsetOld::Code InsetFormulaBase::lyxCode() const
774 {
775         return InsetOld::MATH_CODE;
776 }
777
778
779 int InsetFormulaBase::ylow() const
780 {
781         return yo_ - dim_.asc;
782 }
783
784
785 int InsetFormulaBase::yhigh() const
786 {
787         return yo_ + dim_.des;
788 }
789
790
791 int InsetFormulaBase::xlow() const
792 {
793         return xo_;
794 }
795
796
797 int InsetFormulaBase::xhigh() const
798 {
799         return xo_ + dim_.wid;
800 }
801
802
803 /////////////////////////////////////////////////////////////////////
804
805
806 bool InsetFormulaBase::searchForward(BufferView * bv, string const & str,
807                                      bool, bool)
808 {
809 #ifdef WITH_WARNINGS
810 #warning pretty ugly
811 #endif
812         static InsetFormulaBase * lastformula = 0;
813         static MathIterator current = MathIterator(ibegin(par().nucleus()));
814         static MathArray ar;
815         static string laststr;
816
817         if (lastformula != this || laststr != str) {
818                 //lyxerr << "reset lastformula to " << this << endl;
819                 lastformula = this;
820                 laststr = str;
821                 current = ibegin(par().nucleus());
822                 ar.clear();
823                 mathed_parse_cell(ar, str);
824         } else {
825                 ++current;
826         }
827         //lyxerr << "searching '" << str << "' in " << this << ar << endl;
828
829         for (MathIterator it = current; it != iend(par().nucleus()); ++it) {
830                 if (it.cell().matchpart(ar, it.back().pos_)) {
831                         bv->unlockInset(bv->theLockingInset());
832                         if (!bv->lockInset(this)) {
833                                 lyxerr << "Cannot lock inset" << endl;
834                                 return false;
835                         }
836                         delete mathcursor;
837                         mathcursor = new MathCursor(this, true);
838                         //metrics(bv);
839                         mathcursor->setSelection(it, ar.size());
840                         current = it;
841                         it.jump(ar.size());
842                         bv->updateInset(this);
843                         return true;
844                 }
845         }
846
847         //lyxerr << "not found!" << endl;
848         lastformula = 0;
849         return false;
850 }
851
852
853 bool InsetFormulaBase::searchBackward(BufferView * bv, string const & what,
854                                       bool a, bool b)
855 {
856         lyxerr[Debug::MATHED] << "searching backward not implemented in mathed" << endl;
857         return searchForward(bv, what, a, b);
858 }
859
860
861 bool InsetFormulaBase::display() const
862 {
863         return par()->asHullInset() && par()->asHullInset()->display();
864 }
865
866
867 string InsetFormulaBase::selectionAsString() const
868 {
869         return mathcursor ? mathcursor->grabSelection() : string();
870 }
871
872 /////////////////////////////////////////////////////////////////////
873
874
875 void mathDispatchCreation(FuncRequest const & cmd, bool display)
876 {
877         BufferView * bv = cmd.view();
878         // use selection if available..
879         //string sel;
880         //if (action == LFUN_MATH_IMPORT_SELECTION)
881         //      sel = "";
882         //else
883
884         string sel = bv->getLyXText()->selectionAsString(*bv->buffer(), false);
885
886         if (sel.empty()) {
887                 InsetFormula * f = new InsetFormula(bv);
888                 if (openNewInset(bv, f)) {
889                         bv->theLockingInset()->
890                                 localDispatch(FuncRequest(bv, LFUN_MATH_MUTATE, "simple"));
891                         // don't do that also for LFUN_MATH_MODE unless you want end up with
892                         // always changing to mathrm when opening an inlined inset
893                         // -- I really hate "LyXfunc overloading"...
894                         if (display)
895                                 f->localDispatch(FuncRequest(bv, LFUN_MATH_DISPLAY));
896                         f->localDispatch(FuncRequest(bv, LFUN_INSERT_MATH, cmd.argument));
897                 }
898         } else {
899                 // create a macro if we see "\\newcommand" somewhere, and an ordinary
900                 // formula otherwise
901                 InsetFormulaBase * f;
902                 if (sel.find("\\newcommand") == string::npos &&
903                                 sel.find("\\def") == string::npos)
904                         f = new InsetFormula(sel);
905                 else
906                         f = new InsetFormulaMacro(sel);
907                 bv->getLyXText()->cutSelection(true, false);
908                 openNewInset(bv, f);
909         }
910         cmd.message(N_("Math editor mode"));
911 }
912
913
914 void mathDispatch(FuncRequest const & cmd)
915 {
916         BufferView * bv = cmd.view();
917         if (!bv->available())
918                 return;
919
920         switch (cmd.action) {
921
922                 case LFUN_MATH_DISPLAY:
923                         mathDispatchCreation(cmd, true);
924                         break;
925
926                 case LFUN_MATH_MODE:
927                         mathDispatchCreation(cmd, false);
928                         break;
929
930                 case LFUN_MATH_IMPORT_SELECTION:
931                         mathDispatchCreation(cmd, false);
932                         break;
933
934                 case LFUN_MATH_MACRO:
935                         if (cmd.argument.empty())
936                                 cmd.errorMessage(N_("Missing argument"));
937                         else {
938                                 string s = cmd.argument;
939                                 string const s1 = token(s, ' ', 1);
940                                 int const nargs = s1.empty() ? 0 : atoi(s1);
941                                 string const s2 = token(s, ' ', 2);
942                                 string const type = s2.empty() ? "newcommand" : s2;
943                                 openNewInset(bv, new InsetFormulaMacro(token(s, ' ', 0), nargs, s2));
944                         }
945                         break;
946
947                 case LFUN_INSERT_MATH:
948                 case LFUN_INSERT_MATRIX:
949                 case LFUN_MATH_DELIM: {
950                         InsetFormula * f = new InsetFormula(bv);
951                         if (openNewInset(bv, f)) {
952                                 bv->theLockingInset()->
953                                         localDispatch(FuncRequest(bv, LFUN_MATH_MUTATE, "simple"));
954                                 bv->theLockingInset()->localDispatch(cmd);
955                         }
956                         break;
957                 }
958
959                 default:
960                         break;
961         }
962 }