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