]> git.lyx.org Git - features.git/blob - src/insets/insettabular.C
Some more functor work.
[features.git] / src / insets / insettabular.C
1 /**
2  * \file insettabular.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Jürgen Vigna
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "insettabular.h"
14
15 #include "buffer.h"
16 #include "bufferparams.h"
17 #include "BufferView.h"
18 #include "cursor.h"
19 #include "debug.h"
20 #include "dispatchresult.h"
21 #include "funcrequest.h"
22 #include "FuncStatus.h"
23 #include "gettext.h"
24 #include "language.h"
25 #include "LColor.h"
26 #include "lyx_cb.h"
27 #include "lyxlex.h"
28 #include "metricsinfo.h"
29 #include "outputparams.h"
30 #include "paragraph.h"
31 #include "paragraph_funcs.h"
32 #include "ParagraphParameters.h"
33 #include "undo.h"
34
35 #include "frontends/Alert.h"
36 #include "frontends/font_metrics.h"
37 #include "frontends/LyXView.h"
38 #include "frontends/Painter.h"
39
40 #include "support/std_sstream.h"
41
42 #include <iostream>
43
44 using lyx::graphics::PreviewLoader;
45
46 using lyx::support::ltrim;
47 using lyx::support::strToInt;
48 using lyx::support::strToDbl;
49
50 using std::endl;
51 using std::max;
52 using std::swap;
53 using std::string;
54 using std::auto_ptr;
55 using std::istringstream;
56 using std::ostream;
57 using std::ostringstream;
58
59
60 namespace {
61
62 int const ADD_TO_HEIGHT = 2;
63 int const ADD_TO_TABULAR_WIDTH = 2;
64
65 ///
66 boost::scoped_ptr<LyXTabular> paste_tabular;
67
68
69 struct TabularFeature {
70         LyXTabular::Feature action;
71         string feature;
72 };
73
74
75 TabularFeature tabularFeature[] =
76 {
77         { LyXTabular::APPEND_ROW, "append-row" },
78         { LyXTabular::APPEND_COLUMN, "append-column" },
79         { LyXTabular::DELETE_ROW, "delete-row" },
80         { LyXTabular::DELETE_COLUMN, "delete-column" },
81         { LyXTabular::TOGGLE_LINE_TOP, "toggle-line-top" },
82         { LyXTabular::TOGGLE_LINE_BOTTOM, "toggle-line-bottom" },
83         { LyXTabular::TOGGLE_LINE_LEFT, "toggle-line-left" },
84         { LyXTabular::TOGGLE_LINE_RIGHT, "toggle-line-right" },
85         { LyXTabular::ALIGN_LEFT, "align-left" },
86         { LyXTabular::ALIGN_RIGHT, "align-right" },
87         { LyXTabular::ALIGN_CENTER, "align-center" },
88         { LyXTabular::ALIGN_BLOCK, "align-block" },
89         { LyXTabular::VALIGN_TOP, "valign-top" },
90         { LyXTabular::VALIGN_BOTTOM, "valign-bottom" },
91         { LyXTabular::VALIGN_MIDDLE, "valign-middle" },
92         { LyXTabular::M_TOGGLE_LINE_TOP, "m-toggle-line-top" },
93         { LyXTabular::M_TOGGLE_LINE_BOTTOM, "m-toggle-line-bottom" },
94         { LyXTabular::M_TOGGLE_LINE_LEFT, "m-toggle-line-left" },
95         { LyXTabular::M_TOGGLE_LINE_RIGHT, "m-toggle-line-right" },
96         { LyXTabular::M_ALIGN_LEFT, "m-align-left" },
97         { LyXTabular::M_ALIGN_RIGHT, "m-align-right" },
98         { LyXTabular::M_ALIGN_CENTER, "m-align-center" },
99         { LyXTabular::M_VALIGN_TOP, "m-valign-top" },
100         { LyXTabular::M_VALIGN_BOTTOM, "m-valign-bottom" },
101         { LyXTabular::M_VALIGN_MIDDLE, "m-valign-middle" },
102         { LyXTabular::MULTICOLUMN, "multicolumn" },
103         { LyXTabular::SET_ALL_LINES, "set-all-lines" },
104         { LyXTabular::UNSET_ALL_LINES, "unset-all-lines" },
105         { LyXTabular::SET_LONGTABULAR, "set-longtabular" },
106         { LyXTabular::UNSET_LONGTABULAR, "unset-longtabular" },
107         { LyXTabular::SET_PWIDTH, "set-pwidth" },
108         { LyXTabular::SET_MPWIDTH, "set-mpwidth" },
109         { LyXTabular::SET_ROTATE_TABULAR, "set-rotate-tabular" },
110         { LyXTabular::UNSET_ROTATE_TABULAR, "unset-rotate-tabular" },
111         { LyXTabular::SET_ROTATE_CELL, "set-rotate-cell" },
112         { LyXTabular::UNSET_ROTATE_CELL, "unset-rotate-cell" },
113         { LyXTabular::SET_USEBOX, "set-usebox" },
114         { LyXTabular::SET_LTHEAD, "set-lthead" },
115         { LyXTabular::SET_LTFIRSTHEAD, "set-ltfirsthead" },
116         { LyXTabular::SET_LTFOOT, "set-ltfoot" },
117         { LyXTabular::SET_LTLASTFOOT, "set-ltlastfoot" },
118         { LyXTabular::SET_LTNEWPAGE, "set-ltnewpage" },
119         { LyXTabular::SET_SPECIAL_COLUMN, "set-special-column" },
120         { LyXTabular::SET_SPECIAL_MULTI, "set-special-multi" },
121         { LyXTabular::LAST_ACTION, "" }
122 };
123
124
125 class FeatureEqual : public std::unary_function<TabularFeature, bool> {
126 public:
127         FeatureEqual(LyXTabular::Feature feature)
128                 : feature_(feature) {}
129         bool operator()(TabularFeature const & tf) const {
130                 return tf.action == feature_;
131         }
132 private:
133         LyXTabular::Feature feature_;
134 };
135
136 } // namespace anon
137
138
139 string const featureAsString(LyXTabular::Feature feature)
140 {
141         TabularFeature * end = tabularFeature +
142                 sizeof(tabularFeature) / sizeof(TabularFeature);
143         TabularFeature * it = std::find_if(tabularFeature, end,
144                                            FeatureEqual(feature));
145         return (it == end) ? string() : it->feature;
146 }
147
148
149 bool InsetTabular::hasPasteBuffer() const
150 {
151         return (paste_tabular.get() != 0);
152 }
153
154
155 InsetTabular::InsetTabular(Buffer const & buf, int rows, int columns)
156         : tabular(buf.params(), max(rows, 1), max(columns, 1)),
157           buffer_(&buf), cursorx_(0), cursory_(0)
158 {
159         tabular.setOwner(this);
160         actrow = 0;
161         actcell = 0;
162         clearSelection();
163         in_reset_pos = 0;
164 }
165
166
167 InsetTabular::InsetTabular(InsetTabular const & tab)
168         : UpdatableInset(tab), tabular(tab.tabular),
169                 buffer_(tab.buffer_), cursorx_(0), cursory_(0)
170 {
171         tabular.setOwner(this);
172         actrow = 0;
173         actcell = 0;
174         clearSelection();
175         in_reset_pos = 0;
176 }
177
178
179 InsetTabular::~InsetTabular()
180 {
181         InsetTabularMailer(*this).hideDialog();
182 }
183
184
185 auto_ptr<InsetBase> InsetTabular::clone() const
186 {
187         return auto_ptr<InsetBase>(new InsetTabular(*this));
188 }
189
190
191 Buffer const & InsetTabular::buffer() const
192 {
193         return *buffer_;
194 }
195
196
197 void InsetTabular::buffer(Buffer * b)
198 {
199         buffer_ = b;
200 }
201
202
203 void InsetTabular::write(Buffer const & buf, ostream & os) const
204 {
205         os << "Tabular" << endl;
206         tabular.write(buf, os);
207 }
208
209
210 void InsetTabular::read(Buffer const & buf, LyXLex & lex)
211 {
212         bool const old_format = (lex.getString() == "\\LyXTable");
213
214         tabular.read(buf, lex);
215
216         if (old_format)
217                 return;
218
219         lex.nextToken();
220         string token = lex.getString();
221         while (lex.isOK() && (token != "\\end_inset")) {
222                 lex.nextToken();
223                 token = lex.getString();
224         }
225         if (token != "\\end_inset") {
226                 lex.printError("Missing \\end_inset at this point. "
227                                "Read: `$$Token'");
228         }
229 }
230
231
232 void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const
233 {
234         //lyxerr << "InsetTabular::metrics: " << mi.base.bv << " width: " <<
235         //      mi.base.textwidth << "\n";
236         if (!mi.base.bv) {
237                 lyxerr << "InsetTabular::metrics: need bv" << endl;
238                 BOOST_ASSERT(false);
239         }
240
241         calculate_dimensions_of_cells(mi);
242
243         dim.asc = tabular.getAscentOfRow(0);
244         dim.des = tabular.getHeightOfTabular() - tabular.getAscentOfRow(0) + 1;
245         dim.wid = tabular.getWidthOfTabular() + 2 * ADD_TO_TABULAR_WIDTH;
246         dim_ = dim;
247 }
248
249
250 void InsetTabular::draw(PainterInfo & pi, int x, int y) const
251 {
252         //lyxerr << "InsetTabular::draw: " << x << " " << y << endl;
253
254         BufferView * bv = pi.base.bv;
255
256         if (!owner())
257                 x += scroll();
258
259         xo_ = x;
260         yo_ = y;
261         x += ADD_TO_TABULAR_WIDTH;
262
263         int cell = 0;
264         first_visible_cell = -1;
265         for (int i = 0; i < tabular.rows(); ++i) {
266                 int nx = x;
267                 cell = tabular.getCellNumber(i, 0);
268                 if (y + tabular.getDescentOfRow(i) <= 0 &&
269                           y - tabular.getAscentOfRow(i) < pi.pain.paperHeight())
270                 {
271                         y += tabular.getDescentOfRow(i) +
272                                         tabular.getAscentOfRow(i + 1) +
273                                         tabular.getAdditionalHeight(i + 1);
274                         continue;
275                 }
276                 for (int j = 0; j < tabular.columns(); ++j) {
277                         if (nx > bv->workWidth())
278                                 break;
279                         if (tabular.isPartOfMultiColumn(i, j))
280                                 continue;
281                         if (first_visible_cell < 0)
282                                 first_visible_cell = cell;
283                         if (hasSelection())
284                                 drawCellSelection(pi.pain, nx, y, i, j, cell);
285
286                         int const cx = nx + tabular.getBeginningOfTextInCell(cell);
287                         tabular.getCellInset(cell).draw(pi, cx, y);
288                         drawCellLines(pi.pain, nx, y, i, cell);
289                         nx += tabular.getWidthOfColumn(cell);
290                         ++cell;
291                 }
292
293 // Would be nice, but for some completely unfathomable reason,
294 // on a col resize to a new fixed width, even though the insettexts
295 // are resized, the cell isn't, but drawing all cells in a tall table
296 // has the desired effect somehow. Complete dark magic.
297 #if 0
298                 // avoiding drawing the rest of a long table is
299                 // a pretty big speedup
300                 if (y > bv->workHeight())
301                         break;
302 #endif
303
304                 y += tabular.getDescentOfRow(i) +
305                         tabular.getAscentOfRow(i + 1) +
306                         tabular.getAdditionalHeight(i + 1);
307         }
308 }
309
310
311 void InsetTabular::drawCellLines(Painter & pain, int x, int y,
312                                  int row, int cell) const
313 {
314         int x2 = x + tabular.getWidthOfColumn(cell);
315         bool on_off = false;
316
317         if (!tabular.topAlreadyDrawn(cell)) {
318                 on_off = !tabular.topLine(cell);
319                 pain.line(x, y - tabular.getAscentOfRow(row),
320                           x2, y -  tabular.getAscentOfRow(row),
321                           on_off ? LColor::tabularonoffline : LColor::tabularline,
322                           on_off ? Painter::line_onoffdash : Painter::line_solid);
323         }
324         on_off = !tabular.bottomLine(cell);
325         pain.line(x, y + tabular.getDescentOfRow(row),
326                   x2, y + tabular.getDescentOfRow(row),
327                   on_off ? LColor::tabularonoffline : LColor::tabularline,
328                   on_off ? Painter::line_onoffdash : Painter::line_solid);
329         if (!tabular.leftAlreadyDrawn(cell)) {
330                 on_off = !tabular.leftLine(cell);
331                 pain.line(x, y -  tabular.getAscentOfRow(row),
332                           x, y +  tabular.getDescentOfRow(row),
333                           on_off ? LColor::tabularonoffline : LColor::tabularline,
334                           on_off ? Painter::line_onoffdash : Painter::line_solid);
335         }
336         on_off = !tabular.rightLine(cell);
337         pain.line(x2 - tabular.getAdditionalWidth(cell),
338                   y -  tabular.getAscentOfRow(row),
339                   x2 - tabular.getAdditionalWidth(cell),
340                   y +  tabular.getDescentOfRow(row),
341                   on_off ? LColor::tabularonoffline : LColor::tabularline,
342                   on_off ? Painter::line_onoffdash : Painter::line_solid);
343 }
344
345
346 void InsetTabular::drawCellSelection(Painter & pain, int x, int y,
347                                      int row, int column, int cell) const
348 {
349         if (actcell != -1)
350                 return;
351
352         BOOST_ASSERT(hasSelection());
353         int cs = tabular.column_of_cell(sel_cell_start);
354         int ce = tabular.column_of_cell(sel_cell_end);
355         if (cs > ce) {
356                 ce = cs;
357                 cs = tabular.column_of_cell(sel_cell_end);
358         } else {
359                 ce = tabular.right_column_of_cell(sel_cell_end);
360         }
361
362         int rs = tabular.row_of_cell(sel_cell_start);
363         int re = tabular.row_of_cell(sel_cell_end);
364         if (rs > re)
365                 swap(rs, re);
366
367         if (column >= cs && column <= ce && row >= rs && row <= re) {
368                 int w = tabular.getWidthOfColumn(cell);
369                 int h = tabular.getAscentOfRow(row) + tabular.getDescentOfRow(row)-1;
370                 pain.fillRectangle(x, y - tabular.getAscentOfRow(row) + 1,
371                                    w, h, LColor::selection);
372         }
373 }
374
375
376 string const InsetTabular::editMessage() const
377 {
378         return _("Opened table");
379 }
380
381
382 void InsetTabular::updateLocal(BufferView * bv) const
383 {
384         bv->update();
385         resetPos(bv);
386 }
387
388 extern LCursor theTempCursor;
389
390
391
392 void InsetTabular::lfunMousePress(FuncRequest const & cmd)
393 {
394         if (hasSelection() && cmd.button() == mouse_button::button3)
395                 return;
396
397         if (hasSelection())
398                 clearSelection();
399
400         BufferView * bv = cmd.view();
401
402         int cell = getCell(cmd.x + xo_, cmd.y + yo_);
403         lyxerr << "# InsetTabular::lfunMousePress cell: " << cell << endl;
404         if (cell == -1) {
405                 bv->cursor() = theTempCursor;
406                 bv->cursor().data_.push_back(CursorSlice(this));
407                 bv->cursor().data_.back().idx_ = cell;
408         } else {
409                 setPos(bv, cmd.x, cmd.y);
410                 clearSelection();
411                 bv->cursor() = theTempCursor;
412                 bv->cursor().data_.back().idx_ = cell;
413         }
414         actcell = cell;
415         lyxerr << bv->cursor() << endl;
416
417         if (cmd.button() == mouse_button::button2)
418                 dispatch(FuncRequest(bv, LFUN_PASTESELECTION, "paragraph"));
419 }
420
421
422 void InsetTabular::lfunMouseRelease(FuncRequest const & cmd)
423 {
424         int cell = getCell(cmd.x + xo_, cmd.y + yo_);
425         lyxerr << "# InsetTabular::lfunMouseRelease cell: " << cell << endl;
426         if (cmd.button() == mouse_button::button3)
427                 InsetTabularMailer(*this).showDialog(cmd.view());
428 }
429
430
431 void InsetTabular::lfunMouseMotion(FuncRequest const & cmd)
432 {
433         int cell = getCell(cmd.x + xo_, cmd.y + yo_);
434         lyxerr << "# InsetTabular::lfunMouseMotion cell: " << cell << endl;
435         BufferView * bv = cmd.view();
436         int const old_cell = actcell;
437
438         setPos(bv, cmd.x, cmd.y);
439         if (!hasSelection())
440                 setSelection(actcell, actcell);
441         else if (old_cell != actcell)
442                 setSelection(sel_cell_start, actcell);
443 }
444
445
446 void InsetTabular::edit(BufferView * bv, bool left)
447 {
448         lyxerr << "InsetTabular::edit: " << this << endl;
449         finishUndo();
450         if (left) {
451                 if (isRightToLeft(bv))
452                         actcell = tabular.getLastCellInRow(0);
453                 else
454                         actcell = 0;
455         } else {
456                 if (isRightToLeft(bv))
457                         actcell = tabular.getFirstCellInRow(tabular.rows()-1);
458                 else
459                         actcell = tabular.getNumberOfCells() - 1;
460         }
461         clearSelection();
462         resetPos(bv);
463         bv->fitCursor();
464         bv->cursor().push(this);
465         bv->cursor().data_.back().idx_ = actcell;
466         lyxerr << bv->cursor() << endl;
467 }
468
469
470 void InsetTabular::edit(BufferView * bv, int x, int y)
471 {
472         lyxerr << "InsetTabular::edit: " << this << " first cell "
473                 << &tabular.cell_info[0][0].inset << endl;
474
475         finishUndo();
476         setPos(bv, x, y);
477         clearSelection();
478         finishUndo();
479         int xx = cursorx_ - xo_ + tabular.getBeginningOfTextInCell(actcell);
480         bv->cursor().push(this);
481         if (x > xx)
482                 activateCellInset(bv, actcell, x - xx, y - cursory_);
483 }
484
485
486 DispatchResult
487 InsetTabular::priv_dispatch(FuncRequest const & cmd,
488         idx_type & idx, pos_type & pos)
489 {
490         //lyxerr << "# InsetTabular::dispatch: " << cmd << endl;
491
492         DispatchResult result(true, true);
493         BufferView * bv = cmd.view();
494
495         switch (cmd.action) {
496
497         case LFUN_MOUSE_PRESS:
498                 lfunMousePress(cmd);
499                 return DispatchResult(true, true);
500
501         case LFUN_MOUSE_MOTION:
502                 lfunMouseMotion(cmd);
503                 return DispatchResult(true, true);
504
505         case LFUN_MOUSE_RELEASE:
506                 lfunMouseRelease(cmd);
507                 return DispatchResult(true, true);
508
509         default:
510                 break;
511         }
512
513         int cell = bv->cursor().data_.back().idx_;
514         if (cell != -1) {
515
516                 if (cell != actcell) {
517                         lyxerr << "## ERROR ## InsetTabular::priv_dispatch: actcell: "
518                                 << actcell << " and cell " << cell << " should be the same "
519                                 << "here" << endl;
520                 }
521
522                 result = tabular.getCellInset(cell).dispatch(cmd, idx, pos);
523
524                 switch (result.val()) {
525                 case FINISHED:
526                         if (movePrevCell(bv))
527                                 result = DispatchResult(true, true);
528                         else
529                                 result = DispatchResult(false, FINISHED);
530                         break;
531
532                 case FINISHED_RIGHT:
533                         if (moveNextCell(bv))
534                                 result = DispatchResult(true, true);
535                         else
536                                 result = DispatchResult(false, FINISHED_RIGHT);
537                         break;
538
539                 case FINISHED_UP:
540                         result = moveUpLock(bv);
541                         break;
542
543                 case FINISHED_DOWN:
544                         result = moveDownLock(bv);
545                         break;
546
547                 default:
548                         lyxerr << "# don't handle dispatch in act: " << actcell << endl;
549                         break;
550                 }
551
552                 return result;
553         }
554
555         lyxerr << "# InsetTabular::dispatch 3: " << cmd << endl;
556         switch (cmd.action) {
557
558         case LFUN_CELL_BACKWARD:
559         case LFUN_CELL_FORWARD:
560                 if (cmd.action == LFUN_CELL_FORWARD)
561                         moveNextCell(bv);
562                 else
563                         movePrevCell(bv);
564                 clearSelection();
565                 return result;
566
567         case LFUN_SCROLL_INSET:
568                 if (!cmd.argument.empty()) {
569                         if (cmd.argument.find('.') != cmd.argument.npos)
570                                 scroll(cmd.view(), static_cast<float>(strToDbl(cmd.argument)));
571                         else
572                                 scroll(cmd.view(), strToInt(cmd.argument));
573                         cmd.view()->update();
574                         return DispatchResult(true, true);
575                 }
576
577         case LFUN_RIGHTSEL: {
578                 int const start = hasSelection() ? sel_cell_start : actcell;
579                 if (tabular.isLastCellInRow(actcell)) {
580                         setSelection(start, actcell);
581                         break;
582                 }
583
584                 int end = actcell;
585                 // if we are starting a selection, only select
586                 // the current cell at the beginning
587                 if (hasSelection()) {
588                         moveRight(bv);
589                         end = actcell;
590                 }
591                 setSelection(start, end);
592                 break;
593         }
594
595         case LFUN_RIGHT:
596                 result = moveRightLock(bv);
597                 clearSelection();
598                 break;
599
600         case LFUN_LEFTSEL: {
601                 int const start = hasSelection() ? sel_cell_start : actcell;
602                 if (tabular.isFirstCellInRow(actcell)) {
603                         setSelection(start, actcell);
604                         break;
605                 }
606
607                 int end = actcell;
608                 // if we are starting a selection, only select
609                 // the current cell at the beginning
610                 if (hasSelection()) {
611                         moveLeft(bv);
612                         end = actcell;
613                 }
614                 setSelection(start, end);
615                 break;
616         }
617
618         case LFUN_LEFT:
619                 result = moveLeftLock(bv);
620                 clearSelection();
621                 break;
622
623         case LFUN_DOWNSEL: {
624                 int const start = hasSelection() ? sel_cell_start : actcell;
625                 int const ocell = actcell;
626                 // if we are starting a selection, only select
627                 // the current cell at the beginning
628                 if (hasSelection()) {
629                         moveDown(bv);
630                         if (ocell == sel_cell_end ||
631                             tabular.column_of_cell(ocell) > tabular.column_of_cell(actcell))
632                                 setSelection(start, tabular.getCellBelow(sel_cell_end));
633                         else
634                                 setSelection(start, tabular.getLastCellBelow(sel_cell_end));
635                 } else {
636                         setSelection(start, start);
637                 }
638                 break;
639         }
640
641         case LFUN_DOWN:
642                 result = moveDown(bv);
643                 clearSelection();
644                 break;
645
646         case LFUN_UPSEL: {
647                 int const start = hasSelection() ? sel_cell_start : actcell;
648                 int const ocell = actcell;
649                 // if we are starting a selection, only select
650                 // the current cell at the beginning
651                 if (hasSelection()) {
652                         moveUp(bv);
653                         if (ocell == sel_cell_end ||
654                             tabular.column_of_cell(ocell) > tabular.column_of_cell(actcell))
655                                 setSelection(start, tabular.getCellAbove(sel_cell_end));
656                         else
657                                 setSelection(start, tabular.getLastCellAbove(sel_cell_end));
658                 } else {
659                         setSelection(start, start);
660                 }
661                 break;
662         }
663
664         case LFUN_UP:
665                 result = moveUp(bv);
666                 clearSelection();
667                 break;
668
669         case LFUN_NEXT: {
670                 if (hasSelection())
671                         clearSelection();
672                 int column = actcol;
673                 if (bv->top_y() + bv->painter().paperHeight()
674                     < yo_ + tabular.getHeightOfTabular())
675                 {
676                         bv->scrollDocView(bv->top_y() + bv->painter().paperHeight());
677                         actcell = tabular.getCellBelow(first_visible_cell) + column;
678                 } else {
679                         actcell = tabular.getFirstCellInRow(tabular.rows() - 1) + column;
680                 }
681                 resetPos(bv);
682                 break;
683         }
684
685         case LFUN_PRIOR: {
686                 if (hasSelection())
687                         clearSelection();
688                 int column = actcol;
689                 if (yo_ < 0) {
690                         bv->scrollDocView(bv->top_y() - bv->painter().paperHeight());
691                         if (yo_ > 0)
692                                 actcell = column;
693                         else
694                                 actcell = tabular.getCellBelow(first_visible_cell) + column;
695                 } else {
696                         actcell = column;
697                 }
698                 resetPos(bv);
699                 break;
700         }
701
702         // none of these make sense for insettabular,
703         // but we must catch them to prevent any
704         // selection from being confused
705         case LFUN_PRIORSEL:
706         case LFUN_NEXTSEL:
707         case LFUN_WORDLEFT:
708         case LFUN_WORDLEFTSEL:
709         case LFUN_WORDRIGHT:
710         case LFUN_WORDRIGHTSEL:
711         case LFUN_WORDSEL:
712         case LFUN_DOWN_PARAGRAPH:
713         case LFUN_DOWN_PARAGRAPHSEL:
714         case LFUN_UP_PARAGRAPH:
715         case LFUN_UP_PARAGRAPHSEL:
716         case LFUN_BACKSPACE:
717         case LFUN_HOME:
718         case LFUN_HOMESEL:
719         case LFUN_END:
720         case LFUN_ENDSEL:
721         case LFUN_BEGINNINGBUF:
722         case LFUN_BEGINNINGBUFSEL:
723         case LFUN_ENDBUF:
724         case LFUN_ENDBUFSEL:
725                 break;
726
727         case LFUN_LAYOUT_TABULAR:
728                 InsetTabularMailer(*this).showDialog(bv);
729                 break;
730
731         case LFUN_INSET_DIALOG_UPDATE:
732                 InsetTabularMailer(*this).updateDialog(bv);
733                 break;
734
735         case LFUN_TABULAR_FEATURE:
736                 if (!tabularFeatures(bv, cmd.argument))
737                         result = DispatchResult(false);
738                 break;
739
740         // insert file functions
741         case LFUN_FILE_INSERT_ASCII_PARA:
742         case LFUN_FILE_INSERT_ASCII: {
743                 string tmpstr = getContentsOfAsciiFile(bv, cmd.argument, false);
744                 if (!tmpstr.empty() && !insertAsciiString(bv, tmpstr, false))
745                         result = DispatchResult(false);
746                 break;
747         }
748
749         case LFUN_LANGUAGE:
750         case LFUN_EMPH:
751         case LFUN_BOLD:
752         case LFUN_NOUN:
753         case LFUN_CODE:
754         case LFUN_SANS:
755         case LFUN_ROMAN:
756         case LFUN_DEFAULT:
757         case LFUN_UNDERLINE:
758         case LFUN_FONT_SIZE:
759                 lyxerr << "font changes not re-implemented for tables after LOCK" << endl;
760                 break;
761
762         case LFUN_CUT:
763                 if (copySelection(bv)) {
764                         recordUndo(bv, Undo::DELETE);
765                         cutSelection(bv->buffer()->params());
766                 }
767                 break;
768
769         case LFUN_DELETE:
770                 recordUndo(bv, Undo::DELETE);
771                 cutSelection(bv->buffer()->params());
772                 break;
773
774         case LFUN_COPY:
775                 if (!hasSelection())
776                         break;
777                 finishUndo();
778                 copySelection(bv);
779                 break;
780
781         case LFUN_PASTESELECTION: {
782                 string const clip = bv->getClipboard();
783                 if (clip.empty())
784                         break;
785                 if (clip.find('\t') != string::npos) {
786                         int cols = 1;
787                         int rows = 1;
788                         int maxCols = 1;
789                         string::size_type len = clip.length();
790                         string::size_type p = 0;
791
792                         while (p < len &&
793                               (p = clip.find_first_of("\t\n", p)) != string::npos) {
794                                 switch (clip[p]) {
795                                 case '\t':
796                                         ++cols;
797                                         break;
798                                 case '\n':
799                                         if (p + 1 < len)
800                                                 ++rows;
801                                         maxCols = max(cols, maxCols);
802                                         cols = 1;
803                                         break;
804                                 }
805                                 ++p;
806                         }
807                         maxCols = max(cols, maxCols);
808
809                         paste_tabular.reset(
810                                 new LyXTabular(bv->buffer()->params(), rows, maxCols));
811
812                         string::size_type op = 0;
813                         int cell = 0;
814                         int cells = paste_tabular->getNumberOfCells();
815                         p = 0;
816                         cols = 0;
817                         LyXFont font;
818                         while (cell < cells && p < len &&
819                               (p = clip.find_first_of("\t\n", p)) != string::npos) {
820                                 if (p >= len)
821                                         break;
822                                 switch (clip[p]) {
823                                 case '\t':
824                                         paste_tabular->getCellInset(cell).
825                                                 setText(clip.substr(op, p-op), font);
826                                         ++cols;
827                                         ++cell;
828                                         break;
829                                 case '\n':
830                                         paste_tabular->getCellInset(cell).
831                                                 setText(clip.substr(op, p-op), font);
832                                         while (cols++ < maxCols)
833                                                 ++cell;
834                                         cols = 0;
835                                         break;
836                                 }
837                                 ++p;
838                                 op = p;
839                         }
840                         // check for the last cell if there is no trailing '\n'
841                         if (cell < cells && op < len)
842                                 paste_tabular->getCellInset(cell).
843                                         setText(clip.substr(op, len-op), font);
844                 } else if (!insertAsciiString(bv, clip, true))
845                 {
846                         // so that the clipboard is used and it goes on
847                         // to default
848                         // and executes LFUN_PASTESELECTION in insettext!
849                         paste_tabular.reset();
850                 }
851                 // fall through
852         }
853
854         case LFUN_PASTE:
855                 if (hasPasteBuffer()) {
856                         recordUndo(bv, Undo::INSERT);
857                         pasteSelection(bv);
858                         break;
859                 }
860                 // fall through
861
862         // ATTENTION: the function above has to be PASTE and PASTESELECTION!!!
863
864         default:
865                 // handle font changing stuff on selection before we lock the inset
866                 // in the default part!
867                 result = DispatchResult(false);
868                 // we try to activate the actual inset and put this event down to
869                 // the insets dispatch function.
870                 break;
871         }
872
873         updateLocal(bv);
874         InsetTabularMailer(*this).updateDialog(bv);
875         return result;
876 }
877
878
879 int InsetTabular::latex(Buffer const & buf, ostream & os,
880                         OutputParams const & runparams) const
881 {
882         return tabular.latex(buf, os, runparams);
883 }
884
885
886 int InsetTabular::plaintext(Buffer const & buf, ostream & os,
887                         OutputParams const & runparams) const
888 {
889         int dp = runparams.linelen ? ownerPar(buf, this).params().depth() : 0;
890         return tabular.plaintext(buf, os, runparams, dp, false, 0);
891 }
892
893
894 int InsetTabular::linuxdoc(Buffer const & buf, ostream & os,
895                            OutputParams const & runparams) const
896 {
897         return tabular.linuxdoc(buf,os, runparams);
898 }
899
900
901 int InsetTabular::docbook(Buffer const & buf, ostream & os,
902                           OutputParams const & runparams) const
903 {
904         int ret = 0;
905         InsetOld * master;
906
907         // if the table is inside a float it doesn't need the informaltable
908         // wrapper. Search for it.
909         for (master = owner();
910              master && master->lyxCode() != InsetOld::FLOAT_CODE;
911              master = master->owner())
912                 ;
913
914         if (!master) {
915                 os << "<informaltable>";
916                 if (runparams.mixed_content)
917                         os << endl;
918                 ++ret;
919         }
920         ret += tabular.docbook(buf, os, runparams);
921         if (!master) {
922                 os << "</informaltable>";
923                 if (runparams.mixed_content)
924                         os << endl;
925                 ++ret;
926         }
927         return ret;
928 }
929
930
931 void InsetTabular::validate(LaTeXFeatures & features) const
932 {
933         tabular.validate(features);
934 }
935
936
937 void InsetTabular::calculate_dimensions_of_cells(MetricsInfo & mi) const
938 {
939         int cell = -1;
940         for (int i = 0; i < tabular.rows(); ++i) {
941                 int maxAsc = 0;
942                 int maxDesc = 0;
943                 for (int j = 0; j < tabular.columns(); ++j) {
944                         if (tabular.isPartOfMultiColumn(i, j))
945                                 continue;
946                         ++cell;
947                         Dimension dim;
948                         MetricsInfo m = mi;
949                         m.base.textwidth =
950                                 tabular.column_info[j].p_width.inPixels(mi.base.textwidth);
951                         tabular.getCellInset(cell).metrics(m, dim);
952                         maxAsc  = max(maxAsc, dim.asc);
953                         maxDesc = max(maxDesc, dim.des);
954                         tabular.setWidthOfCell(cell, dim.wid);
955                 }
956                 tabular.setAscentOfRow(i, maxAsc + ADD_TO_HEIGHT);
957                 tabular.setDescentOfRow(i, maxDesc + ADD_TO_HEIGHT);
958         }
959 }
960
961
962 void InsetTabular::getCursorPos(int & x, int & y) const
963 {
964         if (actcell == -1) {
965                 x = TEXT_TO_INSET_OFFSET + cursorx_ - xo_;
966                 y = TEXT_TO_INSET_OFFSET + cursory_;
967         } else {
968                 InsetText const & inset = tabular.getCellInset(actcell);
969                 inset.getCursorPos(x, y);
970                 x += inset.x() - xo_;
971                 y += inset.y() - yo_;
972         }
973 }
974
975
976 void InsetTabular::setPos(BufferView * bv, int x, int y) const
977 {
978         cursory_ = 0;
979         actcell = 0;
980         actrow = 0;
981         actcol = 0;
982         int ly = tabular.getDescentOfRow(actrow);
983
984         // first search the right row
985         while (ly < y && actrow + 1 < tabular.rows()) {
986                 cursory_ += tabular.getDescentOfRow(actrow) +
987                                  tabular.getAscentOfRow(actrow + 1) +
988                                  tabular.getAdditionalHeight(actrow + 1);
989                 ++actrow;
990                 ly = cursory_ + tabular.getDescentOfRow(actrow);
991         }
992         actcell = tabular.getCellNumber(actrow, actcol);
993
994         // now search the right column
995         int lx = tabular.getWidthOfColumn(actcell) -
996                 tabular.getAdditionalWidth(actcell);
997
998         for (; !tabular.isLastCellInRow(actcell) && lx < x; ++actcell)
999                 lx += tabular.getWidthOfColumn(actcell + 1)
1000                         + tabular.getAdditionalWidth(actcell);
1001
1002         cursorx_ = lx - tabular.getWidthOfColumn(actcell) + xo_ + 2;
1003         resetPos(bv);
1004 }
1005
1006
1007 int InsetTabular::getCellXPos(int cell) const
1008 {
1009         int c = cell;
1010
1011         for (; !tabular.isFirstCellInRow(c); --c)
1012                 ;
1013         int lx = tabular.getWidthOfColumn(cell);
1014         for (; c < cell; ++c)
1015                 lx += tabular.getWidthOfColumn(c);
1016
1017         return lx - tabular.getWidthOfColumn(cell) + xo_;
1018 }
1019
1020
1021 void InsetTabular::resetPos(BufferView * bv) const
1022 {
1023 #ifdef WITH_WARNINGS
1024 #warning This should be fixed in the right manner (20011128 Jug)
1025 #endif
1026         // fast hack to fix infinite repaintings!
1027         if (in_reset_pos > 0)
1028                 return;
1029
1030         int cell = 0;
1031         actcol = tabular.column_of_cell(actcell);
1032         actrow = 0;
1033         cursory_ = 0;
1034         for (; cell < actcell && !tabular.isLastRow(cell); ++cell) {
1035                 if (tabular.isLastCellInRow(cell)) {
1036                         cursory_ += tabular.getDescentOfRow(actrow) +
1037                                          tabular.getAscentOfRow(actrow + 1) +
1038                                          tabular.getAdditionalHeight(actrow + 1);
1039                         ++actrow;
1040                 }
1041         }
1042
1043         // we need this only from here on!!!
1044         ++in_reset_pos;
1045         int const offset = ADD_TO_TABULAR_WIDTH + 2;
1046         int new_x = getCellXPos(actcell) + offset;
1047         int old_x = cursorx_;
1048         cursorx_ = new_x;
1049 //    cursor.x(getCellXPos(actcell) + offset);
1050         if (actcol < tabular.columns() - 1 && scroll(false) &&
1051                 tabular.getWidthOfTabular() < bv->workWidth()-20)
1052         {
1053                 scroll(bv, 0.0F);
1054                 updateLocal(bv);
1055         } else if (cursorx_ - offset > 20 &&
1056                    cursorx_ - offset + tabular.getWidthOfColumn(actcell)
1057                    > bv->workWidth() - 20) {
1058                 scroll(bv, - tabular.getWidthOfColumn(actcell) - 20);
1059                 updateLocal(bv);
1060         } else if (cursorx_ - offset < 20) {
1061                 scroll(bv, 20 - cursorx_ + offset);
1062                 updateLocal(bv);
1063         } else if (scroll() && xo_ > 20 &&
1064                    xo_ + tabular.getWidthOfTabular() > bv->workWidth() - 20) {
1065                 scroll(bv, old_x - cursorx_);
1066                 updateLocal(bv);
1067         }
1068         InsetTabularMailer(*this).updateDialog(bv);
1069         in_reset_pos = 0;
1070 }
1071
1072
1073 DispatchResult InsetTabular::moveRight(BufferView * bv)
1074 {
1075         bool moved = isRightToLeft(bv) ? movePrevCell(bv) : moveNextCell(bv);
1076         if (!moved)
1077                 return DispatchResult(false, FINISHED_RIGHT);
1078         resetPos(bv);
1079         return DispatchResult(true);
1080 }
1081
1082
1083 DispatchResult InsetTabular::moveRightLock(BufferView * bv)
1084 {
1085         bool moved = isRightToLeft(bv) ? movePrevCell(bv) : moveNextCell(bv);
1086         if (!moved)
1087                 return DispatchResult(false, FINISHED_RIGHT);
1088         activateCellInset(bv, actcell, false);
1089         return DispatchResult(true, true);
1090 }
1091
1092
1093 DispatchResult InsetTabular::moveLeft(BufferView * bv)
1094 {
1095         bool moved = isRightToLeft(bv) ? moveNextCell(bv) : movePrevCell(bv);
1096         if (!moved)
1097                 return DispatchResult(false, FINISHED);
1098         resetPos(bv);
1099         return DispatchResult(true);
1100 }
1101
1102
1103 DispatchResult InsetTabular::moveLeftLock(BufferView * bv)
1104 {
1105         bool moved = isRightToLeft(bv) ? moveNextCell(bv) : movePrevCell(bv);
1106         if (!moved)
1107                 return DispatchResult(false, FINISHED);
1108         activateCellInset(bv, actcell, true);
1109         return DispatchResult(true, true);
1110 }
1111
1112
1113 DispatchResult InsetTabular::moveUp(BufferView * bv)
1114 {
1115         int const ocell = actcell;
1116         actcell = tabular.getCellAbove(actcell);
1117         if (actcell == ocell) // we moved out of the inset
1118                 return DispatchResult(false, FINISHED_UP);
1119         resetPos(bv);
1120         return DispatchResult(true, true);
1121 }
1122
1123
1124 DispatchResult InsetTabular::moveUpLock(BufferView * bv)
1125 {
1126         int const ocell = actcell;
1127         actcell = tabular.getCellAbove(actcell);
1128         if (actcell == ocell) // we moved out of the inset
1129                 return DispatchResult(false, FINISHED_UP);
1130         resetPos(bv);
1131         activateCellInset(bv, actcell, bv->x_target(), 0);
1132         return DispatchResult(true, true);
1133 }
1134
1135
1136 DispatchResult InsetTabular::moveDown(BufferView * bv)
1137 {
1138         int const ocell = actcell;
1139         actcell = tabular.getCellBelow(actcell);
1140         if (actcell == ocell) // we moved out of the inset
1141                 return DispatchResult(false, FINISHED_DOWN);
1142         resetPos(bv);
1143         return DispatchResult(true, true);
1144 }
1145
1146
1147 DispatchResult InsetTabular::moveDownLock(BufferView * bv)
1148 {
1149         int const ocell = actcell;
1150         actcell = tabular.getCellBelow(actcell);
1151         if (actcell == ocell) // we moved out of the inset
1152                 return DispatchResult(false, FINISHED_DOWN);
1153         resetPos(bv);
1154         activateCellInset(bv, actcell, bv->x_target());
1155         return DispatchResult(true, true);
1156 }
1157
1158
1159 bool InsetTabular::moveNextCell(BufferView * bv)
1160 {
1161         lyxerr << "InsetTabular::moveNextCell 1 actcell: " << actcell << endl;
1162         if (isRightToLeft(bv)) {
1163                 if (tabular.isFirstCellInRow(actcell)) {
1164                         int row = tabular.row_of_cell(actcell);
1165                         if (row == tabular.rows() - 1)
1166                                 return false;
1167                         actcell = tabular.getLastCellInRow(row);
1168                         actcell = tabular.getCellBelow(actcell);
1169                 } else {
1170                         if (actcell == 0)
1171                                 return false;
1172                         --actcell;
1173                 }
1174         } else {
1175                 if (tabular.isLastCell(actcell))
1176                         return false;
1177                 ++actcell;
1178         }
1179         lyxerr << "InsetTabular::moveNextCell 2 actcell: " << actcell << endl;
1180         resetPos(bv);
1181         return true;
1182 }
1183
1184
1185 bool InsetTabular::movePrevCell(BufferView * bv)
1186 {
1187         if (isRightToLeft(bv)) {
1188                 if (tabular.isLastCellInRow(actcell)) {
1189                         int row = tabular.row_of_cell(actcell);
1190                         if (row == 0)
1191                                 return false;
1192                         actcell = tabular.getFirstCellInRow(row);
1193                         actcell = tabular.getCellAbove(actcell);
1194                 } else {
1195                         if (tabular.isLastCell(actcell))
1196                                 return false;
1197                         ++actcell;
1198                 }
1199         } else {
1200                 if (actcell == 0) // first cell
1201                         return false;
1202                 --actcell;
1203         }
1204         resetPos(bv);
1205         return true;
1206 }
1207
1208
1209 bool InsetTabular::tabularFeatures(BufferView * bv, string const & what)
1210 {
1211         LyXTabular::Feature action = LyXTabular::LAST_ACTION;
1212
1213         int i = 0;
1214         for (; tabularFeature[i].action != LyXTabular::LAST_ACTION; ++i) {
1215                 string const tmp = tabularFeature[i].feature;
1216
1217                 if (tmp == what.substr(0, tmp.length())) {
1218                         //if (!compare(tabularFeatures[i].feature.c_str(), what.c_str(),
1219                         //tabularFeatures[i].feature.length())) {
1220                         action = tabularFeature[i].action;
1221                         break;
1222                 }
1223         }
1224         if (action == LyXTabular::LAST_ACTION)
1225                 return false;
1226
1227         string const val =
1228                 ltrim(what.substr(tabularFeature[i].feature.length()));
1229         tabularFeatures(bv, action, val);
1230         return true;
1231 }
1232
1233
1234 namespace {
1235
1236 void checkLongtableSpecial(LyXTabular::ltType & ltt,
1237                           string const & special, bool & flag)
1238 {
1239         if (special == "dl_above") {
1240                 ltt.topDL = flag;
1241                 ltt.set = false;
1242         } else if (special == "dl_below") {
1243                 ltt.bottomDL = flag;
1244                 ltt.set = false;
1245         } else if (special == "empty") {
1246                 ltt.empty = flag;
1247                 ltt.set = false;
1248         } else if (flag) {
1249                 ltt.empty = false;
1250                 ltt.set = true;
1251         }
1252 }
1253
1254 } // anon namespace
1255
1256
1257 void InsetTabular::tabularFeatures(BufferView * bv,
1258         LyXTabular::Feature feature, string const & value)
1259 {
1260         int sel_col_start;
1261         int sel_col_end;
1262         int sel_row_start;
1263         int sel_row_end;
1264         bool setLines = false;
1265         LyXAlignment setAlign = LYX_ALIGN_LEFT;
1266         LyXTabular::VAlignment setVAlign = LyXTabular::LYX_VALIGN_TOP;
1267
1268         switch (feature) {
1269
1270         case LyXTabular::M_ALIGN_LEFT:
1271         case LyXTabular::ALIGN_LEFT:
1272                 setAlign = LYX_ALIGN_LEFT;
1273                 break;
1274
1275         case LyXTabular::M_ALIGN_RIGHT:
1276         case LyXTabular::ALIGN_RIGHT:
1277                 setAlign = LYX_ALIGN_RIGHT;
1278                 break;
1279
1280         case LyXTabular::M_ALIGN_CENTER:
1281         case LyXTabular::ALIGN_CENTER:
1282                 setAlign = LYX_ALIGN_CENTER;
1283                 break;
1284
1285         case LyXTabular::ALIGN_BLOCK:
1286                 setAlign = LYX_ALIGN_BLOCK;
1287                 break;
1288
1289         case LyXTabular::M_VALIGN_TOP:
1290         case LyXTabular::VALIGN_TOP:
1291                 setVAlign = LyXTabular::LYX_VALIGN_TOP;
1292                 break;
1293
1294         case LyXTabular::M_VALIGN_BOTTOM:
1295         case LyXTabular::VALIGN_BOTTOM:
1296                 setVAlign = LyXTabular::LYX_VALIGN_BOTTOM;
1297                 break;
1298
1299         case LyXTabular::M_VALIGN_MIDDLE:
1300         case LyXTabular::VALIGN_MIDDLE:
1301                 setVAlign = LyXTabular::LYX_VALIGN_MIDDLE;
1302                 break;
1303
1304         default:
1305                 break;
1306         }
1307
1308         if (hasSelection()) {
1309                 getSelection(sel_row_start, sel_row_end, sel_col_start, sel_col_end);
1310         } else {
1311                 sel_col_start = sel_col_end = tabular.column_of_cell(actcell);
1312                 sel_row_start = sel_row_end = tabular.row_of_cell(actcell);
1313         }
1314         recordUndo(bv, Undo::ATOMIC);
1315
1316         int row =  tabular.row_of_cell(actcell);
1317         int column = tabular.column_of_cell(actcell);
1318         bool flag = true;
1319         LyXTabular::ltType ltt;
1320
1321         switch (feature) {
1322
1323         case LyXTabular::SET_PWIDTH: {
1324                 LyXLength const len(value);
1325                 tabular.setColumnPWidth(actcell, len);
1326                 if (len.zero()
1327                     && tabular.getAlignment(actcell, true) == LYX_ALIGN_BLOCK)
1328                         tabularFeatures(bv, LyXTabular::ALIGN_CENTER, string());
1329                 else if (!len.zero()
1330                          && tabular.getAlignment(actcell, true) != LYX_ALIGN_BLOCK)
1331                         tabularFeatures(bv, LyXTabular::ALIGN_BLOCK, string());
1332                 break;
1333         }
1334
1335         case LyXTabular::SET_MPWIDTH:
1336                 tabular.setMColumnPWidth(actcell, LyXLength(value));
1337                 break;
1338
1339         case LyXTabular::SET_SPECIAL_COLUMN:
1340         case LyXTabular::SET_SPECIAL_MULTI:
1341                 tabular.setAlignSpecial(actcell,value,feature);
1342                 break;
1343
1344         case LyXTabular::APPEND_ROW:
1345                 // append the row into the tabular
1346                 tabular.appendRow(bv->buffer()->params(), actcell);
1347                 tabular.setOwner(this);
1348                 break;
1349
1350         case LyXTabular::APPEND_COLUMN:
1351                 // append the column into the tabular
1352                 tabular.appendColumn(bv->buffer()->params(), actcell);
1353                 tabular.setOwner(this);
1354                 actcell = tabular.getCellNumber(row, column);
1355                 break;
1356
1357         case LyXTabular::DELETE_ROW:
1358                 for (int i = sel_row_start; i <= sel_row_end; ++i)
1359                         tabular.deleteRow(sel_row_start);
1360                 if (sel_row_start >= tabular.rows())
1361                         --sel_row_start;
1362                 actcell = tabular.getCellNumber(sel_row_start, column);
1363                 clearSelection();
1364                 break;
1365
1366         case LyXTabular::DELETE_COLUMN:
1367                 for (int i = sel_col_start; i <= sel_col_end; ++i)
1368                         tabular.deleteColumn(sel_col_start);
1369                 if (sel_col_start >= tabular.columns())
1370                         --sel_col_start;
1371                 actcell = tabular.getCellNumber(row, sel_col_start);
1372                 clearSelection();
1373                 break;
1374
1375         case LyXTabular::M_TOGGLE_LINE_TOP:
1376                 flag = false;
1377         case LyXTabular::TOGGLE_LINE_TOP: {
1378                 bool lineSet = !tabular.topLine(actcell, flag);
1379                 for (int i = sel_row_start; i <= sel_row_end; ++i)
1380                         for (int j = sel_col_start; j <= sel_col_end; ++j)
1381                                 tabular.setTopLine(
1382                                         tabular.getCellNumber(i, j),
1383                                         lineSet, flag);
1384                 break;
1385         }
1386
1387         case LyXTabular::M_TOGGLE_LINE_BOTTOM:
1388                 flag = false;
1389         case LyXTabular::TOGGLE_LINE_BOTTOM: {
1390                 bool lineSet = !tabular.bottomLine(actcell, flag);
1391                 for (int i = sel_row_start; i <= sel_row_end; ++i)
1392                         for (int j = sel_col_start; j <= sel_col_end; ++j)
1393                                 tabular.setBottomLine(
1394                                         tabular.getCellNumber(i, j),
1395                                         lineSet,
1396                                         flag);
1397                 break;
1398         }
1399
1400         case LyXTabular::M_TOGGLE_LINE_LEFT:
1401                 flag = false;
1402         case LyXTabular::TOGGLE_LINE_LEFT: {
1403                 bool lineSet = !tabular.leftLine(actcell, flag);
1404                 for (int i = sel_row_start; i <= sel_row_end; ++i)
1405                         for (int j = sel_col_start; j <= sel_col_end; ++j)
1406                                 tabular.setLeftLine(
1407                                         tabular.getCellNumber(i,j),
1408                                         lineSet,
1409                                         flag);
1410                 break;
1411         }
1412
1413         case LyXTabular::M_TOGGLE_LINE_RIGHT:
1414                 flag = false;
1415         case LyXTabular::TOGGLE_LINE_RIGHT: {
1416                 bool lineSet = !tabular.rightLine(actcell, flag);
1417                 for (int i = sel_row_start; i <= sel_row_end; ++i)
1418                         for (int j = sel_col_start; j <= sel_col_end; ++j)
1419                                 tabular.setRightLine(
1420                                         tabular.getCellNumber(i,j),
1421                                         lineSet,
1422                                         flag);
1423                 break;
1424         }
1425
1426         case LyXTabular::M_ALIGN_LEFT:
1427         case LyXTabular::M_ALIGN_RIGHT:
1428         case LyXTabular::M_ALIGN_CENTER:
1429                 flag = false;
1430         case LyXTabular::ALIGN_LEFT:
1431         case LyXTabular::ALIGN_RIGHT:
1432         case LyXTabular::ALIGN_CENTER:
1433         case LyXTabular::ALIGN_BLOCK:
1434                 for (int i = sel_row_start; i <= sel_row_end; ++i)
1435                         for (int j = sel_col_start; j <= sel_col_end; ++j)
1436                                 tabular.setAlignment(
1437                                         tabular.getCellNumber(i, j),
1438                                         setAlign,
1439                                         flag);
1440                 break;
1441
1442         case LyXTabular::M_VALIGN_TOP:
1443         case LyXTabular::M_VALIGN_BOTTOM:
1444         case LyXTabular::M_VALIGN_MIDDLE:
1445                 flag = false;
1446         case LyXTabular::VALIGN_TOP:
1447         case LyXTabular::VALIGN_BOTTOM:
1448         case LyXTabular::VALIGN_MIDDLE:
1449                 for (int i = sel_row_start; i <= sel_row_end; ++i)
1450                         for (int j = sel_col_start; j <= sel_col_end; ++j)
1451                                 tabular.setVAlignment(
1452                                         tabular.getCellNumber(i, j),
1453                                         setVAlign, flag);
1454                 break;
1455
1456         case LyXTabular::MULTICOLUMN: {
1457                 if (sel_row_start != sel_row_end) {
1458 #ifdef WITH_WARNINGS
1459 #warning Need I say it ? This is horrible.
1460 #endif
1461                         Alert::error(_("Error setting multicolumn"),
1462                                    _("You cannot set multicolumn vertically."));
1463                         return;
1464                 }
1465                 // just multicol for one Single Cell
1466                 if (!hasSelection()) {
1467                         // check wether we are completly in a multicol
1468                         if (tabular.isMultiColumn(actcell))
1469                                 tabular.unsetMultiColumn(actcell);
1470                         else
1471                                 tabular.setMultiColumn(bv->buffer(), actcell, 1);
1472                         break;
1473                 }
1474                 // we have a selection so this means we just add all this
1475                 // cells to form a multicolumn cell
1476                 int s_start;
1477                 int s_end;
1478
1479                 if (sel_cell_start > sel_cell_end) {
1480                         s_start = sel_cell_end;
1481                         s_end = sel_cell_start;
1482                 } else {
1483                         s_start = sel_cell_start;
1484                         s_end = sel_cell_end;
1485                 }
1486                 tabular.setMultiColumn(bv->buffer(), s_start, s_end - s_start + 1);
1487                 actcell = s_start;
1488                 clearSelection();
1489                 break;
1490         }
1491
1492         case LyXTabular::SET_ALL_LINES:
1493                 setLines = true;
1494         case LyXTabular::UNSET_ALL_LINES:
1495                 for (int i = sel_row_start; i <= sel_row_end; ++i)
1496                         for (int j = sel_col_start; j <= sel_col_end; ++j)
1497                                 tabular.setAllLines(
1498                                         tabular.getCellNumber(i,j), setLines);
1499                 break;
1500
1501         case LyXTabular::SET_LONGTABULAR:
1502                 tabular.setLongTabular(true);
1503                 break;
1504
1505         case LyXTabular::UNSET_LONGTABULAR:
1506                 tabular.setLongTabular(false);
1507                 break;
1508
1509         case LyXTabular::SET_ROTATE_TABULAR:
1510                 tabular.setRotateTabular(true);
1511                 break;
1512
1513         case LyXTabular::UNSET_ROTATE_TABULAR:
1514                 tabular.setRotateTabular(false);
1515                 break;
1516
1517         case LyXTabular::SET_ROTATE_CELL:
1518                 for (int i = sel_row_start; i <= sel_row_end; ++i)
1519                         for (int j = sel_col_start; j <= sel_col_end; ++j)
1520                                 tabular.setRotateCell(
1521                                         tabular.getCellNumber(i, j), true);
1522                 break;
1523
1524         case LyXTabular::UNSET_ROTATE_CELL:
1525                 for (int i = sel_row_start; i <= sel_row_end; ++i)
1526                         for (int j = sel_col_start; j <= sel_col_end; ++j)
1527                                 tabular.setRotateCell(
1528                                         tabular.getCellNumber(i, j), false);
1529                 break;
1530
1531         case LyXTabular::SET_USEBOX: {
1532                 LyXTabular::BoxType val = LyXTabular::BoxType(strToInt(value));
1533                 if (val == tabular.getUsebox(actcell))
1534                         val = LyXTabular::BOX_NONE;
1535                 for (int i = sel_row_start; i <= sel_row_end; ++i)
1536                         for (int j = sel_col_start; j <= sel_col_end; ++j)
1537                                 tabular.setUsebox(tabular.getCellNumber(i, j), val);
1538                 break;
1539         }
1540
1541         case LyXTabular::UNSET_LTFIRSTHEAD:
1542                 flag = false;
1543         case LyXTabular::SET_LTFIRSTHEAD:
1544                 tabular.getRowOfLTFirstHead(row, ltt);
1545                 checkLongtableSpecial(ltt, value, flag);
1546                 tabular.setLTHead(row, flag, ltt, true);
1547                 break;
1548
1549         case LyXTabular::UNSET_LTHEAD:
1550                 flag = false;
1551         case LyXTabular::SET_LTHEAD:
1552                 tabular.getRowOfLTHead(row, ltt);
1553                 checkLongtableSpecial(ltt, value, flag);
1554                 tabular.setLTHead(row, flag, ltt, false);
1555                 break;
1556
1557         case LyXTabular::UNSET_LTFOOT:
1558                 flag = false;
1559         case LyXTabular::SET_LTFOOT:
1560                 tabular.getRowOfLTFoot(row, ltt);
1561                 checkLongtableSpecial(ltt, value, flag);
1562                 tabular.setLTFoot(row, flag, ltt, false);
1563                 break;
1564
1565         case LyXTabular::UNSET_LTLASTFOOT:
1566                 flag = false;
1567         case LyXTabular::SET_LTLASTFOOT:
1568                 tabular.getRowOfLTLastFoot(row, ltt);
1569                 checkLongtableSpecial(ltt, value, flag);
1570                 tabular.setLTFoot(row, flag, ltt, true);
1571                 break;
1572
1573         case LyXTabular::SET_LTNEWPAGE:
1574                 tabular.setLTNewPage(row, !tabular.getLTNewPage(row));
1575                 break;
1576
1577         // dummy stuff just to avoid warnings
1578         case LyXTabular::LAST_ACTION:
1579                 break;
1580         }
1581
1582         updateLocal(bv);
1583         InsetTabularMailer(*this).updateDialog(bv);
1584 }
1585
1586
1587 void InsetTabular::activateCellInset(BufferView * bv, int cell, int x, int y)
1588 {
1589         actcell = cell;
1590         tabular.getCellInset(actcell).edit(bv, x, y);
1591         bv->cursor().data_.back().idx_ = actcell;
1592         updateLocal(bv);
1593 }
1594
1595
1596 void InsetTabular::activateCellInset(BufferView * bv, int cell, bool behind)
1597 {
1598         actcell = cell;
1599         tabular.getCellInset(actcell).edit(bv, behind);
1600         bv->cursor().data_.back().idx_ = actcell;
1601         updateLocal(bv);
1602 }
1603
1604
1605
1606 bool InsetTabular::showInsetDialog(BufferView * bv) const
1607 {
1608         InsetTabularMailer(*this).showDialog(bv);
1609         return true;
1610 }
1611
1612
1613 void InsetTabular::openLayoutDialog(BufferView * bv) const
1614 {
1615         InsetTabularMailer(*this).showDialog(bv);
1616 }
1617
1618
1619 //
1620 // function returns an object as defined in func_status.h:
1621 // states OK, Unknown, Disabled, On, Off.
1622 //
1623 FuncStatus InsetTabular::getStatus(string const & what) const
1624 {
1625         int action = LyXTabular::LAST_ACTION;
1626         FuncStatus status;
1627
1628         int i = 0;
1629         for (; tabularFeature[i].action != LyXTabular::LAST_ACTION; ++i) {
1630                 string const tmp = tabularFeature[i].feature;
1631                 if (tmp == what.substr(0, tmp.length())) {
1632                         //if (!compare(tabularFeatures[i].feature.c_str(), what.c_str(),
1633                         //   tabularFeatures[i].feature.length())) {
1634                         action = tabularFeature[i].action;
1635                         break;
1636                 }
1637         }
1638         if (action == LyXTabular::LAST_ACTION) {
1639                 status.clear();
1640                 status.unknown(true);
1641                 return status;
1642         }
1643
1644         string const argument
1645                 = ltrim(what.substr(tabularFeature[i].feature.length()));
1646
1647         int sel_row_start;
1648         int sel_row_end;
1649         int dummy;
1650         LyXTabular::ltType dummyltt;
1651         bool flag = true;
1652
1653         if (hasSelection())
1654                 getSelection(sel_row_start, sel_row_end, dummy, dummy);
1655         else
1656                 sel_row_start = sel_row_end = tabular.row_of_cell(actcell);
1657
1658         switch (action) {
1659         case LyXTabular::SET_PWIDTH:
1660         case LyXTabular::SET_MPWIDTH:
1661         case LyXTabular::SET_SPECIAL_COLUMN:
1662         case LyXTabular::SET_SPECIAL_MULTI:
1663         case LyXTabular::APPEND_ROW:
1664         case LyXTabular::APPEND_COLUMN:
1665         case LyXTabular::DELETE_ROW:
1666         case LyXTabular::DELETE_COLUMN:
1667         case LyXTabular::SET_ALL_LINES:
1668         case LyXTabular::UNSET_ALL_LINES:
1669                 status.clear();
1670                 return status;
1671
1672         case LyXTabular::MULTICOLUMN:
1673                 status.setOnOff(tabular.isMultiColumn(actcell));
1674                 break;
1675
1676         case LyXTabular::M_TOGGLE_LINE_TOP:
1677                 flag = false;
1678         case LyXTabular::TOGGLE_LINE_TOP:
1679                 status.setOnOff(tabular.topLine(actcell, flag));
1680                 break;
1681
1682         case LyXTabular::M_TOGGLE_LINE_BOTTOM:
1683                 flag = false;
1684         case LyXTabular::TOGGLE_LINE_BOTTOM:
1685                 status.setOnOff(tabular.bottomLine(actcell, flag));
1686                 break;
1687
1688         case LyXTabular::M_TOGGLE_LINE_LEFT:
1689                 flag = false;
1690         case LyXTabular::TOGGLE_LINE_LEFT:
1691                 status.setOnOff(tabular.leftLine(actcell, flag));
1692                 break;
1693
1694         case LyXTabular::M_TOGGLE_LINE_RIGHT:
1695                 flag = false;
1696         case LyXTabular::TOGGLE_LINE_RIGHT:
1697                 status.setOnOff(tabular.rightLine(actcell, flag));
1698                 break;
1699
1700         case LyXTabular::M_ALIGN_LEFT:
1701                 flag = false;
1702         case LyXTabular::ALIGN_LEFT:
1703                 status.setOnOff(tabular.getAlignment(actcell, flag) == LYX_ALIGN_LEFT);
1704                 break;
1705
1706         case LyXTabular::M_ALIGN_RIGHT:
1707                 flag = false;
1708         case LyXTabular::ALIGN_RIGHT:
1709                 status.setOnOff(tabular.getAlignment(actcell, flag) == LYX_ALIGN_RIGHT);
1710                 break;
1711
1712         case LyXTabular::M_ALIGN_CENTER:
1713                 flag = false;
1714         case LyXTabular::ALIGN_CENTER:
1715                 status.setOnOff(tabular.getAlignment(actcell, flag) == LYX_ALIGN_CENTER);
1716                 break;
1717
1718         case LyXTabular::ALIGN_BLOCK:
1719                 status.disabled(tabular.getPWidth(actcell).zero());
1720                 status.setOnOff(tabular.getAlignment(actcell, flag) == LYX_ALIGN_BLOCK);
1721                 break;
1722
1723         case LyXTabular::M_VALIGN_TOP:
1724                 flag = false;
1725         case LyXTabular::VALIGN_TOP:
1726                 status.setOnOff(
1727                         tabular.getVAlignment(actcell, flag) == LyXTabular::LYX_VALIGN_TOP);
1728                 break;
1729
1730         case LyXTabular::M_VALIGN_BOTTOM:
1731                 flag = false;
1732         case LyXTabular::VALIGN_BOTTOM:
1733                 status.setOnOff(
1734                         tabular.getVAlignment(actcell, flag) == LyXTabular::LYX_VALIGN_BOTTOM);
1735                 break;
1736
1737         case LyXTabular::M_VALIGN_MIDDLE:
1738                 flag = false;
1739         case LyXTabular::VALIGN_MIDDLE:
1740                 status.setOnOff(
1741                         tabular.getVAlignment(actcell, flag) == LyXTabular::LYX_VALIGN_MIDDLE);
1742                 break;
1743
1744         case LyXTabular::SET_LONGTABULAR:
1745                 status.setOnOff(tabular.isLongTabular());
1746                 break;
1747
1748         case LyXTabular::UNSET_LONGTABULAR:
1749                 status.setOnOff(!tabular.isLongTabular());
1750                 break;
1751
1752         case LyXTabular::SET_ROTATE_TABULAR:
1753                 status.setOnOff(tabular.getRotateTabular());
1754                 break;
1755
1756         case LyXTabular::UNSET_ROTATE_TABULAR:
1757                 status.setOnOff(!tabular.getRotateTabular());
1758                 break;
1759
1760         case LyXTabular::SET_ROTATE_CELL:
1761                 status.setOnOff(tabular.getRotateCell(actcell));
1762                 break;
1763
1764         case LyXTabular::UNSET_ROTATE_CELL:
1765                 status.setOnOff(!tabular.getRotateCell(actcell));
1766                 break;
1767
1768         case LyXTabular::SET_USEBOX:
1769                 status.setOnOff(strToInt(argument) == tabular.getUsebox(actcell));
1770                 break;
1771
1772         case LyXTabular::SET_LTFIRSTHEAD:
1773                 status.setOnOff(tabular.getRowOfLTHead(sel_row_start, dummyltt));
1774                 break;
1775
1776         case LyXTabular::SET_LTHEAD:
1777                 status.setOnOff(tabular.getRowOfLTHead(sel_row_start, dummyltt));
1778                 break;
1779
1780         case LyXTabular::SET_LTFOOT:
1781                 status.setOnOff(tabular.getRowOfLTFoot(sel_row_start, dummyltt));
1782                 break;
1783
1784         case LyXTabular::SET_LTLASTFOOT:
1785                 status.setOnOff(tabular.getRowOfLTFoot(sel_row_start, dummyltt));
1786                 break;
1787
1788         case LyXTabular::SET_LTNEWPAGE:
1789                 status.setOnOff(tabular.getLTNewPage(sel_row_start));
1790                 break;
1791
1792         default:
1793                 status.clear();
1794                 status.disabled(true);
1795                 break;
1796         }
1797         return status;
1798 }
1799
1800
1801 void InsetTabular::getLabelList(Buffer const & buffer,
1802                                 std::vector<string> & list) const
1803 {
1804         tabular.getLabelList(buffer, list);
1805 }
1806
1807
1808 bool InsetTabular::copySelection(BufferView * bv)
1809 {
1810         if (!hasSelection())
1811                 return false;
1812
1813         int sel_col_start = tabular.column_of_cell(sel_cell_start);
1814         int sel_col_end = tabular.column_of_cell(sel_cell_end);
1815         if (sel_col_start > sel_col_end) {
1816                 sel_col_start = sel_col_end;
1817                 sel_col_end = tabular.right_column_of_cell(sel_cell_start);
1818         } else {
1819                 sel_col_end = tabular.right_column_of_cell(sel_cell_end);
1820         }
1821
1822         int sel_row_start = tabular.row_of_cell(sel_cell_start);
1823         int sel_row_end = tabular.row_of_cell(sel_cell_end);
1824         if (sel_row_start > sel_row_end)
1825                 swap(sel_row_start, sel_row_end);
1826
1827         paste_tabular.reset(new LyXTabular(tabular));
1828         paste_tabular->setOwner(this);
1829
1830         for (int i = 0; i < sel_row_start; ++i)
1831                 paste_tabular->deleteRow(0);
1832
1833         int const rows = sel_row_end - sel_row_start + 1;
1834         while (paste_tabular->rows() > rows)
1835                 paste_tabular->deleteRow(rows);
1836
1837         paste_tabular->setTopLine(0, true, true);
1838         paste_tabular->setBottomLine(paste_tabular->getFirstCellInRow(rows - 1),
1839                                      true, true);
1840
1841         for (int i = 0; i < sel_col_start; ++i)
1842                 paste_tabular->deleteColumn(0);
1843
1844         int const columns = sel_col_end - sel_col_start + 1;
1845         while (paste_tabular->columns() > columns)
1846                 paste_tabular->deleteColumn(columns);
1847
1848         paste_tabular->setLeftLine(0, true, true);
1849         paste_tabular->setRightLine(paste_tabular->getLastCellInRow(0),
1850                                     true, true);
1851
1852         ostringstream os;
1853         OutputParams const runparams;
1854         paste_tabular->plaintext(*bv->buffer(), os, runparams,
1855                                  ownerPar(*bv->buffer(), this).params().depth(), true, '\t');
1856         bv->stuffClipboard(os.str());
1857         return true;
1858 }
1859
1860
1861 bool InsetTabular::pasteSelection(BufferView *)
1862 {
1863         if (!paste_tabular)
1864                 return false;
1865
1866         for (int r1 = 0, r2 = actrow;
1867              r1 < paste_tabular->rows() && r2 < tabular.rows();
1868              ++r1, ++r2) {
1869                 for (int c1 = 0, c2 = actcol;
1870                     c1 < paste_tabular->columns() && c2 < tabular.columns();
1871                     ++c1, ++c2) {
1872                         if (paste_tabular->isPartOfMultiColumn(r1, c1) &&
1873                             tabular.isPartOfMultiColumn(r2, c2))
1874                                 continue;
1875                         if (paste_tabular->isPartOfMultiColumn(r1, c1)) {
1876                                 --c2;
1877                                 continue;
1878                         }
1879                         if (tabular.isPartOfMultiColumn(r2, c2)) {
1880                                 --c1;
1881                                 continue;
1882                         }
1883                         InsetText & inset = tabular.getCellInset(r2, c2);
1884                         inset = paste_tabular->getCellInset(r1, c1);
1885                         inset.setOwner(this);
1886                         inset.markNew();
1887                 }
1888         }
1889         return true;
1890 }
1891
1892
1893 bool InsetTabular::cutSelection(BufferParams const & bp)
1894 {
1895         if (!hasSelection())
1896                 return false;
1897
1898         int sel_col_start = tabular.column_of_cell(sel_cell_start);
1899         int sel_col_end = tabular.column_of_cell(sel_cell_end);
1900         if (sel_col_start > sel_col_end) {
1901                 sel_col_start = sel_col_end;
1902                 sel_col_end = tabular.right_column_of_cell(sel_cell_start);
1903         } else {
1904                 sel_col_end = tabular.right_column_of_cell(sel_cell_end);
1905         }
1906
1907         int sel_row_start = tabular.row_of_cell(sel_cell_start);
1908         int sel_row_end = tabular.row_of_cell(sel_cell_end);
1909
1910         if (sel_row_start > sel_row_end)
1911                 swap(sel_row_start, sel_row_end);
1912
1913         if (sel_cell_start > sel_cell_end)
1914                 swap(sel_cell_start, sel_cell_end);
1915
1916         for (int i = sel_row_start; i <= sel_row_end; ++i)
1917                 for (int j = sel_col_start; j <= sel_col_end; ++j)
1918                         tabular.getCellInset(tabular.getCellNumber(i, j))
1919                                 .clear(bp.tracking_changes);
1920         return true;
1921 }
1922
1923
1924 bool InsetTabular::isRightToLeft(BufferView * bv)
1925 {
1926         return bv->getParentLanguage(this)->RightToLeft();
1927 }
1928
1929
1930 void InsetTabular::getSelection(int & srow, int & erow,
1931                                 int & scol, int & ecol) const
1932 {
1933         int const start = hasSelection() ? sel_cell_start : actcell;
1934         int const end = hasSelection() ? sel_cell_end : actcell;
1935
1936         srow = tabular.row_of_cell(start);
1937         erow = tabular.row_of_cell(end);
1938         if (srow > erow)
1939                 swap(srow, erow);
1940
1941         scol = tabular.column_of_cell(start);
1942         ecol = tabular.column_of_cell(end);
1943         if (scol > ecol)
1944                 swap(scol, ecol);
1945         else
1946                 ecol = tabular.right_column_of_cell(end);
1947 }
1948
1949
1950 int InsetTabular::numParagraphs() const
1951 {
1952         return tabular.getNumberOfCells();
1953 }
1954
1955
1956 LyXText * InsetTabular::getText(int i) const
1957 {
1958         return i < tabular.getNumberOfCells()
1959                 ? tabular.getCellInset(i).getText(0)
1960                 : 0;
1961 }
1962
1963
1964 void InsetTabular::markErased()
1965 {
1966         for (int cell = 0; cell < tabular.getNumberOfCells(); ++cell)
1967                 tabular.getCellInset(cell).markErased();
1968 }
1969
1970
1971 bool InsetTabular::insetAllowed(InsetOld::Code) const
1972 {
1973         return false;
1974 }
1975
1976
1977 bool InsetTabular::forceDefaultParagraphs(InsetOld const * in) const
1978 {
1979         const int cell = tabular.getCellFromInset(in);
1980
1981         if (cell != -1)
1982                 return tabular.getPWidth(cell).zero();
1983
1984         // this is a workaround for a crash (New, Insert->Tabular,
1985         // Insert->FootNote)
1986         if (!owner())
1987                 return false;
1988
1989         // well we didn't obviously find it so maybe our owner knows more
1990         BOOST_ASSERT(owner());
1991         return owner()->forceDefaultParagraphs(in);
1992 }
1993
1994
1995 bool InsetTabular::insertAsciiString(BufferView * bv, string const & buf,
1996                                      bool usePaste)
1997 {
1998         if (buf.length() <= 0)
1999                 return true;
2000
2001         int cols = 1;
2002         int rows = 1;
2003         int maxCols = 1;
2004         string::size_type len = buf.length();
2005         string::size_type p = 0;
2006
2007         while (p < len && (p = buf.find_first_of("\t\n", p)) != string::npos) {
2008                 switch (buf[p]) {
2009                 case '\t':
2010                         ++cols;
2011                         break;
2012                 case '\n':
2013                         if (p + 1 < len)
2014                                 ++rows;
2015                         maxCols = max(cols, maxCols);
2016                         cols = 1;
2017                         break;
2018                 }
2019                 ++p;
2020         }
2021         maxCols = max(cols, maxCols);
2022         LyXTabular * loctab;
2023         int cell = 0;
2024         int ocol = 0;
2025         int row = 0;
2026         if (usePaste) {
2027                 paste_tabular.reset(
2028                         new LyXTabular(bv->buffer()->params(), rows, maxCols)
2029                         );
2030
2031                 paste_tabular->setOwner(this);
2032                 loctab = paste_tabular.get();
2033                 cols = 0;
2034         } else {
2035                 loctab = &tabular;
2036                 cell = actcell;
2037                 ocol = actcol;
2038                 row = actrow;
2039         }
2040
2041         string::size_type op = 0;
2042         int cells = loctab->getNumberOfCells();
2043         p = 0;
2044         cols = ocol;
2045         rows = loctab->rows();
2046         int const columns = loctab->columns();
2047
2048         while (cell < cells && p < len && row < rows &&
2049                (p = buf.find_first_of("\t\n", p)) != string::npos)
2050         {
2051                 if (p >= len)
2052                         break;
2053                 switch (buf[p]) {
2054                 case '\t':
2055                         // we can only set this if we are not too far right
2056                         if (cols < columns) {
2057                                 InsetText & inset = loctab->getCellInset(cell);
2058                                 LyXFont const font = inset.text_.
2059                                         getFont(inset.paragraphs().begin(), 0);
2060                                 inset.setText(buf.substr(op, p - op), font);
2061                                 ++cols;
2062                                 ++cell;
2063                         }
2064                         break;
2065                 case '\n':
2066                         // we can only set this if we are not too far right
2067                         if (cols < columns) {
2068                                 InsetText & inset = tabular.getCellInset(cell);
2069                                 LyXFont const font = inset.text_.
2070                                         getFont(inset.paragraphs().begin(), 0);
2071                                 inset.setText(buf.substr(op, p - op), font);
2072                         }
2073                         cols = ocol;
2074                         ++row;
2075                         if (row < rows)
2076                                 cell = loctab->getCellNumber(row, cols);
2077                         break;
2078                 }
2079                 ++p;
2080                 op = p;
2081         }
2082         // check for the last cell if there is no trailing '\n'
2083         if (cell < cells && op < len) {
2084                 InsetText & inset = loctab->getCellInset(cell);
2085                 LyXFont const font = inset.text_.getFont(inset.paragraphs().begin(), 0);
2086                 inset.setText(buf.substr(op, len - op), font);
2087         }
2088
2089         return true;
2090 }
2091
2092
2093 void InsetTabular::addPreview(PreviewLoader & loader) const
2094 {
2095         int const rows = tabular.rows();
2096         int const columns = tabular.columns();
2097         for (int i = 0; i < rows; ++i) {
2098                 for (int j = 0; j < columns; ++j)
2099                         tabular.getCellInset(i, j).addPreview(loader);
2100         }
2101 }
2102
2103
2104 string const InsetTabularMailer::name_("tabular");
2105
2106 InsetTabularMailer::InsetTabularMailer(InsetTabular const & inset)
2107         : inset_(const_cast<InsetTabular &>(inset))
2108 {}
2109
2110
2111 string const InsetTabularMailer::inset2string(Buffer const &) const
2112 {
2113         return params2string(inset_);
2114 }
2115
2116
2117 int InsetTabularMailer::string2params(string const & in, InsetTabular & inset)
2118 {
2119         istringstream data(in);
2120         LyXLex lex(0,0);
2121         lex.setStream(data);
2122
2123 #warning CHECK verify that this is a sane value to return.
2124         if (in.empty())
2125                 return -1;
2126
2127         if (lex.isOK()) {
2128                 lex.next();
2129                 string const token = lex.getString();
2130                 if (token != name_)
2131                         return -1;
2132         }
2133
2134         int cell = -1;
2135         if (lex.isOK()) {
2136                 lex.next();
2137                 string const token = lex.getString();
2138                 if (token != "\\active_cell")
2139                         return -1;
2140                 lex.next();
2141                 cell = lex.getInteger();
2142         }
2143
2144         // This is part of the inset proper that is usually swallowed
2145         // by Buffer::readInset
2146         if (lex.isOK()) {
2147                 lex.next();
2148                 string const token = lex.getString();
2149                 if (token != "Tabular")
2150                         return -1;
2151         }
2152
2153         if (!lex.isOK())
2154                 return -1;
2155
2156         Buffer const & buffer = inset.buffer();
2157         inset.read(buffer, lex);
2158
2159         // We can't set the active cell, but we can tell the frontend
2160         // what it is.
2161         return cell;
2162 }
2163
2164
2165 string const InsetTabularMailer::params2string(InsetTabular const & inset)
2166 {
2167         ostringstream data;
2168         data << name_ << " \\active_cell " << inset.getActCell() << '\n';
2169         inset.write(inset.buffer(), data);
2170         data << "\\end_inset\n";
2171         return data.str();
2172 }