]> git.lyx.org Git - features.git/blob - src/insets/insettabular.C
Replace LString.h with support/std_string.h,
[features.git] / src / insets / insettabular.C
1 /**
2  * \file insettabular.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Jürgen Vigna
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "insettabular.h"
14
15 #include "buffer.h"
16 #include "BufferView.h"
17 #include "debug.h"
18 #include "funcrequest.h"
19 #include "FuncStatus.h"
20 #include "gettext.h"
21 #include "language.h"
22 #include "lyx_cb.h"
23 #include "lyxlex.h"
24 #include "metricsinfo.h"
25 #include "paragraph_funcs.h"
26 #include "ParagraphParameters.h"
27 #include "undo_funcs.h"
28 #include "WordLangTuple.h"
29
30 #include "frontends/Alert.h"
31 #include "frontends/font_metrics.h"
32 #include "frontends/LyXView.h"
33 #include "frontends/Painter.h"
34
35 #include "support/LAssert.h"
36
37 #include "support/std_sstream.h"
38
39 using namespace lyx::support;
40 using namespace lyx::graphics;
41
42 using std::endl;
43 using std::max;
44 using std::swap;
45 using std::auto_ptr;
46 using std::ifstream;
47 using std::ostream;
48 using std::vector;
49
50
51 namespace {
52
53 int const ADD_TO_HEIGHT = 2;
54 int const ADD_TO_TABULAR_WIDTH = 2;
55
56 ///
57 LyXTabular * paste_tabular = 0;
58
59
60 struct TabularFeature {
61         LyXTabular::Feature action;
62         string feature;
63 };
64
65
66 TabularFeature tabularFeature[] =
67 {
68         { LyXTabular::APPEND_ROW, "append-row" },
69         { LyXTabular::APPEND_COLUMN, "append-column" },
70         { LyXTabular::DELETE_ROW, "delete-row" },
71         { LyXTabular::DELETE_COLUMN, "delete-column" },
72         { LyXTabular::TOGGLE_LINE_TOP, "toggle-line-top" },
73         { LyXTabular::TOGGLE_LINE_BOTTOM, "toggle-line-bottom" },
74         { LyXTabular::TOGGLE_LINE_LEFT, "toggle-line-left" },
75         { LyXTabular::TOGGLE_LINE_RIGHT, "toggle-line-right" },
76         { LyXTabular::ALIGN_LEFT, "align-left" },
77         { LyXTabular::ALIGN_RIGHT, "align-right" },
78         { LyXTabular::ALIGN_CENTER, "align-center" },
79         { LyXTabular::ALIGN_BLOCK, "align-block" },
80         { LyXTabular::VALIGN_TOP, "valign-top" },
81         { LyXTabular::VALIGN_BOTTOM, "valign-bottom" },
82         { LyXTabular::VALIGN_MIDDLE, "valign-middle" },
83         { LyXTabular::M_TOGGLE_LINE_TOP, "m-toggle-line-top" },
84         { LyXTabular::M_TOGGLE_LINE_BOTTOM, "m-toggle-line-bottom" },
85         { LyXTabular::M_TOGGLE_LINE_LEFT, "m-toggle-line-left" },
86         { LyXTabular::M_TOGGLE_LINE_RIGHT, "m-toggle-line-right" },
87         { LyXTabular::M_ALIGN_LEFT, "m-align-left" },
88         { LyXTabular::M_ALIGN_RIGHT, "m-align-right" },
89         { LyXTabular::M_ALIGN_CENTER, "m-align-center" },
90         { LyXTabular::M_VALIGN_TOP, "m-valign-top" },
91         { LyXTabular::M_VALIGN_BOTTOM, "m-valign-bottom" },
92         { LyXTabular::M_VALIGN_MIDDLE, "m-valign-middle" },
93         { LyXTabular::MULTICOLUMN, "multicolumn" },
94         { LyXTabular::SET_ALL_LINES, "set-all-lines" },
95         { LyXTabular::UNSET_ALL_LINES, "unset-all-lines" },
96         { LyXTabular::SET_LONGTABULAR, "set-longtabular" },
97         { LyXTabular::UNSET_LONGTABULAR, "unset-longtabular" },
98         { LyXTabular::SET_PWIDTH, "set-pwidth" },
99         { LyXTabular::SET_MPWIDTH, "set-mpwidth" },
100         { LyXTabular::SET_ROTATE_TABULAR, "set-rotate-tabular" },
101         { LyXTabular::UNSET_ROTATE_TABULAR, "unset-rotate-tabular" },
102         { LyXTabular::SET_ROTATE_CELL, "set-rotate-cell" },
103         { LyXTabular::UNSET_ROTATE_CELL, "unset-rotate-cell" },
104         { LyXTabular::SET_USEBOX, "set-usebox" },
105         { LyXTabular::SET_LTHEAD, "set-lthead" },
106         { LyXTabular::SET_LTFIRSTHEAD, "set-ltfirsthead" },
107         { LyXTabular::SET_LTFOOT, "set-ltfoot" },
108         { LyXTabular::SET_LTLASTFOOT, "set-ltlastfoot" },
109         { LyXTabular::SET_LTNEWPAGE, "set-ltnewpage" },
110         { LyXTabular::SET_SPECIAL_COLUMN, "set-special-column" },
111         { LyXTabular::SET_SPECIAL_MULTI, "set-special-multi" },
112         { LyXTabular::LAST_ACTION, "" }
113 };
114
115 struct FindFeature {
116         FindFeature(LyXTabular::Feature feature) : feature_(feature) {}
117         bool operator()(TabularFeature & tf)
118         {
119                 return tf.action == feature_;
120         }
121 private:
122         LyXTabular::Feature feature_;
123 };
124
125 } // namespace anon
126
127
128 string const featureAsString(LyXTabular::Feature feature)
129 {
130         TabularFeature * it  = tabularFeature;
131         TabularFeature * end = it +
132                 sizeof(tabularFeature) / sizeof(TabularFeature);
133         it = std::find_if(it, end, FindFeature(feature));
134         return (it == end) ? string() : it->feature;
135 }
136
137
138 bool InsetTabular::hasPasteBuffer() const
139 {
140         return (paste_tabular != 0);
141 }
142
143
144 InsetTabular::InsetTabular(Buffer const & buf, int rows, int columns)
145         : tabular(buf.params, this, max(rows, 1), max(columns, 1)),
146           buffer_(&buf), cursorx_(0), cursory_(0)
147 {
148         // for now make it always display as display() inset
149         // just for test!!!
150         the_locking_inset = 0;
151         old_locking_inset = 0;
152         locked = false;
153         oldcell = -1;
154         actrow = actcell = 0;
155         clearSelection();
156         in_reset_pos = 0;
157         inset_x = 0;
158         inset_y = 0;
159 }
160
161
162 InsetTabular::InsetTabular(InsetTabular const & tab)
163         : UpdatableInset(tab),
164                 tabular(tab.buffer_->params, this, tab.tabular),
165                 buffer_(tab.buffer_), cursorx_(0), cursory_(0)
166 {
167         the_locking_inset = 0;
168         old_locking_inset = 0;
169         locked = false;
170         oldcell = -1;
171         actrow = actcell = 0;
172         clearSelection();
173         in_reset_pos = 0;
174         inset_x = 0;
175         inset_y = 0;
176 }
177
178
179 InsetTabular::~InsetTabular()
180 {
181         InsetTabularMailer(*this).hideDialog();
182 }
183
184
185 auto_ptr<InsetBase> InsetTabular::clone() const
186 {
187         return auto_ptr<InsetBase>(new InsetTabular(*this));
188 }
189
190
191 Buffer const & InsetTabular::buffer() const
192 {
193         return *buffer_;
194 }
195
196
197 BufferView * InsetTabular::view() const
198 {
199         Assert(false);
200         return 0;
201 }
202
203
204 void InsetTabular::buffer(Buffer * b)
205 {
206         buffer_ = b;
207 }
208
209
210 void InsetTabular::write(Buffer const & buf, ostream & os) const
211 {
212         os << "Tabular" << endl;
213         tabular.write(buf, os);
214 }
215
216
217 void InsetTabular::read(Buffer const & buf, LyXLex & lex)
218 {
219         bool const old_format = (lex.getString() == "\\LyXTable");
220
221         tabular.read(buf, lex);
222
223         if (old_format)
224                 return;
225
226         lex.nextToken();
227         string token = lex.getString();
228         while (lex.isOK() && (token != "\\end_inset")) {
229                 lex.nextToken();
230                 token = lex.getString();
231         }
232         if (token != "\\end_inset") {
233                 lex.printError("Missing \\end_inset at this point. "
234                                "Read: `$$Token'");
235         }
236 }
237
238
239 void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const
240 {
241         //lyxerr << "InsetTabular::metrics: " << mi.base.bv << " width: " <<
242         //      mi.base.textwidth << "\n";
243         if (!mi.base.bv) {
244                 lyxerr << "InsetTabular::metrics: need bv" << endl;
245                 Assert(0);
246         }
247
248         calculate_dimensions_of_cells(mi);
249
250         dim.asc = tabular.getAscentOfRow(0);
251         dim.des = tabular.getHeightOfTabular() - tabular.getAscentOfRow(0) + 1;
252         dim.wid = tabular.getWidthOfTabular() + 2 * ADD_TO_TABULAR_WIDTH;
253         dim_ = dim;
254 }
255
256
257 void InsetTabular::draw(PainterInfo & pi, int x, int y) const
258 {
259         //lyxerr << "InsetTabular::draw: " << x << " " << y << endl;
260
261         BufferView * bv = pi.base.bv;
262
263 #if 0
264         UpdatableInset::draw(pi, x, y);
265 #else
266         if (!owner())
267                 x += scroll();
268 #endif
269
270         top_x = x;
271         top_baseline = y;
272         x += ADD_TO_TABULAR_WIDTH;
273
274         int cell = 0;
275         first_visible_cell = -1;
276         for (int i = 0; i < tabular.rows(); ++i) {
277                 int nx = x;
278                 cell = tabular.getCellNumber(i, 0);
279                 if (y + tabular.getDescentOfRow(i) <= 0 &&
280                           y - tabular.getAscentOfRow(i) < pi.pain.paperHeight())
281                 {
282                         y += tabular.getDescentOfRow(i) +
283                                         tabular.getAscentOfRow(i + 1) +
284                                         tabular.getAdditionalHeight(i + 1);
285                         continue;
286                 }
287                 for (int j = 0; j < tabular.columns(); ++j) {
288                         if (nx > bv->workWidth())
289                                 break;
290                         if (tabular.isPartOfMultiColumn(i, j))
291                                 continue;
292                         int cx = nx + tabular.getBeginningOfTextInCell(cell);
293                         if (first_visible_cell < 0)
294                                 first_visible_cell = cell;
295                         if (hasSelection()) {
296                                 drawCellSelection(pi.pain, nx, y, i, j, cell);
297                         }
298
299                         tabular.getCellInset(cell).draw(pi, cx, y);
300                         drawCellLines(pi.pain, nx, y, i, cell);
301                         nx += tabular.getWidthOfColumn(cell);
302                         ++cell;
303                 }
304
305 // Would be nice, but for some completely unfathomable reason,
306 // on a col resize to a new fixed width, even though the insettexts
307 // are resized, the cell isn't, but drawing all cells in a tall table
308 // has the desired effect somehow. Complete dark magic.
309 #if 0
310                 // avoiding drawing the rest of a long table is
311                 // a pretty big speedup
312                 if (y > bv->workHeight())
313                         break;
314 #endif
315
316                 y += tabular.getDescentOfRow(i) +
317                         tabular.getAscentOfRow(i + 1) +
318                         tabular.getAdditionalHeight(i + 1);
319         }
320 }
321
322
323 void InsetTabular::drawCellLines(Painter & pain, int x, int y,
324                                  int row, int cell) const
325 {
326         int x2 = x + tabular.getWidthOfColumn(cell);
327         bool on_off;
328
329         if (!tabular.topAlreadyDrawn(cell)) {
330                 on_off = !tabular.topLine(cell);
331                 pain.line(x, y - tabular.getAscentOfRow(row),
332                           x2, y -  tabular.getAscentOfRow(row),
333                           on_off ? LColor::tabularonoffline : LColor::tabularline,
334                           on_off ? Painter::line_onoffdash : Painter::line_solid);
335         }
336         on_off = !tabular.bottomLine(cell);
337         pain.line(x, y + tabular.getDescentOfRow(row),
338                   x2, y + tabular.getDescentOfRow(row),
339                   on_off ? LColor::tabularonoffline : LColor::tabularline,
340                   on_off ? Painter::line_onoffdash : Painter::line_solid);
341         if (!tabular.leftAlreadyDrawn(cell)) {
342                 on_off = !tabular.leftLine(cell);
343                 pain.line(x, y -  tabular.getAscentOfRow(row),
344                           x, y +  tabular.getDescentOfRow(row),
345                           on_off ? LColor::tabularonoffline : LColor::tabularline,
346                           on_off ? Painter::line_onoffdash : Painter::line_solid);
347         }
348         on_off = !tabular.rightLine(cell);
349         pain.line(x2 - tabular.getAdditionalWidth(cell),
350                   y -  tabular.getAscentOfRow(row),
351                   x2 - tabular.getAdditionalWidth(cell),
352                   y +  tabular.getDescentOfRow(row),
353                   on_off ? LColor::tabularonoffline : LColor::tabularline,
354                   on_off ? Painter::line_onoffdash : Painter::line_solid);
355 }
356
357
358 void InsetTabular::drawCellSelection(Painter & pain, int x, int y,
359                                      int row, int column, int cell) const
360 {
361         Assert(hasSelection());
362         int cs = tabular.column_of_cell(sel_cell_start);
363         int ce = tabular.column_of_cell(sel_cell_end);
364         if (cs > ce) {
365                 ce = cs;
366                 cs = tabular.column_of_cell(sel_cell_end);
367         } else {
368                 ce = tabular.right_column_of_cell(sel_cell_end);
369         }
370
371         int rs = tabular.row_of_cell(sel_cell_start);
372         int re = tabular.row_of_cell(sel_cell_end);
373         if (rs > re)
374                 swap(rs, re);
375
376         if ((column >= cs) && (column <= ce) && (row >= rs) && (row <= re)) {
377                 int w = tabular.getWidthOfColumn(cell);
378                 int h = tabular.getAscentOfRow(row) + tabular.getDescentOfRow(row)-1;
379                 pain.fillRectangle(x, y - tabular.getAscentOfRow(row) + 1,
380                                    w, h, LColor::selection);
381         }
382 }
383
384
385 string const InsetTabular::editMessage() const
386 {
387         return _("Opened table");
388 }
389
390
391 void InsetTabular::insetUnlock(BufferView * bv)
392 {
393         if (the_locking_inset) {
394                 the_locking_inset->insetUnlock(bv);
395                 updateLocal(bv);
396                 the_locking_inset = 0;
397         }
398         actcell = 0;
399         oldcell = -1;
400         locked = false;
401         if (scroll(false) || hasSelection()) {
402                 clearSelection();
403                 if (scroll(false))
404                         scroll(bv, 0.0F);
405                 updateLocal(bv);
406         }
407 }
408
409
410 void InsetTabular::updateLocal(BufferView * bv) const
411 {
412         bv->updateInset(this);
413         if (locked)
414                 resetPos(bv);
415 }
416
417
418 bool InsetTabular::lockInsetInInset(BufferView * bv, UpdatableInset * inset)
419 {
420         lyxerr[Debug::INSETTEXT] << "InsetTabular::LockInsetInInset("
421                               << inset << "): ";
422         if (!inset)
423                 return false;
424         oldcell = -1;
425         if (inset == &tabular.getCellInset(actcell)) {
426                 lyxerr[Debug::INSETTEXT] << "OK" << endl;
427                 the_locking_inset = &tabular.getCellInset(actcell);
428                 resetPos(bv);
429                 return true;
430         } else if (!the_locking_inset) {
431                 int const n = tabular.getNumberOfCells();
432                 int const id = inset->id();
433                 for (int i = 0; i < n; ++i) {
434                         InsetText * in = &tabular.getCellInset(i);
435                         if (inset == in) {
436                                 actcell = i;
437                                 the_locking_inset = in;
438                                 locked = true;
439                                 resetPos(bv);
440                                 return true;
441                         }
442                         if (in->getInsetFromID(id)) {
443                                 actcell = i;
444                                 in->localDispatch(FuncRequest(bv, LFUN_INSET_EDIT));
445                                 return the_locking_inset->lockInsetInInset(bv, inset);
446                         }
447                 }
448         } else if (the_locking_inset && (the_locking_inset == inset)) {
449                 lyxerr[Debug::INSETTEXT] << "OK" << endl;
450                 resetPos(bv);
451         } else if (the_locking_inset) {
452                 lyxerr[Debug::INSETTEXT] << "MAYBE" << endl;
453                 return the_locking_inset->lockInsetInInset(bv, inset);
454         }
455         lyxerr[Debug::INSETTEXT] << "NOT OK" << endl;
456         return false;
457 }
458
459
460 bool InsetTabular::unlockInsetInInset(BufferView * bv, UpdatableInset * inset,
461                                       bool lr)
462 {
463         if (!the_locking_inset)
464                 return false;
465         if (the_locking_inset == inset) {
466                 the_locking_inset->insetUnlock(bv);
467 #ifdef WITH_WARNINGS
468 #warning fix scrolling when cellinset has requested a scroll (Jug)!!!
469 #endif
470 #if 0
471                 if (scroll(false))
472                         scroll(bv, 0.0F);
473 #endif
474                 updateLocal(bv);
475                 // this has to be here otherwise we don't redraw the cell!
476                 the_locking_inset = 0;
477                 return true;
478         }
479         if (the_locking_inset->unlockInsetInInset(bv, inset, lr)) {
480                 if (inset->lyxCode() == TABULAR_CODE &&
481                     !the_locking_inset->getFirstLockingInsetOfType(TABULAR_CODE)) {
482                         InsetTabularMailer(*this).updateDialog(bv);
483                         oldcell = actcell;
484                 }
485                 return true;
486         }
487         return false;
488 }
489
490
491 int InsetTabular::insetInInsetY() const
492 {
493         if (!the_locking_inset)
494                 return 0;
495         return inset_y + the_locking_inset->insetInInsetY();
496 }
497
498
499 UpdatableInset * InsetTabular::getLockingInset() const
500 {
501         return the_locking_inset ? the_locking_inset->getLockingInset() :
502                 const_cast<InsetTabular *>(this);
503 }
504
505
506 UpdatableInset * InsetTabular::getFirstLockingInsetOfType(InsetOld::Code c)
507 {
508         if (c == lyxCode())
509                 return this;
510         if (the_locking_inset)
511                 return the_locking_inset->getFirstLockingInsetOfType(c);
512         return 0;
513 }
514
515
516 bool InsetTabular::insertInset(BufferView * bv, InsetOld * inset)
517 {
518         if (the_locking_inset)
519                 return the_locking_inset->insertInset(bv, inset);
520         return false;
521 }
522
523
524 void InsetTabular::lfunMousePress(FuncRequest const & cmd)
525 {
526         if (hasSelection() && cmd.button() == mouse_button::button3)
527                 return;
528
529         if (hasSelection()) {
530                 clearSelection();
531                 updateLocal(cmd.view());
532         }
533
534         int const ocell = actcell;
535         BufferView * bv = cmd.view();
536
537         if (!locked) {
538                 locked = true;
539                 the_locking_inset = 0;
540                 inset_x = 0;
541                 inset_y = 0;
542         }
543         setPos(bv, cmd.x, cmd.y);
544         clearSelection();
545
546         bool const inset_hit = insetHit(bv, cmd.x, cmd.y);
547
548         if ((ocell == actcell) && the_locking_inset && inset_hit) {
549                 resetPos(bv);
550                 FuncRequest cmd1 = cmd;
551                 cmd1.x -= inset_x;
552                 cmd1.y -= inset_y;
553                 the_locking_inset->localDispatch(cmd1);
554                 return;
555         }
556
557         if (the_locking_inset) {
558                 the_locking_inset->insetUnlock(bv);
559                 updateLocal(bv);
560                 the_locking_inset = 0;
561         }
562
563         if (cmd.button() == mouse_button::button2) {
564                 localDispatch(FuncRequest(bv, LFUN_PASTESELECTION, "paragraph"));
565                 return;
566         }
567
568         if (inset_hit && bv->theLockingInset()) {
569                 if (!bv->lockInset(&tabular.getCellInset(actcell))) {
570                         lyxerr[Debug::INSETS] << "Cannot lock inset" << endl;
571                         return;
572                 }
573                 FuncRequest cmd1 = cmd;
574                 cmd1.x -= inset_x;
575                 cmd1.y -= inset_y;
576                 the_locking_inset->localDispatch(cmd1);
577         }
578 }
579
580
581 bool InsetTabular::lfunMouseRelease(FuncRequest const & cmd)
582 {
583         bool ret = false;
584         if (the_locking_inset) {
585                 FuncRequest cmd1 = cmd;
586                 cmd1.x -= inset_x;
587                 cmd1.y -= inset_y;
588                 ret = the_locking_inset->localDispatch(cmd1);
589         }
590         if (cmd.button() == mouse_button::button3 && !ret) {
591                 InsetTabularMailer(*this).showDialog(cmd.view());
592                 return true;
593         }
594         return ret;
595 }
596
597
598 void InsetTabular::lfunMouseMotion(FuncRequest const & cmd)
599 {
600         if (the_locking_inset) {
601                 FuncRequest cmd1 = cmd;
602                 cmd1.x -= inset_x;
603                 cmd1.y -= inset_y;
604                 the_locking_inset->localDispatch(cmd1);
605                 return;
606         }
607
608         BufferView * bv = cmd.view();
609         int const old_cell = actcell;
610
611         setPos(bv, cmd.x, cmd.y);
612         if (!hasSelection()) {
613                 setSelection(actcell, actcell);
614                 updateLocal(bv);
615         } else if (old_cell != actcell) {
616                 setSelection(sel_cell_start, actcell);
617                 updateLocal(bv);
618         }
619 }
620
621
622 InsetOld::RESULT InsetTabular::localDispatch(FuncRequest const & cmd)
623 {
624         // We need to save the value of the_locking_inset as the call to
625         // the_locking_inset->localDispatch might unlock it.
626         old_locking_inset = the_locking_inset;
627         RESULT result = UpdatableInset::localDispatch(cmd);
628         BufferView * bv = cmd.view();
629
630         if (cmd.action == LFUN_INSET_EDIT) {
631
632                 if (!bv->lockInset(this)) {
633                         lyxerr[Debug::INSETTEXT] << "InsetTabular::Cannot lock inset" << endl;
634                         return DISPATCHED;
635                 }
636
637                 finishUndo();
638                 locked = true;
639                 the_locking_inset = 0;
640                 inset_x = 0;
641                 inset_y = 0;
642
643                 if (cmd.argument.size()) {
644                         if (cmd.argument == "left") {
645                                 if (isRightToLeft(bv))
646                                         actcell = tabular.getLastCellInRow(0);
647                                 else
648                                         actcell = 0;
649                         } else {
650                                 if (isRightToLeft(bv))
651                                         actcell = tabular.getFirstCellInRow(tabular.rows()-1);
652                                 else
653                                         actcell = tabular.getNumberOfCells() - 1;
654                         }
655                         clearSelection();
656                         resetPos(bv);
657                         bv->fitCursor();
658                 }
659
660                 else {
661                         setPos(bv, cmd.x, cmd.y);
662                         clearSelection();
663                         finishUndo();
664                         if (insetHit(bv, cmd.x, cmd.y) && cmd.button() != mouse_button::button3) {
665                                 activateCellInsetAbs(bv, cmd.x, cmd.y, cmd.button());
666                         }
667                 }
668                 return DISPATCHED;
669         }
670
671         if (result == DISPATCHED || result == DISPATCHED_NOUPDATE) {
672                 resetPos(bv);
673                 return result;
674         }
675
676         if (cmd.action < 0 && cmd.argument.empty())
677                 return FINISHED;
678
679         bool hs = hasSelection();
680
681         result = DISPATCHED;
682         // this one have priority over the locked InsetText, if we're not already
683         // inside another tabular then that one get's priority!
684         if (getFirstLockingInsetOfType(InsetOld::TABULAR_CODE) == this) {
685                 switch (cmd.action) {
686                 case LFUN_MOUSE_PRESS:
687                         lfunMousePress(cmd);
688                         return DISPATCHED;
689
690                 case LFUN_MOUSE_MOTION:
691                         lfunMouseMotion(cmd);
692                         return DISPATCHED;
693
694                 case LFUN_MOUSE_RELEASE:
695                         return lfunMouseRelease(cmd) ? DISPATCHED : UNDISPATCHED;
696
697                 case LFUN_CELL_BACKWARD:
698                 case LFUN_CELL_FORWARD:
699                         unlockInsetInInset(bv, the_locking_inset);
700                         if (cmd.action == LFUN_CELL_FORWARD)
701                                 moveNextCell(bv, old_locking_inset != 0);
702                         else
703                                 movePrevCell(bv, old_locking_inset != 0);
704                         clearSelection();
705                         if (hs)
706                                 updateLocal(bv);
707                         if (!the_locking_inset)
708                                 return DISPATCHED_NOUPDATE;
709                         return result;
710                 // this to avoid compiler warnings.
711                 default:
712                         break;
713                 }
714         }
715
716         kb_action action = cmd.action;
717         string    arg    = cmd.argument;
718         if (the_locking_inset) {
719                 result = the_locking_inset->localDispatch(cmd);
720                 if (result == DISPATCHED_NOUPDATE) {
721                         int sc = scroll();
722                         resetPos(bv);
723                         if (sc != scroll()) { // inset has been scrolled
724                                 updateLocal(bv);
725                         }
726                         return result;
727                 } else if (result == DISPATCHED) {
728                         updateLocal(bv);
729                         return result;
730                 } else if (result == FINISHED_UP) {
731                         action = LFUN_UP;
732                         // Make sure to reset status message after
733                         // exiting, e.g. math inset
734                         bv->owner()->clearMessage();
735                 } else if (result == FINISHED_DOWN) {
736                         action = LFUN_DOWN;
737                         bv->owner()->clearMessage();
738                 } else if (result == FINISHED_RIGHT) {
739                         action = LFUN_RIGHT;
740                         bv->owner()->clearMessage();
741                 } else if (result == FINISHED) {
742                         bv->owner()->clearMessage();
743                 }
744         }
745
746         result = DISPATCHED;
747         switch (action) {
748                 // --- Cursor Movements ----------------------------------
749         case LFUN_RIGHTSEL: {
750                 int const start = hasSelection() ? sel_cell_start : actcell;
751                 if (tabular.isLastCellInRow(actcell)) {
752                         setSelection(start, actcell);
753                         break;
754                 }
755
756                 int end = actcell;
757                 // if we are starting a selection, only select
758                 // the current cell at the beginning
759                 if (hasSelection()) {
760                         moveRight(bv, false);
761                         end = actcell;
762                 }
763                 setSelection(start, end);
764                 updateLocal(bv);
765                 break;
766         }
767         case LFUN_RIGHT:
768                 result = moveRight(bv);
769                 clearSelection();
770                 if (hs)
771                         updateLocal(bv);
772                 break;
773         case LFUN_LEFTSEL: {
774                 int const start = hasSelection() ? sel_cell_start : actcell;
775                 if (tabular.isFirstCellInRow(actcell)) {
776                         setSelection(start, actcell);
777                         break;
778                 }
779
780                 int end = actcell;
781                 // if we are starting a selection, only select
782                 // the current cell at the beginning
783                 if (hasSelection()) {
784                         moveLeft(bv, false);
785                         end = actcell;
786                 }
787                 setSelection(start, end);
788                 updateLocal(bv);
789                 break;
790         }
791         case LFUN_LEFT:
792                 result = moveLeft(bv);
793                 clearSelection();
794                 if (hs)
795                         updateLocal(bv);
796                 break;
797         case LFUN_DOWNSEL: {
798                 int const start = hasSelection() ? sel_cell_start : actcell;
799                 int const ocell = actcell;
800                 // if we are starting a selection, only select
801                 // the current cell at the beginning
802                 if (hasSelection()) {
803                         moveDown(bv, false);
804                         if (ocell == sel_cell_end ||
805                             tabular.column_of_cell(ocell) > tabular.column_of_cell(actcell))
806                                 setSelection(start, tabular.getCellBelow(sel_cell_end));
807                         else
808                                 setSelection(start, tabular.getLastCellBelow(sel_cell_end));
809                 } else {
810                         setSelection(start, start);
811                 }
812                 updateLocal(bv);
813         }
814         break;
815         case LFUN_DOWN:
816                 result = moveDown(bv, old_locking_inset != 0);
817                 clearSelection();
818                 if (hs)
819                         updateLocal(bv);
820                 break;
821         case LFUN_UPSEL: {
822                 int const start = hasSelection() ? sel_cell_start : actcell;
823                 int const ocell = actcell;
824                 // if we are starting a selection, only select
825                 // the current cell at the beginning
826                 if (hasSelection()) {
827                         moveUp(bv, false);
828                         if ((ocell == sel_cell_end) ||
829                             (tabular.column_of_cell(ocell)>tabular.column_of_cell(actcell)))
830                                 setSelection(start, tabular.getCellAbove(sel_cell_end));
831                         else
832                                 setSelection(start, tabular.getLastCellAbove(sel_cell_end));
833                 } else {
834                         setSelection(start, start);
835                 }
836                 updateLocal(bv);
837         }
838         break;
839         case LFUN_UP:
840                 result = moveUp(bv, old_locking_inset != 0);
841                 clearSelection();
842                 if (hs)
843                         updateLocal(bv);
844                 break;
845         case LFUN_NEXT: {
846                 if (hs)
847                         clearSelection();
848                 int column = actcol;
849                 unlockInsetInInset(bv, the_locking_inset);
850                 if (bv->top_y() + bv->painter().paperHeight() <
851                     top_baseline + tabular.getHeightOfTabular())
852                         {
853                                 bv->scrollDocView(bv->top_y() + bv->painter().paperHeight());
854                                 actcell = tabular.getCellBelow(first_visible_cell) + column;
855                         } else {
856                                 actcell = tabular.getFirstCellInRow(tabular.rows() - 1) + column;
857                         }
858                 resetPos(bv);
859                 updateLocal(bv);
860                 break;
861         }
862         case LFUN_PRIOR: {
863                 if (hs)
864                         clearSelection();
865                 int column = actcol;
866                 unlockInsetInInset(bv, the_locking_inset);
867                 if (top_baseline < 0) {
868                         bv->scrollDocView(bv->top_y() - bv->painter().paperHeight());
869                         if (top_baseline > 0)
870                                 actcell = column;
871                         else
872                                 actcell = tabular.getCellBelow(first_visible_cell) + column;
873                 } else {
874                         actcell = column;
875                 }
876                 resetPos(bv);
877                 updateLocal(bv);
878                 break;
879         }
880         // none of these make sense for insettabular,
881         // but we must catch them to prevent any
882         // selection from being confused
883         case LFUN_PRIORSEL:
884         case LFUN_NEXTSEL:
885         case LFUN_WORDLEFT:
886         case LFUN_WORDLEFTSEL:
887         case LFUN_WORDRIGHT:
888         case LFUN_WORDRIGHTSEL:
889         case LFUN_WORDSEL:
890         case LFUN_DOWN_PARAGRAPH:
891         case LFUN_DOWN_PARAGRAPHSEL:
892         case LFUN_UP_PARAGRAPH:
893         case LFUN_UP_PARAGRAPHSEL:
894         case LFUN_BACKSPACE:
895         case LFUN_HOME:
896         case LFUN_HOMESEL:
897         case LFUN_END:
898         case LFUN_ENDSEL:
899         case LFUN_BEGINNINGBUF:
900         case LFUN_BEGINNINGBUFSEL:
901         case LFUN_ENDBUF:
902         case LFUN_ENDBUFSEL:
903                 break;
904         case LFUN_LAYOUT_TABULAR: {
905                 InsetTabularMailer(*this).showDialog(bv);
906                 break;
907         }
908         case LFUN_INSET_DIALOG_UPDATE: {
909                 InsetTabularMailer(*this).updateDialog(bv);
910                 break;
911         }
912         case LFUN_TABULAR_FEATURE:
913                 if (!tabularFeatures(bv, arg))
914                         result = UNDISPATCHED;
915                 break;
916                 // insert file functions
917         case LFUN_FILE_INSERT_ASCII_PARA:
918         case LFUN_FILE_INSERT_ASCII:
919         {
920                 string tmpstr = getContentsOfAsciiFile(bv, arg, false);
921                 if (tmpstr.empty())
922                         break;
923                 if (insertAsciiString(bv, tmpstr, false))
924                         updateLocal(bv);
925                 else
926                         result = UNDISPATCHED;
927                 break;
928         }
929         // cut and paste functions
930         case LFUN_CUT:
931                 if (!copySelection(bv))
932                         break;
933                 // no break here!
934         case LFUN_DELETE:
935                 recordUndo(bv, Undo::DELETE);
936                 cutSelection(bv->buffer()->params);
937                 updateLocal(bv);
938                 break;
939         case LFUN_COPY:
940                 if (!hasSelection())
941                         break;
942                 finishUndo();
943                 copySelection(bv);
944                 break;
945         case LFUN_PASTESELECTION:
946         {
947                 string const clip(bv->getClipboard());
948                         if (clip.empty())
949                         break;
950 #if 0
951                 if (clip.find('\t') != string::npos) {
952                         int cols = 1;
953                         int rows = 1;
954                         int maxCols = 1;
955                         string::size_type len = clip.length();
956                         string::size_type p = 0;
957
958                         while (p < len &&
959                               ((p = clip.find_first_of("\t\n", p)) != string::npos)) {
960                                 switch (clip[p]) {
961                                 case '\t':
962                                         ++cols;
963                                         break;
964                                 case '\n':
965                                         if ((p+1) < len)
966                                                 ++rows;
967                                         maxCols = max(cols, maxCols);
968                                         cols = 1;
969                                         break;
970                                 }
971                                 ++p;
972                         }
973                         maxCols = max(cols, maxCols);
974                         delete paste_tabular;
975                         paste_tabular = new LyXTabular(bv->buffer()->params,
976                                                        this, rows, maxCols);
977                         string::size_type op = 0;
978                         int cell = 0;
979                         int cells = paste_tabular->getNumberOfCells();
980                         p = cols = 0;
981                         while ((cell < cells) && (p < len) &&
982                               (p = clip.find_first_of("\t\n", p)) != string::npos) {
983                                 if (p >= len)
984                                         break;
985                                 switch (clip[p]) {
986                                 case '\t':
987                                         paste_tabular->getCellInset(cell)->setText(clip.substr(op, p-op));
988                                         ++cols;
989                                         ++cell;
990                                         break;
991                                 case '\n':
992                                         paste_tabular->getCellInset(cell)->setText(clip.substr(op, p-op));
993                                         while (cols++ < maxCols)
994                                                 ++cell;
995                                         cols = 0;
996                                         break;
997                                 }
998                                 ++p;
999                                 op = p;
1000                         }
1001                         // check for the last cell if there is no trailing '\n'
1002                         if ((cell < cells) && (op < len))
1003                                 paste_tabular->getCellInset(cell)->setText(clip.substr(op, len-op));
1004                 } else
1005 #else
1006                 if (!insertAsciiString(bv, clip, true))
1007 #endif
1008                 {
1009                         // so that the clipboard is used and it goes on
1010                         // to default
1011                         // and executes LFUN_PASTESELECTION in insettext!
1012                         delete paste_tabular;
1013                         paste_tabular = 0;
1014                 }
1015         }
1016         case LFUN_PASTE:
1017                 if (hasPasteBuffer()) {
1018                         recordUndo(bv, Undo::INSERT);
1019                         pasteSelection(bv);
1020                         updateLocal(bv);
1021                         break;
1022                 }
1023                 // ATTENTION: the function above has to be PASTE and PASTESELECTION!!!
1024         default:
1025                 // handle font changing stuff on selection before we lock the inset
1026                 // in the default part!
1027                 result = UNDISPATCHED;
1028                 if (hs) {
1029                         switch(action) {
1030                         case LFUN_LANGUAGE:
1031                         case LFUN_EMPH:
1032                         case LFUN_BOLD:
1033                         case LFUN_NOUN:
1034                         case LFUN_CODE:
1035                         case LFUN_SANS:
1036                         case LFUN_ROMAN:
1037                         case LFUN_DEFAULT:
1038                         case LFUN_UNDERLINE:
1039                         case LFUN_FONT_SIZE:
1040                                 if (bv->dispatch(FuncRequest(bv, action, arg)))
1041                                         result = DISPATCHED;
1042                                 break;
1043                         default:
1044                                 break;
1045                         }
1046                 }
1047                 // we try to activate the actual inset and put this event down to
1048                 // the insets dispatch function.
1049                 if (result == DISPATCHED || the_locking_inset)
1050                         break;
1051                 if (activateCellInset(bv)) {
1052                         result = the_locking_inset->localDispatch(FuncRequest(bv, action, arg));
1053                         if (result == UNDISPATCHED || result >= FINISHED) {
1054                                 unlockInsetInInset(bv, the_locking_inset);
1055                                 // we need to update if this was requested before
1056                                 updateLocal(bv);
1057                                 return UNDISPATCHED;
1058                         }
1059                         if (hs)
1060                                 clearSelection();
1061                         updateLocal(bv);
1062                         return result;
1063                 }
1064                 break;
1065         }
1066         if (result < FINISHED) {
1067                 if (!the_locking_inset && bv->fitCursor())
1068                         updateLocal(bv);
1069         } else
1070                 bv->unlockInset(this);
1071         return result;
1072 }
1073
1074
1075 int InsetTabular::latex(Buffer const & buf, ostream & os,
1076                         LatexRunParams const & runparams) const
1077 {
1078         return tabular.latex(buf, os, runparams);
1079 }
1080
1081
1082 int InsetTabular::ascii(Buffer const & buf, ostream & os, int ll) const
1083 {
1084         if (ll > 0)
1085                 return tabular.ascii(buf, os, ownerPar(buf, this).params().depth(),
1086                                       false, 0);
1087         return tabular.ascii(buf, os, 0, false, 0);
1088 }
1089
1090
1091 int InsetTabular::linuxdoc(Buffer const & buf, ostream & os) const
1092 {
1093         return tabular.linuxdoc(buf,os);
1094 }
1095
1096
1097 int InsetTabular::docbook(Buffer const & buf, ostream & os, bool mixcont) const
1098 {
1099         int ret = 0;
1100         InsetOld * master;
1101
1102         // if the table is inside a float it doesn't need the informaltable
1103         // wrapper. Search for it.
1104         for (master = owner();
1105              master && master->lyxCode() != InsetOld::FLOAT_CODE;
1106              master = master->owner());
1107
1108         if (!master) {
1109                 os << "<informaltable>";
1110                 if (mixcont)
1111                         os << endl;
1112                 ++ret;
1113         }
1114         ret += tabular.docbook(buf, os, mixcont);
1115         if (!master) {
1116                 os << "</informaltable>";
1117                 if (mixcont)
1118                         os << endl;
1119                 ++ret;
1120         }
1121         return ret;
1122 }
1123
1124
1125 void InsetTabular::validate(LaTeXFeatures & features) const
1126 {
1127         tabular.validate(features);
1128 }
1129
1130
1131 void InsetTabular::calculate_dimensions_of_cells(MetricsInfo & mi) const
1132 {
1133 #if 1
1134         // if we have a locking_inset we should have to check only this cell for
1135         // change so I'll try this to have a boost, but who knows ;) (Jug?)
1136         // This is _really_ important (André)
1137         if (the_locking_inset == &tabular.getCellInset(actcell)) {
1138                 int maxAsc = 0;
1139                 int maxDesc = 0;
1140                 for (int j = 0; j < tabular.columns(); ++j) {
1141                         Dimension dim;
1142                         MetricsInfo m = mi;
1143                         m.base.textwidth =
1144                                 tabular.column_info[j].p_width.inPixels(mi.base.textwidth);
1145                         tabular.getCellInset(actrow, j).metrics(m, dim);
1146                         maxAsc  = max(dim.asc, maxAsc);
1147                         maxDesc = max(dim.des, maxDesc);
1148                 }
1149                 tabular.setWidthOfCell(actcell, the_locking_inset->width());
1150                 tabular.setAscentOfRow(actrow, maxAsc + ADD_TO_HEIGHT);
1151                 tabular.setDescentOfRow(actrow, maxDesc + ADD_TO_HEIGHT);
1152                 return;
1153         }
1154 #endif
1155
1156         int cell = -1;
1157         for (int i = 0; i < tabular.rows(); ++i) {
1158                 int maxAsc = 0;
1159                 int maxDesc = 0;
1160                 for (int j = 0; j < tabular.columns(); ++j) {
1161                         if (tabular.isPartOfMultiColumn(i, j))
1162                                 continue;
1163                         ++cell;
1164                         Dimension dim;
1165                         MetricsInfo m = mi;
1166                         m.base.textwidth =
1167                                 tabular.column_info[j].p_width.inPixels(mi.base.textwidth);
1168                         tabular.getCellInset(cell).metrics(m, dim);
1169                         maxAsc  = max(maxAsc, dim.asc);
1170                         maxDesc = max(maxDesc, dim.des);
1171                         tabular.setWidthOfCell(cell, dim.wid);
1172                 }
1173                 tabular.setAscentOfRow(i, maxAsc + ADD_TO_HEIGHT);
1174                 tabular.setDescentOfRow(i, maxDesc + ADD_TO_HEIGHT);
1175         }
1176 }
1177
1178
1179 void InsetTabular::getCursor(BufferView & bv, int & x, int & y) const
1180 {
1181         if (the_locking_inset) {
1182                 the_locking_inset->getCursor(bv, x, y);
1183                 return;
1184         }
1185
1186         x = cursorx_;
1187         y = cursory_ + InsetTabular::y();
1188
1189         // Fun stuff
1190         int desc = tabular.getDescentOfRow(actrow);
1191         y += desc;
1192         int ascdesc = tabular.getAscentOfRow(actrow) + desc;
1193         y -= ascdesc / 2;
1194         y += ADD_TO_HEIGHT * 2;
1195         y += TEXT_TO_INSET_OFFSET;
1196 }
1197
1198
1199 void InsetTabular::getCursorPos(BufferView * bv, int & x, int & y) const
1200 {
1201         if (the_locking_inset) {
1202                 the_locking_inset->getCursorPos(bv, x, y);
1203                 return;
1204         }
1205         x = cursorx_ - top_x;
1206         y = cursory_;
1207 }
1208
1209
1210 void InsetTabular::fitInsetCursor(BufferView * bv) const
1211 {
1212         if (the_locking_inset) {
1213                 the_locking_inset->fitInsetCursor(bv);
1214                 return;
1215         }
1216
1217         LyXFont font;
1218         int const asc = font_metrics::maxAscent(font);
1219         int const desc = font_metrics::maxDescent(font);
1220         resetPos(bv);
1221
1222         bv->fitLockedInsetCursor(cursorx_, cursory_, asc, desc);
1223 }
1224
1225
1226 void InsetTabular::setPos(BufferView * bv, int x, int y) const
1227 {
1228         cursory_ = 0;
1229         actcell = actrow = actcol = 0;
1230         int ly = tabular.getDescentOfRow(actrow);
1231
1232         // first search the right row
1233         while (ly < y && actrow + 1 < tabular.rows()) {
1234                 cursory_ += tabular.getDescentOfRow(actrow) +
1235                                  tabular.getAscentOfRow(actrow + 1) +
1236                                  tabular.getAdditionalHeight(actrow + 1);
1237                 ++actrow;
1238                 ly = cursory_ + tabular.getDescentOfRow(actrow);
1239         }
1240         actcell = tabular.getCellNumber(actrow, actcol);
1241
1242         // now search the right column
1243         int lx = tabular.getWidthOfColumn(actcell) -
1244                 tabular.getAdditionalWidth(actcell);
1245
1246         for (; !tabular.isLastCellInRow(actcell) && lx < x; ++actcell)
1247                 lx += tabular.getWidthOfColumn(actcell + 1)
1248                         + tabular.getAdditionalWidth(actcell);
1249
1250         cursorx_ = lx - tabular.getWidthOfColumn(actcell) + top_x + 2;
1251         resetPos(bv);
1252 }
1253
1254
1255 int InsetTabular::getCellXPos(int cell) const
1256 {
1257         int c = cell;
1258
1259         for (; !tabular.isFirstCellInRow(c); --c)
1260                 ;
1261         int lx = tabular.getWidthOfColumn(cell);
1262         for (; c < cell; ++c)
1263                 lx += tabular.getWidthOfColumn(c);
1264
1265         return (lx - tabular.getWidthOfColumn(cell) + top_x);
1266 }
1267
1268
1269 void InsetTabular::resetPos(BufferView * bv) const
1270 {
1271 #ifdef WITH_WARNINGS
1272 #warning This should be fixed in the right manner (20011128 Jug)
1273 #endif
1274         // fast hack to fix infinite repaintings!
1275         if (in_reset_pos > 0)
1276                 return;
1277
1278         int cell = 0;
1279         actcol = tabular.column_of_cell(actcell);
1280         actrow = 0;
1281         cursory_ = 0;
1282         for (; cell < actcell && !tabular.isLastRow(cell); ++cell) {
1283                 if (tabular.isLastCellInRow(cell)) {
1284                         cursory_ += tabular.getDescentOfRow(actrow) +
1285                                          tabular.getAscentOfRow(actrow + 1) +
1286                                          tabular.getAdditionalHeight(actrow + 1);
1287                         ++actrow;
1288                 }
1289         }
1290         if (!locked) {
1291                 if (the_locking_inset)
1292                         inset_y = cursory_;
1293                 return;
1294         }
1295         // we need this only from here on!!!
1296         ++in_reset_pos;
1297         static int const offset = ADD_TO_TABULAR_WIDTH + 2;
1298         int new_x = getCellXPos(actcell);
1299         int old_x = cursorx_;
1300         new_x += offset;
1301         cursorx_ = new_x;
1302 //    cursor.x(getCellXPos(actcell) + offset);
1303         if (actcol < tabular.columns() - 1 && scroll(false) &&
1304                 tabular.getWidthOfTabular() < bv->workWidth()-20)
1305         {
1306                 scroll(bv, 0.0F);
1307                 updateLocal(bv);
1308         } else if (the_locking_inset &&
1309                  tabular.getWidthOfColumn(actcell) > bv->workWidth() - 20)
1310         {
1311                 int xx = cursorx_ - offset + bv->text->getRealCursorX();
1312                 if (xx > bv->workWidth()-20) {
1313                         scroll(bv, -(xx - bv->workWidth() + 60));
1314                         updateLocal(bv);
1315                 } else if (xx < 20) {
1316                         if (xx < 0)
1317                                 xx = -xx + 60;
1318                         else
1319                                 xx = 60;
1320                         scroll(bv, xx);
1321                         updateLocal(bv);
1322                 }
1323         } else if (cursorx_ - offset > 20 &&
1324                    cursorx_ - offset + tabular.getWidthOfColumn(actcell)
1325                    > bv->workWidth() - 20) {
1326                 scroll(bv, -tabular.getWidthOfColumn(actcell) - 20);
1327                 updateLocal(bv);
1328         } else if (cursorx_ - offset < 20) {
1329                 scroll(bv, 20 - cursorx_ + offset);
1330                 updateLocal(bv);
1331         } else if (scroll() && top_x > 20 &&
1332                    (top_x + tabular.getWidthOfTabular()) > bv->workWidth() - 20) {
1333                 scroll(bv, old_x - cursorx_);
1334                 updateLocal(bv);
1335         }
1336         if (the_locking_inset) {
1337                 inset_x = cursorx_ - top_x + tabular.getBeginningOfTextInCell(actcell);
1338                 inset_y = cursory_;
1339         }
1340         if ((!the_locking_inset ||
1341              !the_locking_inset->getFirstLockingInsetOfType(TABULAR_CODE)) &&
1342             actcell != oldcell) {
1343                 InsetTabularMailer(*this).updateDialog(bv);
1344                 oldcell = actcell;
1345         }
1346         in_reset_pos = 0;
1347 }
1348
1349
1350 InsetOld::RESULT InsetTabular::moveRight(BufferView * bv, bool lock)
1351 {
1352         if (lock && !old_locking_inset) {
1353                 if (activateCellInset(bv))
1354                         return DISPATCHED;
1355         } else {
1356                 bool moved = isRightToLeft(bv)
1357                         ? movePrevCell(bv) : moveNextCell(bv);
1358                 if (!moved)
1359                         return FINISHED_RIGHT;
1360                 if (lock && activateCellInset(bv))
1361                         return DISPATCHED;
1362         }
1363         resetPos(bv);
1364         return DISPATCHED_NOUPDATE;
1365 }
1366
1367
1368 InsetOld::RESULT InsetTabular::moveLeft(BufferView * bv, bool lock)
1369 {
1370         bool moved = isRightToLeft(bv) ? moveNextCell(bv) : movePrevCell(bv);
1371         if (!moved)
1372                 return FINISHED;
1373         if (lock) {       // behind the inset
1374                 if (activateCellInset(bv, 0, 0, mouse_button::none, true))
1375                         return DISPATCHED;
1376         }
1377         resetPos(bv);
1378         return DISPATCHED_NOUPDATE;
1379 }
1380
1381
1382 InsetOld::RESULT InsetTabular::moveUp(BufferView * bv, bool lock)
1383 {
1384         int const ocell = actcell;
1385         actcell = tabular.getCellAbove(actcell);
1386         if (actcell == ocell) // we moved out of the inset
1387                 return FINISHED_UP;
1388         resetPos(bv);
1389         if (lock) {
1390                 int x = 0;
1391                 int y = 0;
1392                 if (old_locking_inset) {
1393                         old_locking_inset->getCursorPos(bv, x, y);
1394                         x -= cursorx_ + tabular.getBeginningOfTextInCell(actcell);
1395                 }
1396                 if (activateCellInset(bv, x, 0))
1397                         return DISPATCHED;
1398         }
1399         return DISPATCHED_NOUPDATE;
1400 }
1401
1402
1403 InsetOld::RESULT InsetTabular::moveDown(BufferView * bv, bool lock)
1404 {
1405         int const ocell = actcell;
1406         actcell = tabular.getCellBelow(actcell);
1407         if (actcell == ocell) // we moved out of the inset
1408                 return FINISHED_DOWN;
1409         resetPos(bv);
1410         if (lock) {
1411                 int x = 0;
1412                 int y = 0;
1413                 if (old_locking_inset) {
1414                         old_locking_inset->getCursorPos(bv, x, y);
1415                         x -= cursorx_ + tabular.getBeginningOfTextInCell(actcell);
1416                 }
1417                 if (activateCellInset(bv, x, 0))
1418                         return DISPATCHED;
1419         }
1420         return DISPATCHED_NOUPDATE;
1421 }
1422
1423
1424 bool InsetTabular::moveNextCell(BufferView * bv, bool lock)
1425 {
1426         if (isRightToLeft(bv)) {
1427                 if (tabular.isFirstCellInRow(actcell)) {
1428                         int row = tabular.row_of_cell(actcell);
1429                         if (row == tabular.rows() - 1)
1430                                 return false;
1431                         actcell = tabular.getLastCellInRow(row);
1432                         actcell = tabular.getCellBelow(actcell);
1433                 } else {
1434                         if (!actcell)
1435                                 return false;
1436                         --actcell;
1437                 }
1438         } else {
1439                 if (tabular.isLastCell(actcell))
1440                         return false;
1441                 ++actcell;
1442         }
1443         if (lock) {
1444                 bool rtl = tabular.getCellInset(actcell).paragraphs.begin()->
1445                         isRightToLeftPar(bv->buffer()->params);
1446                 activateCellInset(bv, 0, 0, mouse_button::none, !rtl);
1447         }
1448         resetPos(bv);
1449         return true;
1450 }
1451
1452
1453 bool InsetTabular::movePrevCell(BufferView * bv, bool lock)
1454 {
1455         if (isRightToLeft(bv)) {
1456                 if (tabular.isLastCellInRow(actcell)) {
1457                         int row = tabular.row_of_cell(actcell);
1458                         if (row == 0)
1459                                 return false;
1460                         actcell = tabular.getFirstCellInRow(row);
1461                         actcell = tabular.getCellAbove(actcell);
1462                 } else {
1463                         if (tabular.isLastCell(actcell))
1464                                 return false;
1465                         ++actcell;
1466                 }
1467         } else {
1468                 if (!actcell) // first cell
1469                         return false;
1470                 --actcell;
1471         }
1472         if (lock) {
1473                 bool rtl = tabular.getCellInset(actcell).paragraphs.begin()->
1474                         isRightToLeftPar(bv->buffer()->params);
1475                 activateCellInset(bv, 0, 0, mouse_button::none, !rtl);
1476         }
1477         resetPos(bv);
1478         return true;
1479 }
1480
1481
1482 void InsetTabular::setFont(BufferView * bv, LyXFont const & font, bool tall,
1483                            bool selectall)
1484 {
1485         if (selectall) {
1486                 setSelection(0, tabular.getNumberOfCells() - 1);
1487         }
1488         if (hasSelection()) {
1489                 recordUndo(bv, Undo::ATOMIC);
1490                 bool const frozen = undo_frozen;
1491                 if (!frozen)
1492                         freezeUndo();
1493                 // apply the fontchange on the whole selection
1494                 int sel_row_start;
1495                 int sel_row_end;
1496                 int sel_col_start;
1497                 int sel_col_end;
1498                 getSelection(sel_row_start, sel_row_end, sel_col_start, sel_col_end);
1499                 for(int i = sel_row_start; i <= sel_row_end; ++i)
1500                         for(int j = sel_col_start; j <= sel_col_end; ++j)
1501                                 tabular.getCellInset(i, j).setFont(bv, font, tall, true);
1502
1503                 if (!frozen)
1504                         unFreezeUndo();
1505                 if (selectall)
1506                         clearSelection();
1507                 updateLocal(bv);
1508         }
1509         if (the_locking_inset)
1510                 the_locking_inset->setFont(bv, font, tall);
1511 }
1512
1513
1514 bool InsetTabular::tabularFeatures(BufferView * bv, string const & what)
1515 {
1516         LyXTabular::Feature action = LyXTabular::LAST_ACTION;
1517
1518         int i = 0;
1519         for (; tabularFeature[i].action != LyXTabular::LAST_ACTION; ++i) {
1520                 string const tmp = tabularFeature[i].feature;
1521
1522                 if (tmp == what.substr(0, tmp.length())) {
1523                         //if (!compare(tabularFeatures[i].feature.c_str(), what.c_str(),
1524                         //tabularFeatures[i].feature.length())) {
1525                         action = tabularFeature[i].action;
1526                         break;
1527                 }
1528         }
1529         if (action == LyXTabular::LAST_ACTION)
1530                 return false;
1531
1532         string const val =
1533                 ltrim(what.substr(tabularFeature[i].feature.length()));
1534         tabularFeatures(bv, action, val);
1535         return true;
1536 }
1537
1538 namespace {
1539
1540 void checkLongtableSpecial(LyXTabular::ltType & ltt,
1541                           string const & special, bool & flag)
1542 {
1543         if (special == "dl_above") {
1544                 ltt.topDL = flag;
1545                 ltt.set = false;
1546         } else if (special == "dl_below") {
1547                 ltt.bottomDL = flag;
1548                 ltt.set = false;
1549         } else if (special == "empty") {
1550                 ltt.empty = flag;
1551                 ltt.set = false;
1552         } else if (flag) {
1553                 ltt.empty = false;
1554                 ltt.set = true;
1555         }
1556 }
1557
1558 }
1559
1560
1561 void InsetTabular::tabularFeatures(BufferView * bv,
1562                                    LyXTabular::Feature feature,
1563                                    string const & value)
1564 {
1565         int sel_col_start;
1566         int sel_col_end;
1567         int sel_row_start;
1568         int sel_row_end;
1569         bool setLines = false;
1570         LyXAlignment setAlign = LYX_ALIGN_LEFT;
1571         LyXTabular::VAlignment setVAlign = LyXTabular::LYX_VALIGN_TOP;
1572
1573         switch (feature) {
1574
1575         case LyXTabular::M_ALIGN_LEFT:
1576         case LyXTabular::ALIGN_LEFT:
1577                 setAlign = LYX_ALIGN_LEFT;
1578                 break;
1579
1580         case LyXTabular::M_ALIGN_RIGHT:
1581         case LyXTabular::ALIGN_RIGHT:
1582                 setAlign = LYX_ALIGN_RIGHT;
1583                 break;
1584
1585         case LyXTabular::M_ALIGN_CENTER:
1586         case LyXTabular::ALIGN_CENTER:
1587                 setAlign = LYX_ALIGN_CENTER;
1588                 break;
1589
1590         case LyXTabular::ALIGN_BLOCK:
1591                 setAlign = LYX_ALIGN_BLOCK;
1592                 break;
1593
1594         case LyXTabular::M_VALIGN_TOP:
1595         case LyXTabular::VALIGN_TOP:
1596                 setVAlign = LyXTabular::LYX_VALIGN_TOP;
1597                 break;
1598
1599         case LyXTabular::M_VALIGN_BOTTOM:
1600         case LyXTabular::VALIGN_BOTTOM:
1601                 setVAlign = LyXTabular::LYX_VALIGN_BOTTOM;
1602                 break;
1603
1604         case LyXTabular::M_VALIGN_MIDDLE:
1605         case LyXTabular::VALIGN_MIDDLE:
1606                 setVAlign = LyXTabular::LYX_VALIGN_MIDDLE;
1607                 break;
1608
1609         default:
1610                 break;
1611         }
1612
1613         if (hasSelection()) {
1614                 getSelection(sel_row_start, sel_row_end, sel_col_start, sel_col_end);
1615         } else {
1616                 sel_col_start = sel_col_end = tabular.column_of_cell(actcell);
1617                 sel_row_start = sel_row_end = tabular.row_of_cell(actcell);
1618         }
1619         recordUndo(bv, Undo::ATOMIC);
1620
1621         int row =  tabular.row_of_cell(actcell);
1622         int column = tabular.column_of_cell(actcell);
1623         bool flag = true;
1624         LyXTabular::ltType ltt;
1625
1626         switch (feature) {
1627
1628         case LyXTabular::SET_PWIDTH:
1629         {
1630                 LyXLength const vallen(value);
1631                 LyXLength const & tmplen = tabular.getColumnPWidth(actcell);
1632
1633                 bool const update = (tmplen != vallen);
1634                 tabular.setColumnPWidth(actcell, vallen);
1635                 if (update) {
1636                         // We need this otherwise we won't resize
1637                         // the insettext of the active cell (if any)
1638                         // until later (see InsetText::do_resize)
1639                         unlockInsetInInset(bv, the_locking_inset);
1640                         bv->update();
1641                 }
1642
1643                 if (vallen.zero()
1644                     && tabular.getAlignment(actcell, true) == LYX_ALIGN_BLOCK)
1645                         tabularFeatures(bv, LyXTabular::ALIGN_CENTER, string());
1646                 else if (!vallen.zero()
1647                          && tabular.getAlignment(actcell, true) != LYX_ALIGN_BLOCK)
1648                         tabularFeatures(bv, LyXTabular::ALIGN_BLOCK, string());
1649                 break;
1650         }
1651
1652         case LyXTabular::SET_MPWIDTH:
1653         {
1654                 LyXLength const vallen(value);
1655                 LyXLength const & tmplen = tabular.getPWidth(actcell);
1656
1657                 bool const update = (tmplen != vallen);
1658                 tabular.setMColumnPWidth(actcell, vallen);
1659                 if (update) {
1660                         // We need this otherwise we won't resize
1661                         // the insettext of the active cell (if any)
1662                         // until later (see InsetText::do_resize)
1663                         unlockInsetInInset(bv, the_locking_inset);
1664                         updateLocal(bv);
1665                 }
1666         }
1667         break;
1668         case LyXTabular::SET_SPECIAL_COLUMN:
1669         case LyXTabular::SET_SPECIAL_MULTI:
1670                 tabular.setAlignSpecial(actcell,value,feature);
1671                 updateLocal(bv);
1672                 break;
1673         case LyXTabular::APPEND_ROW:
1674                 // append the row into the tabular
1675                 unlockInsetInInset(bv, the_locking_inset);
1676                 tabular.appendRow(bv->buffer()->params, actcell);
1677                 updateLocal(bv);
1678                 break;
1679         case LyXTabular::APPEND_COLUMN:
1680                 // append the column into the tabular
1681                 unlockInsetInInset(bv, the_locking_inset);
1682                 tabular.appendColumn(bv->buffer()->params, actcell);
1683                 actcell = tabular.getCellNumber(row, column);
1684                 updateLocal(bv);
1685                 break;
1686         case LyXTabular::DELETE_ROW:
1687                 unlockInsetInInset(bv, the_locking_inset);
1688                 for(int i = sel_row_start; i <= sel_row_end; ++i) {
1689                         tabular.deleteRow(sel_row_start);
1690                 }
1691                 if (sel_row_start >= tabular.rows())
1692                         --sel_row_start;
1693                 actcell = tabular.getCellNumber(sel_row_start, column);
1694                 clearSelection();
1695                 updateLocal(bv);
1696                 break;
1697         case LyXTabular::DELETE_COLUMN:
1698                 unlockInsetInInset(bv, the_locking_inset);
1699                 for(int i = sel_col_start; i <= sel_col_end; ++i) {
1700                         tabular.deleteColumn(sel_col_start);
1701                 }
1702                 if (sel_col_start >= tabular.columns())
1703                         --sel_col_start;
1704                 actcell = tabular.getCellNumber(row, sel_col_start);
1705                 clearSelection();
1706                 updateLocal(bv);
1707                 break;
1708         case LyXTabular::M_TOGGLE_LINE_TOP:
1709                 flag = false;
1710         case LyXTabular::TOGGLE_LINE_TOP:
1711         {
1712                 bool lineSet = !tabular.topLine(actcell, flag);
1713                 for (int i = sel_row_start; i <= sel_row_end; ++i)
1714                         for (int j = sel_col_start; j <= sel_col_end; ++j)
1715                                 tabular.setTopLine(
1716                                         tabular.getCellNumber(i, j),
1717                                         lineSet, flag);
1718                 updateLocal(bv);
1719                 break;
1720         }
1721
1722         case LyXTabular::M_TOGGLE_LINE_BOTTOM:
1723                 flag = false;
1724         case LyXTabular::TOGGLE_LINE_BOTTOM:
1725         {
1726                 bool lineSet = !tabular.bottomLine(actcell, flag);
1727                 for (int i = sel_row_start; i <= sel_row_end; ++i)
1728                         for (int j = sel_col_start; j <= sel_col_end; ++j)
1729                                 tabular.setBottomLine(
1730                                         tabular.getCellNumber(i, j),
1731                                         lineSet,
1732                                         flag);
1733                 updateLocal(bv);
1734                 break;
1735         }
1736
1737         case LyXTabular::M_TOGGLE_LINE_LEFT:
1738                 flag = false;
1739         case LyXTabular::TOGGLE_LINE_LEFT:
1740         {
1741                 bool lineSet = !tabular.leftLine(actcell, flag);
1742                 for (int i = sel_row_start; i <= sel_row_end; ++i)
1743                         for (int j = sel_col_start; j <= sel_col_end; ++j)
1744                                 tabular.setLeftLine(
1745                                         tabular.getCellNumber(i,j),
1746                                         lineSet,
1747                                         flag);
1748                 updateLocal(bv);
1749                 break;
1750         }
1751
1752         case LyXTabular::M_TOGGLE_LINE_RIGHT:
1753                 flag = false;
1754         case LyXTabular::TOGGLE_LINE_RIGHT:
1755         {
1756                 bool lineSet = !tabular.rightLine(actcell, flag);
1757                 for (int i = sel_row_start; i <= sel_row_end; ++i)
1758                         for (int j = sel_col_start; j <= sel_col_end; ++j)
1759                                 tabular.setRightLine(
1760                                         tabular.getCellNumber(i,j),
1761                                         lineSet,
1762                                         flag);
1763                 updateLocal(bv);
1764                 break;
1765         }
1766
1767         case LyXTabular::M_ALIGN_LEFT:
1768         case LyXTabular::M_ALIGN_RIGHT:
1769         case LyXTabular::M_ALIGN_CENTER:
1770                 flag = false;
1771         case LyXTabular::ALIGN_LEFT:
1772         case LyXTabular::ALIGN_RIGHT:
1773         case LyXTabular::ALIGN_CENTER:
1774         case LyXTabular::ALIGN_BLOCK:
1775                 for (int i = sel_row_start; i <= sel_row_end; ++i)
1776                         for (int j = sel_col_start; j <= sel_col_end; ++j)
1777                                 tabular.setAlignment(
1778                                         tabular.getCellNumber(i, j),
1779                                         setAlign,
1780                                         flag);
1781                 updateLocal(bv);
1782                 break;
1783
1784         case LyXTabular::M_VALIGN_TOP:
1785         case LyXTabular::M_VALIGN_BOTTOM:
1786         case LyXTabular::M_VALIGN_MIDDLE:
1787                 flag = false;
1788         case LyXTabular::VALIGN_TOP:
1789         case LyXTabular::VALIGN_BOTTOM:
1790         case LyXTabular::VALIGN_MIDDLE:
1791                 for (int i = sel_row_start; i <= sel_row_end; ++i)
1792                         for (int j = sel_col_start; j <= sel_col_end; ++j)
1793                                 tabular.setVAlignment(
1794                                         tabular.getCellNumber(i, j),
1795                                         setVAlign, flag);
1796                 updateLocal(bv);
1797                 break;
1798
1799         case LyXTabular::MULTICOLUMN: {
1800                 if (sel_row_start != sel_row_end) {
1801 #ifdef WITH_WARNINGS
1802 #warning Need I say it ? This is horrible.
1803 #endif
1804                         Alert::error(_("Error setting multicolumn"),
1805                                    _("You cannot set multicolumn vertically."));
1806                         return;
1807                 }
1808                 // just multicol for one Single Cell
1809                 if (!hasSelection()) {
1810                         // check wether we are completly in a multicol
1811                         if (tabular.isMultiColumn(actcell))
1812                                 tabular.unsetMultiColumn(actcell);
1813                         else
1814                                 tabular.setMultiColumn(bv->buffer(), actcell, 1);
1815                         updateLocal(bv);
1816                         break;
1817                 }
1818                 // we have a selection so this means we just add all this
1819                 // cells to form a multicolumn cell
1820                 int s_start;
1821                 int s_end;
1822
1823                 if (sel_cell_start > sel_cell_end) {
1824                         s_start = sel_cell_end;
1825                         s_end = sel_cell_start;
1826                 } else {
1827                         s_start = sel_cell_start;
1828                         s_end = sel_cell_end;
1829                 }
1830                 tabular.setMultiColumn(bv->buffer(), s_start, s_end - s_start + 1);
1831                 actcell = s_start;
1832                 clearSelection();
1833                 updateLocal(bv);
1834                 break;
1835         }
1836
1837         case LyXTabular::SET_ALL_LINES:
1838                 setLines = true;
1839         case LyXTabular::UNSET_ALL_LINES:
1840                 for (int i = sel_row_start; i <= sel_row_end; ++i)
1841                         for (int j = sel_col_start; j <= sel_col_end; ++j)
1842                                 tabular.setAllLines(
1843                                         tabular.getCellNumber(i,j), setLines);
1844                 updateLocal(bv);
1845                 break;
1846
1847         case LyXTabular::SET_LONGTABULAR:
1848                 tabular.setLongTabular(true);
1849                 updateLocal(bv); // because this toggles displayed
1850                 break;
1851
1852         case LyXTabular::UNSET_LONGTABULAR:
1853                 tabular.setLongTabular(false);
1854                 updateLocal(bv); // because this toggles displayed
1855                 break;
1856
1857         case LyXTabular::SET_ROTATE_TABULAR:
1858                 tabular.setRotateTabular(true);
1859                 break;
1860
1861         case LyXTabular::UNSET_ROTATE_TABULAR:
1862                 tabular.setRotateTabular(false);
1863                 break;
1864
1865         case LyXTabular::SET_ROTATE_CELL:
1866                 for (int i = sel_row_start; i <= sel_row_end; ++i)
1867                         for (int j = sel_col_start; j<=sel_col_end; ++j)
1868                                 tabular.setRotateCell(
1869                                         tabular.getCellNumber(i, j), true);
1870                 break;
1871
1872         case LyXTabular::UNSET_ROTATE_CELL:
1873                 for (int i = sel_row_start; i <= sel_row_end; ++i)
1874                         for (int j = sel_col_start; j <= sel_col_end; ++j)
1875                                 tabular.setRotateCell(
1876                                         tabular.getCellNumber(i, j), false);
1877                 break;
1878
1879         case LyXTabular::SET_USEBOX: {
1880                 LyXTabular::BoxType val = LyXTabular::BoxType(strToInt(value));
1881                 if (val == tabular.getUsebox(actcell))
1882                         val = LyXTabular::BOX_NONE;
1883                 for (int i = sel_row_start; i <= sel_row_end; ++i)
1884                         for (int j = sel_col_start; j <= sel_col_end; ++j)
1885                                 tabular.setUsebox(tabular.getCellNumber(i, j), val);
1886                 break;
1887         }
1888
1889         case LyXTabular::UNSET_LTFIRSTHEAD:
1890                 flag = false;
1891         case LyXTabular::SET_LTFIRSTHEAD:
1892                 tabular.getRowOfLTFirstHead(row, ltt);
1893                 checkLongtableSpecial(ltt, value, flag);
1894                 tabular.setLTHead(row, flag, ltt, true);
1895                 break;
1896
1897         case LyXTabular::UNSET_LTHEAD:
1898                 flag = false;
1899         case LyXTabular::SET_LTHEAD:
1900                 tabular.getRowOfLTHead(row, ltt);
1901                 checkLongtableSpecial(ltt, value, flag);
1902                 tabular.setLTHead(row, flag, ltt, false);
1903                 break;
1904
1905         case LyXTabular::UNSET_LTFOOT:
1906                 flag = false;
1907         case LyXTabular::SET_LTFOOT:
1908                 tabular.getRowOfLTFoot(row, ltt);
1909                 checkLongtableSpecial(ltt, value, flag);
1910                 tabular.setLTFoot(row, flag, ltt, false);
1911                 break;
1912
1913         case LyXTabular::UNSET_LTLASTFOOT:
1914                 flag = false;
1915         case LyXTabular::SET_LTLASTFOOT:
1916                 tabular.getRowOfLTLastFoot(row, ltt);
1917                 checkLongtableSpecial(ltt, value, flag);
1918                 tabular.setLTFoot(row, flag, ltt, true);
1919                 break;
1920
1921         case LyXTabular::SET_LTNEWPAGE: {
1922                 bool what = !tabular.getLTNewPage(row);
1923                 tabular.setLTNewPage(row, what);
1924                 break;
1925         }
1926
1927         // dummy stuff just to avoid warnings
1928         case LyXTabular::LAST_ACTION:
1929                 break;
1930         }
1931
1932         InsetTabularMailer(*this).updateDialog(bv);
1933 }
1934
1935
1936 bool InsetTabular::activateCellInset(BufferView * bv, int x, int y,
1937         mouse_button::state button, bool behind)
1938 {
1939         UpdatableInset & inset = tabular.getCellInset(actcell);
1940         if (behind) {
1941 #warning metrics?
1942                 x = inset.x() + inset.width();
1943                 y = inset.descent();
1944         }
1945         //inset_x = cursorx_ - top_x + tabular.getBeginningOfTextInCell(actcell);
1946         //inset_y = cursory_;
1947         inset.localDispatch(FuncRequest(bv, LFUN_INSET_EDIT, x,  y, button));
1948         if (!the_locking_inset)
1949                 return false;
1950         updateLocal(bv);
1951         return the_locking_inset;
1952 }
1953
1954
1955 bool InsetTabular::activateCellInsetAbs(BufferView * bv, int x, int y,
1956                                         mouse_button::state button)
1957 {
1958         inset_x = cursorx_ - top_x + tabular.getBeginningOfTextInCell(actcell);
1959         inset_y = cursory_;
1960         return activateCellInset(bv, x - inset_x, y - inset_y, button);
1961 }
1962
1963
1964 bool InsetTabular::insetHit(BufferView *, int x, int) const
1965 {
1966         return x + top_x > cursorx_ + tabular.getBeginningOfTextInCell(actcell);
1967 }
1968
1969
1970 void InsetTabular::deleteLyXText(BufferView * /*bv*/, bool /*recursive*/) const
1971 {
1972         //resizeLyXText(bv, recursive);
1973 }
1974
1975
1976 LyXText * InsetTabular::getLyXText(BufferView const * bv,
1977                                    bool const recursive) const
1978 {
1979         if (the_locking_inset)
1980                 return the_locking_inset->getLyXText(bv, recursive);
1981         return InsetOld::getLyXText(bv, recursive);
1982 }
1983
1984
1985 bool InsetTabular::showInsetDialog(BufferView * bv) const
1986 {
1987         if (!the_locking_inset || !the_locking_inset->showInsetDialog(bv))
1988                 InsetTabularMailer(*this).showDialog(bv);
1989         return true;
1990 }
1991
1992
1993 void InsetTabular::openLayoutDialog(BufferView * bv) const
1994 {
1995         if (the_locking_inset) {
1996                 InsetTabular * inset = static_cast<InsetTabular *>
1997                         (the_locking_inset->getFirstLockingInsetOfType(TABULAR_CODE));
1998                 if (inset) {
1999                         inset->openLayoutDialog(bv);
2000                         return;
2001                 }
2002         }
2003         InsetTabularMailer(*this).showDialog(bv);
2004 }
2005
2006
2007 //
2008 // function returns an object as defined in func_status.h:
2009 // states OK, Unknown, Disabled, On, Off.
2010 //
2011 FuncStatus InsetTabular::getStatus(string const & what) const
2012 {
2013         int action = LyXTabular::LAST_ACTION;
2014         FuncStatus status;
2015
2016         int i = 0;
2017         for (; tabularFeature[i].action != LyXTabular::LAST_ACTION; ++i) {
2018                 string const tmp = tabularFeature[i].feature;
2019                 if (tmp == what.substr(0, tmp.length())) {
2020                         //if (!compare(tabularFeatures[i].feature.c_str(), what.c_str(),
2021                         //   tabularFeatures[i].feature.length())) {
2022                         action = tabularFeature[i].action;
2023                         break;
2024                 }
2025         }
2026         if (action == LyXTabular::LAST_ACTION) {
2027                 status.clear();
2028                 return status.unknown(true);
2029         }
2030
2031         string const argument
2032                 = ltrim(what.substr(tabularFeature[i].feature.length()));
2033
2034         int sel_row_start;
2035         int sel_row_end;
2036         int dummy;
2037         LyXTabular::ltType dummyltt;
2038         bool flag = true;
2039
2040         if (hasSelection())
2041                 getSelection(sel_row_start, sel_row_end, dummy, dummy);
2042         else
2043                 sel_row_start = sel_row_end = tabular.row_of_cell(actcell);
2044
2045         switch (action) {
2046         case LyXTabular::SET_PWIDTH:
2047         case LyXTabular::SET_MPWIDTH:
2048         case LyXTabular::SET_SPECIAL_COLUMN:
2049         case LyXTabular::SET_SPECIAL_MULTI:
2050         case LyXTabular::APPEND_ROW:
2051         case LyXTabular::APPEND_COLUMN:
2052         case LyXTabular::DELETE_ROW:
2053         case LyXTabular::DELETE_COLUMN:
2054         case LyXTabular::SET_ALL_LINES:
2055         case LyXTabular::UNSET_ALL_LINES:
2056                 return status.clear();
2057
2058         case LyXTabular::MULTICOLUMN:
2059                 status.setOnOff(tabular.isMultiColumn(actcell));
2060                 break;
2061
2062         case LyXTabular::M_TOGGLE_LINE_TOP:
2063                 flag = false;
2064         case LyXTabular::TOGGLE_LINE_TOP:
2065                 status.setOnOff(tabular.topLine(actcell, flag));
2066                 break;
2067
2068         case LyXTabular::M_TOGGLE_LINE_BOTTOM:
2069                 flag = false;
2070         case LyXTabular::TOGGLE_LINE_BOTTOM:
2071                 status.setOnOff(tabular.bottomLine(actcell, flag));
2072                 break;
2073
2074         case LyXTabular::M_TOGGLE_LINE_LEFT:
2075                 flag = false;
2076         case LyXTabular::TOGGLE_LINE_LEFT:
2077                 status.setOnOff(tabular.leftLine(actcell, flag));
2078                 break;
2079
2080         case LyXTabular::M_TOGGLE_LINE_RIGHT:
2081                 flag = false;
2082         case LyXTabular::TOGGLE_LINE_RIGHT:
2083                 status.setOnOff(tabular.rightLine(actcell, flag));
2084                 break;
2085
2086         case LyXTabular::M_ALIGN_LEFT:
2087                 flag = false;
2088         case LyXTabular::ALIGN_LEFT:
2089                 status.setOnOff(tabular.getAlignment(actcell, flag) == LYX_ALIGN_LEFT);
2090                 break;
2091
2092         case LyXTabular::M_ALIGN_RIGHT:
2093                 flag = false;
2094         case LyXTabular::ALIGN_RIGHT:
2095                 status.setOnOff(tabular.getAlignment(actcell, flag) == LYX_ALIGN_RIGHT);
2096                 break;
2097
2098         case LyXTabular::M_ALIGN_CENTER:
2099                 flag = false;
2100         case LyXTabular::ALIGN_CENTER:
2101                 status.setOnOff(tabular.getAlignment(actcell, flag) == LYX_ALIGN_CENTER);
2102                 break;
2103
2104         case LyXTabular::ALIGN_BLOCK:
2105                 status.disabled(tabular.getPWidth(actcell).zero());
2106                 status.setOnOff(tabular.getAlignment(actcell, flag) == LYX_ALIGN_BLOCK);
2107                 break;
2108
2109         case LyXTabular::M_VALIGN_TOP:
2110                 flag = false;
2111         case LyXTabular::VALIGN_TOP:
2112                 status.setOnOff(tabular.getVAlignment(actcell, flag) == LyXTabular::LYX_VALIGN_TOP);
2113                 break;
2114
2115         case LyXTabular::M_VALIGN_BOTTOM:
2116                 flag = false;
2117         case LyXTabular::VALIGN_BOTTOM:
2118                 status.setOnOff(tabular.getVAlignment(actcell, flag) == LyXTabular::LYX_VALIGN_BOTTOM);
2119                 break;
2120
2121         case LyXTabular::M_VALIGN_MIDDLE:
2122                 flag = false;
2123         case LyXTabular::VALIGN_MIDDLE:
2124                 status.setOnOff(tabular.getVAlignment(actcell, flag) == LyXTabular::LYX_VALIGN_MIDDLE);
2125                 break;
2126
2127         case LyXTabular::SET_LONGTABULAR:
2128                 status.setOnOff(tabular.isLongTabular());
2129                 break;
2130
2131         case LyXTabular::UNSET_LONGTABULAR:
2132                 status.setOnOff(!tabular.isLongTabular());
2133                 break;
2134
2135         case LyXTabular::SET_ROTATE_TABULAR:
2136                 status.setOnOff(tabular.getRotateTabular());
2137                 break;
2138
2139         case LyXTabular::UNSET_ROTATE_TABULAR:
2140                 status.setOnOff(!tabular.getRotateTabular());
2141                 break;
2142
2143         case LyXTabular::SET_ROTATE_CELL:
2144                 status.setOnOff(tabular.getRotateCell(actcell));
2145                 break;
2146
2147         case LyXTabular::UNSET_ROTATE_CELL:
2148                 status.setOnOff(!tabular.getRotateCell(actcell));
2149                 break;
2150
2151         case LyXTabular::SET_USEBOX:
2152                 status.setOnOff(strToInt(argument) == tabular.getUsebox(actcell));
2153                 break;
2154
2155         case LyXTabular::SET_LTFIRSTHEAD:
2156                 status.setOnOff(tabular.getRowOfLTHead(sel_row_start, dummyltt));
2157                 break;
2158
2159         case LyXTabular::SET_LTHEAD:
2160                 status.setOnOff(tabular.getRowOfLTHead(sel_row_start, dummyltt));
2161                 break;
2162
2163         case LyXTabular::SET_LTFOOT:
2164                 status.setOnOff(tabular.getRowOfLTFoot(sel_row_start, dummyltt));
2165                 break;
2166
2167         case LyXTabular::SET_LTLASTFOOT:
2168                 status.setOnOff(tabular.getRowOfLTFoot(sel_row_start, dummyltt));
2169                 break;
2170
2171         case LyXTabular::SET_LTNEWPAGE:
2172                 status.setOnOff(tabular.getLTNewPage(sel_row_start));
2173                 break;
2174
2175         default:
2176                 status.clear();
2177                 status.disabled(true);
2178                 break;
2179         }
2180         return status;
2181 }
2182
2183
2184 void InsetTabular::getLabelList(std::vector<string> & list) const
2185 {
2186         tabular.getLabelList(list);
2187 }
2188
2189
2190 bool InsetTabular::copySelection(BufferView * bv)
2191 {
2192         if (!hasSelection())
2193                 return false;
2194
2195         int sel_col_start = tabular.column_of_cell(sel_cell_start);
2196         int sel_col_end = tabular.column_of_cell(sel_cell_end);
2197         if (sel_col_start > sel_col_end) {
2198                 sel_col_start = sel_col_end;
2199                 sel_col_end = tabular.right_column_of_cell(sel_cell_start);
2200         } else {
2201                 sel_col_end = tabular.right_column_of_cell(sel_cell_end);
2202         }
2203
2204         int sel_row_start = tabular.row_of_cell(sel_cell_start);
2205         int sel_row_end = tabular.row_of_cell(sel_cell_end);
2206         if (sel_row_start > sel_row_end)
2207                 swap(sel_row_start, sel_row_end);
2208
2209         delete paste_tabular;
2210         paste_tabular = new LyXTabular(bv->buffer()->params, this, tabular);
2211
2212         for (int i = 0; i < sel_row_start; ++i)
2213                 paste_tabular->deleteRow(0);
2214
2215         int const rows = sel_row_end - sel_row_start + 1;
2216         while (paste_tabular->rows() > rows)
2217                 paste_tabular->deleteRow(rows);
2218
2219         paste_tabular->setTopLine(0, true, true);
2220         paste_tabular->setBottomLine(paste_tabular->getFirstCellInRow(rows - 1),
2221                                      true, true);
2222
2223         for (int i = 0; i < sel_col_start; ++i)
2224                 paste_tabular->deleteColumn(0);
2225
2226         int const columns = sel_col_end - sel_col_start + 1;
2227         while (paste_tabular->columns() > columns)
2228                 paste_tabular->deleteColumn(columns);
2229
2230         paste_tabular->setLeftLine(0, true, true);
2231         paste_tabular->setRightLine(paste_tabular->getLastCellInRow(0),
2232                                     true, true);
2233
2234         ostringstream os;
2235         paste_tabular->ascii(*bv->buffer(), os,
2236                              ownerPar(*bv->buffer(), this).params().depth(), true, '\t');
2237         bv->stuffClipboard(STRCONV(os.str()));
2238         return true;
2239 }
2240
2241
2242 bool InsetTabular::pasteSelection(BufferView * bv)
2243 {
2244         if (!paste_tabular)
2245                 return false;
2246
2247         for (int r1 = 0, r2 = actrow;
2248              r1 < paste_tabular->rows() && r2 < tabular.rows();
2249              ++r1, ++r2) {
2250                 for (int c1 = 0, c2 = actcol;
2251                     c1 < paste_tabular->columns() && c2 < tabular.columns();
2252                     ++c1, ++c2) {
2253                         if (paste_tabular->isPartOfMultiColumn(r1, c1) &&
2254                             tabular.isPartOfMultiColumn(r2, c2))
2255                                 continue;
2256                         if (paste_tabular->isPartOfMultiColumn(r1, c1)) {
2257                                 --c2;
2258                                 continue;
2259                         }
2260                         if (tabular.isPartOfMultiColumn(r2, c2)) {
2261                                 --c1;
2262                                 continue;
2263                         }
2264                         InsetText & inset = tabular.getCellInset(r2, c2);
2265                         inset = paste_tabular->getCellInset(r1, c1);
2266                         inset.setOwner(this);
2267                         inset.deleteLyXText(bv);
2268                         inset.markNew();
2269                 }
2270         }
2271         return true;
2272 }
2273
2274
2275 bool InsetTabular::cutSelection(BufferParams const & bp)
2276 {
2277         if (!hasSelection())
2278                 return false;
2279
2280         int sel_col_start = tabular.column_of_cell(sel_cell_start);
2281         int sel_col_end = tabular.column_of_cell(sel_cell_end);
2282         if (sel_col_start > sel_col_end) {
2283                 sel_col_start = sel_col_end;
2284                 sel_col_end = tabular.right_column_of_cell(sel_cell_start);
2285         } else {
2286                 sel_col_end = tabular.right_column_of_cell(sel_cell_end);
2287         }
2288
2289         int sel_row_start = tabular.row_of_cell(sel_cell_start);
2290         int sel_row_end = tabular.row_of_cell(sel_cell_end);
2291
2292         if (sel_row_start > sel_row_end)
2293                 swap(sel_row_start, sel_row_end);
2294
2295         if (sel_cell_start > sel_cell_end)
2296                 swap(sel_cell_start, sel_cell_end);
2297
2298         for (int i = sel_row_start; i <= sel_row_end; ++i)
2299                 for (int j = sel_col_start; j <= sel_col_end; ++j)
2300                         tabular.getCellInset(tabular.getCellNumber(i, j)).clear(bp.tracking_changes);
2301         return true;
2302 }
2303
2304
2305 bool InsetTabular::isRightToLeft(BufferView * bv)
2306 {
2307         return bv->getParentLanguage(this)->RightToLeft();
2308 }
2309
2310
2311 int InsetTabular::scroll(bool recursive) const
2312 {
2313         int sx = UpdatableInset::scroll(false);
2314
2315         if (recursive && the_locking_inset)
2316                 sx += the_locking_inset->scroll(recursive);
2317
2318         return sx;
2319 }
2320
2321
2322 void InsetTabular::getSelection(int & srow, int & erow,
2323                                 int & scol, int & ecol) const
2324 {
2325         int const start = hasSelection() ? sel_cell_start : actcell;
2326         int const end = hasSelection() ? sel_cell_end : actcell;
2327
2328         srow = tabular.row_of_cell(start);
2329         erow = tabular.row_of_cell(end);
2330         if (srow > erow)
2331                 swap(srow, erow);
2332
2333         scol = tabular.column_of_cell(start);
2334         ecol = tabular.column_of_cell(end);
2335         if (scol > ecol)
2336                 swap(scol, ecol);
2337         else
2338                 ecol = tabular.right_column_of_cell(end);
2339 }
2340
2341
2342 ParagraphList * InsetTabular::getParagraphs(int i) const
2343 {
2344         return (i < tabular.getNumberOfCells())
2345                 ? tabular.getCellInset(i).getParagraphs(0)
2346                 : 0;
2347 }
2348
2349
2350 LyXCursor const & InsetTabular::cursor(BufferView * bv) const
2351 {
2352         if (the_locking_inset)
2353                 return the_locking_inset->cursor(bv);
2354         return InsetOld::cursor(bv);
2355 }
2356
2357
2358 InsetOld * InsetTabular::getInsetFromID(int id_arg) const
2359 {
2360         if (id_arg == id())
2361                 return const_cast<InsetTabular *>(this);
2362
2363         for (int i = 0; i < tabular.rows(); ++i) {
2364                 for (int j = 0; j < tabular.columns(); ++j) {
2365                         InsetOld * inset = tabular.getCellInset(i, j).getInsetFromID(id_arg);
2366                         if (inset)
2367                                 return inset;
2368                 }
2369         }
2370         return 0;
2371 }
2372
2373
2374 WordLangTuple const
2375 InsetTabular::selectNextWordToSpellcheck(BufferView * bv, float & value) const
2376 {
2377         if (the_locking_inset) {
2378                 WordLangTuple word(the_locking_inset->selectNextWordToSpellcheck(bv, value));
2379                 if (!word.word().empty())
2380                         return word;
2381                 if (tabular.isLastCell(actcell)) {
2382                         bv->unlockInset(const_cast<InsetTabular *>(this));
2383                         return WordLangTuple();
2384                 }
2385                 ++actcell;
2386         }
2387         // otherwise we have to lock the next inset and ask for it's selecttion
2388         tabular.getCellInset(actcell)
2389                 .localDispatch(FuncRequest(bv, LFUN_INSET_EDIT));
2390         WordLangTuple word(selectNextWordInt(bv, value));
2391         if (!word.word().empty())
2392                 resetPos(bv);
2393         return word;
2394 }
2395
2396
2397 WordLangTuple InsetTabular::selectNextWordInt(BufferView * bv, float & value) const
2398 {
2399         // when entering this function the inset should be ALWAYS locked!
2400         Assert(the_locking_inset);
2401
2402         WordLangTuple word(the_locking_inset->selectNextWordToSpellcheck(bv, value));
2403         if (!word.word().empty())
2404                 return word;
2405
2406         if (tabular.isLastCell(actcell)) {
2407                 bv->unlockInset(const_cast<InsetTabular *>(this));
2408                 return WordLangTuple();
2409         }
2410
2411         // otherwise we have to lock the next inset and ask for it's selecttion
2412         ++actcell;
2413         tabular.getCellInset(actcell)
2414                 .localDispatch(FuncRequest(bv, LFUN_INSET_EDIT));
2415         return selectNextWordInt(bv, value);
2416 }
2417
2418
2419 void InsetTabular::selectSelectedWord(BufferView * bv)
2420 {
2421         if (the_locking_inset)
2422                 the_locking_inset->selectSelectedWord(bv);
2423 }
2424
2425
2426 void InsetTabular::markErased()
2427 {
2428         for (int cell = 0; cell < tabular.getNumberOfCells(); ++cell)
2429                 tabular.getCellInset(cell).markErased();
2430 }
2431
2432
2433 bool InsetTabular::nextChange(BufferView * bv, lyx::pos_type & length)
2434 {
2435         if (the_locking_inset) {
2436                 if (the_locking_inset->nextChange(bv, length)) {
2437                         updateLocal(bv);
2438                         return true;
2439                 }
2440                 if (tabular.isLastCell(actcell))
2441                         return false;
2442                 ++actcell;
2443         }
2444         InsetText & inset = tabular.getCellInset(actcell);
2445         if (inset.nextChange(bv, length)) {
2446                 updateLocal(bv);
2447                 return true;
2448         }
2449         while (!tabular.isLastCell(actcell)) {
2450                 ++actcell;
2451                 InsetText & inset = tabular.getCellInset(actcell);
2452                 if (inset.nextChange(bv, length)) {
2453                         updateLocal(bv);
2454                         return true;
2455                 }
2456         }
2457         return false;
2458 }
2459
2460
2461 bool InsetTabular::searchForward(BufferView * bv, string const & str,
2462                                  bool cs, bool mw)
2463 {
2464         int cell = 0;
2465         if (the_locking_inset) {
2466                 if (the_locking_inset->searchForward(bv, str, cs, mw)) {
2467                         updateLocal(bv);
2468                         return true;
2469                 }
2470                 if (tabular.isLastCell(actcell))
2471                         return false;
2472                 cell = actcell + 1;
2473         }
2474         InsetText & inset = tabular.getCellInset(cell);
2475         if (inset.searchForward(bv, str, cs, mw)) {
2476                 updateLocal(bv);
2477                 return true;
2478         }
2479         while (!tabular.isLastCell(cell)) {
2480                 ++cell;
2481                 InsetText & inset = tabular.getCellInset(cell);
2482                 if (inset.searchForward(bv, str, cs, mw)) {
2483                         updateLocal(bv);
2484                         return true;
2485                 }
2486         }
2487         return false;
2488 }
2489
2490
2491 bool InsetTabular::searchBackward(BufferView * bv, string const & str,
2492                                bool cs, bool mw)
2493 {
2494         int cell = tabular.getNumberOfCells();
2495         if (the_locking_inset) {
2496                 if (the_locking_inset->searchBackward(bv, str, cs, mw)) {
2497                         updateLocal(bv);
2498                         return true;
2499                 }
2500                 cell = actcell;
2501         }
2502
2503         while (cell) {
2504                 --cell;
2505                 InsetText & inset = tabular.getCellInset(cell);
2506                 if (inset.searchBackward(bv, str, cs, mw)) {
2507                         updateLocal(bv);
2508                         return true;
2509                 }
2510         }
2511         return false;
2512 }
2513
2514
2515 bool InsetTabular::insetAllowed(InsetOld::Code code) const
2516 {
2517         if (the_locking_inset)
2518                 return the_locking_inset->insetAllowed(code);
2519         // we return true here because if the inset is not locked someone
2520         // wants to insert something in one of our insettexts and we generally
2521         // allow to do so.
2522         return true;
2523 }
2524
2525
2526 bool InsetTabular::forceDefaultParagraphs(InsetOld const * in) const
2527 {
2528         const int cell = tabular.getCellFromInset(in, actcell);
2529
2530         if (cell != -1)
2531                 return tabular.getPWidth(cell).zero();
2532
2533         // well we didn't obviously find it so maybe our owner knows more
2534         if (owner())
2535                 return owner()->forceDefaultParagraphs(in);
2536
2537         lyxerr << "If we're here there is really something strange going on!"
2538                << endl;
2539         return false;
2540 }
2541
2542
2543 bool InsetTabular::insertAsciiString(BufferView * bv, string const & buf,
2544                                      bool usePaste)
2545 {
2546         if (buf.length() <= 0)
2547                 return true;
2548
2549         int cols = 1;
2550         int rows = 1;
2551         int maxCols = 1;
2552         string::size_type len = buf.length();
2553         string::size_type p = 0;
2554
2555         while (p < len && (p = buf.find_first_of("\t\n", p)) != string::npos) {
2556                 switch (buf[p]) {
2557                 case '\t':
2558                         ++cols;
2559                         break;
2560                 case '\n':
2561                         if ((p+1) < len)
2562                                 ++rows;
2563                         maxCols = max(cols, maxCols);
2564                         cols = 1;
2565                         break;
2566                 }
2567                 ++p;
2568         }
2569         maxCols = max(cols, maxCols);
2570         LyXTabular * loctab;
2571         int cell = 0;
2572         int ocol = 0;
2573         int row = 0;
2574         if (usePaste) {
2575                 delete paste_tabular;
2576                 paste_tabular = new LyXTabular(bv->buffer()->params,
2577                                                this, rows, maxCols);
2578                 loctab = paste_tabular;
2579                 cols = 0;
2580         } else {
2581                 loctab = &tabular;
2582                 cell = actcell;
2583                 ocol = actcol;
2584                 row = actrow;
2585         }
2586
2587         string::size_type op = 0;
2588         int cells = loctab->getNumberOfCells();
2589         p = 0;
2590         cols = ocol;
2591         rows = loctab->rows();
2592         int const columns = loctab->columns();
2593
2594         while (cell < cells && p < len && row < rows &&
2595                (p = buf.find_first_of("\t\n", p)) != string::npos)
2596         {
2597                 if (p >= len)
2598                         break;
2599                 switch (buf[p]) {
2600                 case '\t':
2601                         // we can only set this if we are not too far right
2602                         if (cols < columns) {
2603                                 InsetText & inset = loctab->getCellInset(cell);
2604                                 LyXFont const font = inset.getLyXText(bv)->
2605                                         getFont(inset.paragraphs.begin(), 0);
2606                                 inset.setText(buf.substr(op, p - op), font);
2607                                 ++cols;
2608                                 ++cell;
2609                         }
2610                         break;
2611                 case '\n':
2612                         // we can only set this if we are not too far right
2613                         if (cols < columns) {
2614                                 InsetText & inset = tabular.getCellInset(cell);
2615                                 LyXFont const font = inset.getLyXText(bv)->
2616                                         getFont(inset.paragraphs.begin(), 0);
2617                                 inset.setText(buf.substr(op, p - op), font);
2618                         }
2619                         cols = ocol;
2620                         ++row;
2621                         if (row < rows)
2622                                 cell = loctab->getCellNumber(row, cols);
2623                         break;
2624                 }
2625                 ++p;
2626                 op = p;
2627         }
2628         // check for the last cell if there is no trailing '\n'
2629         if (cell < cells && op < len) {
2630                 InsetText & inset = loctab->getCellInset(cell);
2631                 LyXFont const font = inset.getLyXText(bv)->
2632                         getFont(inset.paragraphs.begin(), 0);
2633                 inset.setText(buf.substr(op, len - op), font);
2634         }
2635
2636         return true;
2637 }
2638
2639
2640 void InsetTabular::addPreview(PreviewLoader & loader) const
2641 {
2642         int const rows = tabular.rows();
2643         int const columns = tabular.columns();
2644         for (int i = 0; i < rows; ++i)
2645                 for (int j = 0; j < columns; ++j)
2646                         tabular.getCellInset(i, j).addPreview(loader);
2647 }
2648
2649
2650 string const InsetTabularMailer::name_("tabular");
2651
2652 InsetTabularMailer::InsetTabularMailer(InsetTabular const & inset)
2653         : inset_(const_cast<InsetTabular &>(inset))
2654 {}
2655
2656
2657 string const InsetTabularMailer::inset2string(Buffer const &) const
2658 {
2659         return params2string(inset_);
2660 }
2661
2662
2663 int InsetTabularMailer::string2params(string const & in, InsetTabular & inset)
2664 {
2665         istringstream data(STRCONV(in));
2666         LyXLex lex(0,0);
2667         lex.setStream(data);
2668
2669 #warning CHECK verify that this is a sane value to return.
2670         if (in.empty())
2671                 return -1;
2672
2673         if (lex.isOK()) {
2674                 lex.next();
2675                 string const token = lex.getString();
2676                 if (token != name_)
2677                         return -1;
2678         }
2679
2680         int cell = -1;
2681         if (lex.isOK()) {
2682                 lex.next();
2683                 string const token = lex.getString();
2684                 if (token != "\\active_cell")
2685                         return -1;
2686                 lex.next();
2687                 cell = lex.getInteger();
2688         }
2689
2690         // This is part of the inset proper that is usually swallowed
2691         // by Buffer::readInset
2692         if (lex.isOK()) {
2693                 lex.next();
2694                 string const token = lex.getString();
2695                 if (token != "Tabular")
2696                         return -1;
2697         }
2698
2699         if (!lex.isOK())
2700                 return -1;
2701
2702         Buffer const & buffer = inset.buffer();
2703         inset.read(buffer, lex);
2704
2705         // We can't set the active cell, but we can tell the frontend
2706         // what it is.
2707         return cell;
2708 }
2709
2710
2711 string const InsetTabularMailer::params2string(InsetTabular const & inset)
2712 {
2713         Buffer const & buffer = inset.buffer();
2714
2715         ostringstream data;
2716         data << name_ << " \\active_cell " << inset.getActCell() << '\n';
2717         inset.write(buffer, data);
2718         data << "\\end_inset\n";
2719         return STRCONV(data.str());
2720 }