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