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