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