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