]> git.lyx.org Git - lyx.git/blob - src/mathed/math_hullinset.C
c_str fixes
[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 void MathHullInset::splitTo2Cols()
611 {
612         BOOST_ASSERT(ncols() == 1);
613         MathGridInset::addCol(1);
614         for (row_type row = 0; row < nrows(); ++row) {
615                 idx_type const i = 2 * row;
616                 pos_type pos = firstRelOp(cell(i));
617                 cell(i + 1) = MathArray(cell(i).begin() + pos, cell(i).end());
618                 cell(i).erase(pos, cell(i).size());
619         }
620 }
621
622
623 void MathHullInset::splitTo3Cols()
624 {
625         BOOST_ASSERT(ncols() < 3);
626         if (ncols() < 2)
627                 splitTo2Cols();
628         MathGridInset::addCol(1);
629         for (row_type row = 0; row < nrows(); ++row) {
630                 idx_type const i = 3 * row + 1;
631                 if (cell(i).size()) {
632                         cell(i + 1) = MathArray(cell(i).begin() + 1, cell(i).end());
633                         cell(i).erase(1, cell(i).size());
634                 }
635         }
636 }
637
638
639 void MathHullInset::changeCols(col_type cols)
640 {
641         if (ncols() == cols)
642                 return;
643         else if (ncols() < cols) {
644                 // split columns
645                 if (cols < 3)
646                         splitTo2Cols();
647                 else {
648                         splitTo3Cols();
649                         while (ncols() < cols)
650                                 MathGridInset::addCol(ncols() - 1);
651                 }
652                 return;
653         }
654
655         // combine columns
656         for (row_type row = 0; row < nrows(); ++row) {
657                 idx_type const i = row * ncols();
658                 for (col_type col = cols; col < ncols(); ++col) {
659                         cell(i + cols - 1).append(cell(i + col));
660                 }
661         }
662         // delete columns
663         while (ncols() > cols) {
664                 MathGridInset::delCol(ncols() - 1);
665         }
666 }
667
668
669 string const & MathHullInset::getType() const
670 {
671         return type_;
672 }
673
674
675 void MathHullInset::setType(string const & type)
676 {
677         type_ = type;
678         setDefaults();
679 }
680
681
682
683 void MathHullInset::mutate(string const & newtype)
684 {
685         lyxerr << "mutating from '" << type_ << "' to '" << newtype << "'" << endl;
686
687         // we try to move along the chain
688         // none <-> simple <-> equation <-> eqnarray -> *align* -> multline, gather -+
689         //                                     ^                                     |
690         //                                     +-------------------------------------+
691         // we use eqnarray as intermediate type for mutations that are not
692         // directly supported because it handles labels and numbering for
693         // "down mutation".
694
695         if (newtype == "dump") {
696                 dump();
697         }
698
699         else if (newtype == type_) {
700                 // done
701         }
702
703         else if (type_ == "none") {
704                 setType("simple");
705                 numbered(0, false);
706                 mutate(newtype);
707         }
708
709         else if (type_ == "simple") {
710                 if (newtype == "none") {
711                         setType("none");
712                         numbered(0, false);
713                 } else {
714                         setType("equation");
715                         numbered(0, false);
716                         mutate(newtype);
717                 }
718         }
719
720         else if (type_ == "equation") {
721                 if (smaller(newtype, type_)) {
722                         setType("simple");
723                         numbered(0, false);
724                         mutate(newtype);
725                 } else if (newtype == "eqnarray") {
726                         // split it "nicely" on the first relop
727                         splitTo3Cols();
728                         setType("eqnarray");
729                 } else if (newtype == "multline" || newtype == "gather") {
730                         setType(newtype);
731                 } else {
732                         // split it "nicely"
733                         splitTo2Cols();
734                         setType("align");
735                         mutate(newtype);
736                 }
737         }
738
739         else if (type_ == "eqnarray") {
740                 if (smaller(newtype, type_)) {
741                         // set correct (no)numbering
742                         bool allnonum = true;
743                         for (row_type row = 0; row < nrows(); ++row)
744                                 if (!nonum_[row])
745                                         allnonum = false;
746
747                         // set first non-empty label
748                         string label;
749                         for (row_type row = 0; row < nrows(); ++row) {
750                                 if (!label_[row].empty()) {
751                                         label = label_[row];
752                                         break;
753                                 }
754                         }
755
756                         glueall();
757                         nonum_[0] = allnonum;
758                         label_[0] = label;
759                         mutate(newtype);
760                 } else { // align & Co.
761                         changeCols(2);
762                         setType("align");
763                         mutate(newtype);
764                 }
765         }
766
767         else if (type_ ==  "align"   || type_ == "alignat" ||
768                  type_ == "xalignat" || type_ == "flalign") {
769                 if (smaller(newtype, "align")) {
770                         changeCols(3);
771                         setType("eqnarray");
772                         mutate(newtype);
773                 } else if (newtype == "gather" || newtype == "multline") {
774                         changeCols(1);
775                         setType(newtype);
776                 } else if (newtype ==   "xxalignat") {
777                         for (row_type row = 0; row < nrows(); ++row)
778                                 numbered(row, false);
779                         setType(newtype);
780                 } else {
781                         setType(newtype);
782                 }
783         }
784
785         else if (type_ == "xxalignat") {
786                 for (row_type row = 0; row < nrows(); ++row)
787                         numbered(row, false);
788                 if (smaller(newtype, "align")) {
789                         changeCols(3);
790                         setType("eqnarray");
791                         mutate(newtype);
792                 } else if (newtype == "gather" || newtype == "multline") {
793                         changeCols(1);
794                         setType(newtype);
795                 } else {
796                         setType(newtype);
797                 }
798         }
799
800         else if (type_ == "multline" || type_ == "gather") {
801                 if (newtype == "gather" || newtype == "multline")
802                         setType(newtype);
803                 else if (newtype ==   "align"   || newtype == "flalign"  ||
804                          newtype ==   "alignat" || newtype == "xalignat") {
805                         splitTo2Cols();
806                         setType(newtype);
807                 } else if (newtype ==   "xxalignat") {
808                         splitTo2Cols();
809                         for (row_type row = 0; row < nrows(); ++row)
810                                 numbered(row, false);
811                         setType(newtype);
812                 } else {
813                         splitTo3Cols();
814                         setType("eqnarray");
815                         mutate(newtype);
816                 }
817         }
818
819         else {
820                 lyxerr << "mutation from '" << type_
821                        << "' to '" << newtype << "' not implemented" << endl;
822         }
823 }
824
825
826 string MathHullInset::eolString(row_type row, bool fragile) const
827 {
828         string res;
829         if (numberedType()) {
830                 if (!label_[row].empty() && !nonum_[row])
831                         res += "\\label{" + label_[row] + '}';
832                 if (nonum_[row] && (type_ != "multline"))
833                         res += "\\nonumber ";
834         }
835         return res + MathGridInset::eolString(row, fragile);
836 }
837
838
839 void MathHullInset::write(WriteStream & os) const
840 {
841         header_write(os);
842         MathGridInset::write(os);
843         footer_write(os);
844 }
845
846
847 void MathHullInset::normalize(NormalStream & os) const
848 {
849         os << "[formula " << type_ << ' ';
850         MathGridInset::normalize(os);
851         os << "] ";
852 }
853
854
855 void MathHullInset::mathmlize(MathMLStream & os) const
856 {
857         MathGridInset::mathmlize(os);
858 }
859
860
861 void MathHullInset::infoize(ostream & os) const
862 {
863         os << "Type: " << type_;
864 }
865
866
867 void MathHullInset::check() const
868 {
869         BOOST_ASSERT(nonum_.size() == nrows());
870         BOOST_ASSERT(label_.size() == nrows());
871 }
872
873
874 void MathHullInset::doExtern(LCursor & cur, FuncRequest & func)
875 {
876         string lang;
877         string extra;
878         istringstream iss(func.argument);
879         iss >> lang >> extra;
880         if (extra.empty())
881                 extra = "noextra";
882
883 #ifdef WITH_WARNINGS
884 #warning temporarily disabled
885         //if (cur.selection()) {
886         //      MathArray ar;
887         //      selGet(cur.ar);
888         //      lyxerr << "use selection: " << ar << endl;
889         //      insert(pipeThroughExtern(lang, extra, ar));
890         //      return;
891         //}
892 #endif
893
894         MathArray eq;
895         eq.push_back(MathAtom(new MathCharInset('=')));
896
897         // go to first item in line
898         cur.idx() -= cur.idx() % ncols();
899         cur.pos() = 0;
900
901         if (getType() == "simple") {
902                 size_type pos = cur.cell().find_last(eq);
903                 MathArray ar;
904                 if (cur.inMathed() && cur.selection()) {
905                         asArray(grabAndEraseSelection(cur), ar);
906                 } else if (pos == cur.cell().size()) {
907                         ar = cur.cell();
908                         lyxerr << "use whole cell: " << ar << endl;
909                 } else {
910                         ar = MathArray(cur.cell().begin() + pos + 1, cur.cell().end());
911                         lyxerr << "use partial cell form pos: " << pos << endl;
912                 }
913                 cur.cell().append(eq);
914                 cur.cell().append(pipeThroughExtern(lang, extra, ar));
915                 cur.pos() = cur.lastpos();
916                 return;
917         }
918
919         if (getType() == "equation") {
920                 lyxerr << "use equation inset" << endl;
921                 mutate("eqnarray");
922                 MathArray & ar = cur.cell();
923                 lyxerr << "use cell: " << ar << endl;
924                 ++cur.idx();
925                 cur.cell() = eq;
926                 ++cur.idx();
927                 cur.cell() = pipeThroughExtern(lang, extra, ar);
928                 // move to end of line
929                 cur.pos() = cur.lastpos();
930                 return;
931         }
932
933         {
934                 lyxerr << "use eqnarray" << endl;
935                 cur.idx() += 2 - cur.idx() % ncols();
936                 cur.pos() = 0;
937                 MathArray ar = cur.cell();
938                 lyxerr << "use cell: " << ar << endl;
939 #ifdef WITH_WARNINGS
940 #warning temporarily disabled
941 #endif
942                 addRow(cur.row());
943                 ++cur.idx();
944                 ++cur.idx();
945                 cur.cell() = eq;
946                 ++cur.idx();
947                 cur.cell() = pipeThroughExtern(lang, extra, ar);
948                 cur.pos() = cur.lastpos();
949         }
950 }
951
952
953 void MathHullInset::priv_dispatch(LCursor & cur, FuncRequest & cmd)
954 {
955         switch (cmd.action) {
956
957         case LFUN_FINISHED_LEFT:
958         case LFUN_FINISHED_RIGHT:
959         case LFUN_FINISHED_UP:
960         case LFUN_FINISHED_DOWN:
961                 MathGridInset::priv_dispatch(cur, cmd);
962                 notifyCursorLeaves(cur);
963                 break;
964
965         case LFUN_BREAKPARAGRAPH:
966                 // just swallow this
967                 break;
968
969         case LFUN_BREAKLINE:
970                 // some magic for the common case
971                 if (type_ == "simple" || type_ == "equation") {
972                         recordUndoInset(cur);
973                         mutate("eqnarray");
974                         cur.idx() = 0;
975                         cur.pos() = cur.lastpos();
976                 }
977                 MathGridInset::priv_dispatch(cur, cmd);
978                 break;
979
980         case LFUN_MATH_NUMBER:
981                 //lyxerr << "toggling all numbers" << endl;
982                 if (display()) {
983                         recordUndoInset(cur);
984                         bool old = numberedType();
985                         if (type_ == "multline")
986                                 numbered(nrows() - 1, !old);
987                         else
988                                 for (row_type row = 0; row < nrows(); ++row)
989                                         numbered(row, !old);
990                         cur.message(old ? _("No number") : _("Number"));
991                 }
992                 break;
993
994         case LFUN_MATH_NONUMBER:
995                 if (display()) {
996                         recordUndoInset(cur);
997                         row_type r = (type_ == "multline") ? nrows() - 1 : cur.row();
998                         bool old = numbered(r);
999                         cur.message(old ? _("No number") : _("Number"));
1000                         numbered(r, !old);
1001                 }
1002                 break;
1003
1004         case LFUN_INSERT_LABEL: {
1005                 recordUndoInset(cur);
1006                 row_type r = (type_ == "multline") ? nrows() - 1 : cur.row();
1007                 string old_label = label(r);
1008                 string new_label = cmd.argument;
1009
1010                 if (new_label.empty()) {
1011                         string const default_label =
1012                                 (lyxrc.label_init_length >= 0) ? "eq:" : "";
1013                         pair<bool, string> const res = old_label.empty()
1014                                 ? Alert::askForText(_("Enter new label to insert:"), default_label)
1015                                 : Alert::askForText(_("Enter label:"), old_label);
1016                         if (res.first)
1017                                 new_label = lyx::support::trim(res.second);
1018                         else
1019                                 new_label = old_label;
1020                 }
1021
1022                 if (!new_label.empty())
1023                         numbered(r, true);
1024                 label(r, new_label);
1025                 break;
1026         }
1027
1028         case LFUN_MATH_EXTERN:
1029                 recordUndoInset(cur);
1030                 doExtern(cur, cmd);
1031                 break;
1032
1033         case LFUN_MATH_MUTATE: {
1034                 recordUndoInset(cur);
1035                 row_type row = cur.row();
1036                 col_type col = cur.col();
1037                 mutate(cmd.argument);
1038                 cur.idx() = row * ncols() + col;
1039                 if (cur.idx() > cur.lastidx()) {
1040                         cur.idx() = cur.lastidx();
1041                         cur.pos() = cur.lastpos();
1042                 }
1043                 if (cur.pos() > cur.lastpos())
1044                         cur.pos() = cur.lastpos();
1045                 //cur.dispatched(FINISHED);
1046                 break;
1047         }
1048
1049         case LFUN_MATH_DISPLAY: {
1050                 recordUndoInset(cur);
1051                 mutate(type_ == "simple" ? "equation" : "simple");
1052                 cur.idx() = 0;
1053                 cur.pos() = cur.lastpos();
1054                 //cur.dispatched(FINISHED);
1055                 break;
1056         }
1057
1058         default:
1059                 MathGridInset::priv_dispatch(cur, cmd);
1060                 break;
1061         }
1062 }
1063
1064
1065 bool MathHullInset::getStatus(LCursor & cur, FuncRequest const & cmd,
1066                 FuncStatus & flag) const
1067 {
1068         switch (cmd.action) {
1069         case LFUN_BREAKLINE:
1070         case LFUN_MATH_NUMBER:
1071         case LFUN_MATH_NONUMBER:
1072         case LFUN_INSERT_LABEL:
1073         case LFUN_MATH_EXTERN:
1074         case LFUN_MATH_MUTATE:
1075         case LFUN_MATH_DISPLAY:
1076                 // we handle these
1077                 return true;
1078         case LFUN_TABULAR_FEATURE: {
1079                 // should be more precise
1080                 istringstream is(cmd.argument);
1081                 string s;
1082                 is >> s;
1083                 if ((type_ == "simple" || type_ == "equation")
1084         && (s == "append-column"
1085          || s == "delete-column"
1086          || s == "swap-column"
1087          || s == "copy-column"
1088          || s == "delete-column"
1089          || s == "append-row"
1090          || s == "delete-row"
1091          || s == "swap-row"
1092          || s == "copy-row"))
1093                         return false;
1094                 if ((type_ == "eqnarray")
1095         && (s == "appen-column"
1096          || s == "delete-column"))
1097                         return false;
1098                 return MathGridInset::getStatus(cur, cmd, flag);
1099         }
1100         default:
1101                 return MathGridInset::getStatus(cur, cmd, flag);
1102         }
1103 }
1104
1105
1106 /////////////////////////////////////////////////////////////////////
1107
1108 #include "math_arrayinset.h"
1109 #include "math_deliminset.h"
1110 #include "math_factory.h"
1111 #include "math_parser.h"
1112 #include "math_spaceinset.h"
1113 #include "ref_inset.h"
1114
1115 #include "bufferview_funcs.h"
1116 #include "lyxtext.h"
1117
1118 #include "frontends/LyXView.h"
1119 #include "frontends/Dialogs.h"
1120
1121 #include "support/lstrings.h"
1122 #include "support/lyxlib.h"
1123
1124
1125 // simply scrap this function if you want
1126 void MathHullInset::mutateToText()
1127 {
1128 #if 0
1129         // translate to latex
1130         ostringstream os;
1131         latex(NULL, os, false, false);
1132         string str = os.str();
1133
1134         // insert this text
1135         LyXText * lt = view_->getLyXText();
1136         string::const_iterator cit = str.begin();
1137         string::const_iterator end = str.end();
1138         for (; cit != end; ++cit)
1139                 view_->owner()->getIntl()->getTransManager().TranslateAndInsert(*cit, lt);
1140
1141         // remove ourselves
1142         //view_->owner()->dispatch(LFUN_ESCAPE);
1143 #endif
1144 }
1145
1146
1147 void MathHullInset::handleFont(LCursor & cur, string const & arg,
1148         string const & font)
1149 {
1150         // this whole function is a hack and won't work for incremental font
1151         // changes...
1152         recordUndo(cur);
1153         if (cur.inset().asMathInset()->name() == font)
1154                 cur.handleFont(font);
1155         else {
1156                 cur.handleNest(createMathInset(font));
1157                 cur.insert(arg);
1158         }
1159 }
1160
1161
1162 void MathHullInset::handleFont2(LCursor & cur, string const & arg)
1163 {
1164         recordUndo(cur);
1165         LyXFont font;
1166         bool b;
1167         bv_funcs::string2font(arg, font, b);
1168         if (font.color() != LColor::inherit) {
1169                 MathAtom at = createMathInset("color");
1170                 asArray(lcolor.getGUIName(font.color()), at.nucleus()->cell(0));
1171                 cur.handleNest(at, 1);
1172         }
1173 }
1174
1175
1176 void MathHullInset::edit(LCursor & cur, bool left)
1177 {
1178         cur.push(*this);
1179         left ? idxFirst(cur) : idxLast(cur);
1180 }
1181
1182
1183 string const MathHullInset::editMessage() const
1184 {
1185         return _("Math editor mode");
1186 }
1187
1188
1189 void MathHullInset::getCursorDim(int & asc, int & desc) const
1190 {
1191         asc = 10;
1192         desc = 2;
1193         //math_font_max_dim(font_, asc, des);
1194 }
1195
1196
1197 void MathHullInset::revealCodes(LCursor & cur) const
1198 {
1199         if (!cur.inMathed())
1200                 return;
1201         ostringstream os;
1202         cur.info(os);
1203         cur.message(os.str());
1204 /*
1205         // write something to the minibuffer
1206         // translate to latex
1207         cur.markInsert(bv);
1208         ostringstream os;
1209         write(NULL, os);
1210         string str = os.str();
1211         cur.markErase(bv);
1212         string::size_type pos = 0;
1213         string res;
1214         for (string::iterator it = str.begin(); it != str.end(); ++it) {
1215                 if (*it == '\n')
1216                         res += ' ';
1217                 else if (*it == '\0') {
1218                         res += "  -X-  ";
1219                         pos = it - str.begin();
1220                 }
1221                 else
1222                         res += *it;
1223         }
1224         if (pos > 30)
1225                 res = res.substr(pos - 30);
1226         if (res.size() > 60)
1227                 res = res.substr(0, 60);
1228         cur.message(res);
1229 */
1230 }
1231
1232
1233 InsetBase::Code MathHullInset::lyxCode() const
1234 {
1235         return MATH_CODE;
1236 }
1237
1238
1239 /////////////////////////////////////////////////////////////////////
1240
1241
1242 #if 0
1243 bool MathHullInset::searchForward(BufferView * bv, string const & str,
1244                                      bool, bool)
1245 {
1246 #ifdef WITH_WARNINGS
1247 #warning completely broken
1248 #endif
1249         static MathHullInset * lastformula = 0;
1250         static CursorBase current = DocIterator(ibegin(nucleus()));
1251         static MathArray ar;
1252         static string laststr;
1253
1254         if (lastformula != this || laststr != str) {
1255                 //lyxerr << "reset lastformula to " << this << endl;
1256                 lastformula = this;
1257                 laststr = str;
1258                 current = ibegin(nucleus());
1259                 ar.clear();
1260                 mathed_parse_cell(ar, str);
1261         } else {
1262                 increment(current);
1263         }
1264         //lyxerr << "searching '" << str << "' in " << this << ar << endl;
1265
1266         for (DocIterator it = current; it != iend(nucleus()); increment(it)) {
1267                 CursorSlice & top = it.back();
1268                 MathArray const & a = top.asMathInset()->cell(top.idx_);
1269                 if (a.matchpart(ar, top.pos_)) {
1270                         bv->cursor().setSelection(it, ar.size());
1271                         current = it;
1272                         top.pos_ += ar.size();
1273                         bv->update();
1274                         return true;
1275                 }
1276         }
1277
1278         //lyxerr << "not found!" << endl;
1279         lastformula = 0;
1280         return false;
1281 }
1282 #endif
1283
1284
1285 void MathHullInset::write(Buffer const &, std::ostream & os) const
1286 {
1287         WriteStream wi(os, false, false);
1288         os << "Formula ";
1289         write(wi);
1290 }
1291
1292
1293 void MathHullInset::read(Buffer const &, LyXLex & lex)
1294 {
1295         MathAtom at;
1296         mathed_parse_normal(at, lex);
1297         operator=(*at->asHullInset());
1298 }
1299
1300
1301 int MathHullInset::plaintext(Buffer const &, ostream & os,
1302                         OutputParams const &) const
1303 {
1304         if (0 && display()) {
1305                 Dimension dim;
1306                 TextMetricsInfo mi;
1307                 metricsT(mi, dim);
1308                 TextPainter tpain(dim.width(), dim.height());
1309                 drawT(tpain, 0, dim.ascent());
1310                 tpain.show(os, 3);
1311                 // reset metrics cache to "real" values
1312                 //metrics();
1313                 return tpain.textheight();
1314         } else {
1315                 WriteStream wi(os, false, true);
1316                 wi << ' ' << cell(0) << ' ';
1317                 return wi.line();
1318         }
1319 }
1320
1321
1322 int MathHullInset::linuxdoc(Buffer const & buf, ostream & os,
1323                            OutputParams const & runparams) const
1324 {
1325         return docbook(buf, os, runparams);
1326 }
1327
1328
1329 int MathHullInset::docbook(Buffer const & buf, ostream & os,
1330                           OutputParams const & runparams) const
1331 {
1332         MathMLStream ms(os);
1333         int res = 0;
1334         string name;
1335         if (getType() == "simple")
1336                 name= "inlineequation";
1337         else
1338                 name = "informalequation";
1339
1340         string bname = name;
1341         if (! label(0).empty()) bname += " id=\"" + label(0)+ "\"";
1342         ms << MTag(bname.c_str());
1343
1344         if (runparams.flavor == OutputParams::XML) {
1345                 ms <<   MTag("math");
1346                 MathGridInset::mathmlize(ms);
1347                 ms <<   ETag("math");
1348         } else {
1349                 ms <<   MTag("alt");
1350                 res = latex(buf, ms.os(), runparams);
1351                 ms <<   ETag("alt");
1352         }
1353
1354         ms << ETag(name.c_str());
1355         return ms.line() + res;
1356 }