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