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