]> git.lyx.org Git - lyx.git/blob - src/mathed/math_hullinset.C
remove warning message
[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 <boost/bind.hpp>
44
45 #include <sstream>
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                 Buffer const & buffer = cur.buffer();
373                 string const snippet = latex_string(*this);
374                 preview_->addPreview(snippet, buffer);
375                 preview_->startLoading(buffer);
376         }
377 }
378
379
380 string MathHullInset::label(row_type row) const
381 {
382         row_type n = nrows();
383         BOOST_ASSERT(row < n);
384         return label_[row];
385 }
386
387
388 void MathHullInset::label(row_type row, string const & label)
389 {
390         //lyxerr << "setting label '" << label << "' for row " << row << endl;
391         label_[row] = label;
392 }
393
394
395 void MathHullInset::numbered(row_type row, bool num)
396 {
397         nonum_[row] = !num;
398 }
399
400
401 bool MathHullInset::numbered(row_type row) const
402 {
403         return !nonum_[row];
404 }
405
406
407 bool MathHullInset::ams() const
408 {
409         return
410                 type_ == "align" ||
411                 type_ == "flalign" ||
412                 type_ == "multline" ||
413                 type_ == "gather" ||
414                 type_ == "alignat" ||
415                 type_ == "xalignat" ||
416                 type_ == "xxalignat";
417 }
418
419
420 bool MathHullInset::display() const
421 {
422         return type_ != "simple" && type_ != "none";
423 }
424
425
426 void MathHullInset::getLabelList(Buffer const &, vector<string> & labels) const
427 {
428         for (row_type row = 0; row < nrows(); ++row)
429                 if (!label_[row].empty() && nonum_[row] != 1)
430                         labels.push_back(label_[row]);
431 }
432
433
434 bool MathHullInset::numberedType() const
435 {
436         if (type_ == "none")
437                 return false;
438         if (type_ == "simple")
439                 return false;
440         if (type_ == "xxalignat")
441                 return false;
442         for (row_type row = 0; row < nrows(); ++row)
443                 if (!nonum_[row])
444                         return true;
445         return false;
446 }
447
448
449 void MathHullInset::validate(LaTeXFeatures & features) const
450 {
451         if (ams())
452                 features.require("amsmath");
453
454
455         // Validation is necessary only if not using AMS math.
456         // To be safe, we will always run mathedvalidate.
457         //if (features.amsstyle)
458         //  return;
459
460         features.require("boldsymbol");
461         //features.binom      = true;
462
463         MathGridInset::validate(features);
464 }
465
466
467 void MathHullInset::header_write(WriteStream & os) const
468 {
469         bool n = numberedType();
470
471         if (type_ == "none")
472                 ;
473
474         else if (type_ == "simple") {
475                 os << '$';
476                 if (cell(0).empty())
477                         os << ' ';
478         }
479
480         else if (type_ == "equation") {
481                 if (n)
482                         os << "\\begin{equation" << star(n) << "}\n";
483                 else
484                         os << "\\[\n";
485         }
486
487         else if (type_ == "eqnarray" || type_ == "align" || type_ == "flalign"
488                  || type_ == "gather" || type_ == "multline")
489                         os << "\\begin{" << type_ << star(n) << "}\n";
490
491         else if (type_ == "alignat" || type_ == "xalignat")
492                 os << "\\begin{" << type_ << star(n) << '}'
493                   << '{' << static_cast<unsigned int>((ncols() + 1)/2) << "}\n";
494
495         else if (type_ == "xxalignat")
496                 os << "\\begin{" << type_ << '}'
497                   << '{' << static_cast<unsigned int>((ncols() + 1)/2) << "}\n";
498
499         else
500                 os << "\\begin{unknown" << star(n) << '}';
501 }
502
503
504 void MathHullInset::footer_write(WriteStream & os) const
505 {
506         bool n = numberedType();
507
508         if (type_ == "none")
509                 os << "\n";
510
511         else if (type_ == "simple")
512                 os << '$';
513
514         else if (type_ == "equation")
515                 if (n)
516                         os << "\\end{equation" << star(n) << "}\n";
517                 else
518                         os << "\\]\n";
519
520         else if (type_ == "eqnarray" || type_ == "align" || type_ == "flalign"
521                  || type_ == "alignat" || type_ == "xalignat"
522                  || type_ == "gather" || type_ == "multline")
523                 os << "\\end{" << type_ << star(n) << "}\n";
524
525         else if (type_ == "xxalignat")
526                 os << "\\end{" << type_ << "}\n";
527
528         else
529                 os << "\\end{unknown" << star(n) << '}';
530 }
531
532
533 bool MathHullInset::colChangeOK() const
534 {
535         return
536                 type_ == "align" || type_ == "flalign" ||type_ == "alignat" ||
537                 type_ == "xalignat" || type_ == "xxalignat";
538 }
539
540
541 void MathHullInset::addRow(row_type row)
542 {
543         nonum_.insert(nonum_.begin() + row + 1, !numberedType());
544         label_.insert(label_.begin() + row + 1, string());
545         MathGridInset::addRow(row);
546 }
547
548
549 void MathHullInset::swapRow(row_type row)
550 {
551         if (nrows() == 1)
552                 return;
553         if (row + 1 == nrows())
554                 --row;
555         swap(nonum_[row], nonum_[row + 1]);
556         swap(label_[row], label_[row + 1]);
557         MathGridInset::swapRow(row);
558 }
559
560
561 void MathHullInset::delRow(row_type row)
562 {
563         if (nrows() <= 1)
564                 return;
565         MathGridInset::delRow(row);
566         nonum_.erase(nonum_.begin() + row);
567         label_.erase(label_.begin() + row);
568 }
569
570
571 void MathHullInset::addCol(col_type col)
572 {
573         if (colChangeOK())
574                 MathGridInset::addCol(col);
575         else
576                 lyxerr << "Can't change number of columns in '" << type_ << "'" << endl;
577 }
578
579
580 void MathHullInset::delCol(col_type col)
581 {
582         if (colChangeOK())
583                 MathGridInset::delCol(col);
584         else
585                 lyxerr << "Can't change number of columns in '" << type_ << "'" << endl;
586 }
587
588
589 string MathHullInset::nicelabel(row_type row) const
590 {
591         if (nonum_[row])
592                 return string();
593         if (label_[row].empty())
594                 return string("(#)");
595         return '(' + label_[row] + ')';
596 }
597
598
599 void MathHullInset::glueall()
600 {
601         MathArray ar;
602         for (idx_type i = 0; i < nargs(); ++i)
603                 ar.append(cell(i));
604         *this = MathHullInset("simple");
605         cell(0) = ar;
606         setDefaults();
607 }
608
609
610 string const & MathHullInset::getType() const
611 {
612         return type_;
613 }
614
615
616 void MathHullInset::setType(string const & type)
617 {
618         type_ = type;
619         setDefaults();
620 }
621
622
623
624 void MathHullInset::mutate(string const & newtype)
625 {
626         lyxerr << "mutating from '" << type_ << "' to '" << newtype << "'" << endl;
627
628         // we try to move along the chain
629         // none <-> simple <-> equation <-> eqnarray
630
631         if (newtype == "dump") {
632                 dump();
633         }
634
635         else if (newtype == type_) {
636                 // done
637         }
638
639         else if (type_ == "none") {
640                 setType("simple");
641                 numbered(0, false);
642                 mutate(newtype);
643         }
644
645         else if (type_ == "simple") {
646                 if (newtype == "none") {
647                         setType("none");
648                 } else {
649                         setType("equation");
650                         numbered(0, false);
651                         mutate(newtype);
652                 }
653         }
654
655         else if (type_ == "equation") {
656                 if (smaller(newtype, type_)) {
657                         setType("simple");
658                         mutate(newtype);
659                 } else if (newtype == "eqnarray") {
660                         MathGridInset::addCol(1);
661                         MathGridInset::addCol(1);
662
663                         // split it "nicely" on the firest relop
664                         pos_type pos = firstRelOp(cell(0));
665                         cell(1) = MathArray(cell(0).begin() + pos, cell(0).end());
666                         cell(0).erase(pos, cell(0).size());
667
668                         if (cell(1).size()) {
669                                 cell(2) = MathArray(cell(1).begin() + 1, cell(1).end());
670                                 cell(1).erase(1, cell(1).size());
671                         }
672                         setType("eqnarray");
673                         mutate(newtype);
674                 } else if (newtype == "multline" || newtype == "gather") {
675                         setType(newtype);
676                         numbered(0, false);
677                 } else {
678                         MathGridInset::addCol(1);
679                         // split it "nicely"
680                         pos_type pos = firstRelOp(cell(0));
681                         cell(1) = cell(0);
682                         cell(0).erase(pos, cell(0).size());
683                         cell(1).erase(0, pos);
684                         setType("align");
685                         mutate(newtype);
686                 }
687         }
688
689         else if (type_ == "eqnarray") {
690                 if (smaller(newtype, type_)) {
691                         // set correct (no)numbering
692                         bool allnonum = true;
693                         for (row_type row = 0; row < nrows(); ++row)
694                                 if (!nonum_[row])
695                                         allnonum = false;
696
697                         // set first non-empty label
698                         string label;
699                         for (row_type row = 0; row < nrows(); ++row) {
700                                 if (!label_[row].empty()) {
701                                         label = label_[row];
702                                         break;
703                                 }
704                         }
705
706                         glueall();
707                         nonum_[0] = allnonum;
708                         label_[0] = label;
709                         mutate(newtype);
710                 } else { // align & Co.
711                         for (row_type row = 0; row < nrows(); ++row) {
712                                 idx_type c = 3 * row + 1;
713                                 cell(c).append(cell(c + 1));
714                         }
715                         MathGridInset::delCol(2);
716                         setType("align");
717                         mutate(newtype);
718                 }
719         }
720
721         else if (type_ == "align") {
722                 if (smaller(newtype, type_)) {
723                         MathGridInset::addCol(1);
724                         setType("eqnarray");
725                         mutate(newtype);
726                 } else {
727                         setType(newtype);
728                 }
729         }
730
731         else if (type_ == "multline") {
732                 if (newtype == "gather" || newtype == "align" ||
733                     newtype == "xalignat" || newtype == "xxalignat" || newtype == "flalign")
734                         setType(newtype);
735                 else if (newtype == "eqnarray") {
736                         MathGridInset::addCol(1);
737                         MathGridInset::addCol(1);
738                         setType("eqnarray");
739                 } else {
740                         lyxerr << "mutation from '" << type_
741                                 << "' to '" << newtype << "' not implemented" << endl;
742                 }
743         }
744
745         else if (type_ == "gather") {
746                 if (newtype == "multline") {
747                         setType(newtype);
748                 } else {
749                         lyxerr << "mutation from '" << type_
750                                 << "' to '" << newtype << "' not implemented" << endl;
751                 }
752         }
753
754         else {
755                 lyxerr << "mutation from '" << type_
756                                          << "' to '" << newtype << "' not implemented" << endl;
757         }
758 }
759
760
761 string MathHullInset::eolString(row_type row, bool fragile) const
762 {
763         string res;
764         if (numberedType()) {
765                 if (!label_[row].empty() && !nonum_[row])
766                         res += "\\label{" + label_[row] + '}';
767                 if (nonum_[row] && (type_ != "multline"))
768                         res += "\\nonumber ";
769         }
770         return res + MathGridInset::eolString(row, fragile);
771 }
772
773
774 void MathHullInset::write(WriteStream & os) const
775 {
776         header_write(os);
777         MathGridInset::write(os);
778         footer_write(os);
779 }
780
781
782 void MathHullInset::normalize(NormalStream & os) const
783 {
784         os << "[formula " << type_ << ' ';
785         MathGridInset::normalize(os);
786         os << "] ";
787 }
788
789
790 void MathHullInset::mathmlize(MathMLStream & os) const
791 {
792         MathGridInset::mathmlize(os);
793 }
794
795
796 void MathHullInset::infoize(ostream & os) const
797 {
798         os << "Type: " << type_;
799 }
800
801
802 void MathHullInset::check() const
803 {
804         BOOST_ASSERT(nonum_.size() == nrows());
805         BOOST_ASSERT(label_.size() == nrows());
806 }
807
808
809 void MathHullInset::doExtern(LCursor & cur, FuncRequest & func)
810 {
811         string lang;
812         string extra;
813         istringstream iss(func.argument.c_str());
814         iss >> lang >> extra;
815         if (extra.empty())
816                 extra = "noextra";
817
818 #ifdef WITH_WARNINGS
819 #warning temporarily disabled
820         //if (cur.selection()) {
821         //      MathArray ar;
822         //      selGet(cur.ar);
823         //      lyxerr << "use selection: " << ar << endl;
824         //      insert(pipeThroughExtern(lang, extra, ar));
825         //      return;
826         //}
827 #endif
828
829         MathArray eq;
830         eq.push_back(MathAtom(new MathCharInset('=')));
831
832         // go to first item in line
833         cur.idx() -= cur.idx() % ncols();
834         cur.pos() = 0;
835
836         if (getType() == "simple") {
837                 size_type pos = cur.cell().find_last(eq);
838                 MathArray ar;
839                 if (cur.inMathed() && cur.selection()) {
840                         asArray(grabAndEraseSelection(cur), ar);
841                 } else if (pos == cur.cell().size()) {
842                         ar = cur.cell();
843                         lyxerr << "use whole cell: " << ar << endl;
844                 } else {
845                         ar = MathArray(cur.cell().begin() + pos + 1, cur.cell().end());
846                         lyxerr << "use partial cell form pos: " << pos << endl;
847                 }
848                 cur.cell().append(eq);
849                 cur.cell().append(pipeThroughExtern(lang, extra, ar));
850                 cur.pos() = cur.lastpos();
851                 return;
852         }
853
854         if (getType() == "equation") {
855                 lyxerr << "use equation inset" << endl;
856                 mutate("eqnarray");
857                 MathArray & ar = cur.cell();
858                 lyxerr << "use cell: " << ar << endl;
859                 ++cur.idx();
860                 cur.cell() = eq;
861                 ++cur.idx();
862                 cur.cell() = pipeThroughExtern(lang, extra, ar);
863                 // move to end of line
864                 cur.pos() = cur.lastpos();
865                 return;
866         }
867
868         {
869                 lyxerr << "use eqnarray" << endl;
870                 cur.idx() += 2 - cur.idx() % ncols();
871                 cur.pos() = 0;
872                 MathArray ar = cur.cell();
873                 lyxerr << "use cell: " << ar << endl;
874 #ifdef WITH_WARNINGS
875 #warning temporarily disabled
876 #endif
877                 addRow(cur.row());
878                 ++cur.idx();
879                 ++cur.idx();
880                 cur.cell() = eq;
881                 ++cur.idx();
882                 cur.cell() = pipeThroughExtern(lang, extra, ar);
883                 cur.pos() = cur.lastpos();
884         }
885 }
886
887
888 void MathHullInset::priv_dispatch(LCursor & cur, FuncRequest & cmd)
889 {
890         switch (cmd.action) {
891
892         case LFUN_FINISHED_LEFT:
893         case LFUN_FINISHED_RIGHT:
894         case LFUN_FINISHED_UP:
895         case LFUN_FINISHED_DOWN:
896                 MathGridInset::priv_dispatch(cur, cmd);
897                 notifyCursorLeaves(cur);
898                 break;
899
900         case LFUN_BREAKPARAGRAPH:
901                 // just swallow this
902                 break;
903
904         case LFUN_BREAKLINE:
905                 // some magic for the common case
906                 if (type_ == "simple" || type_ == "equation") {
907                         recordUndoInset(cur);
908                         mutate("eqnarray");
909                         cur.idx() = 0;
910                         cur.pos() = cur.lastpos();
911                 }
912                 MathGridInset::priv_dispatch(cur, cmd);
913                 break;
914
915         case LFUN_MATH_NUMBER:
916                 //lyxerr << "toggling all numbers" << endl;
917                 if (display()) {
918                         recordUndoInset(cur);
919                         bool old = numberedType();
920                         if (type_ == "multline")
921                                 numbered(nrows() - 1, !old);
922                         else
923                                 for (row_type row = 0; row < nrows(); ++row)
924                                         numbered(row, !old);
925                         cur.message(old ? _("No number") : _("Number"));
926                 }
927                 break;
928
929         case LFUN_MATH_NONUMBER:
930                 if (display()) {
931                         recordUndoInset(cur);
932                         row_type r = (type_ == "multline") ? nrows() - 1 : cur.row();
933                         bool old = numbered(r);
934                         cur.message(old ? _("No number") : _("Number"));
935                         numbered(r, !old);
936                 }
937                 break;
938
939         case LFUN_INSERT_LABEL: {
940                 recordUndoInset(cur);
941                 row_type r = (type_ == "multline") ? nrows() - 1 : cur.row();
942                 string old_label = label(r);
943                 string new_label = cmd.argument;
944
945                 if (new_label.empty()) {
946                         string const default_label =
947                                 (lyxrc.label_init_length >= 0) ? "eq:" : "";
948                         pair<bool, string> const res = old_label.empty()
949                                 ? Alert::askForText(_("Enter new label to insert:"), default_label)
950                                 : Alert::askForText(_("Enter label:"), old_label);
951                         if (res.first)
952                                 new_label = lyx::support::trim(res.second);
953                         else
954                                 new_label = old_label;
955                 }
956
957                 if (!new_label.empty())
958                         numbered(r, true);
959                 label(r, new_label);
960                 break;
961         }
962
963         case LFUN_MATH_EXTERN:
964                 recordUndoInset(cur);
965                 doExtern(cur, cmd);
966                 break;
967
968         case LFUN_MATH_MUTATE: {
969                 recordUndoInset(cur);
970                 row_type row = cur.row();
971                 col_type col = cur.col();
972                 mutate(cmd.argument);
973                 cur.idx() = row * ncols() + col;
974                 if (cur.idx() > cur.lastidx()) {
975                         cur.idx() = cur.lastidx();
976                         cur.pos() = cur.lastpos();
977                 }
978                 if (cur.pos() > cur.lastpos())
979                         cur.pos() = cur.lastpos();
980                 //cur.dispatched(FINISHED);
981                 break;
982         }
983
984         case LFUN_MATH_DISPLAY: {
985                 recordUndoInset(cur);
986                 mutate(type_ == "simple" ? "equation" : "simple");
987                 cur.idx() = 0;
988                 cur.pos() = cur.lastpos();
989                 //cur.dispatched(FINISHED);
990                 break;
991         }
992
993         default:
994                 MathGridInset::priv_dispatch(cur, cmd);
995                 break;
996         }
997 }
998
999
1000 bool MathHullInset::getStatus(LCursor & cur, FuncRequest const & cmd,
1001                 FuncStatus & flag) const
1002 {
1003         switch (cmd.action) {
1004         case LFUN_BREAKLINE:
1005         case LFUN_MATH_NUMBER:
1006         case LFUN_MATH_NONUMBER:
1007         case LFUN_INSERT_LABEL:
1008         case LFUN_MATH_EXTERN:
1009         case LFUN_MATH_MUTATE:
1010         case LFUN_MATH_DISPLAY:
1011                 // we handle these
1012                 return true;
1013         case LFUN_TABULAR_FEATURE: {
1014                 // should be more precise
1015                 istringstream is(cmd.argument);
1016                 string s;
1017                 is >> s;
1018                 if ((type_ == "simple" || type_ == "equation")
1019         && (s == "append-column"
1020          || s == "delete-column"
1021          || s == "swap-column"
1022          || s == "copy-column"
1023          || s == "delete-column"
1024          || s == "append-row"
1025          || s == "delete-row"
1026          || s == "swap-row"
1027          || s == "copy-row"))
1028                         return false;
1029                 if ((type_ == "eqnarray")
1030         && (s == "appen-column"
1031          || s == "delete-column"))
1032                         return false;
1033                 return MathGridInset::getStatus(cur, cmd, flag);
1034         }
1035         default:
1036                 return MathGridInset::getStatus(cur, cmd, flag);
1037         }
1038 }
1039
1040
1041 /////////////////////////////////////////////////////////////////////
1042
1043 #include "math_arrayinset.h"
1044 #include "math_deliminset.h"
1045 #include "math_factory.h"
1046 #include "math_parser.h"
1047 #include "math_spaceinset.h"
1048 #include "ref_inset.h"
1049
1050 #include "bufferview_funcs.h"
1051 #include "lyxtext.h"
1052
1053 #include "frontends/LyXView.h"
1054 #include "frontends/Dialogs.h"
1055
1056 #include "support/lstrings.h"
1057 #include "support/lyxlib.h"
1058
1059
1060 // simply scrap this function if you want
1061 void MathHullInset::mutateToText()
1062 {
1063 #if 0
1064         // translate to latex
1065         ostringstream os;
1066         latex(NULL, os, false, false);
1067         string str = os.str();
1068
1069         // insert this text
1070         LyXText * lt = view_->getLyXText();
1071         string::const_iterator cit = str.begin();
1072         string::const_iterator end = str.end();
1073         for (; cit != end; ++cit)
1074                 view_->owner()->getIntl()->getTransManager().TranslateAndInsert(*cit, lt);
1075
1076         // remove ourselves
1077         //view_->owner()->dispatch(LFUN_ESCAPE);
1078 #endif
1079 }
1080
1081
1082 void MathHullInset::handleFont(LCursor & cur, string const & arg,
1083         string const & font)
1084 {
1085         // this whole function is a hack and won't work for incremental font
1086         // changes...
1087         recordUndo(cur);
1088         if (cur.inset().asMathInset()->name() == font)
1089                 cur.handleFont(font);
1090         else {
1091                 cur.handleNest(createMathInset(font));
1092                 cur.insert(arg);
1093         }
1094 }
1095
1096
1097 void MathHullInset::handleFont2(LCursor & cur, string const & arg)
1098 {
1099         recordUndo(cur);
1100         LyXFont font;
1101         bool b;
1102         bv_funcs::string2font(arg, font, b);
1103         if (font.color() != LColor::inherit) {
1104                 MathAtom at = createMathInset("color");
1105                 asArray(lcolor.getGUIName(font.color()), at.nucleus()->cell(0));
1106                 cur.handleNest(at, 1);
1107         }
1108 }
1109
1110
1111 void MathHullInset::edit(LCursor & cur, bool left)
1112 {
1113         cur.push(*this);
1114         left ? idxFirst(cur) : idxLast(cur);
1115 }
1116
1117
1118 string const MathHullInset::editMessage() const
1119 {
1120         return _("Math editor mode");
1121 }
1122
1123
1124 void MathHullInset::getCursorDim(int & asc, int & desc) const
1125 {
1126         asc = 10;
1127         desc = 2;
1128         //math_font_max_dim(font_, asc, des);
1129 }
1130
1131
1132 void MathHullInset::revealCodes(LCursor & cur) const
1133 {
1134         if (!cur.inMathed())
1135                 return;
1136         ostringstream os;
1137         cur.info(os);
1138         cur.message(os.str());
1139 /*
1140         // write something to the minibuffer
1141         // translate to latex
1142         cur.markInsert(bv);
1143         ostringstream os;
1144         write(NULL, os);
1145         string str = os.str();
1146         cur.markErase(bv);
1147         string::size_type pos = 0;
1148         string res;
1149         for (string::iterator it = str.begin(); it != str.end(); ++it) {
1150                 if (*it == '\n')
1151                         res += ' ';
1152                 else if (*it == '\0') {
1153                         res += "  -X-  ";
1154                         pos = it - str.begin();
1155                 }
1156                 else
1157                         res += *it;
1158         }
1159         if (pos > 30)
1160                 res = res.substr(pos - 30);
1161         if (res.size() > 60)
1162                 res = res.substr(0, 60);
1163         cur.message(res);
1164 */
1165 }
1166
1167
1168 InsetBase::Code MathHullInset::lyxCode() const
1169 {
1170         return MATH_CODE;
1171 }
1172
1173
1174 /////////////////////////////////////////////////////////////////////
1175
1176
1177 #if 0
1178 bool MathHullInset::searchForward(BufferView * bv, string const & str,
1179                                      bool, bool)
1180 {
1181 #ifdef WITH_WARNINGS
1182 #warning completely broken
1183 #endif
1184         static MathHullInset * lastformula = 0;
1185         static CursorBase current = DocIterator(ibegin(nucleus()));
1186         static MathArray ar;
1187         static string laststr;
1188
1189         if (lastformula != this || laststr != str) {
1190                 //lyxerr << "reset lastformula to " << this << endl;
1191                 lastformula = this;
1192                 laststr = str;
1193                 current = ibegin(nucleus());
1194                 ar.clear();
1195                 mathed_parse_cell(ar, str);
1196         } else {
1197                 increment(current);
1198         }
1199         //lyxerr << "searching '" << str << "' in " << this << ar << endl;
1200
1201         for (DocIterator it = current; it != iend(nucleus()); increment(it)) {
1202                 CursorSlice & top = it.back();
1203                 MathArray const & a = top.asMathInset()->cell(top.idx_);
1204                 if (a.matchpart(ar, top.pos_)) {
1205                         bv->cursor().setSelection(it, ar.size());
1206                         current = it;
1207                         top.pos_ += ar.size();
1208                         bv->update();
1209                         return true;
1210                 }
1211         }
1212
1213         //lyxerr << "not found!" << endl;
1214         lastformula = 0;
1215         return false;
1216 }
1217 #endif
1218
1219
1220 void MathHullInset::write(Buffer const &, std::ostream & os) const
1221 {
1222         WriteStream wi(os, false, false);
1223         os << "Formula ";
1224         write(wi);
1225 }
1226
1227
1228 void MathHullInset::read(Buffer const &, LyXLex & lex)
1229 {
1230         MathAtom at;
1231         mathed_parse_normal(at, lex);
1232         operator=(*at->asHullInset());
1233 }
1234
1235
1236 int MathHullInset::plaintext(Buffer const &, ostream & os,
1237                         OutputParams const &) const
1238 {
1239         if (0 && display()) {
1240                 Dimension dim;
1241                 TextMetricsInfo mi;
1242                 metricsT(mi, dim);
1243                 TextPainter tpain(dim.width(), dim.height());
1244                 drawT(tpain, 0, dim.ascent());
1245                 tpain.show(os, 3);
1246                 // reset metrics cache to "real" values
1247                 //metrics();
1248                 return tpain.textheight();
1249         } else {
1250                 WriteStream wi(os, false, true);
1251                 wi << ' ' << cell(0) << ' ';
1252                 return wi.line();
1253         }
1254 }
1255
1256
1257 int MathHullInset::linuxdoc(Buffer const & buf, ostream & os,
1258                            OutputParams const & runparams) const
1259 {
1260         return docbook(buf, os, runparams);
1261 }
1262
1263
1264 int MathHullInset::docbook(Buffer const & buf, ostream & os,
1265                           OutputParams const & runparams) const
1266 {
1267         MathMLStream ms(os);
1268         int res = 0;
1269         string name;
1270         if (getType() == "simple")
1271                 name= "inlineequation";
1272         else
1273                 name = "informalequation";
1274
1275         string bname = name;    
1276         if (! label(0).empty()) bname += " id=\"" + label(0)+ "\"";
1277         ms << MTag(bname.c_str());
1278
1279         if (runparams.flavor == OutputParams::XML) {
1280                 ms <<   MTag("math");
1281                 MathGridInset::mathmlize(ms);
1282                 ms <<   ETag("math");
1283         } else {
1284                 ms <<   MTag("alt");
1285                 res = latex(buf, ms.os(), runparams);
1286                 ms <<   ETag("alt");
1287         }
1288         
1289         ms << ETag(name.c_str());
1290         return ms.line() + res;
1291 }