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