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