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