]> git.lyx.org Git - lyx.git/blob - src/mathed/math_hullinset.C
macro rework
[lyx.git] / src / mathed / math_hullinset.C
1 /**
2  * \file math_hullinset.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author André Pönitz
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "math_charinset.h"
14 #include "math_data.h"
15 #include "math_extern.h"
16 #include "math_hullinset.h"
17 #include "math_mathmlstream.h"
18 #include "math_streamstr.h"
19 #include "math_support.h"
20
21 #include "BufferView.h"
22 #include "cursor.h"
23 #include "dispatchresult.h"
24 #include "debug.h"
25 #include "funcrequest.h"
26 #include "gettext.h"
27 #include "LaTeXFeatures.h"
28 #include "LColor.h"
29 #include "lyxrc.h"
30 #include "outputparams.h"
31 #include "textpainter.h"
32 #include "undo.h"
33
34 #include "frontends/Alert.h"
35
36 #include "support/std_sstream.h"
37
38
39 using std::endl;
40 using std::max;
41 using std::string;
42 using std::ostream;
43 using std::auto_ptr;
44 using std::istringstream;
45 using std::ostream;
46 using std::ostringstream;
47 using std::pair;
48 using std::swap;
49 using std::vector;
50
51
52 namespace {
53
54         int getCols(string const & type)
55         {
56                 if (type == "eqnarray")
57                         return 3;
58                 if (type == "align")
59                         return 2;
60                 if (type == "flalign")
61                         return 2;
62                 if (type == "alignat")
63                         return 2;
64                 if (type == "xalignat")
65                         return 2;
66                 if (type == "xxalignat")
67                         return 2;
68                 return 1;
69         }
70
71
72         // returns position of first relation operator in the array
73         // used for "intelligent splitting"
74         size_t firstRelOp(MathArray const & ar)
75         {
76                 for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it)
77                         if ((*it)->isRelOp())
78                                 return it - ar.begin();
79                 return ar.size();
80         }
81
82
83         char const * star(bool numbered)
84         {
85                 return numbered ? "" : "*";
86         }
87
88
89         int typecode(string const & s)
90         {
91                 if (s == "none")      return 0;
92                 if (s == "simple")    return 1;
93                 if (s == "equation")  return 2;
94                 if (s == "eqnarray")  return 3;
95                 if (s == "align")     return 4;
96                 if (s == "alignat")   return 5;
97                 if (s == "xalignat")  return 6;
98                 if (s == "xxalignat") return 7;
99                 if (s == "multline")  return 8;
100                 if (s == "gather")    return 9;
101                 if (s == "flalign")   return 10;
102                 lyxerr << "unknown hull type '" << s << "'" << endl;
103                 return 0;
104         }
105
106         bool smaller(string const & s, string const & t)
107         {
108                 return typecode(s) < typecode(t);
109         }
110
111
112 } // end anon namespace
113
114
115
116 MathHullInset::MathHullInset()
117         : MathGridInset(1, 1), type_("none"), nonum_(1), label_(1)
118 {
119         //lyxerr << "sizeof MathInset: " << sizeof(MathInset) << endl;
120         //lyxerr << "sizeof MetricsInfo: " << sizeof(MetricsInfo) << endl;
121         //lyxerr << "sizeof MathCharInset: " << sizeof(MathCharInset) << endl;
122         //lyxerr << "sizeof LyXFont: " << sizeof(LyXFont) << endl;
123         setDefaults();
124 }
125
126
127 MathHullInset::MathHullInset(string const & type)
128         : MathGridInset(getCols(type), 1), type_(type), nonum_(1), label_(1)
129 {
130         setDefaults();
131 }
132
133
134 auto_ptr<InsetBase> MathHullInset::clone() const
135 {
136         return auto_ptr<InsetBase>(new MathHullInset(*this));
137 }
138
139
140 MathInset::mode_type MathHullInset::currentMode() const
141 {
142         if (type_ == "none")
143                 return UNDECIDED_MODE;
144         // definitely math mode ...
145         return MATH_MODE;
146 }
147
148
149 bool MathHullInset::idxFirst(LCursor & cur) const
150 {
151         cur.idx() = 0;
152         cur.pos() = 0;
153         return true;
154 }
155
156
157 bool MathHullInset::idxLast(LCursor & cur) const
158 {
159         cur.idx() = nargs() - 1;
160         cur.pos() = cur.lastpos();
161         return true;
162 }
163
164
165 char MathHullInset::defaultColAlign(col_type col)
166 {
167         if (type_ == "eqnarray")
168                 return "rcl"[col];
169         if (typecode(type_) >= typecode("align"))
170                 return "rl"[col & 1];
171         return 'c';
172 }
173
174
175 int MathHullInset::defaultColSpace(col_type col)
176 {
177         if (type_ == "align" || type_ == "alignat")
178                 return 0;
179         if (type_ == "xalignat")
180                 return (col & 1) ? 20 : 0;
181         if (type_ == "xxalignat" || type_ == "flalign")
182                 return (col & 1) ? 40 : 0;
183         return 0;
184 }
185
186
187 char const * MathHullInset::standardFont() const
188 {
189         if (type_ == "none")
190                 return "lyxnochange";
191         return "mathnormal";
192 }
193
194
195 void MathHullInset::metrics(MetricsInfo & mi, Dimension & dim) const
196 {
197         FontSetChanger dummy1(mi.base, standardFont());
198         StyleChanger dummy2(mi.base, display() ? LM_ST_DISPLAY : LM_ST_TEXT);
199
200         // let the cells adjust themselves
201         MathGridInset::metrics(mi, dim);
202
203         if (display()) {
204                 dim.asc += 12;
205                 dim.des += 12;
206         }
207
208         if (numberedType()) {
209                 FontSetChanger dummy(mi.base, "mathbf");
210                 int l = 0;
211                 for (row_type row = 0; row < nrows(); ++row)
212                         l = max(l, mathed_string_width(mi.base.font, nicelabel(row)));
213
214                 if (l)
215                         dim.wid += 30 + l;
216         }
217
218         // make it at least as high as the current font
219         int asc = 0;
220         int des = 0;
221         math_font_max_dim(mi.base.font, asc, des);
222         dim.asc = max(dim.asc, asc);
223         dim.des = max(dim.des, des);
224
225         dim_ = dim;
226 }
227
228
229 void MathHullInset::draw(PainterInfo & pi, int x, int y) const
230 {
231         FontSetChanger dummy1(pi.base, standardFont());
232         StyleChanger dummy2(pi.base, display() ? LM_ST_DISPLAY : LM_ST_TEXT);
233         MathGridInset::draw(pi, x + 1, y);
234
235         if (numberedType()) {
236                 int const xx = x + colinfo_.back().offset_ + colinfo_.back().width_ + 20;
237                 for (row_type row = 0; row < nrows(); ++row) {
238                         int const yy = y + rowinfo_[row].offset_;
239                         FontSetChanger dummy(pi.base, "mathrm");
240                         drawStr(pi, pi.base.font, xx, yy, nicelabel(row));
241                 }
242         }
243         setPosCache(pi, x, y);
244 }
245
246
247 void MathHullInset::metricsT(TextMetricsInfo const & mi, Dimension & dim) const
248 {
249         if (display()) {
250                 MathGridInset::metricsT(mi, dim);
251         } else {
252                 ostringstream os;
253                 WriteStream wi(os, false, true);
254                 write(wi);
255                 dim.wid = os.str().size();
256                 dim.asc = 1;
257                 dim.des = 0;
258         }
259 }
260
261
262 void MathHullInset::drawT(TextPainter & pain, int x, int y) const
263 {
264         if (display()) {
265                 MathGridInset::drawT(pain, x, y);
266         } else {
267                 ostringstream os;
268                 WriteStream wi(os, false, true);
269                 write(wi);
270                 pain.draw(x, y, os.str().c_str());
271         }
272 }
273
274
275 string MathHullInset::label(row_type row) const
276 {
277         row_type n = nrows();
278         BOOST_ASSERT(row < n);
279         return label_[row];
280 }
281
282
283 void MathHullInset::label(row_type row, string const & label)
284 {
285         //lyxerr << "setting label '" << label << "' for row " << row << endl;
286         label_[row] = label;
287 }
288
289
290 void MathHullInset::numbered(row_type row, bool num)
291 {
292         nonum_[row] = !num;
293 }
294
295
296 bool MathHullInset::numbered(row_type row) const
297 {
298         return !nonum_[row];
299 }
300
301
302 bool MathHullInset::ams() const
303 {
304         return
305                 type_ == "align" ||
306                 type_ == "flalign" ||
307                 type_ == "multline" ||
308                 type_ == "gather" ||
309                 type_ == "alignat" ||
310                 type_ == "xalignat" ||
311                 type_ == "xxalignat";
312 }
313
314
315 bool MathHullInset::display() const
316 {
317         return type_ != "simple" && type_ != "none";
318 }
319
320
321 void MathHullInset::getLabelList(Buffer const &, vector<string> & labels) const
322 {
323         for (row_type row = 0; row < nrows(); ++row)
324                 if (!label_[row].empty() && nonum_[row] != 1)
325                         labels.push_back(label_[row]);
326 }
327
328
329 bool MathHullInset::numberedType() const
330 {
331         if (type_ == "none")
332                 return false;
333         if (type_ == "simple")
334                 return false;
335         if (type_ == "xxalignat")
336                 return false;
337         for (row_type row = 0; row < nrows(); ++row)
338                 if (!nonum_[row])
339                         return true;
340         return false;
341 }
342
343
344 void MathHullInset::validate(LaTeXFeatures & features) const
345 {
346         if (ams())
347                 features.require("amsmath");
348
349
350         // Validation is necessary only if not using AMS math.
351         // To be safe, we will always run mathedvalidate.
352         //if (features.amsstyle)
353         //  return;
354
355         features.require("boldsymbol");
356         //features.binom      = true;
357
358         MathGridInset::validate(features);
359 }
360
361
362 void MathHullInset::header_write(WriteStream & os) const
363 {
364         bool n = numberedType();
365
366         if (type_ == "none")
367                 ;
368
369         else if (type_ == "simple") {
370                 os << '$';
371                 if (cell(0).empty())
372                         os << ' ';
373         }
374
375         else if (type_ == "equation") {
376                 if (n)
377                         os << "\\begin{equation" << star(n) << "}\n";
378                 else
379                         os << "\\[\n";
380         }
381
382         else if (type_ == "eqnarray" || type_ == "align" || type_ == "flalign"
383                  || type_ == "gather" || type_ == "multline")
384                         os << "\\begin{" << type_ << star(n) << "}\n";
385
386         else if (type_ == "alignat" || type_ == "xalignat")
387                 os << "\\begin{" << type_ << star(n) << '}'
388                   << '{' << static_cast<unsigned int>((ncols() + 1)/2) << "}\n";
389
390         else if (type_ == "xxalignat")
391                 os << "\\begin{" << type_ << '}'
392                   << '{' << static_cast<unsigned int>((ncols() + 1)/2) << "}\n";
393
394         else
395                 os << "\\begin{unknown" << star(n) << '}';
396 }
397
398
399 void MathHullInset::footer_write(WriteStream & os) const
400 {
401         bool n = numberedType();
402
403         if (type_ == "none")
404                 os << "\n";
405
406         else if (type_ == "simple")
407                 os << '$';
408
409         else if (type_ == "equation")
410                 if (n)
411                         os << "\\end{equation" << star(n) << "}\n";
412                 else
413                         os << "\\]\n";
414
415         else if (type_ == "eqnarray" || type_ == "align" || type_ == "flalign"
416                  || type_ == "alignat" || type_ == "xalignat"
417                  || type_ == "gather" || type_ == "multline")
418                 os << "\\end{" << type_ << star(n) << "}\n";
419
420         else if (type_ == "xxalignat")
421                 os << "\\end{" << type_ << "}\n";
422
423         else
424                 os << "\\end{unknown" << star(n) << '}';
425 }
426
427
428 bool MathHullInset::colChangeOK() const
429 {
430         return
431                 type_ == "align" || type_ == "flalign" ||type_ == "alignat" ||
432                 type_ == "xalignat" || type_ == "xxalignat";
433 }
434
435
436 void MathHullInset::addRow(row_type row)
437 {
438         nonum_.insert(nonum_.begin() + row + 1, !numberedType());
439         label_.insert(label_.begin() + row + 1, string());
440         MathGridInset::addRow(row);
441 }
442
443
444 void MathHullInset::swapRow(row_type row)
445 {
446         if (nrows() == 1)
447                 return;
448         if (row + 1 == nrows())
449                 --row;
450         swap(nonum_[row], nonum_[row + 1]);
451         swap(label_[row], label_[row + 1]);
452         MathGridInset::swapRow(row);
453 }
454
455
456 void MathHullInset::delRow(row_type row)
457 {
458         if (nrows() <= 1)
459                 return;
460         MathGridInset::delRow(row);
461         nonum_.erase(nonum_.begin() + row);
462         label_.erase(label_.begin() + row);
463 }
464
465
466 void MathHullInset::addCol(col_type col)
467 {
468         if (colChangeOK())
469                 MathGridInset::addCol(col);
470         else
471                 lyxerr << "Can't change number of columns in '" << type_ << "'" << endl;
472 }
473
474
475 void MathHullInset::delCol(col_type col)
476 {
477         if (colChangeOK())
478                 MathGridInset::delCol(col);
479         else
480                 lyxerr << "Can't change number of columns in '" << type_ << "'" << endl;
481 }
482
483
484 string MathHullInset::nicelabel(row_type row) const
485 {
486         if (nonum_[row])
487                 return string();
488         if (label_[row].empty())
489                 return string("(#)");
490         return '(' + label_[row] + ')';
491 }
492
493
494 void MathHullInset::glueall()
495 {
496         MathArray ar;
497         for (idx_type i = 0; i < nargs(); ++i)
498                 ar.append(cell(i));
499         *this = MathHullInset("simple");
500         cell(0) = ar;
501         setDefaults();
502 }
503
504
505 string const & MathHullInset::getType() const
506 {
507         return type_;
508 }
509
510
511 void MathHullInset::setType(string const & type)
512 {
513         type_ = type;
514         setDefaults();
515 }
516
517
518
519 void MathHullInset::mutate(string const & newtype)
520 {
521         lyxerr << "mutating from '" << type_ << "' to '" << newtype << "'" << endl;
522
523         // we try to move along the chain
524         // none <-> simple <-> equation <-> eqnarray
525
526         if (newtype == "dump") {
527                 dump();
528         }
529
530         else if (newtype == type_) {
531                 // done
532         }
533
534         else if (type_ == "none") {
535                 setType("simple");
536                 numbered(0, false);
537                 mutate(newtype);
538         }
539
540         else if (type_ == "simple") {
541                 if (newtype == "none") {
542                         setType("none");
543                 } else {
544                         setType("equation");
545                         numbered(0, false);
546                         mutate(newtype);
547                 }
548         }
549
550         else if (type_ == "equation") {
551                 if (smaller(newtype, type_)) {
552                         setType("simple");
553                         mutate(newtype);
554                 } else if (newtype == "eqnarray") {
555                         MathGridInset::addCol(1);
556                         MathGridInset::addCol(1);
557
558                         // split it "nicely" on the firest relop
559                         pos_type pos = firstRelOp(cell(0));
560                         cell(1) = MathArray(cell(0).begin() + pos, cell(0).end());
561                         cell(0).erase(pos, cell(0).size());
562
563                         if (cell(1).size()) {
564                                 cell(2) = MathArray(cell(1).begin() + 1, cell(1).end());
565                                 cell(1).erase(1, cell(1).size());
566                         }
567                         setType("eqnarray");
568                         mutate(newtype);
569                 } else if (newtype == "multline" || newtype == "gather") {
570                         setType(newtype);
571                         numbered(0, false);
572                 } else {
573                         MathGridInset::addCol(1);
574                         // split it "nicely"
575                         pos_type pos = firstRelOp(cell(0));
576                         cell(1) = cell(0);
577                         cell(0).erase(pos, cell(0).size());
578                         cell(1).erase(0, pos);
579                         setType("align");
580                         mutate(newtype);
581                 }
582         }
583
584         else if (type_ == "eqnarray") {
585                 if (smaller(newtype, type_)) {
586                         // set correct (no)numbering
587                         bool allnonum = true;
588                         for (row_type row = 0; row < nrows(); ++row)
589                                 if (!nonum_[row])
590                                         allnonum = false;
591
592                         // set first non-empty label
593                         string label;
594                         for (row_type row = 0; row < nrows(); ++row) {
595                                 if (!label_[row].empty()) {
596                                         label = label_[row];
597                                         break;
598                                 }
599                         }
600
601                         glueall();
602                         nonum_[0] = allnonum;
603                         label_[0] = label;
604                         mutate(newtype);
605                 } else { // align & Co.
606                         for (row_type row = 0; row < nrows(); ++row) {
607                                 idx_type c = 3 * row + 1;
608                                 cell(c).append(cell(c + 1));
609                         }
610                         MathGridInset::delCol(2);
611                         setType("align");
612                         mutate(newtype);
613                 }
614         }
615
616         else if (type_ == "align") {
617                 if (smaller(newtype, type_)) {
618                         MathGridInset::addCol(1);
619                         setType("eqnarray");
620                         mutate(newtype);
621                 } else {
622                         setType(newtype);
623                 }
624         }
625
626         else if (type_ == "multline") {
627                 if (newtype == "gather" || newtype == "align" ||
628                     newtype == "xalignat" || newtype == "xxalignat" || newtype == "flalign")
629                         setType(newtype);
630                 else if (newtype == "eqnarray") {
631                         MathGridInset::addCol(1);
632                         MathGridInset::addCol(1);
633                         setType("eqnarray");
634                 } else {
635                         lyxerr << "mutation from '" << type_
636                                 << "' to '" << newtype << "' not implemented" << endl;
637                 }
638         }
639
640         else if (type_ == "gather") {
641                 if (newtype == "multline") {
642                         setType("multline");
643                 } else {
644                         lyxerr << "mutation from '" << type_
645                                 << "' to '" << newtype << "' not implemented" << endl;
646                 }
647         }
648
649         else {
650                 lyxerr << "mutation from '" << type_
651                                          << "' to '" << newtype << "' not implemented" << endl;
652         }
653 }
654
655
656 string MathHullInset::eolString(row_type row, bool fragile) const
657 {
658         string res;
659         if (numberedType()) {
660                 if (!label_[row].empty() && !nonum_[row])
661                         res += "\\label{" + label_[row] + '}';
662                 if (nonum_[row] && (type_ != "multline"))
663                         res += "\\nonumber ";
664         }
665         return res + MathGridInset::eolString(row, fragile);
666 }
667
668
669 void MathHullInset::write(WriteStream & os) const
670 {
671         header_write(os);
672         MathGridInset::write(os);
673         footer_write(os);
674 }
675
676
677 void MathHullInset::normalize(NormalStream & os) const
678 {
679         os << "[formula " << type_ << ' ';
680         MathGridInset::normalize(os);
681         os << "] ";
682 }
683
684
685 void MathHullInset::mathmlize(MathMLStream & os) const
686 {
687         MathGridInset::mathmlize(os);
688 }
689
690
691 void MathHullInset::infoize(ostream & os) const
692 {
693         os << "Type: " << type_;
694 }
695
696
697 void MathHullInset::check() const
698 {
699         BOOST_ASSERT(nonum_.size() == nrows());
700         BOOST_ASSERT(label_.size() == nrows());
701 }
702
703
704 void MathHullInset::doExtern(LCursor & cur, FuncRequest & func)
705 {
706         string lang;
707         string extra;
708         istringstream iss(func.argument.c_str());
709         iss >> lang >> extra;
710         if (extra.empty())
711                 extra = "noextra";
712
713 #ifdef WITH_WARNINGS
714 #warning temporarily disabled
715         //if (cur.selection()) {
716         //      MathArray ar;
717         //      selGet(cur.ar);
718         //      lyxerr << "use selection: " << ar << endl;
719         //      insert(pipeThroughExtern(lang, extra, ar));
720         //      return;
721         //}
722 #endif
723
724         MathArray eq;
725         eq.push_back(MathAtom(new MathCharInset('=')));
726
727         // go to first item in line
728         cur.idx() -= cur.idx() % ncols();
729         cur.pos() = 0;
730
731         if (getType() == "simple") {
732                 size_type pos = cur.cell().find_last(eq);
733                 MathArray ar;
734                 if (cur.inMathed() && cur.selection()) {
735                         asArray(cur.grabAndEraseSelection(), ar);
736                 } else if (pos == cur.cell().size()) {
737                         ar = cur.cell();
738                         lyxerr << "use whole cell: " << ar << endl;
739                 } else {
740                         ar = MathArray(cur.cell().begin() + pos + 1, cur.cell().end());
741                         lyxerr << "use partial cell form pos: " << pos << endl;
742                 }
743                 cur.cell().append(eq);
744                 cur.cell().append(pipeThroughExtern(lang, extra, ar));
745                 cur.pos() = cur.lastpos();
746                 return;
747         }
748
749         if (getType() == "equation") {
750                 lyxerr << "use equation inset" << endl;
751                 mutate("eqnarray");
752                 MathArray & ar = cur.cell();
753                 lyxerr << "use cell: " << ar << endl;
754                 ++cur.idx();
755                 cur.cell() = eq;
756                 ++cur.idx();
757                 cur.cell() = pipeThroughExtern(lang, extra, ar);
758                 // move to end of line
759                 cur.pos() = cur.lastpos();
760                 return;
761         }
762
763         {
764                 lyxerr << "use eqnarray" << endl;
765                 cur.idx() += 2 - cur.idx() % ncols();
766                 cur.pos() = 0;
767                 MathArray ar = cur.cell();
768                 lyxerr << "use cell: " << ar << endl;
769 #ifdef WITH_WARNINGS
770 #warning temporarily disabled
771 #endif
772                 addRow(cur.row());
773                 ++cur.idx();
774                 ++cur.idx();
775                 cur.cell() = eq;
776                 ++cur.idx();
777                 cur.cell() = pipeThroughExtern(lang, extra, ar);
778                 cur.pos() = cur.lastpos();
779         }
780 }
781
782
783 void MathHullInset::priv_dispatch(LCursor & cur, FuncRequest & cmd)
784 {
785         switch (cmd.action) {
786
787         case LFUN_BREAKPARAGRAPH:
788                 // just swallow this
789                 break;
790
791         case LFUN_BREAKLINE:
792                 if (type_ == "simple" || type_ == "equation") {
793                         mutate("eqnarray");
794                         cur.idx() = 1;
795                         cur.pos() = 0;
796                         //cur.dispatched(FINISHED);
797                         break;
798                 }
799                 MathGridInset::priv_dispatch(cur, cmd);
800                 break;
801
802         case LFUN_MATH_NUMBER:
803                 //lyxerr << "toggling all numbers" << endl;
804                 if (display()) {
805                         recordUndo(cur);
806                         bool old = numberedType();
807                         if (type_ == "multline")
808                                 numbered(nrows() - 1, !old);
809                         else
810                                 for (row_type row = 0; row < nrows(); ++row)
811                                         numbered(row, !old);
812                         cur.message(old ? _("No number") : _("Number"));
813                 }
814                 break;
815
816         case LFUN_MATH_NONUMBER:
817                 if (display()) {
818                         row_type r = (type_ == "multline") ? nrows() - 1 : cur.row();
819                         recordUndo(cur);
820                         bool old = numbered(r);
821                         cur.message(old ? _("No number") : _("Number"));
822                         numbered(r, !old);
823                 }
824                 break;
825
826         case LFUN_INSERT_LABEL: {
827                 row_type r = (type_ == "multline") ? nrows() - 1 : cur.row();
828                 string old_label = label(r);
829                 string new_label = cmd.argument;
830
831                 if (new_label.empty()) {
832                         string const default_label =
833                                 (lyxrc.label_init_length >= 0) ? "eq:" : "";
834                         pair<bool, string> const res = old_label.empty()
835                                 ? Alert::askForText(_("Enter new label to insert:"), default_label)
836                                 : Alert::askForText(_("Enter label:"), old_label);
837                         new_label = lyx::support::trim(res.second);
838                 }
839
840                 if (!new_label.empty())
841                         numbered(r, true);
842                 label(r, new_label);
843                 break;
844         }
845
846         case LFUN_MATH_EXTERN:
847                 doExtern(cur, cmd);
848                 //cur.dispatched(FINISHED);
849                 break;
850
851         case LFUN_MATH_MUTATE: {
852                 lyxerr << "Hull: MUTATE: " << cmd.argument << endl;
853                 row_type row = cur.row();
854                 col_type col = cur.col();
855                 mutate(cmd.argument);
856                 cur.idx() = row * ncols() + col;
857                 if (cur.idx() > cur.lastidx()) {
858                         cur.idx() = cur.lastidx();
859                         cur.pos() = cur.lastpos();
860                 }
861                 if (cur.pos() > cur.lastpos())
862                         cur.pos() = cur.lastpos();
863                 //cur.dispatched(FINISHED);
864                 break;
865         }
866
867         case LFUN_MATH_DISPLAY: {
868                 mutate(type_ == "simple" ? "equation" : "simple");
869                 cur.idx() = 0;
870                 cur.pos() = cur.lastpos();
871                 //cur.dispatched(FINISHED);
872                 break;
873         }
874
875         default:
876                 MathGridInset::priv_dispatch(cur, cmd);
877                 break;
878         }
879 }
880
881
882 bool MathHullInset::getStatus(LCursor & cur, FuncRequest const & cmd,
883                 FuncStatus & flag) const
884 {
885         switch (cmd.action) {
886         case LFUN_BREAKLINE:
887         case LFUN_MATH_NUMBER:
888         case LFUN_MATH_NONUMBER:
889         case LFUN_INSERT_LABEL:
890         case LFUN_MATH_EXTERN:
891         case LFUN_MATH_MUTATE:
892         case LFUN_MATH_DISPLAY:
893                 // we handle these
894                 return true;
895         default:
896                 return MathGridInset::getStatus(cur, cmd, flag);
897         }
898 }
899
900
901 /////////////////////////////////////////////////////////////////////
902
903 #include "math_arrayinset.h"
904 #include "math_deliminset.h"
905 #include "math_factory.h"
906 #include "math_parser.h"
907 #include "math_spaceinset.h"
908 #include "ref_inset.h"
909
910 #include "bufferview_funcs.h"
911 #include "lyxtext.h"
912
913 #include "frontends/LyXView.h"
914 #include "frontends/Dialogs.h"
915
916 #include "support/lstrings.h"
917 #include "support/lyxlib.h"
918
919
920 // simply scrap this function if you want
921 void MathHullInset::mutateToText()
922 {
923 #if 0
924         // translate to latex
925         ostringstream os;
926         latex(NULL, os, false, false);
927         string str = os.str();
928
929         // insert this text
930         LyXText * lt = view_->getLyXText();
931         string::const_iterator cit = str.begin();
932         string::const_iterator end = str.end();
933         for (; cit != end; ++cit)
934                 view_->owner()->getIntl()->getTransManager().TranslateAndInsert(*cit, lt);
935
936         // remove ourselves
937         //view_->owner()->dispatch(LFUN_ESCAPE);
938 #endif
939 }
940
941
942 void MathHullInset::handleFont(LCursor & cur, string const & arg,
943         string const & font)
944 {
945         // this whole function is a hack and won't work for incremental font
946         // changes...
947         recordUndo(cur);
948         if (cur.inset().asMathInset()->name() == font)
949                 cur.handleFont(font);
950         else {
951                 cur.handleNest(createMathInset(font));
952                 cur.insert(arg);
953         }
954 }
955
956
957 void MathHullInset::handleFont2(LCursor & cur, string const & arg)
958 {
959         recordUndo(cur);
960         LyXFont font;
961         bool b;
962         bv_funcs::string2font(arg, font, b);
963         if (font.color() != LColor::inherit) {
964                 MathAtom at = createMathInset("color");
965                 asArray(lcolor.getGUIName(font.color()), at.nucleus()->cell(0));
966                 cur.handleNest(at, 1);
967         }
968 }
969
970
971 void MathHullInset::edit(LCursor & cur, bool left)
972 {
973         cur.push(*this);
974         left ? idxFirst(cur) : idxLast(cur);
975 }
976
977
978 string const MathHullInset::editMessage() const
979 {
980         return _("Math editor mode");
981 }
982
983
984 void MathHullInset::getCursorDim(int & asc, int & desc) const
985 {
986         asc = 10;
987         desc = 2;
988         //math_font_max_dim(font_, asc, des);
989 }
990
991
992 void MathHullInset::revealCodes(LCursor & cur) const
993 {
994         if (!cur.inMathed())
995                 return;
996         ostringstream os;
997         cur.info(os);
998         cur.message(os.str());
999 /*
1000         // write something to the minibuffer
1001         // translate to latex
1002         cur.markInsert(bv);
1003         ostringstream os;
1004         write(NULL, os);
1005         string str = os.str();
1006         cur.markErase(bv);
1007         string::size_type pos = 0;
1008         string res;
1009         for (string::iterator it = str.begin(); it != str.end(); ++it) {
1010                 if (*it == '\n')
1011                         res += ' ';
1012                 else if (*it == '\0') {
1013                         res += "  -X-  ";
1014                         pos = it - str.begin();
1015                 }
1016                 else
1017                         res += *it;
1018         }
1019         if (pos > 30)
1020                 res = res.substr(pos - 30);
1021         if (res.size() > 60)
1022                 res = res.substr(0, 60);
1023         cur.message(res);
1024 */
1025 }
1026
1027
1028 InsetBase::Code MathHullInset::lyxCode() const
1029 {
1030         return MATH_CODE;
1031 }
1032
1033
1034 /////////////////////////////////////////////////////////////////////
1035
1036
1037 #if 0
1038 bool MathHullInset::searchForward(BufferView * bv, string const & str,
1039                                      bool, bool)
1040 {
1041 #warning completely broken
1042         static MathHullInset * lastformula = 0;
1043         static CursorBase current = DocIterator(ibegin(nucleus()));
1044         static MathArray ar;
1045         static string laststr;
1046
1047         if (lastformula != this || laststr != str) {
1048                 //lyxerr << "reset lastformula to " << this << endl;
1049                 lastformula = this;
1050                 laststr = str;
1051                 current = ibegin(nucleus());
1052                 ar.clear();
1053                 mathed_parse_cell(ar, str);
1054         } else {
1055                 increment(current);
1056         }
1057         //lyxerr << "searching '" << str << "' in " << this << ar << endl;
1058
1059         for (DocIterator it = current; it != iend(nucleus()); increment(it)) {
1060                 CursorSlice & top = it.back();
1061                 MathArray const & a = top.asMathInset()->cell(top.idx_);
1062                 if (a.matchpart(ar, top.pos_)) {
1063                         bv->cursor().setSelection(it, ar.size());
1064                         current = it;
1065                         top.pos_ += ar.size();
1066                         bv->update();
1067                         return true;
1068                 }
1069         }
1070
1071         //lyxerr << "not found!" << endl;
1072         lastformula = 0;
1073         return false;
1074 }
1075 #endif
1076
1077
1078 void MathHullInset::write(Buffer const &, std::ostream & os) const
1079 {
1080         WriteStream wi(os, false, false);
1081         os << "Formula ";
1082         write(wi);
1083 }
1084
1085
1086 void MathHullInset::read(Buffer const &, LyXLex & lex)
1087 {
1088         MathAtom at;
1089         mathed_parse_normal(at, lex);
1090         operator=(*at->asHullInset());
1091 }
1092
1093
1094 int MathHullInset::plaintext(Buffer const &, ostream & os,
1095                         OutputParams const &) const
1096 {
1097         if (0 && display()) {
1098                 Dimension dim;
1099                 TextMetricsInfo mi;
1100                 metricsT(mi, dim);
1101                 TextPainter tpain(dim.width(), dim.height());
1102                 drawT(tpain, 0, dim.ascent());
1103                 tpain.show(os, 3);
1104                 // reset metrics cache to "real" values
1105                 //metrics();
1106                 return tpain.textheight();
1107         } else {
1108                 WriteStream wi(os, false, true);
1109                 wi << ' ' << cell(0) << ' ';
1110                 return wi.line();
1111         }
1112 }
1113
1114
1115 int MathHullInset::linuxdoc(Buffer const & buf, ostream & os,
1116                            OutputParams const & runparams) const
1117 {
1118         return docbook(buf, os, runparams);
1119 }
1120
1121
1122 int MathHullInset::docbook(Buffer const & buf, ostream & os,
1123                           OutputParams const & runparams) const
1124 {
1125         MathMLStream ms(os);
1126         ms << MTag("equation");
1127         ms <<   MTag("alt");
1128         ms <<    "<[CDATA[";
1129         int res = plaintext(buf, ms.os(), runparams);
1130         ms <<    "]]>";
1131         ms <<   ETag("alt");
1132         ms <<   MTag("math");
1133         MathGridInset::mathmlize(ms);
1134         ms <<   ETag("math");
1135         ms << ETag("equation");
1136         return ms.line() + res;
1137 }