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