]> git.lyx.org Git - lyx.git/blob - src/mathed/InsetMathGrid.cpp
d1d6108fd06cdbb46cbdd1d00d20b025109f5e27
[lyx.git] / src / mathed / InsetMathGrid.cpp
1 /**
2  * \file InsetMathGrid.cpp
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 "InsetMathGrid.h"
14
15 #include "MathData.h"
16 #include "MathParser.h"
17 #include "MathStream.h"
18 #include "MetricsInfo.h"
19
20 #include "BufferView.h"
21 #include "CutAndPaste.h"
22 #include "FuncStatus.h"
23 #include "Cursor.h"
24 #include "support/debug.h"
25 #include "FuncRequest.h"
26 #include "support/gettext.h"
27
28 #include "frontends/Clipboard.h"
29 #include "frontends/Painter.h"
30
31 #include "support/lstrings.h"
32 #include "support/docstream.h"
33
34 #include <sstream>
35
36 using namespace std;
37 using namespace lyx::support;
38
39 namespace lyx {
40
41 namespace {
42
43 docstring verboseHLine(int n)
44 {
45         docstring res;
46         for (int i = 0; i < n; ++i)
47                 res += "\\hline";
48         if (n)
49                 res += ' ';
50         return res;
51 }
52
53
54 int extractInt(istream & is)
55 {
56         int num = 1;
57         is >> num;
58         return (num == 0) ? 1 : num;
59 }
60
61 }
62
63
64 //////////////////////////////////////////////////////////////
65
66
67 InsetMathGrid::CellInfo::CellInfo()
68         : dummy_(false)
69 {}
70
71
72
73
74 //////////////////////////////////////////////////////////////
75
76
77 InsetMathGrid::RowInfo::RowInfo()
78         : lines_(0), skip_(0), allow_newpage_(true)
79 {}
80
81
82
83 int InsetMathGrid::RowInfo::skipPixels() const
84 {
85         return crskip_.inBP();
86 }
87
88
89
90 //////////////////////////////////////////////////////////////
91
92
93 InsetMathGrid::ColInfo::ColInfo()
94         : align_('c'), lines_(0)
95 {}
96
97
98 //////////////////////////////////////////////////////////////
99
100
101 InsetMathGrid::InsetMathGrid(char v, docstring const & h)
102         : InsetMathNest(guessColumns(h)),
103           rowinfo_(2),
104           colinfo_(guessColumns(h) + 1),
105           cellinfo_(1 * guessColumns(h))
106 {
107         setDefaults();
108         valign(v);
109         halign(h);
110         //lyxerr << "created grid with " << ncols() << " columns" << endl;
111 }
112
113
114 InsetMathGrid::InsetMathGrid()
115         : InsetMathNest(1),
116           rowinfo_(1 + 1),
117                 colinfo_(1 + 1),
118                 cellinfo_(1),
119                 v_align_('c')
120 {
121         setDefaults();
122 }
123
124
125 InsetMathGrid::InsetMathGrid(col_type m, row_type n)
126         : InsetMathNest(m * n),
127           rowinfo_(n + 1),
128                 colinfo_(m + 1),
129                 cellinfo_(m * n),
130                 v_align_('c')
131 {
132         setDefaults();
133 }
134
135
136 InsetMathGrid::InsetMathGrid(col_type m, row_type n, char v, docstring const & h)
137         : InsetMathNest(m * n),
138           rowinfo_(n + 1),
139           colinfo_(m + 1),
140                 cellinfo_(m * n),
141                 v_align_(v)
142 {
143         setDefaults();
144         valign(v);
145         halign(h);
146 }
147
148
149 Inset * InsetMathGrid::clone() const
150 {
151         return new InsetMathGrid(*this);
152 }
153
154
155 InsetMath::idx_type InsetMathGrid::index(row_type row, col_type col) const
156 {
157         return col + ncols() * row;
158 }
159
160
161 void InsetMathGrid::setDefaults()
162 {
163         if (ncols() <= 0)
164                 lyxerr << "positive number of columns expected" << endl;
165         //if (nrows() <= 0)
166         //      lyxerr << "positive number of rows expected" << endl;
167         for (col_type col = 0; col < ncols(); ++col) {
168                 colinfo_[col].align_ = defaultColAlign(col);
169                 colinfo_[col].skip_  = defaultColSpace(col);
170                 colinfo_[col].special_.clear();
171         }
172 }
173
174
175 void InsetMathGrid::halign(docstring const & hh)
176 {
177         col_type col = 0;
178         for (docstring::const_iterator it = hh.begin(); it != hh.end(); ++it) {
179                 char_type c = *it;
180                 if (c == '|') {
181                         colinfo_[col].lines_++;
182                 } else if ((c == 'p' || c == 'm' || c == 'b'||
183                             c == '!' || c == '@' || c == '>' || c == '<') &&
184                            it + 1 != hh.end() && *(it + 1) == '{') {
185                         // @{decl.} and p{width} are standard LaTeX, the
186                         // others are extensions by array.sty
187                         bool const newcolumn = c == 'p' || c == 'm' || c == 'b';
188                         if (newcolumn) {
189                                 // this declares a new column
190                                 if (col >= ncols())
191                                         // Only intercolumn stuff is allowed
192                                         // in the last dummy column
193                                         break;
194                                 colinfo_[col].align_ = 'l';
195                         } else {
196                                 // this is intercolumn stuff
197                                 if (colinfo_[col].special_.empty())
198                                         // Overtake possible lines
199                                         colinfo_[col].special_ = docstring(colinfo_[col].lines_, '|');
200                         }
201                         int brace_open = 0;
202                         int brace_close = 0;
203                         while (it != hh.end()) {
204                                 c = *it;
205                                 colinfo_[col].special_ += c;
206                                 if (c == '{')
207                                         ++brace_open;
208                                 else if (c == '}')
209                                         ++brace_close;
210                                 ++it;
211                                 if (brace_open > 0 && brace_open == brace_close)
212                                         break;
213                         }
214                         --it;
215                         if (newcolumn) {
216                                 colinfo_[col].lines_ = count(
217                                         colinfo_[col].special_.begin(),
218                                         colinfo_[col].special_.end(), '|');
219                                 LYXERR(Debug::MATHED, "special column separator: `"
220                                         << to_utf8(colinfo_[col].special_) << '\'');
221                                 ++col;
222                                 colinfo_[col].lines_ = 0;
223                                 colinfo_[col].special_.clear();
224                         }
225                 } else if (col >= ncols()) {
226                         // Only intercolumn stuff is allowed in the last
227                         // dummy column
228                         break;
229                 } else if (c == 'c' || c == 'l' || c == 'r') {
230                         colinfo_[col].align_ = static_cast<char>(c);
231                         if (!colinfo_[col].special_.empty()) {
232                                 colinfo_[col].special_ += c;
233                                 colinfo_[col].lines_ = count(
234                                                 colinfo_[col].special_.begin(),
235                                                 colinfo_[col].special_.end(), '|');
236                                 LYXERR(Debug::MATHED, "special column separator: `"
237                                         << to_utf8(colinfo_[col].special_) << '\'');
238                         }
239                         ++col;
240                         colinfo_[col].lines_ = 0;
241                         colinfo_[col].special_.clear();
242                 } else {
243                         lyxerr << "unknown column separator: '" << c << "'" << endl;
244                 }
245         }
246
247 /*
248         col_type n = hh.size();
249         if (n > ncols())
250                 n = ncols();
251         for (col_type col = 0; col < n; ++col)
252                 colinfo_[col].align_ = hh[col];
253 */
254 }
255
256
257 InsetMathGrid::col_type InsetMathGrid::guessColumns(docstring const & hh) const
258 {
259         col_type col = 0;
260         for (docstring::const_iterator it = hh.begin(); it != hh.end(); ++it)
261                 if (*it == 'c' || *it == 'l' || *it == 'r'||
262                     *it == 'p' || *it == 'm' || *it == 'b')
263                         ++col;
264         // let's have at least one column, even if we did not recognize its
265         // alignment
266         if (col == 0)
267                 col = 1;
268         return col;
269 }
270
271
272 void InsetMathGrid::halign(char h, col_type col)
273 {
274         colinfo_[col].align_ = h;
275         if (!colinfo_[col].special_.empty()) {
276                 char_type & c = colinfo_[col].special_[colinfo_[col].special_.size() - 1];
277                 if (c == 'l' || c == 'c' || c == 'r')
278                         c = h;
279         }
280         // FIXME: Change alignment of p, m and b columns, too
281 }
282
283
284 char InsetMathGrid::halign(col_type col) const
285 {
286         return colinfo_[col].align_;
287 }
288
289
290 docstring InsetMathGrid::halign() const
291 {
292         docstring res;
293         for (col_type col = 0; col < ncols(); ++col) {
294                 if (colinfo_[col].special_.empty()) {
295                         res += docstring(colinfo_[col].lines_, '|');
296                         res += colinfo_[col].align_;
297                 } else
298                         res += colinfo_[col].special_;
299         }
300         if (colinfo_[ncols()].special_.empty())
301                 return res + docstring(colinfo_[ncols()].lines_, '|');
302         return res + colinfo_[ncols()].special_;
303 }
304
305
306 void InsetMathGrid::valign(char c)
307 {
308         v_align_ = c;
309 }
310
311
312 char InsetMathGrid::valign() const
313 {
314         return v_align_;
315 }
316
317
318 InsetMathGrid::col_type InsetMathGrid::ncols() const
319 {
320         return colinfo_.size() - 1;
321 }
322
323
324 InsetMathGrid::row_type InsetMathGrid::nrows() const
325 {
326         return rowinfo_.size() - 1;
327 }
328
329
330 InsetMathGrid::col_type InsetMathGrid::col(idx_type idx) const
331 {
332         return idx % ncols();
333 }
334
335
336 InsetMathGrid::row_type InsetMathGrid::row(idx_type idx) const
337 {
338         return idx / ncols();
339 }
340
341
342 void InsetMathGrid::vcrskip(Length const & crskip, row_type row)
343 {
344         rowinfo_[row].crskip_ = crskip;
345 }
346
347
348 Length InsetMathGrid::vcrskip(row_type row) const
349 {
350         return rowinfo_[row].crskip_;
351 }
352
353
354 void InsetMathGrid::metrics(MetricsInfo & mi, Dimension & dim) const
355 {
356         // let the cells adjust themselves
357         InsetMathNest::metrics(mi);
358
359         BufferView & bv = *mi.base.bv;
360
361         // compute absolute sizes of vertical structure
362         for (row_type row = 0; row < nrows(); ++row) {
363                 int asc  = 0;
364                 int desc = 0;
365                 for (col_type col = 0; col < ncols(); ++col) {
366                         Dimension const & dimc = cell(index(row, col)).dimension(bv);
367                         asc  = max(asc,  dimc.asc);
368                         desc = max(desc, dimc.des);
369                 }
370                 rowinfo_[row].ascent_  = asc;
371                 rowinfo_[row].descent_ = desc;
372         }
373         rowinfo_[0].ascent_       += hlinesep() * rowinfo_[0].lines_;
374         rowinfo_[nrows()].ascent_  = 0;
375         rowinfo_[nrows()].descent_ = 0;
376
377         // compute vertical offsets
378         rowinfo_[0].offset_ = 0;
379         for (row_type row = 1; row <= nrows(); ++row) {
380                 rowinfo_[row].offset_  =
381                         rowinfo_[row - 1].offset_  +
382                         rowinfo_[row - 1].descent_ +
383                         rowinfo_[row - 1].skipPixels() +
384                         rowsep() +
385                         rowinfo_[row].lines_ * hlinesep() +
386                         rowinfo_[row].ascent_;
387         }
388
389         // adjust vertical offset
390         int h = 0;
391         switch (v_align_) {
392                 case 't':
393                         h = 0;
394                         break;
395                 case 'b':
396                         h = rowinfo_[nrows() - 1].offset_;
397                         break;
398                 default:
399                         h = rowinfo_[nrows() - 1].offset_ / 2;
400         }
401         for (row_type row = 0; row <= nrows(); ++row)
402                 rowinfo_[row].offset_ -= h;
403
404
405         // compute absolute sizes of horizontal structure
406         for (col_type col = 0; col < ncols(); ++col) {
407                 int wid = 0;
408                 for (row_type row = 0; row < nrows(); ++row)
409                         wid = max(wid, cell(index(row, col)).dimension(bv).wid);
410                 colinfo_[col].width_ = wid;
411         }
412         colinfo_[ncols()].width_  = 0;
413
414         // compute horizontal offsets
415         colinfo_[0].offset_ = border();
416         for (col_type col = 1; col <= ncols(); ++col) {
417                 colinfo_[col].offset_ =
418                         colinfo_[col - 1].offset_ +
419                         colinfo_[col - 1].width_ +
420                         colinfo_[col - 1].skip_ +
421                         colsep() +
422                         colinfo_[col].lines_ * vlinesep();
423         }
424
425
426         dim.wid   =   colinfo_[ncols() - 1].offset_
427                        + colinfo_[ncols() - 1].width_
428                  + vlinesep() * colinfo_[ncols()].lines_
429                        + border();
430
431         dim.asc  = - rowinfo_[0].offset_
432                        + rowinfo_[0].ascent_
433                  + hlinesep() * rowinfo_[0].lines_
434                        + border();
435
436         dim.des =   rowinfo_[nrows() - 1].offset_
437                        + rowinfo_[nrows() - 1].descent_
438                  + hlinesep() * rowinfo_[nrows()].lines_
439                        + border();
440
441
442 /*
443         // Increase ws_[i] for 'R' columns (except the first one)
444         for (int i = 1; i < nc_; ++i)
445                 if (align_[i] == 'R')
446                         ws_[i] += 10 * df_width;
447         // Increase ws_[i] for 'C' column
448         if (align_[0] == 'C')
449                 if (ws_[0] < 7 * workwidth / 8)
450                         ws_[0] = 7 * workwidth / 8;
451
452         // Adjust local tabs
453         width = colsep();
454         for (cxrow = row_.begin(); cxrow; ++cxrow) {
455                 int rg = COLSEP;
456                 int lf = 0;
457                 for (int i = 0; i < nc_; ++i) {
458                         bool isvoid = false;
459                         if (cxrow->getTab(i) <= 0) {
460                                 cxrow->setTab(i, df_width);
461                                 isvoid = true;
462                         }
463                         switch (align_[i]) {
464                         case 'l':
465                                 lf = 0;
466                                 break;
467                         case 'c':
468                                 lf = (ws_[i] - cxrow->getTab(i))/2;
469                                 break;
470                         case 'r':
471                         case 'R':
472                                 lf = ws_[i] - cxrow->getTab(i);
473                                 break;
474                         case 'C':
475                                 if (cxrow == row_.begin())
476                                         lf = 0;
477                                 else if (cxrow.is_last())
478                                         lf = ws_[i] - cxrow->getTab(i);
479                                 else
480                                         lf = (ws_[i] - cxrow->getTab(i))/2;
481                                 break;
482                         }
483                         int const ww = (isvoid) ? lf : lf + cxrow->getTab(i);
484                         cxrow->setTab(i, lf + rg);
485                         rg = ws_[i] - ww + colsep();
486                         if (cxrow == row_.begin())
487                                 width += ws_[i] + colsep();
488                 }
489                 cxrow->setBaseline(cxrow->getBaseline() - ascent);
490         }
491 */
492         metricsMarkers2(dim);
493         // Cache the inset dimension. 
494         setDimCache(mi, dim);
495 }
496
497
498 void InsetMathGrid::draw(PainterInfo & pi, int x, int y) const
499 {
500         drawWithMargin(pi, x, y, 1, 1);
501 }
502
503
504 void InsetMathGrid::drawWithMargin(PainterInfo & pi, int x, int y,
505         int lmargin, int rmargin) const
506 {
507         Dimension const dim = dimension(*pi.base.bv);
508         BufferView const & bv = *pi.base.bv;
509
510         for (idx_type idx = 0; idx < nargs(); ++idx)
511                 cell(idx).draw(pi, x + lmargin + cellXOffset(bv, idx),
512                         y + cellYOffset(idx));
513
514         for (row_type row = 0; row <= nrows(); ++row)
515                 for (unsigned int i = 0; i < rowinfo_[row].lines_; ++i) {
516                         int yy = y + rowinfo_[row].offset_ - rowinfo_[row].ascent_
517                                 - i * hlinesep() - hlinesep()/2 - rowsep()/2;
518                         pi.pain.line(x + lmargin + 1, yy,
519                                      x + dim.width() - rmargin - 1, yy,
520                                      Color_foreground);
521                 }
522
523         for (col_type col = 0; col <= ncols(); ++col)
524                 for (unsigned int i = 0; i < colinfo_[col].lines_; ++i) {
525                         int xx = x + lmargin + colinfo_[col].offset_
526                                 - i * vlinesep() - vlinesep()/2 - colsep()/2;
527                         pi.pain.line(xx, y - dim.ascent() + 1,
528                                      xx, y + dim.descent() - 1,
529                                      Color_foreground);
530                 }
531         drawMarkers2(pi, x, y);
532 }
533
534
535 void InsetMathGrid::metricsT(TextMetricsInfo const & mi, Dimension & dim) const
536 {
537         // let the cells adjust themselves
538         //InsetMathNest::metrics(mi);
539         for (idx_type i = 0; i < nargs(); ++i)
540                 cell(i).metricsT(mi, dim);
541
542         // compute absolute sizes of vertical structure
543         for (row_type row = 0; row < nrows(); ++row) {
544                 int asc  = 0;
545                 int desc = 0;
546                 for (col_type col = 0; col < ncols(); ++col) {
547                         //MathData const & c = cell(index(row, col));
548                         // FIXME: BROKEN!
549                         Dimension dimc;
550                         asc  = max(asc,  dimc.ascent());
551                         desc = max(desc, dimc.descent());
552                 }
553                 rowinfo_[row].ascent_  = asc;
554                 rowinfo_[row].descent_ = desc;
555         }
556         //rowinfo_[0].ascent_       += hlinesep() * rowinfo_[0].lines_;
557         rowinfo_[nrows()].ascent_  = 0;
558         rowinfo_[nrows()].descent_ = 0;
559
560         // compute vertical offsets
561         rowinfo_[0].offset_ = 0;
562         for (row_type row = 1; row <= nrows(); ++row) {
563                 rowinfo_[row].offset_  =
564                         rowinfo_[row - 1].offset_  +
565                         rowinfo_[row - 1].descent_ +
566                         //rowinfo_[row - 1].skipPixels() +
567                         1 + //rowsep() +
568                         //rowinfo_[row].lines_ * hlinesep() +
569                         rowinfo_[row].ascent_;
570         }
571
572         // adjust vertical offset
573         int h = 0;
574         switch (v_align_) {
575                 case 't':
576                         h = 0;
577                         break;
578                 case 'b':
579                         h = rowinfo_[nrows() - 1].offset_;
580                         break;
581                 default:
582                         h = rowinfo_[nrows() - 1].offset_ / 2;
583         }
584         for (row_type row = 0; row <= nrows(); ++row)
585                 rowinfo_[row].offset_ -= h;
586
587
588         // compute absolute sizes of horizontal structure
589         for (col_type col = 0; col < ncols(); ++col) {
590                 int wid = 0;
591                 for (row_type row = 0; row < nrows(); ++row) {
592                         // FIXME: BROKEN!
593                         //wid = max(wid, cell(index(row, col)).width());
594                 }
595                 colinfo_[col].width_ = wid;
596         }
597         colinfo_[ncols()].width_  = 0;
598
599         // compute horizontal offsets
600         colinfo_[0].offset_ = border();
601         for (col_type col = 1; col <= ncols(); ++col) {
602                 colinfo_[col].offset_ =
603                         colinfo_[col - 1].offset_ +
604                         colinfo_[col - 1].width_ +
605                         colinfo_[col - 1].skip_ +
606                         1 ; //colsep() +
607                         //colinfo_[col].lines_ * vlinesep();
608         }
609
610
611         dim.wid  =  colinfo_[ncols() - 1].offset_
612                        + colinfo_[ncols() - 1].width_
613                  //+ vlinesep() * colinfo_[ncols()].lines_
614                        + 2;
615
616         dim.asc  = -rowinfo_[0].offset_
617                        + rowinfo_[0].ascent_
618                  //+ hlinesep() * rowinfo_[0].lines_
619                        + 1;
620
621         dim.des  =  rowinfo_[nrows() - 1].offset_
622                        + rowinfo_[nrows() - 1].descent_
623                  //+ hlinesep() * rowinfo_[nrows()].lines_
624                        + 1;
625 }
626
627
628 void InsetMathGrid::drawT(TextPainter & /*pain*/, int /*x*/, int /*y*/) const
629 {
630 //      for (idx_type idx = 0; idx < nargs(); ++idx)
631 //              cell(idx).drawT(pain, x + cellXOffset(idx), y + cellYOffset(idx));
632 }
633
634
635 docstring InsetMathGrid::eolString(row_type row, bool emptyline, bool fragile) const
636 {
637         docstring eol;
638
639         if (!rowinfo_[row].crskip_.zero())
640                 eol += '[' + from_utf8(rowinfo_[row].crskip_.asLatexString()) + ']';
641         else if(!rowinfo_[row].allow_newpage_)
642                 eol += '*';
643
644         // make sure an upcoming '[' does not break anything
645         if (row + 1 < nrows()) {
646                 MathData const & c = cell(index(row + 1, 0));
647                 if (c.size() && c.front()->getChar() == '[')
648                         //eol += "[0pt]";
649                         eol += "{}";
650         }
651
652         // only add \\ if necessary
653         if (eol.empty() && row + 1 == nrows() && (nrows() == 1 || !emptyline))
654                 return docstring();
655
656         return (fragile ? "\\protect\\\\" : "\\\\") + eol;
657 }
658
659
660 docstring InsetMathGrid::eocString(col_type col, col_type lastcol) const
661 {
662         if (col + 1 == lastcol)
663                 return docstring();
664         return from_ascii(" & ");
665 }
666
667
668 void InsetMathGrid::addRow(row_type row)
669 {
670         rowinfo_.insert(rowinfo_.begin() + row + 1, RowInfo());
671         cells_.insert
672                 (cells_.begin() + (row + 1) * ncols(), ncols(), MathData());
673         cellinfo_.insert
674                 (cellinfo_.begin() + (row + 1) * ncols(), ncols(), CellInfo());
675 }
676
677
678 void InsetMathGrid::appendRow()
679 {
680         rowinfo_.push_back(RowInfo());
681         //cells_.insert(cells_.end(), ncols(), MathData());
682         for (col_type col = 0; col < ncols(); ++col) {
683                 cells_.push_back(cells_type::value_type());
684                 cellinfo_.push_back(CellInfo());
685         }
686 }
687
688
689 void InsetMathGrid::delRow(row_type row)
690 {
691         if (nrows() == 1)
692                 return;
693
694         cells_type::iterator it = cells_.begin() + row * ncols();
695         cells_.erase(it, it + ncols());
696
697         vector<CellInfo>::iterator jt = cellinfo_.begin() + row * ncols();
698         cellinfo_.erase(jt, jt + ncols());
699
700         rowinfo_.erase(rowinfo_.begin() + row);
701 }
702
703
704 void InsetMathGrid::copyRow(row_type row)
705 {
706         addRow(row);
707         for (col_type col = 0; col < ncols(); ++col)
708                 cells_[(row + 1) * ncols() + col] = cells_[row * ncols() + col];
709 }
710
711
712 void InsetMathGrid::swapRow(row_type row)
713 {
714         if (nrows() == 1)
715                 return;
716         if (row + 1 == nrows())
717                 --row;
718         for (col_type col = 0; col < ncols(); ++col)
719                 swap(cells_[row * ncols() + col], cells_[(row + 1) * ncols() + col]);
720 }
721
722
723 void InsetMathGrid::addCol(col_type newcol)
724 {
725         const col_type nc = ncols();
726         const row_type nr = nrows();
727         cells_type new_cells((nc + 1) * nr);
728         vector<CellInfo> new_cellinfo((nc + 1) * nr);
729
730         for (row_type row = 0; row < nr; ++row)
731                 for (col_type col = 0; col < nc; ++col) {
732                         new_cells[row * (nc + 1) + col + (col >= newcol)]
733                                 = cells_[row * nc + col];
734                         new_cellinfo[row * (nc + 1) + col + (col >= newcol)]
735                                 = cellinfo_[row * nc + col];
736                 }
737         swap(cells_, new_cells);
738         swap(cellinfo_, new_cellinfo);
739
740         ColInfo inf;
741         inf.skip_  = defaultColSpace(newcol);
742         inf.align_ = defaultColAlign(newcol);
743         colinfo_.insert(colinfo_.begin() + newcol, inf);
744 }
745
746
747 void InsetMathGrid::delCol(col_type col)
748 {
749         if (ncols() == 1)
750                 return;
751
752         cells_type tmpcells;
753         vector<CellInfo> tmpcellinfo;
754         for (col_type i = 0; i < nargs(); ++i)
755                 if (i % ncols() != col) {
756                         tmpcells.push_back(cells_[i]);
757                         tmpcellinfo.push_back(cellinfo_[i]);
758                 }
759         swap(cells_, tmpcells);
760         swap(cellinfo_, tmpcellinfo);
761
762         colinfo_.erase(colinfo_.begin() + col);
763 }
764
765
766 void InsetMathGrid::copyCol(col_type col)
767 {
768         addCol(col);
769         for (row_type row = 0; row < nrows(); ++row)
770                 cells_[row * ncols() + col + 1] = cells_[row * ncols() + col];
771 }
772
773
774 void InsetMathGrid::swapCol(col_type col)
775 {
776         if (ncols() == 1)
777                 return;
778         if (col + 1 == ncols())
779                 --col;
780         for (row_type row = 0; row < nrows(); ++row)
781                 swap(cells_[row * ncols() + col], cells_[row * ncols() + col + 1]);
782 }
783
784
785 int InsetMathGrid::cellXOffset(BufferView const & bv, idx_type idx) const
786 {
787         col_type c = col(idx);
788         int x = colinfo_[c].offset_;
789         char align = colinfo_[c].align_;
790         Dimension const & celldim = cell(idx).dimension(bv);
791         if (align == 'r' || align == 'R')
792                 x += colinfo_[c].width_ - celldim.wid;
793         if (align == 'c' || align == 'C')
794                 x += (colinfo_[c].width_ - celldim.wid) / 2;
795         return x;
796 }
797
798
799 int InsetMathGrid::cellYOffset(idx_type idx) const
800 {
801         return rowinfo_[row(idx)].offset_;
802 }
803
804
805 bool InsetMathGrid::idxUpDown(Cursor & cur, bool up) const
806 {
807         if (up) {
808                 if (cur.row() == 0)
809                         return false;
810                 cur.idx() -= ncols();
811         } else {
812                 if (cur.row() + 1 >= nrows())
813                         return false;
814                 cur.idx() += ncols();
815         }
816         cur.pos() = cur.cell().x2pos(&cur.bv(), cur.x_target() - cur.cell().xo(cur.bv()));
817         return true;
818 }
819
820
821 bool InsetMathGrid::idxBackward(Cursor & cur) const
822 {
823         // leave matrix if at the front edge
824         if (cur.col() == 0)
825                 return false;
826         --cur.idx();
827         cur.pos() = cur.lastpos();
828         return true;
829 }
830
831
832 bool InsetMathGrid::idxForward(Cursor & cur) const
833 {
834         // leave matrix if at the back edge
835         if (cur.col() + 1 == ncols())
836                 return false;
837         ++cur.idx();
838         cur.pos() = 0;
839         return true;
840 }
841
842
843 bool InsetMathGrid::idxFirst(Cursor & cur) const
844 {
845         switch (v_align_) {
846                 case 't':
847                         cur.idx() = 0;
848                         break;
849                 case 'b':
850                         cur.idx() = (nrows() - 1) * ncols();
851                         break;
852                 default:
853                         cur.idx() = ((nrows() - 1) / 2) * ncols();
854         }
855         cur.pos() = 0;
856         return true;
857 }
858
859
860 bool InsetMathGrid::idxLast(Cursor & cur) const
861 {
862         switch (v_align_) {
863                 case 't':
864                         cur.idx() = ncols() - 1;
865                         break;
866                 case 'b':
867                         cur.idx() = nargs() - 1;
868                         break;
869                 default:
870                         cur.idx() = ((nrows() - 1) / 2 + 1) * ncols() - 1;
871         }
872         cur.pos() = cur.lastpos();
873         return true;
874 }
875
876
877 bool InsetMathGrid::idxDelete(idx_type & idx)
878 {
879         // nothing to do if we have just one row
880         if (nrows() == 1)
881                 return false;
882
883         // nothing to do if we are in the middle of the last row of the inset
884         if (idx + ncols() > nargs())
885                 return false;
886
887         // try to delete entire sequence of ncols() empty cells if possible
888         for (idx_type i = idx; i < idx + ncols(); ++i)
889                 if (cell(i).size())
890                         return false;
891
892         // move cells if necessary
893         for (idx_type i = index(row(idx), 0); i < idx; ++i)
894                 swap(cell(i), cell(i + ncols()));
895
896         delRow(row(idx));
897
898         if (idx >= nargs())
899                 idx = nargs() - 1;
900
901         // undo effect of Ctrl-Tab (i.e. pull next cell)
902         //if (idx + 1 != nargs())
903         //      cell(idx).swap(cell(idx + 1));
904
905         // we handled the event..
906         return true;
907 }
908
909
910 // reimplement old behaviour when pressing Delete in the last position
911 // of a cell
912 void InsetMathGrid::idxGlue(idx_type idx)
913 {
914         col_type c = col(idx);
915         if (c + 1 == ncols()) {
916                 if (row(idx) + 1 != nrows()) {
917                         for (col_type cc = 0; cc < ncols(); ++cc)
918                                 cell(idx).append(cell(idx + cc + 1));
919                         delRow(row(idx) + 1);
920                 }
921         } else {
922                 cell(idx).append(cell(idx + 1));
923                 for (col_type cc = c + 2; cc < ncols(); ++cc)
924                         cell(idx - c + cc - 1) = cell(idx - c + cc);
925                 cell(idx - c + ncols() - 1).clear();
926         }
927 }
928
929
930 InsetMathGrid::RowInfo const & InsetMathGrid::rowinfo(row_type row) const
931 {
932         return rowinfo_[row];
933 }
934
935
936 InsetMathGrid::RowInfo & InsetMathGrid::rowinfo(row_type row)
937 {
938         return rowinfo_[row];
939 }
940
941
942 bool InsetMathGrid::idxBetween(idx_type idx, idx_type from, idx_type to) const
943 {
944         row_type const ri = row(idx);
945         row_type const r1 = min(row(from), row(to));
946         row_type const r2 = max(row(from), row(to));
947         col_type const ci = col(idx);
948         col_type const c1 = min(col(from), col(to));
949         col_type const c2 = max(col(from), col(to));
950         return r1 <= ri && ri <= r2 && c1 <= ci && ci <= c2;
951 }
952
953
954
955 void InsetMathGrid::normalize(NormalStream & os) const
956 {
957         os << "[grid ";
958         for (row_type row = 0; row < nrows(); ++row) {
959                 os << "[row ";
960                 for (col_type col = 0; col < ncols(); ++col)
961                         os << "[cell " << cell(index(row, col)) << ']';
962                 os << ']';
963         }
964         os << ']';
965 }
966
967
968 void InsetMathGrid::mathmlize(MathStream & os) const
969 {
970         os << MTag("mtable");
971         for (row_type row = 0; row < nrows(); ++row) {
972                 os << MTag("mtr");
973                 for (col_type col = 0; col < ncols(); ++col)
974                         os << cell(index(row, col));
975                 os << ETag("mtr");
976         }
977         os << ETag("mtable");
978 }
979
980
981 void InsetMathGrid::write(WriteStream & os) const
982 {
983         docstring eol;
984         for (row_type row = 0; row < nrows(); ++row) {
985                 os << verboseHLine(rowinfo_[row].lines_);
986                 // don't write & and empty cells at end of line
987                 col_type lastcol = 0;
988                 bool emptyline = true;
989                 for (col_type col = 0; col < ncols(); ++col)
990                         if (!cell(index(row, col)).empty()) {
991                                 lastcol = col + 1;
992                                 emptyline = false;
993                         }
994                 for (col_type col = 0; col < lastcol; ++col)
995                         os << cell(index(row, col)) << eocString(col, lastcol);
996                 eol = eolString(row, emptyline, os.fragile());
997                 os << eol;
998                 // append newline only if line wasn't completely empty
999                 // and this was not the last line in the grid
1000                 if (!emptyline && row + 1 < nrows())
1001                         os << "\n";
1002         }
1003         docstring const s = verboseHLine(rowinfo_[nrows()].lines_);
1004         if (!s.empty()) {
1005                 if (eol.empty()) {
1006                         if (os.fragile())
1007                                 os << "\\protect";
1008                         os << "\\\\";
1009                 }
1010                 os << s;
1011         }
1012 }
1013
1014
1015 int InsetMathGrid::colsep() const
1016 {
1017         return 6;
1018 }
1019
1020
1021 int InsetMathGrid::rowsep() const
1022 {
1023         return 6;
1024 }
1025
1026
1027 int InsetMathGrid::hlinesep() const
1028 {
1029         return 3;
1030 }
1031
1032
1033 int InsetMathGrid::vlinesep() const
1034 {
1035         return 3;
1036 }
1037
1038
1039 int InsetMathGrid::border() const
1040 {
1041         return 1;
1042 }
1043
1044
1045 void InsetMathGrid::splitCell(Cursor & cur)
1046 {
1047         if (cur.idx() == cur.lastidx())
1048                 return;
1049         MathData ar = cur.cell();
1050         ar.erase(0, cur.pos());
1051         cur.cell().erase(cur.pos(), cur.lastpos());
1052         ++cur.idx();
1053         cur.pos() = 0;
1054         cur.cell().insert(0, ar);
1055 }
1056
1057
1058 void InsetMathGrid::doDispatch(Cursor & cur, FuncRequest & cmd)
1059 {
1060         //lyxerr << "*** InsetMathGrid: request: " << cmd << endl;
1061         switch (cmd.action) {
1062
1063         // insert file functions
1064         case LFUN_LINE_DELETE:
1065                 // FIXME: We use recordUndoInset when a change reflects more
1066                 // than one cell, because recordUndo does not work for
1067                 // multiple cells. Unfortunately this puts the cursor in front
1068                 // of the inset after undo. This is (especilally for large
1069                 // grids) annoying.
1070                 cur.recordUndoInset();
1071                 //autocorrect_ = false;
1072                 //macroModeClose();
1073                 //if (selection_) {
1074                 //      selDel();
1075                 //      break;
1076                 //}
1077                 if (nrows() > 1)
1078                         delRow(cur.row());
1079                 if (cur.idx() > cur.lastidx())
1080                         cur.idx() = cur.lastidx();
1081                 if (cur.pos() > cur.lastpos())
1082                         cur.pos() = cur.lastpos();
1083                 break;
1084
1085         case LFUN_CELL_SPLIT:
1086                 cur.recordUndo();
1087                 splitCell(cur);
1088                 break;
1089
1090         case LFUN_CELL_BACKWARD:
1091                 // See below.
1092                 cur.selection() = false;
1093                 if (!idxPrev(cur)) {
1094                         cmd = FuncRequest(LFUN_FINISHED_BACKWARD);
1095                         cur.undispatched();
1096                 }
1097                 break;
1098
1099         case LFUN_CELL_FORWARD:
1100                 // Can't handle selection by additional 'shift' as this is
1101                 // hard bound to LFUN_CELL_BACKWARD
1102                 cur.selection() = false;
1103                 if (!idxNext(cur)) {
1104                         cmd = FuncRequest(LFUN_FINISHED_FORWARD);
1105                         cur.undispatched();
1106                 }
1107                 break;
1108
1109         case LFUN_NEW_LINE: {
1110                 cur.recordUndoInset();
1111                 row_type const r = cur.row();
1112                 addRow(r);
1113
1114                 // split line
1115                 for (col_type c = col(cur.idx()) + 1; c < ncols(); ++c)
1116                         swap(cell(index(r, c)), cell(index(r + 1, c)));
1117
1118                 // split cell
1119                 splitCell(cur);
1120                 swap(cell(cur.idx()), cell(cur.idx() + ncols() - 1));
1121                 if (cur.idx() > 0)
1122                         --cur.idx();
1123                 cur.pos() = cur.lastpos();
1124
1125                 //mathcursor->normalize();
1126                 //cmd = FuncRequest(LFUN_FINISHED_BACKWARD);
1127                 break;
1128         }
1129
1130         case LFUN_TABULAR_FEATURE: {
1131                 cur.recordUndoInset();
1132                 //lyxerr << "handling tabular-feature " << to_utf8(cmd.argument()) << endl;
1133                 istringstream is(to_utf8(cmd.argument()));
1134                 string s;
1135                 is >> s;
1136                 if (s == "valign-top")
1137                         valign('t');
1138                 else if (s == "valign-middle")
1139                         valign('c');
1140                 else if (s == "valign-bottom")
1141                         valign('b');
1142                 else if (s == "align-left")
1143                         halign('l', cur.col());
1144                 else if (s == "align-right")
1145                         halign('r', cur.col());
1146                 else if (s == "align-center")
1147                         halign('c', cur.col());
1148                 else if (s == "append-row")
1149                         for (int i = 0, n = extractInt(is); i < n; ++i)
1150                                 addRow(cur.row());
1151                 else if (s == "delete-row") {
1152                         cur.clearSelection(); // bug 4323
1153                         for (int i = 0, n = extractInt(is); i < n; ++i) {
1154                                 delRow(cur.row());
1155                                 if (cur.idx() >= nargs())
1156                                         cur.idx() -= ncols();
1157                         }
1158                         cur.pos() = 0; // trick, see below
1159                 }
1160                 else if (s == "copy-row") {
1161                         // Here (as later) we save the cursor col/row
1162                         // in order to restore it after operation.
1163                         row_type const r = cur.row();
1164                         col_type const c = cur.col();
1165                         for (int i = 0, n = extractInt(is); i < n; ++i)
1166                                 copyRow(cur.row());
1167                         cur.idx() = index(r, c);
1168                 }
1169                 else if (s == "swap-row") {
1170                         swapRow(cur.row());
1171                         // Trick to suppress same-idx-means-different-cell
1172                         // assertion crash:
1173                         cur.pos() = 0;
1174                 }
1175                 else if (s == "add-hline-above")
1176                         rowinfo_[cur.row()].lines_++;
1177                 else if (s == "add-hline-below")
1178                         rowinfo_[cur.row()+1].lines_++;
1179                 else if (s == "delete-hline-above")
1180                         rowinfo_[cur.row()].lines_--;
1181                 else if (s == "delete-hline-below")
1182                         rowinfo_[cur.row()+1].lines_--;
1183                 else if (s == "append-column") {
1184                         row_type const r = cur.row();
1185                         col_type const c = cur.col();
1186                         for (int i = 0, n = extractInt(is); i < n; ++i)
1187                                 addCol(cur.col() + 1);
1188                         cur.idx() = index(r, c);
1189                 }
1190                 else if (s == "delete-column") {
1191                         cur.clearSelection(); // bug 4323
1192                         row_type const r = cur.row();
1193                         col_type const c = cur.col();
1194                         for (int i = 0, n = extractInt(is); i < n; ++i)
1195                                 delCol(col(cur.idx()));
1196                         cur.idx() = index(r, min(c, cur.ncols() - 1));
1197                         cur.pos() = 0; // trick, see above
1198                 }
1199                 else if (s == "copy-column") {
1200                         row_type const r = cur.row();
1201                         col_type const c = cur.col();
1202                         copyCol(cur.col());
1203                         cur.idx() = index(r, c);
1204                 }
1205                 else if (s == "swap-column") {
1206                         swapCol(cur.col());
1207                         cur.pos() = 0; // trick, see above
1208                 }
1209                 else if (s == "add-vline-left") {
1210                         colinfo_[cur.col()].lines_++;
1211                         if (!colinfo_[cur.col()].special_.empty())
1212                                 colinfo_[cur.col()].special_ += '|';
1213                 }
1214                 else if (s == "add-vline-right") {
1215                         colinfo_[cur.col()+1].lines_++;
1216                         if (!colinfo_[cur.col()+1].special_.empty())
1217                                 colinfo_[cur.col()+1].special_.insert(0, 1, '|');
1218                 }
1219                 else if (s == "delete-vline-left") {
1220                         colinfo_[cur.col()].lines_--;
1221                         docstring & special = colinfo_[cur.col()].special_;
1222                         if (!special.empty()) {
1223                                 docstring::size_type i = special.rfind('|');
1224                                 BOOST_ASSERT(i != docstring::npos);
1225                                 special.erase(i, 1);
1226                         }
1227                 }
1228                 else if (s == "delete-vline-right") {
1229                         colinfo_[cur.col()+1].lines_--;
1230                         docstring & special = colinfo_[cur.col()+1].special_;
1231                         if (!special.empty()) {
1232                                 docstring::size_type i = special.find('|');
1233                                 BOOST_ASSERT(i != docstring::npos);
1234                                 special.erase(i, 1);
1235                         }
1236                 }
1237                 else {
1238                         cur.undispatched();
1239                         break;
1240                 }
1241                 // perhaps this should be FINISHED_BACKWARD -- just for clarity?
1242                 lyxerr << "returning FINISHED_LEFT" << endl;
1243                 break;
1244         }
1245
1246         case LFUN_PASTE: {
1247                 cur.message(_("Paste"));
1248                 cap::replaceSelection(cur);
1249                 docstring topaste;
1250                 if (cmd.argument().empty() && !theClipboard().isInternal())
1251                         topaste = theClipboard().getAsText();
1252                 else {
1253                         idocstringstream is(cmd.argument());
1254                         int n = 0;
1255                         is >> n;
1256                         topaste = cap::getSelection(cur.buffer(), n);
1257                 }
1258                 InsetMathGrid grid(1, 1);
1259                 if (!topaste.empty())
1260                         mathed_parse_normal(grid, topaste);
1261
1262                 if (grid.nargs() == 1) {
1263                         // single cell/part of cell
1264                         cur.recordUndo();
1265                         cur.cell().insert(cur.pos(), grid.cell(0));
1266                         cur.pos() += grid.cell(0).size();
1267                 } else {
1268                         // multiple cells
1269                         cur.recordUndoInset();
1270                         col_type const numcols =
1271                                 min(grid.ncols(), ncols() - col(cur.idx()));
1272                         row_type const numrows =
1273                                 min(grid.nrows(), nrows() - cur.row());
1274                         for (row_type r = 0; r < numrows; ++r) {
1275                                 for (col_type c = 0; c < numcols; ++c) {
1276                                         idx_type i = index(r + cur.row(), c + col(cur.idx()));
1277                                         cell(i).insert(0, grid.cell(grid.index(r, c)));
1278                                 }
1279                                 // append the left over horizontal cells to the last column
1280                                 idx_type i = index(r + cur.row(), ncols() - 1);
1281                                 for (InsetMath::col_type c = numcols; c < grid.ncols(); ++c)
1282                                         cell(i).append(grid.cell(grid.index(r, c)));
1283                         }
1284                         // append the left over vertical cells to the last _cell_
1285                         idx_type i = nargs() - 1;
1286                         for (row_type r = numrows; r < grid.nrows(); ++r)
1287                                 for (col_type c = 0; c < grid.ncols(); ++c)
1288                                         cell(i).append(grid.cell(grid.index(r, c)));
1289                 }
1290                 cur.clearSelection(); // bug 393
1291                 cur.finishUndo();
1292                 break;
1293         }
1294
1295         case LFUN_LINE_BEGIN_SELECT:
1296         case LFUN_LINE_BEGIN:
1297         case LFUN_WORD_BACKWARD_SELECT:
1298         case LFUN_WORD_BACKWARD:
1299         case LFUN_WORD_LEFT_SELECT:
1300         case LFUN_WORD_LEFT:
1301                 cur.selHandle(cmd.action == LFUN_WORD_BACKWARD_SELECT ||
1302                                 cmd.action == LFUN_WORD_LEFT_SELECT ||
1303                                 cmd.action == LFUN_LINE_BEGIN_SELECT);
1304                 cur.macroModeClose();
1305                 if (cur.pos() != 0) {
1306                         cur.pos() = 0;
1307                 } else if (cur.idx() % cur.ncols() != 0) {
1308                         cur.idx() -= cur.idx() % cur.ncols();
1309                         cur.pos() = 0;
1310                 } else if (cur.idx() != 0) {
1311                         cur.idx() = 0;
1312                         cur.pos() = 0;
1313                 } else {
1314                         cmd = FuncRequest(LFUN_FINISHED_BACKWARD);
1315                         cur.undispatched();
1316                 }
1317                 break;
1318
1319         case LFUN_WORD_FORWARD_SELECT:
1320         case LFUN_WORD_FORWARD:
1321         case LFUN_WORD_RIGHT_SELECT:
1322         case LFUN_WORD_RIGHT:
1323         case LFUN_LINE_END_SELECT:
1324         case LFUN_LINE_END:
1325                 cur.selHandle(cmd.action == LFUN_WORD_FORWARD_SELECT ||
1326                                 cmd.action == LFUN_WORD_RIGHT_SELECT ||
1327                                 cmd.action == LFUN_LINE_END_SELECT);
1328                 cur.macroModeClose();
1329                 cur.clearTargetX();
1330                 if (cur.pos() != cur.lastpos()) {
1331                         cur.pos() = cur.lastpos();
1332                 } else if ((cur.idx() + 1) % cur.ncols() != 0) {
1333                         cur.idx() += cur.ncols() - 1 - cur.idx() % cur.ncols();
1334                         cur.pos() = cur.lastpos();
1335                 } else if (cur.idx() != cur.lastidx()) {
1336                         cur.idx() = cur.lastidx();
1337                         cur.pos() = cur.lastpos();
1338                 } else {
1339                         cmd = FuncRequest(LFUN_FINISHED_FORWARD);
1340                         cur.undispatched();
1341                 }
1342                 break;
1343
1344         default:
1345                 InsetMathNest::doDispatch(cur, cmd);
1346         }
1347 }
1348
1349
1350 bool InsetMathGrid::getStatus(Cursor & cur, FuncRequest const & cmd,
1351                 FuncStatus & status) const
1352 {
1353         switch (cmd.action) {
1354         case LFUN_TABULAR_FEATURE: {
1355                 string const s = to_utf8(cmd.argument());
1356                 if (nrows() <= 1 && (s == "delete-row" || s == "swap-row")) {
1357                         status.enabled(false);
1358                         status.message(from_utf8(N_("Only one row")));
1359                         return true;
1360                 }
1361                 if (ncols() <= 1 &&
1362                     (s == "delete-column" || s == "swap-column")) {
1363                         status.enabled(false);
1364                         status.message(from_utf8(N_("Only one column")));
1365                         return true;
1366                 }
1367                 if ((rowinfo_[cur.row()].lines_ == 0 &&
1368                      s == "delete-hline-above") ||
1369                     (rowinfo_[cur.row() + 1].lines_ == 0 &&
1370                      s == "delete-hline-below")) {
1371                         status.enabled(false);
1372                         status.message(from_utf8(N_("No hline to delete")));
1373                         return true;
1374                 }
1375
1376                 if ((colinfo_[cur.col()].lines_ == 0 &&
1377                      s == "delete-vline-left") ||
1378                     (colinfo_[cur.col() + 1].lines_ == 0 &&
1379                      s == "delete-vline-right")) {
1380                         status.enabled(false);
1381                         status.message(from_utf8(N_("No vline to delete")));
1382                         return true;
1383                 }
1384                 if (s == "valign-top" || s == "valign-middle" ||
1385                     s == "valign-bottom" || s == "align-left" ||
1386                     s == "align-right" || s == "align-center" ||
1387                     s == "append-row" || s == "delete-row" ||
1388                     s == "copy-row" || s == "swap-row" ||
1389                     s == "add-hline-above" || s == "add-hline-below" ||
1390                     s == "delete-hline-above" || s == "delete-hline-below" ||
1391                     s == "append-column" || s == "delete-column" ||
1392                     s == "copy-column" || s == "swap-column" ||
1393                     s == "add-vline-left" || s == "add-vline-right" ||
1394                     s == "delete-vline-left" || s == "delete-vline-right")
1395                         status.enabled(true);
1396                 else {
1397                         status.enabled(false);
1398                         status.message(bformat(
1399                                 from_utf8(N_("Unknown tabular feature '%1$s'")), lyx::from_ascii(s)));
1400                 }
1401
1402                 status.setOnOff((s == "align-left" && halign(cur.col()) == 'l')
1403                            || (s == "align-right"   && halign(cur.col()) == 'r')
1404                            || (s == "align-center"  && halign(cur.col()) == 'c')
1405                            || (s == "valign-top"    && valign() == 't')
1406                            || (s == "valign-bottom" && valign() == 'b')
1407                            || (s == "valign-middle" && valign() == 'm'));
1408
1409 #if 0
1410                 // FIXME: What did this code do?
1411                 // Please check whether it is still needed!
1412                 // should be more precise
1413                 if (v_align_ == '\0') {
1414                         status.enable(true);
1415                         break;
1416                 }
1417                 if (cmd.argument().empty()) {
1418                         status.enable(false);
1419                         break;
1420                 }
1421                 if (!contains("tcb", cmd.argument()[0])) {
1422                         status.enable(false);
1423                         break;
1424                 }
1425                 status.setOnOff(cmd.argument()[0] == v_align_);
1426                 status.enabled(true);
1427 #endif
1428                 return true;
1429         }
1430
1431         case LFUN_CELL_SPLIT:
1432                 status.enabled(true);
1433                 return true;
1434
1435         case LFUN_CELL_BACKWARD:
1436         case LFUN_CELL_FORWARD:
1437                 status.enabled(true);
1438                 return true;
1439
1440         default:
1441                 return InsetMathNest::getStatus(cur, cmd, status);
1442         }
1443 }
1444
1445
1446 } // namespace lyx