]> git.lyx.org Git - features.git/blob - src/mathed/math_hullinset.C
the dispatch patch
[features.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_hullinset.h"
14 #include "math_mathmlstream.h"
15 #include "math_streamstr.h"
16 #include "math_cursor.h"
17 #include "math_support.h"
18 #include "math_extern.h"
19 #include "math_charinset.h"
20 #include "textpainter.h"
21 #include "debug.h"
22 #include "funcrequest.h"
23 #include "gettext.h"
24 #include "LaTeXFeatures.h"
25 #include "LColor.h"
26 #include "lyxrc.h"
27
28 #include "frontends/Alert.h"
29
30 #include "support/std_sstream.h"
31
32
33 using lyx::support::trim;
34
35 using std::endl;
36 using std::max;
37
38 using std::string;
39 using std::auto_ptr;
40 using std::istringstream;
41 using std::ostringstream;
42 using std::pair;
43
44
45 namespace {
46
47         int getCols(string const & type)
48         {
49                 if (type == "eqnarray")
50                         return 3;
51                 if (type == "align")
52                         return 2;
53                 if (type == "flalign")
54                         return 2;
55                 if (type == "alignat")
56                         return 2;
57                 if (type == "xalignat")
58                         return 2;
59                 if (type == "xxalignat")
60                         return 2;
61                 return 1;
62         }
63
64
65         // returns position of first relation operator in the array
66         // used for "intelligent splitting"
67         MathArray::size_type firstRelOp(MathArray const & ar)
68         {
69                 for (MathArray::const_iterator it = ar.begin(); it != ar.end(); ++it)
70                         if ((*it)->isRelOp())
71                                 return it - ar.begin();
72                 return ar.size();
73         }
74
75
76         char const * star(bool numbered)
77         {
78                 return numbered ? "" : "*";
79         }
80
81
82         int typecode(string const & s)
83         {
84                 if (s == "none")      return 0;
85                 if (s == "simple")    return 1;
86                 if (s == "equation")  return 2;
87                 if (s == "eqnarray")  return 3;
88                 if (s == "align")     return 4;
89                 if (s == "alignat")   return 5;
90                 if (s == "xalignat")  return 6;
91                 if (s == "xxalignat") return 7;
92                 if (s == "multline")  return 8;
93                 if (s == "gather")    return 9;
94                 if (s == "flalign")   return 10;
95                 lyxerr << "unknown hull type '" << s << "'" << endl;
96                 return 0;
97         }
98
99         bool smaller(string const & s, string const & t)
100         {
101                 return typecode(s) < typecode(t);
102         }
103
104
105 } // end anon namespace
106
107
108 MathHullInset::MathHullInset()
109         : MathGridInset(1, 1), type_("none"), nonum_(1), label_(1)
110 {
111         setDefaults();
112 }
113
114
115 MathHullInset::MathHullInset(string const & type)
116         : MathGridInset(getCols(type), 1), type_(type), nonum_(1), label_(1)
117 {
118         setDefaults();
119 }
120
121
122 auto_ptr<InsetBase> MathHullInset::clone() const
123 {
124         return auto_ptr<InsetBase>(new MathHullInset(*this));
125 }
126
127
128 MathInset::mode_type MathHullInset::currentMode() const
129 {
130         if (type_ == "none")
131                 return UNDECIDED_MODE;
132         // definitely math mode ...
133         return MATH_MODE;
134 }
135
136
137 bool MathHullInset::idxFirst(idx_type & idx, pos_type & pos) const
138 {
139         idx = 0;
140         pos = 0;
141         return true;
142 }
143
144
145 bool MathHullInset::idxLast(idx_type & idx, pos_type & pos) const
146 {
147         idx = nargs() - 1;
148         pos = cell(idx).size();
149         return true;
150 }
151
152
153 char MathHullInset::defaultColAlign(col_type col)
154 {
155         if (type_ == "eqnarray")
156                 return "rcl"[col];
157         if (typecode(type_) >= typecode("align"))
158                 return "rl"[col & 1];
159         return 'c';
160 }
161
162
163 int MathHullInset::defaultColSpace(col_type col)
164 {
165         if (type_ == "align" || type_ == "alignat")
166                 return 0;
167         if (type_ == "xalignat")
168                 return (col & 1) ? 20 : 0;
169         if (type_ == "xxalignat" || type_ == "flalign")
170                 return (col & 1) ? 40 : 0;
171         return 0;
172 }
173
174
175 char const * MathHullInset::standardFont() const
176 {
177         if (type_ == "none")
178                 return "lyxnochange";
179         return "mathnormal";
180 }
181
182
183 void MathHullInset::metrics(MetricsInfo & mi, Dimension & dim) const
184 {
185         FontSetChanger dummy1(mi.base, standardFont());
186         StyleChanger dummy2(mi.base, display() ? LM_ST_DISPLAY : LM_ST_TEXT);
187
188         // let the cells adjust themselves
189         MathGridInset::metrics(mi);
190
191         if (display()) {
192                 dim_.asc += 12;
193                 dim_.des += 12;
194         }
195
196         if (numberedType()) {
197                 FontSetChanger dummy(mi.base, "mathbf");
198                 int l = 0;
199                 for (row_type row = 0; row < nrows(); ++row)
200                         l = max(l, mathed_string_width(mi.base.font, nicelabel(row)));
201
202                 if (l)
203                         dim_.wid += 30 + l;
204         }
205
206         // make it at least as high as the current font
207         int asc = 0;
208         int des = 0;
209         math_font_max_dim(mi.base.font, asc, des);
210         dim_.asc = max(dim_.asc, asc);
211         dim_.des = max(dim_.des, des);
212
213         // for markers
214         metricsMarkers2();
215         dim = dim_;
216 }
217
218
219 void MathHullInset::draw(PainterInfo & pi, int x, int y) const
220 {
221         FontSetChanger dummy1(pi.base, standardFont());
222         StyleChanger dummy2(pi.base, display() ? LM_ST_DISPLAY : LM_ST_TEXT);
223         MathGridInset::draw(pi, x + 1, y);
224
225         if (numberedType()) {
226                 int const xx = x + colinfo_.back().offset_ + colinfo_.back().width_ + 20;
227                 for (row_type row = 0; row < nrows(); ++row) {
228                         int const yy = y + rowinfo_[row].offset_;
229                         FontSetChanger dummy(pi.base, "mathrm");
230                         drawStr(pi, pi.base.font, xx, yy, nicelabel(row));
231                 }
232         }
233
234         drawMarkers2(pi, x, y);
235 }
236
237
238 void MathHullInset::metricsT(TextMetricsInfo const & mi, Dimension & dim) const
239 {
240         if (display()) {
241                 MathGridInset::metricsT(mi, dim);
242         } else {
243                 ostringstream os;
244                 WriteStream wi(os, false, true);
245                 write(wi);
246                 dim.wid = os.str().size();
247                 dim.asc = 1;
248                 dim.des = 0;
249         }
250 }
251
252
253 void MathHullInset::drawT(TextPainter & pain, int x, int y) const
254 {
255         if (display()) {
256                 MathGridInset::drawT(pain, x, y);
257         } else {
258                 ostringstream os;
259                 WriteStream wi(os, false, true);
260                 write(wi);
261                 pain.draw(x, y, os.str().c_str());
262         }
263 }
264
265
266 string MathHullInset::label(row_type row) const
267 {
268         row_type n = nrows();
269         BOOST_ASSERT(row < n);
270         return label_[row];
271 }
272
273
274 void MathHullInset::label(row_type row, string const & label)
275 {
276         //lyxerr << "setting label '" << label << "' for row " << row << endl;
277         label_[row] = label;
278 }
279
280
281 void MathHullInset::numbered(row_type row, bool num)
282 {
283         nonum_[row] = !num;
284 }
285
286
287 bool MathHullInset::numbered(row_type row) const
288 {
289         return !nonum_[row];
290 }
291
292
293 bool MathHullInset::ams() const
294 {
295         return
296                 type_ == "align" ||
297                 type_ == "flalign" ||
298                 type_ == "multline" ||
299                 type_ == "gather" ||
300                 type_ == "alignat" ||
301                 type_ == "xalignat" ||
302                 type_ == "xxalignat";
303 }
304
305
306 bool MathHullInset::display() const
307 {
308         return type_ != "simple" && type_ != "none";
309 }
310
311
312 void MathHullInset::getLabelList(Buffer const &,
313                                  std::vector<string> & labels) const
314 {
315         for (row_type row = 0; row < nrows(); ++row)
316                 if (!label_[row].empty() && nonum_[row] != 1)
317                         labels.push_back(label_[row]);
318 }
319
320
321 bool MathHullInset::numberedType() const
322 {
323         if (type_ == "none")
324                 return false;
325         if (type_ == "simple")
326                 return false;
327         if (type_ == "xxalignat")
328                 return false;
329         for (row_type row = 0; row < nrows(); ++row)
330                 if (!nonum_[row])
331                         return true;
332         return false;
333 }
334
335
336 void MathHullInset::validate(LaTeXFeatures & features) const
337 {
338         if (ams())
339                 features.require("amsmath");
340
341
342         // Validation is necessary only if not using AMS math.
343         // To be safe, we will always run mathedvalidate.
344         //if (features.amsstyle)
345         //  return;
346
347         features.require("boldsymbol");
348         //features.binom      = true;
349
350         MathGridInset::validate(features);
351 }
352
353
354 void MathHullInset::header_write(WriteStream & os) const
355 {
356         bool n = numberedType();
357
358         if (type_ == "none")
359                 ;
360
361         else if (type_ == "simple") {
362                 os << '$';
363                 if (cell(0).empty())
364                         os << ' ';
365         }
366
367         else if (type_ == "equation") {
368                 if (n)
369                         os << "\\begin{equation" << star(n) << "}\n";
370                 else
371                         os << "\\[\n";
372         }
373
374         else if (type_ == "eqnarray" || type_ == "align" || type_ == "flalign"
375                  || type_ == "gather" || type_ == "multline")
376                         os << "\\begin{" << type_ << star(n) << "}\n";
377
378         else if (type_ == "alignat" || type_ == "xalignat")
379                 os << "\\begin{" << type_ << star(n) << '}'
380                   << '{' << static_cast<unsigned int>((ncols() + 1)/2) << "}\n";
381
382         else if (type_ == "xxalignat")
383                 os << "\\begin{" << type_ << '}'
384                   << '{' << static_cast<unsigned int>((ncols() + 1)/2) << "}\n";
385
386         else
387                 os << "\\begin{unknown" << star(n) << '}';
388 }
389
390
391 void MathHullInset::footer_write(WriteStream & os) const
392 {
393         bool n = numberedType();
394
395         if (type_ == "none")
396                 os << "\n";
397
398         else if (type_ == "simple")
399                 os << '$';
400
401         else if (type_ == "equation")
402                 if (n)
403                         os << "\\end{equation" << star(n) << "}\n";
404                 else
405                         os << "\\]\n";
406
407         else if (type_ == "eqnarray" || type_ == "align" || type_ == "flalign"
408                  || type_ == "alignat" || type_ == "xalignat"
409                  || type_ == "gather" || type_ == "multline")
410                 os << "\\end{" << type_ << star(n) << "}\n";
411
412         else if (type_ == "xxalignat")
413                 os << "\\end{" << type_ << "}\n";
414
415         else
416                 os << "\\end{unknown" << star(n) << '}';
417 }
418
419
420 bool MathHullInset::colChangeOK() const
421 {
422         return
423                 type_ == "align" || type_ == "flalign" ||type_ == "alignat" ||
424                 type_ == "xalignat" || type_ == "xxalignat";
425 }
426
427
428 void MathHullInset::addRow(row_type row)
429 {
430         nonum_.insert(nonum_.begin() + row + 1, !numberedType());
431         label_.insert(label_.begin() + row + 1, string());
432         MathGridInset::addRow(row);
433 }
434
435
436 void MathHullInset::swapRow(row_type row)
437 {
438         if (nrows() == 1)
439                 return;
440         if (row + 1 == nrows())
441                 --row;
442         std::swap(nonum_[row], nonum_[row + 1]);
443         std::swap(label_[row], label_[row + 1]);
444         MathGridInset::swapRow(row);
445 }
446
447
448 void MathHullInset::delRow(row_type row)
449 {
450         if (nrows() <= 1)
451                 return;
452         MathGridInset::delRow(row);
453         nonum_.erase(nonum_.begin() + row);
454         label_.erase(label_.begin() + row);
455 }
456
457
458 void MathHullInset::addCol(col_type col)
459 {
460         if (colChangeOK())
461                 MathGridInset::addCol(col);
462         else
463                 lyxerr << "Can't change number of columns in '" << type_ << "'" << endl;
464 }
465
466
467 void MathHullInset::delCol(col_type col)
468 {
469         if (colChangeOK())
470                 MathGridInset::delCol(col);
471         else
472                 lyxerr << "Can't change number of columns in '" << type_ << "'" << endl;
473 }
474
475
476 string MathHullInset::nicelabel(row_type row) const
477 {
478         if (nonum_[row])
479                 return string();
480         if (label_[row].empty())
481                 return string("(#)");
482         return '(' + label_[row] + ')';
483 }
484
485
486 void MathHullInset::glueall()
487 {
488         MathArray ar;
489         for (idx_type i = 0; i < nargs(); ++i)
490                 ar.append(cell(i));
491         *this = MathHullInset("simple");
492         cell(0) = ar;
493         setDefaults();
494 }
495
496
497 string const & MathHullInset::getType() const
498 {
499         return type_;
500 }
501
502
503 void MathHullInset::setType(string const & type)
504 {
505         type_ = type;
506         setDefaults();
507 }
508
509
510
511 void MathHullInset::mutate(string const & newtype)
512 {
513         //lyxerr << "mutating from '" << type_ << "' to '" << newtype << "'" << endl;
514
515         // we try to move along the chain
516         // none <-> simple <-> equation <-> eqnarray
517
518         if (newtype == "dump") {
519                 dump();
520         }
521
522         else if (newtype == type_) {
523                 // done
524         }
525
526         else if (type_ == "none") {
527                 setType("simple");
528                 numbered(0, false);
529                 mutate(newtype);
530         }
531
532         else if (type_ == "simple") {
533                 if (newtype == "none") {
534                         setType("none");
535                 } else {
536                         setType("equation");
537                         numbered(0, false);
538                         mutate(newtype);
539                 }
540         }
541
542         else if (type_ == "equation") {
543                 if (smaller(newtype, type_)) {
544                         setType("simple");
545                         mutate(newtype);
546                 } else if (newtype == "eqnarray") {
547                         MathGridInset::addCol(1);
548                         MathGridInset::addCol(1);
549
550                         // split it "nicely" on the firest relop
551                         pos_type pos = firstRelOp(cell(0));
552                         cell(1) = MathArray(cell(0).begin() + pos, cell(0).end());
553                         cell(0).erase(pos, cell(0).size());
554
555                         if (cell(1).size()) {
556                                 cell(2) = MathArray(cell(1).begin() + 1, cell(1).end());
557                                 cell(1).erase(1, cell(1).size());
558                         }
559                         setType("eqnarray");
560                         mutate(newtype);
561                 } else if (newtype == "multline" || newtype == "gather") {
562                         setType(newtype);
563                         numbered(0, false);
564                 } else {
565                         MathGridInset::addCol(1);
566                         // split it "nicely"
567                         pos_type pos = firstRelOp(cell(0));
568                         cell(1) = cell(0);
569                         cell(0).erase(pos, cell(0).size());
570                         cell(1).erase(0, pos);
571                         setType("align");
572                         mutate(newtype);
573                 }
574         }
575
576         else if (type_ == "eqnarray") {
577                 if (smaller(newtype, type_)) {
578                         // set correct (no)numbering
579                         bool allnonum = true;
580                         for (row_type row = 0; row < nrows(); ++row)
581                                 if (!nonum_[row])
582                                         allnonum = false;
583
584                         // set first non-empty label
585                         string label;
586                         for (row_type row = 0; row < nrows(); ++row) {
587                                 if (!label_[row].empty()) {
588                                         label = label_[row];
589                                         break;
590                                 }
591                         }
592
593                         glueall();
594                         nonum_[0] = allnonum;
595                         label_[0] = label;
596                         mutate(newtype);
597                 } else { // align & Co.
598                         for (row_type row = 0; row < nrows(); ++row) {
599                                 idx_type c = 3 * row + 1;
600                                 cell(c).append(cell(c + 1));
601                         }
602                         MathGridInset::delCol(2);
603                         setType("align");
604                         mutate(newtype);
605                 }
606         }
607
608         else if (type_ == "align") {
609                 if (smaller(newtype, type_)) {
610                         MathGridInset::addCol(1);
611                         setType("eqnarray");
612                         mutate(newtype);
613                 } else {
614                         setType(newtype);
615                 }
616         }
617
618         else if (type_ == "multline") {
619                 if (newtype == "gather" || newtype == "align" ||
620                     newtype == "xalignat" || newtype == "xxalignat" || newtype == "flalign")
621                         setType(newtype);
622                 else if (newtype == "eqnarray") {
623                         MathGridInset::addCol(1);
624                         MathGridInset::addCol(1);
625                         setType("eqnarray");
626                 } else {
627                         lyxerr << "mutation from '" << type_
628                                 << "' to '" << newtype << "' not implemented" << endl;
629                 }
630         }
631
632         else if (type_ == "gather") {
633                 if (newtype == "multline") {
634                         setType("multline");
635                 } else {
636                         lyxerr << "mutation from '" << type_
637                                 << "' to '" << newtype << "' not implemented" << endl;
638                 }
639         }
640
641         else {
642                 lyxerr << "mutation from '" << type_
643                                          << "' to '" << newtype << "' not implemented" << endl;
644         }
645 }
646
647
648 string MathHullInset::eolString(row_type row, bool fragile) const
649 {
650         string res;
651         if (numberedType()) {
652                 if (!label_[row].empty() && !nonum_[row])
653                         res += "\\label{" + label_[row] + '}';
654                 if (nonum_[row] && (type_ != "multline"))
655                         res += "\\nonumber ";
656         }
657         return res + MathGridInset::eolString(row, fragile);
658 }
659
660
661 void MathHullInset::write(WriteStream & os) const
662 {
663         header_write(os);
664         MathGridInset::write(os);
665         footer_write(os);
666 }
667
668
669 void MathHullInset::normalize(NormalStream & os) const
670 {
671         os << "[formula " << type_ << ' ';
672         MathGridInset::normalize(os);
673         os << "] ";
674 }
675
676
677 void MathHullInset::mathmlize(MathMLStream & os) const
678 {
679         MathGridInset::mathmlize(os);
680 }
681
682
683 void MathHullInset::infoize(std::ostream & os) const
684 {
685         os << "Type: " << type_;
686 }
687
688
689 void MathHullInset::check() const
690 {
691         BOOST_ASSERT(nonum_.size() == nrows());
692         BOOST_ASSERT(label_.size() == nrows());
693 }
694
695
696 void MathHullInset::doExtern
697         (FuncRequest const & func, idx_type & idx, pos_type & pos)
698 {
699         string lang;
700         string extra;
701         istringstream iss(func.argument.c_str());
702         iss >> lang >> extra;
703         if (extra.empty())
704                 extra = "noextra";
705
706 #ifdef WITH_WARNINGS
707 #warning temporarily disabled
708         //if (selection()) {
709         //      MathArray ar;
710         //      selGet(ar);
711         //      lyxerr << "use selection: " << ar << endl;
712         //      insert(pipeThroughExtern(lang, extra, ar));
713         //      return;
714         //}
715 #endif
716
717         MathArray eq;
718         eq.push_back(MathAtom(new MathCharInset('=')));
719
720         // go to first item in line
721         idx -= idx % ncols();
722         pos = 0;
723
724         if (getType() == "simple") {
725                 size_type pos = cell(idx).find_last(eq);
726                 MathArray ar;
727                 if (mathcursor && mathcursor->selection()) {
728                         asArray(mathcursor->grabAndEraseSelection(), ar);
729                 } else if (pos == cell(idx).size()) {
730                         ar = cell(idx);
731                         lyxerr << "use whole cell: " << ar << endl;
732                 } else {
733                         ar = MathArray(cell(idx).begin() + pos + 1, cell(idx).end());
734                         lyxerr << "use partial cell form pos: " << pos << endl;
735                 }
736                 cell(idx).append(eq);
737                 cell(idx).append(pipeThroughExtern(lang, extra, ar));
738                 pos = cell(idx).size();
739                 return;
740         }
741
742         if (getType() == "equation") {
743                 lyxerr << "use equation inset" << endl;
744                 mutate("eqnarray");
745                 MathArray & ar = cell(idx);
746                 lyxerr << "use cell: " << ar << endl;
747                 cell(idx + 1) = eq;
748                 cell(idx + 2) = pipeThroughExtern(lang, extra, ar);
749                 // move to end of line
750                 idx += 2;
751                 pos = cell(idx).size();
752                 return;
753         }
754
755         {
756                 lyxerr << "use eqnarray" << endl;
757                 idx -= idx % ncols();
758                 idx += 2;
759                 pos = 0;
760                 MathArray ar = cell(idx);
761                 lyxerr << "use cell: " << ar << endl;
762 #ifdef WITH_WARNINGS
763 #warning temporarily disabled
764 #endif
765                 addRow(row(idx));
766                 cell(idx + 2) = eq;
767                 cell(idx + 3) = pipeThroughExtern(lang, extra, ar);
768                 idx += 3;
769                 pos = cell(idx).size();
770         }
771 }
772
773
774 dispatch_result MathHullInset::dispatch
775         (FuncRequest const & cmd, idx_type & idx, pos_type & pos)
776 {
777         switch (cmd.action) {
778
779                 case LFUN_BREAKLINE:
780                         if (type_ == "simple" || type_ == "equation") {
781                                 mutate("eqnarray");
782                                 idx = 1;
783                                 pos = 0;
784                                 return DISPATCHED_POP;
785                         }
786                         return MathGridInset::priv_dispatch(cmd, idx, pos);
787
788                 case LFUN_MATH_NUMBER:
789                         //lyxerr << "toggling all numbers" << endl;
790                         if (display()) {
791                                 //recordUndo(bv, Undo::INSERT);
792                                 bool old = numberedType();
793                                 if (type_ == "multline")
794                                         numbered(nrows() - 1, !old);
795                                 else
796                                         for (row_type row = 0; row < nrows(); ++row)
797                                                 numbered(row, !old);
798                                 //bv->owner()->message(old ? _("No number") : _("Number"));
799                         }
800                         return DISPATCHED;
801
802                 case LFUN_MATH_NONUMBER:
803                         if (display()) {
804                                 row_type r = (type_ == "multline") ? nrows() - 1 : row(idx);
805                                 //recordUndo(bv, Undo::INSERT);
806                                 bool old = numbered(r);
807                                 //bv->owner()->message(old ? _("No number") : _("Number"));
808                                 numbered(r, !old);
809                         }
810                         return DISPATCHED;
811
812                 case LFUN_INSERT_LABEL: {
813                         row_type r = (type_ == "multline") ? nrows() - 1 : row(idx);
814                         string old_label = label(r);
815                         string new_label = cmd.argument;
816
817                         if (new_label.empty()) {
818                                 string const default_label =
819                                         (lyxrc.label_init_length >= 0) ? "eq:" : "";
820                                 pair<bool, string> const res = old_label.empty()
821                                         ? Alert::askForText(_("Enter new label to insert:"), default_label)
822                                         : Alert::askForText(_("Enter label:"), old_label);
823                                 if (!res.first)
824                                         return UNDISPATCHED;
825                                 new_label = trim(res.second);
826                         }
827
828                         //if (new_label == old_label)
829                         //      break;  // Nothing to do
830
831                         if (!new_label.empty())
832                                 numbered(r, true);
833                         label(r, new_label);
834                         return DISPATCHED;
835                 }
836
837                 case LFUN_MATH_EXTERN:
838                         doExtern(cmd, idx, pos);
839                         return DISPATCHED_POP;
840
841                 case LFUN_MATH_MUTATE: {
842                         row_type r = row(idx);
843                         col_type c = col(idx);
844                         mutate(cmd.argument);
845                         idx = r * ncols() + c;
846                         if (idx >= nargs())
847                                 idx = nargs() - 1;
848                         if (pos > cell(idx).size())
849                                 pos = cell(idx).size();
850                         return DISPATCHED_POP;
851                 }
852
853                 case LFUN_MATH_DISPLAY: {
854                         mutate(type_ == "simple" ? "equation" : "simple");
855                         idx = 0;
856                         pos = cell(idx).size();
857                         return DISPATCHED_POP;
858                 }
859
860                 default:
861                         return MathGridInset::priv_dispatch(cmd, idx, pos);
862         }
863 }
864
865
866 string MathHullInset::fileInsetLabel() const
867 {
868         return "Formula";
869 }