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