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