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