]> git.lyx.org Git - lyx.git/blob - src/insets/insettabular.C
Make it compile when USE_BOOST_FORMAT is unset
[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 #ifdef __GNUG__
14 #pragma implementation
15 #endif
16
17 #include "insettabular.h"
18 #include "insettext.h"
19
20 #include "buffer.h"
21 #include "BufferView.h"
22 #include "commandtags.h"
23 #include "debug.h"
24 #include "funcrequest.h"
25 #include "gettext.h"
26 #include "language.h"
27 #include "LaTeXFeatures.h"
28 #include "lyx_cb.h"
29 #include "lyxfunc.h"
30 #include "lyxlength.h"
31 #include "lyxlex.h"
32 #include "lyxtext.h"
33 #include "ParagraphParameters.h"
34 #include "undo_funcs.h"
35 #include "WordLangTuple.h"
36
37 #include "frontends/Alert.h"
38 #include "frontends/Dialogs.h"
39 #include "frontends/font_metrics.h"
40 #include "frontends/LyXView.h"
41 #include "frontends/Painter.h"
42
43 #include "support/LAssert.h"
44 #include "support/lstrings.h"
45
46 #include <fstream>
47 #include <algorithm>
48 #include <cstdlib>
49 #include <map>
50 //#include <signal.h>
51
52
53 using std::vector;
54 using std::ostream;
55 using std::ifstream;
56 using std::max;
57 using std::endl;
58 using std::swap;
59 using std::max;
60
61 namespace {
62
63 int const ADD_TO_HEIGHT = 2;
64 int const ADD_TO_TABULAR_WIDTH = 2;
65
66 ///
67 LyXTabular * paste_tabular = 0;
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_CENTER, "valign-center" },
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_CENTER, "m-valign-center" },
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 } // namespace anon
126
127
128 bool InsetTabular::hasPasteBuffer() const
129 {
130         return (paste_tabular != 0);
131 }
132
133
134 InsetTabular::InsetTabular(Buffer const & buf, int rows, int columns)
135         : buffer(&buf)
136 {
137         if (rows <= 0)
138                 rows = 1;
139         if (columns <= 0)
140                 columns = 1;
141         tabular.reset(new LyXTabular(buf.params, this, rows, columns));
142         // for now make it always display as display() inset
143         // just for test!!!
144         the_locking_inset = 0;
145         old_locking_inset = 0;
146         locked = false;
147         oldcell = -1;
148         actrow = actcell = 0;
149         clearSelection();
150         need_update = INIT;
151         in_update = false;
152         in_reset_pos = 0;
153         inset_x = 0;
154         inset_y = 0;
155 }
156
157
158 InsetTabular::InsetTabular(InsetTabular const & tab, Buffer const & buf,
159                                                    bool same_id)
160         : UpdatableInset(tab, same_id), buffer(&buf)
161 {
162         tabular.reset(new LyXTabular(buf.params,
163                                      this, *(tab.tabular), same_id));
164         the_locking_inset = 0;
165         old_locking_inset = 0;
166         locked = false;
167         oldcell = -1;
168         actrow = actcell = 0;
169         clearSelection();
170         need_update = INIT;
171         in_update = false;
172         in_reset_pos = 0;
173         inset_x = 0;
174         inset_y = 0;
175 }
176
177
178 InsetTabular::~InsetTabular()
179 {
180         hideDialog();
181 }
182
183
184 Inset * InsetTabular::clone(Buffer const & buf, bool same_id) const
185 {
186         return new InsetTabular(*this, buf, same_id);
187 }
188
189
190 void InsetTabular::write(Buffer const * buf, ostream & os) const
191 {
192         os << " Tabular" << endl;
193         tabular->Write(buf, os);
194 }
195
196
197 void InsetTabular::read(Buffer const * buf, LyXLex & lex)
198 {
199         bool const old_format = (lex.getString() == "\\LyXTable");
200
201         tabular.reset(new LyXTabular(buf, this, lex));
202
203         need_update = INIT;
204
205         if (old_format)
206                 return;
207
208         lex.nextToken();
209         string token = lex.getString();
210         while (lex.isOK() && (token != "\\end_inset")) {
211                 lex.nextToken();
212                 token = lex.getString();
213         }
214         if (token != "\\end_inset") {
215                 lex.printError("Missing \\end_inset at this point. "
216                                "Read: `$$Token'");
217         }
218 }
219
220
221 int InsetTabular::ascent(BufferView *, LyXFont const &) const
222 {
223         return tabular->GetAscentOfRow(0);
224 }
225
226
227 int InsetTabular::descent(BufferView *, LyXFont const &) const
228 {
229         return tabular->GetHeightOfTabular() - tabular->GetAscentOfRow(0) + 1;
230 }
231
232
233 int InsetTabular::width(BufferView *, LyXFont const &) const
234 {
235         return tabular->GetWidthOfTabular() + (2 * ADD_TO_TABULAR_WIDTH);
236 }
237
238
239 void InsetTabular::draw(BufferView * bv, LyXFont const & font, int baseline,
240                         float & x, bool cleared) const
241 {
242         if (nodraw()) {
243                 if (cleared)
244                         need_update = FULL;
245                 return;
246         }
247 #if 0
248         if (need_update == INIT) {
249                 if (calculate_dimensions_of_cells(bv, font, true))
250                         bv->text->status = LyXText::CHANGED_IN_DRAW;
251                 need_update = FULL;
252         }
253 #endif
254
255         Painter & pain = bv->painter();
256         int i;
257         int j;
258         int nx;
259
260 #if 0
261         UpdatableInset::draw(bv, font, baseline, x, cleared);
262 #else
263         if (!owner())
264                 x += static_cast<float>(scroll());
265 #endif
266         if (!cleared && ((need_update == INIT) || (need_update == FULL) ||
267                          (top_x != int(x)) || (top_baseline != baseline)))
268         {
269                 int h = ascent(bv, font) + descent(bv, font);
270                 int const tx = display() || !owner() ? 0 : top_x;
271                 int w =  tx ? width(bv, font) : pain.paperWidth();
272                 int ty = baseline - ascent(bv, font);
273
274                 if (ty < 0)
275                         ty = 0;
276                 if ((ty + h) > pain.paperHeight())
277                         h = pain.paperHeight();
278                 if ((top_x + w) > pain.paperWidth())
279                         w = pain.paperWidth();
280                 pain.fillRectangle(tx, ty, w, h, backgroundColor());
281                 need_update = FULL;
282                 cleared = true;
283         }
284         top_x = int(x);
285         topx_set = true;
286         top_baseline = baseline;
287         x += ADD_TO_TABULAR_WIDTH;
288         if (cleared) {
289                 int cell = 0;
290                 float cx;
291                 first_visible_cell = -1;
292                 for (i = 0; i < tabular->rows(); ++i) {
293                         nx = int(x);
294                         cell = tabular->GetCellNumber(i, 0);
295                         if (!((baseline + tabular->GetDescentOfRow(i)) > 0) &&
296                                 (baseline - tabular->GetAscentOfRow(i))<pain.paperHeight())
297                         {
298                                 baseline += tabular->GetDescentOfRow(i) +
299                                         tabular->GetAscentOfRow(i + 1) +
300                                         tabular->GetAdditionalHeight(i + 1);
301                                 continue;
302                         }
303                         for (j = 0; j < tabular->columns(); ++j) {
304                                 if (nx > bv->workWidth())
305                                         break;
306                                 if (tabular->IsPartOfMultiColumn(i, j))
307                                         continue;
308                                 cx = nx + tabular->GetBeginningOfTextInCell(cell);
309                                 if (first_visible_cell < 0)
310                                         first_visible_cell = cell;
311                                 if (hasSelection()) {
312                                         drawCellSelection(pain, nx, baseline, i, j, cell);
313                                 }
314
315                                 tabular->GetCellInset(cell)->draw(bv, font, baseline, cx, cleared);
316                                 drawCellLines(pain, nx, baseline, i, cell);
317                                 nx += tabular->GetWidthOfColumn(cell);
318                                 ++cell;
319                         }
320                         baseline += tabular->GetDescentOfRow(i) +
321                                 tabular->GetAscentOfRow(i + 1) +
322                                 tabular->GetAdditionalHeight(i + 1);
323                 }
324         } else if (need_update == CELL) {
325                 int cell = 0;
326                 nx = int(x);
327                 if (the_locking_inset &&
328                         tabular->GetCellInset(actcell) != the_locking_inset)
329                 {
330                         Inset * inset = tabular->GetCellInset(cell);
331                         for (i = 0;
332                              inset != the_locking_inset && i < tabular->rows();
333                              ++i)
334                         {
335                                 for (j = 0;
336                                      inset != the_locking_inset && j < tabular->columns();
337                                      ++j)
338                                 {
339                                         if (tabular->IsPartOfMultiColumn(i, j))
340                                                 continue;
341                                         nx += tabular->GetWidthOfColumn(cell);
342                                         ++cell;
343                                         inset = tabular->GetCellInset(cell);
344                                 }
345                                 if (tabular->row_of_cell(cell) > i) {
346                                         nx = int(x);
347                                         baseline += tabular->GetDescentOfRow(i) +
348                                                 tabular->GetAscentOfRow(i + 1) +
349                                                 tabular->GetAdditionalHeight(i + 1);
350                                 }
351                         }
352                 } else {
353                         // compute baseline for actual row
354                         for (i = 0; i < actrow; ++i) {
355                                 baseline += tabular->GetDescentOfRow(i) +
356                                         tabular->GetAscentOfRow(i + 1) +
357                                         tabular->GetAdditionalHeight(i + 1);
358                         }
359                         // now compute the right x position
360                         cell = tabular->GetCellNumber(actrow, 0);
361                         for (j = 0; (cell < actcell) && (j < tabular->columns()); ++j) {
362                                         if (tabular->IsPartOfMultiColumn(actrow, j))
363                                                 continue;
364                                         nx += tabular->GetWidthOfColumn(cell);
365                                         ++cell;
366                         }
367                 }
368                 i = tabular->row_of_cell(cell);
369                 if (the_locking_inset != tabular->GetCellInset(cell)) {
370                         lyxerr[Debug::INSETTEXT] << "ERROR this shouldn't happen\n";
371                         return;
372                 }
373                 float dx = nx + tabular->GetBeginningOfTextInCell(cell);
374                 float cx = dx;
375                 tabular->GetCellInset(cell)->draw(bv, font, baseline, dx, false);
376                 //
377                 // Here we use rectangular backgroundColor patches to clean up
378                 // within a cell around the cell's red inset box. As follows:
379                 //
380                 //  +--------------------+
381                 //  |         C          |   The rectangles are A, B and C
382                 //  | A |------------| B |   below, origin top left (tx, ty),
383                 //  |   |  inset box |   |   dimensions w(idth), h(eight).
384                 //  +---+------------+---+   x grows rightward, y downward
385                 //  |         D          |
386                 //  +--------------------+
387                 //
388 #if 0
389                 // clear only if we didn't have a change
390                 if (bv->text->status() != LyXText::CHANGED_IN_DRAW) {
391 #endif
392                         // clear before the inset
393                         int tx, ty, w, h;
394                         tx = nx + 1;
395                         ty = baseline - tabular->GetAscentOfRow(i) + 1;
396                         w = int(cx - nx - 1);
397                         h = tabular->GetAscentOfRow(i) +
398                                 tabular->GetDescentOfRow(i) - 1;
399                         pain.fillRectangle(tx, ty, w, h, backgroundColor());
400                         // clear behind the inset
401                         tx = int(cx + the_locking_inset->width(bv,font) + 1);
402                         ty = baseline - tabular->GetAscentOfRow(i) + 1;
403                         w = tabular->GetWidthOfColumn(cell) -
404                                 tabular->GetBeginningOfTextInCell(cell) -
405                                 the_locking_inset->width(bv,font) -
406                                 tabular->GetAdditionalWidth(cell) - 1;
407                         h = tabular->GetAscentOfRow(i) + tabular->GetDescentOfRow(i) - 1;
408                         pain.fillRectangle(tx, ty, w, h, backgroundColor());
409                         // clear below the inset
410                         tx = nx + 1;
411                         ty = baseline + the_locking_inset->descent(bv, font) + 1;
412                         w = tabular->GetWidthOfColumn(cell) -
413                                 tabular->GetAdditionalWidth(cell) - 1;
414                         h = tabular->GetDescentOfRow(i) -
415                                 the_locking_inset->descent(bv, font) - 1;
416                         pain.fillRectangle(tx, ty, w, h, backgroundColor());
417                         // clear above the inset
418                         tx = nx + 1;
419                         ty = baseline - tabular->GetAscentOfRow(i) + 1;
420                         w = tabular->GetWidthOfColumn(cell) -
421                                 tabular->GetAdditionalWidth(cell) - 1;
422                         h = tabular->GetAscentOfRow(i) - the_locking_inset->ascent(bv, font);
423                         pain.fillRectangle(tx, ty, w, h, backgroundColor());
424 #if 0
425                 }
426 #endif
427         }
428         x -= ADD_TO_TABULAR_WIDTH;
429         x += width(bv, font);
430         if (bv->text->status() == LyXText::CHANGED_IN_DRAW) {
431                 int i = 0;
432                 for(Inset * inset = owner(); inset; ++i)
433                         inset = inset->owner();
434                 if (calculate_dimensions_of_cells(bv, font, false))
435                         need_update = INIT;
436         } else {
437                 need_update = NONE;
438         }
439 }
440
441
442 void InsetTabular::drawCellLines(Painter & pain, int x, int baseline,
443                                  int row, int cell) const
444 {
445         int x2 = x + tabular->GetWidthOfColumn(cell);
446         bool on_off;
447
448         if (!tabular->TopAlreadyDrawed(cell)) {
449                 on_off = !tabular->TopLine(cell);
450                 pain.line(x, baseline - tabular->GetAscentOfRow(row),
451                           x2, baseline -  tabular->GetAscentOfRow(row),
452                           on_off ? LColor::tabularonoffline : LColor::tabularline,
453                           on_off ? Painter::line_onoffdash : Painter::line_solid);
454         }
455         on_off = !tabular->BottomLine(cell);
456         pain.line(x, baseline + tabular->GetDescentOfRow(row),
457                   x2, baseline + tabular->GetDescentOfRow(row),
458                   on_off ? LColor::tabularonoffline : LColor::tabularline,
459                   on_off ? Painter::line_onoffdash : Painter::line_solid);
460         if (!tabular->LeftAlreadyDrawed(cell)) {
461                 on_off = !tabular->LeftLine(cell);
462                 pain.line(x, baseline -  tabular->GetAscentOfRow(row),
463                           x, baseline +  tabular->GetDescentOfRow(row),
464                           on_off ? LColor::tabularonoffline : LColor::tabularline,
465                           on_off ? Painter::line_onoffdash : Painter::line_solid);
466         }
467         on_off = !tabular->RightLine(cell);
468         pain.line(x2 - tabular->GetAdditionalWidth(cell),
469                   baseline -  tabular->GetAscentOfRow(row),
470                   x2 - tabular->GetAdditionalWidth(cell),
471                   baseline +  tabular->GetDescentOfRow(row),
472                   on_off ? LColor::tabularonoffline : LColor::tabularline,
473                   on_off ? Painter::line_onoffdash : Painter::line_solid);
474 }
475
476
477 void InsetTabular::drawCellSelection(Painter & pain, int x, int baseline,
478                                      int row, int column, int cell) const
479 {
480         lyx::Assert(hasSelection());
481         int cs = tabular->column_of_cell(sel_cell_start);
482         int ce = tabular->column_of_cell(sel_cell_end);
483         if (cs > ce) {
484                 ce = cs;
485                 cs = tabular->column_of_cell(sel_cell_end);
486         } else {
487                 ce = tabular->right_column_of_cell(sel_cell_end);
488         }
489
490         int rs = tabular->row_of_cell(sel_cell_start);
491         int re = tabular->row_of_cell(sel_cell_end);
492         if (rs > re)
493                 swap(rs, re);
494
495         if ((column >= cs) && (column <= ce) && (row >= rs) && (row <= re)) {
496                 int w = tabular->GetWidthOfColumn(cell);
497                 int h = tabular->GetAscentOfRow(row) + tabular->GetDescentOfRow(row)-1;
498                 pain.fillRectangle(x, baseline - tabular->GetAscentOfRow(row) + 1,
499                                    w, h, LColor::selection);
500         }
501 }
502
503
504 void InsetTabular::update(BufferView * bv, LyXFont const & font, bool reinit)
505 {
506         if (in_update) {
507                 if (reinit) {
508                         resetPos(bv);
509                         if (owner())
510                                 owner()->update(bv, font, true);
511                 }
512                 return;
513         }
514         in_update = true;
515         if (reinit) {
516                 need_update = INIT;
517                 if (calculate_dimensions_of_cells(bv, font, true))
518                         resetPos(bv);
519                 if (owner())
520                         owner()->update(bv, font, true);
521                 in_update = false;
522                 return;
523         }
524         if (the_locking_inset)
525                 the_locking_inset->update(bv, font, reinit);
526         if (need_update < FULL &&
527                 bv->text->status() == LyXText::NEED_MORE_REFRESH)
528         {
529                 need_update = FULL;
530         }
531
532         switch (need_update) {
533         case INIT:
534         case FULL:
535         case CELL:
536                 if (calculate_dimensions_of_cells(bv, font, false)) {
537                         need_update = INIT;
538                         resetPos(bv);
539                 }
540                 break;
541         case SELECTION:
542                 need_update = FULL;
543                 break;
544         default:
545                 break;
546         }
547         in_update = false;
548 }
549
550
551 string const InsetTabular::editMessage() const
552 {
553         return _("Opened Tabular Inset");
554 }
555
556
557 void InsetTabular::edit(BufferView * bv, int x, int y, mouse_button::state button)
558 {
559         UpdatableInset::edit(bv, x, y, button);
560
561         if (!bv->lockInset(this)) {
562                 lyxerr[Debug::INSETTEXT] << "InsetTabular::Cannot lock inset" << endl;
563                 return;
564         }
565         locked = true;
566         the_locking_inset = 0;
567         inset_x = 0;
568         inset_y = 0;
569         setPos(bv, x, y);
570         clearSelection();
571         finishUndo();
572         if (insetHit(bv, x, y) && (button != mouse_button::button3)) {
573                 activateCellInsetAbs(bv, x, y, button);
574         }
575 }
576
577
578 void InsetTabular::edit(BufferView * bv, bool front)
579 {
580         UpdatableInset::edit(bv, front);
581
582         if (!bv->lockInset(this)) {
583                 lyxerr[Debug::INSETTEXT] << "InsetTabular::Cannot lock inset" << endl;
584                 return;
585         }
586         finishUndo();
587         locked = true;
588         the_locking_inset = 0;
589         inset_x = 0;
590         inset_y = 0;
591         if (front) {
592                 if (isRightToLeft(bv))
593                         actcell = tabular->GetLastCellInRow(0);
594                 else
595                         actcell = 0;
596         } else {
597                 if (isRightToLeft(bv))
598                         actcell = tabular->GetFirstCellInRow(tabular->rows()-1);
599                 else
600                         actcell = tabular->GetNumberOfCells() - 1;
601         }
602         clearSelection();
603         resetPos(bv);
604         bv->fitCursor();
605 }
606
607
608 void InsetTabular::insetUnlock(BufferView * bv)
609 {
610         if (the_locking_inset) {
611                 the_locking_inset->insetUnlock(bv);
612                 updateLocal(bv, CELL, false);
613                 the_locking_inset = 0;
614         }
615         hideInsetCursor(bv);
616         actcell = 0;
617         oldcell = -1;
618         locked = false;
619         if (scroll(false) || hasSelection()) {
620                 clearSelection();
621                 if (scroll(false)) {
622                         scroll(bv, 0.0F);
623                 }
624                 updateLocal(bv, FULL, false);
625         }
626 }
627
628
629 void InsetTabular::updateLocal(BufferView * bv, UpdateCodes what,
630                                bool mark_dirty) const
631 {
632         if (what == INIT) {
633                 LyXFont font;
634                 calculate_dimensions_of_cells(bv, font, true);
635         }
636         if (!locked && what == CELL)
637                 what = FULL;
638         if (need_update < what) // only set this if it has greater update
639                 need_update = what;
640         // Dirty Cast! (Lgb)
641         if (need_update != NONE) {
642                 bv->updateInset(const_cast<InsetTabular *>(this), mark_dirty);
643                 if (locked)
644                         resetPos(bv);
645         }
646 }
647
648
649 bool InsetTabular::lockInsetInInset(BufferView * bv, UpdatableInset * inset)
650 {
651         lyxerr[Debug::INSETTEXT] << "InsetTabular::LockInsetInInset("
652                               << inset << "): ";
653         if (!inset)
654                 return false;
655         oldcell = -1;
656         if (inset == tabular->GetCellInset(actcell)) {
657                 lyxerr[Debug::INSETTEXT] << "OK" << endl;
658                 the_locking_inset = tabular->GetCellInset(actcell);
659                 resetPos(bv);
660                 return true;
661         } else if (!the_locking_inset) {
662                 int const n = tabular->GetNumberOfCells();
663                 int const id = inset->id();
664                 for (int i = 0; i < n; ++i) {
665                         InsetText * in = tabular->GetCellInset(i);
666                         if (inset == in) {
667                                 actcell = i;
668                                 the_locking_inset = in;
669                                 locked = true;
670                                 resetPos(bv);
671                                 return true;
672                         }
673                         if (in->getInsetFromID(id)) {
674                                 actcell = i;
675                                 in->edit(bv);
676                                 return the_locking_inset->lockInsetInInset(bv, inset);
677                         }
678                 }
679         } else if (the_locking_inset && (the_locking_inset == inset)) {
680                 lyxerr[Debug::INSETTEXT] << "OK" << endl;
681                 resetPos(bv);
682         } else if (the_locking_inset) {
683                 lyxerr[Debug::INSETTEXT] << "MAYBE" << endl;
684                 return the_locking_inset->lockInsetInInset(bv, inset);
685         }
686         lyxerr[Debug::INSETTEXT] << "NOT OK" << endl;
687         return false;
688 }
689
690
691 bool InsetTabular::unlockInsetInInset(BufferView * bv, UpdatableInset * inset,
692                                       bool lr)
693 {
694         if (!the_locking_inset)
695                 return false;
696         if (the_locking_inset == inset) {
697                 the_locking_inset->insetUnlock(bv);
698 #ifdef WITH_WARNINGS
699 #warning fix scrolling when cellinset has requested a scroll (Jug)!!!
700 #endif
701 #if 0
702                 if (scroll(false))
703                         scroll(bv, 0.0F);
704 #endif
705                 updateLocal(bv, CELL, false);
706                 // this has to be here otherwise we don't redraw the cell!
707                 the_locking_inset = 0;
708 //              showInsetCursor(bv, false);
709                 return true;
710         }
711         if (the_locking_inset->unlockInsetInInset(bv, inset, lr)) {
712                 if (inset->lyxCode() == TABULAR_CODE &&
713                     !the_locking_inset->getFirstLockingInsetOfType(TABULAR_CODE)) {
714                         bv->owner()->getDialogs().updateTabular(this);
715                         oldcell = actcell;
716                 }
717                 return true;
718         }
719         return false;
720 }
721
722
723 bool InsetTabular::updateInsetInInset(BufferView * bv, Inset * inset)
724 {
725         Inset * tl_inset = inset;
726         // look if this inset is really inside myself!
727         while(tl_inset->owner() && tl_inset->owner() != this)
728                 tl_inset = tl_inset->owner();
729         // if we enter here it's not ower inset
730         if (!tl_inset->owner())
731                 return false;
732         // we only have to do this if this is a subinset of our cells
733         if (tl_inset != inset) {
734                 if (!static_cast<InsetText *>(tl_inset)->updateInsetInInset(bv, inset))
735                         return false;
736         }
737         updateLocal(bv, CELL, false);
738         return true;
739 }
740
741
742 int InsetTabular::insetInInsetY() const
743 {
744         if (!the_locking_inset)
745                 return 0;
746         return inset_y + the_locking_inset->insetInInsetY();
747 }
748
749
750 UpdatableInset * InsetTabular::getLockingInset() const
751 {
752         return the_locking_inset ? the_locking_inset->getLockingInset() :
753                 const_cast<InsetTabular *>(this);
754 }
755
756
757 UpdatableInset * InsetTabular::getFirstLockingInsetOfType(Inset::Code c)
758 {
759         if (c == lyxCode())
760                 return this;
761         if (the_locking_inset)
762                 return the_locking_inset->getFirstLockingInsetOfType(c);
763         return 0;
764 }
765
766
767 bool InsetTabular::insertInset(BufferView * bv, Inset * inset)
768 {
769         if (the_locking_inset)
770                 return the_locking_inset->insertInset(bv, inset);
771         return false;
772 }
773
774
775 void InsetTabular::lfunMousePress(FuncRequest const & cmd)
776 {
777         if (hasSelection() && cmd.button() == mouse_button::button3)
778                 return;
779
780         if (hasSelection()) {
781                 clearSelection();
782                 updateLocal(cmd.view(), SELECTION, false);
783         }
784
785         int const ocell = actcell;
786         int const orow = actrow;
787         BufferView * bv = cmd.view();
788
789         hideInsetCursor(bv);
790         if (!locked) {
791                 locked = true;
792                 the_locking_inset = 0;
793                 inset_x = 0;
794                 inset_y = 0;
795         }
796         setPos(bv, cmd.x, cmd.y);
797         if (actrow != orow)
798                 updateLocal(bv, NONE, false);
799         clearSelection();
800 #if 0
801         if (cmd.button() == mouse_button::button3) {
802                 if ((ocell != actcell) && the_locking_inset) {
803                         the_locking_inset->insetUnlock(bv);
804                         updateLocal(bv, CELL, false);
805                         the_locking_inset = 0;
806                 }
807                 showInsetCursor(bv);
808                 return;
809         }
810 #endif
811
812         bool const inset_hit = insetHit(bv, cmd.x, cmd.y);
813
814         if ((ocell == actcell) && the_locking_inset && inset_hit) {
815                 resetPos(bv);
816                 FuncRequest cmd1 = cmd;
817                 cmd1.x -= inset_x;
818                 cmd1.y -= inset_y;
819                 the_locking_inset->localDispatch(cmd1);
820                 return;
821         }
822
823         if (the_locking_inset) {
824                 the_locking_inset->insetUnlock(bv);
825                 updateLocal(bv, CELL, false);
826                 the_locking_inset = 0;
827         }
828
829         if (cmd.button() == mouse_button::button2) {
830                 localDispatch(FuncRequest(bv, LFUN_PASTESELECTION, "paragraph"));
831                 return;
832         }
833
834         if (inset_hit && bv->theLockingInset()) {
835                 if (!bv->lockInset(static_cast<UpdatableInset*>
836                                 (tabular->GetCellInset(actcell))))
837                 {
838                         lyxerr[Debug::INSETS] << "Cannot lock inset" << endl;
839                         return;
840                 }
841                 FuncRequest cmd1 = cmd;
842                 cmd1.x -= inset_x;
843                 cmd1.y -= inset_y;
844                 the_locking_inset->localDispatch(cmd1);
845                 return;
846         }
847         showInsetCursor(bv);
848 }
849
850
851 bool InsetTabular::lfunMouseRelease(FuncRequest const & cmd)
852 {
853         bool ret = false;
854         if (the_locking_inset) {
855                 FuncRequest cmd1 = cmd;
856                 cmd1.x -= inset_x;
857                 cmd1.y -= inset_y;
858                 ret = the_locking_inset->localDispatch(cmd1);
859         }
860         if (cmd.button() == mouse_button::button3 && !ret) {
861                 cmd.view()->owner()->getDialogs().showTabular(this);
862                 return true;
863         }
864         return ret;
865 }
866
867
868 void InsetTabular::lfunMouseMotion(FuncRequest const & cmd)
869 {
870         if (the_locking_inset) {
871                 FuncRequest cmd1 = cmd;
872                 cmd1.x -= inset_x;
873                 cmd1.y -= inset_y;
874                 the_locking_inset->localDispatch(cmd1);
875                 return;
876         }
877
878         BufferView * bv = cmd.view();
879         hideInsetCursor(bv);
880         int const old_cell = actcell;
881
882         setPos(bv, cmd.x, cmd.y);
883         if (!hasSelection()) {
884                 setSelection(actcell, actcell);
885                 updateLocal(bv, SELECTION, false);
886         } else if (old_cell != actcell) {
887                 setSelection(sel_cell_start, actcell);
888                 updateLocal(bv, SELECTION, false);
889         }
890         showInsetCursor(bv);
891 }
892
893
894 Inset::RESULT InsetTabular::localDispatch(FuncRequest const & cmd)
895 {
896         // We need to save the value of the_locking_inset as the call to
897         // the_locking_inset->localDispatch might unlock it.
898         old_locking_inset = the_locking_inset;
899         RESULT result = UpdatableInset::localDispatch(cmd);
900
901         BufferView * bv = cmd.view();
902         if (result == DISPATCHED || result == DISPATCHED_NOUPDATE) {
903                 resetPos(bv);
904                 return result;
905         }
906
907         if (cmd.action < 0 && cmd.argument.empty())
908                 return FINISHED;
909
910         bool hs = hasSelection();
911
912         result = DISPATCHED;
913         // this one have priority over the locked InsetText, if we're not already
914         // inside another tabular then that one get's priority!
915         if (getFirstLockingInsetOfType(Inset::TABULAR_CODE) == this) {
916                 switch (cmd.action) {
917                 case LFUN_MOUSE_PRESS:
918                         lfunMousePress(cmd);
919                         return DISPATCHED;
920
921                 case LFUN_MOUSE_MOTION:
922                         lfunMouseMotion(cmd);
923                         return DISPATCHED;
924
925                 case LFUN_MOUSE_RELEASE:
926                         return lfunMouseRelease(cmd) ? DISPATCHED : UNDISPATCHED;
927
928                 case LFUN_SHIFT_TAB:
929                 case LFUN_TAB:
930                         hideInsetCursor(bv);
931                         unlockInsetInInset(bv, the_locking_inset);
932                         if (cmd.action == LFUN_TAB)
933                                 moveNextCell(bv, old_locking_inset != 0);
934                         else
935                                 movePrevCell(bv, old_locking_inset != 0);
936                         clearSelection();
937                         if (hs)
938                                 updateLocal(bv, SELECTION, false);
939                         if (!the_locking_inset) {
940                                 showInsetCursor(bv);
941                                 return DISPATCHED_NOUPDATE;
942                         }
943                         return result;
944                 // this to avoid compiler warnings.
945                 default:
946                         break;
947                 }
948         }
949
950         kb_action action = cmd.action;
951         string    arg    = cmd.argument;
952         if (the_locking_inset) {
953                 result = the_locking_inset->localDispatch(cmd);
954                 if (result == DISPATCHED_NOUPDATE) {
955                         int sc = scroll();
956                         resetPos(bv);
957                         if (sc != scroll()) { // inset has been scrolled
958                                 the_locking_inset->toggleInsetCursor(bv);
959                                 updateLocal(bv, FULL, false);
960                                 the_locking_inset->toggleInsetCursor(bv);
961                         }
962                         return result;
963                 } else if (result == DISPATCHED) {
964                         the_locking_inset->toggleInsetCursor(bv);
965                         updateLocal(bv, CELL, false);
966                         the_locking_inset->toggleInsetCursor(bv);
967                         return result;
968                 } else if (result == FINISHED_UP) {
969                         action = LFUN_UP;
970                 } else if (result == FINISHED_DOWN) {
971                         action = LFUN_DOWN;
972                 } else if (result == FINISHED_RIGHT) {
973                         action = LFUN_RIGHT;
974                 }
975         }
976
977         hideInsetCursor(bv);
978         result = DISPATCHED;
979         switch (action) {
980                 // --- Cursor Movements ----------------------------------
981         case LFUN_RIGHTSEL: {
982                 int const start = hasSelection() ? sel_cell_start : actcell;
983                 if (tabular->IsLastCellInRow(actcell)) {
984                         setSelection(start, actcell);
985                         break;
986                 }
987
988                 int end = actcell;
989                 // if we are starting a selection, only select
990                 // the current cell at the beginning
991                 if (hasSelection()) {
992                         moveRight(bv, false);
993                         end = actcell;
994                 }
995                 setSelection(start, end);
996                 updateLocal(bv, SELECTION, false);
997                 break;
998         }
999         case LFUN_RIGHT:
1000                 result = moveRight(bv);
1001                 clearSelection();
1002                 if (hs)
1003                         updateLocal(bv, SELECTION, false);
1004                 break;
1005         case LFUN_LEFTSEL: {
1006                 int const start = hasSelection() ? sel_cell_start : actcell;
1007                 if (tabular->IsFirstCellInRow(actcell)) {
1008                         setSelection(start, actcell);
1009                         break;
1010                 }
1011
1012                 int end = actcell;
1013                 // if we are starting a selection, only select
1014                 // the current cell at the beginning
1015                 if (hasSelection()) {
1016                         moveLeft(bv, false);
1017                         end = actcell;
1018                 }
1019                 setSelection(start, end);
1020                 updateLocal(bv, SELECTION, false);
1021                 break;
1022         }
1023         case LFUN_LEFT:
1024                 result = moveLeft(bv);
1025                 clearSelection();
1026                 if (hs)
1027                         updateLocal(bv, SELECTION, false);
1028                 break;
1029         case LFUN_DOWNSEL: {
1030                 int const start = hasSelection() ? sel_cell_start : actcell;
1031                 int const ocell = actcell;
1032                 // if we are starting a selection, only select
1033                 // the current cell at the beginning
1034                 if (hasSelection()) {
1035                         moveDown(bv, false);
1036                         if ((ocell == sel_cell_end) ||
1037                             (tabular->column_of_cell(ocell)>tabular->column_of_cell(actcell)))
1038                                 setSelection(start, tabular->GetCellBelow(sel_cell_end));
1039                         else
1040                                 setSelection(start, tabular->GetLastCellBelow(sel_cell_end));
1041                 } else {
1042                         setSelection(start, start);
1043                 }
1044                 updateLocal(bv, SELECTION, false);
1045         }
1046         break;
1047         case LFUN_DOWN:
1048                 result = moveDown(bv, old_locking_inset != 0);
1049                 clearSelection();
1050                 if (hs) {
1051                         updateLocal(bv, SELECTION, false);
1052                 }
1053                 break;
1054         case LFUN_UPSEL: {
1055                 int const start = hasSelection() ? sel_cell_start : actcell;
1056                 int const ocell = actcell;
1057                 // if we are starting a selection, only select
1058                 // the current cell at the beginning
1059                 if (hasSelection()) {
1060                         moveUp(bv, false);
1061                         if ((ocell == sel_cell_end) ||
1062                             (tabular->column_of_cell(ocell)>tabular->column_of_cell(actcell)))
1063                                 setSelection(start, tabular->GetCellAbove(sel_cell_end));
1064                         else
1065                                 setSelection(start, tabular->GetLastCellAbove(sel_cell_end));
1066                 } else {
1067                         setSelection(start, start);
1068                 }
1069                 updateLocal(bv, SELECTION, false);
1070         }
1071         break;
1072         case LFUN_UP:
1073                 result = moveUp(bv, old_locking_inset != 0);
1074                 clearSelection();
1075                 if (hs)
1076                         updateLocal(bv, SELECTION, false);
1077                 break;
1078         case LFUN_NEXT: {
1079                 UpdateCodes code = CURSOR;
1080                 if (hs) {
1081                         clearSelection();
1082                         code = SELECTION;
1083                 }
1084                 int column = actcol;
1085                 unlockInsetInInset(bv, the_locking_inset);
1086                 if (bv->text->first_y + bv->painter().paperHeight() <
1087                     (top_baseline + tabular->GetHeightOfTabular()))
1088                         {
1089                                 bv->scrollDocView(bv->text->first_y + bv->painter().paperHeight());
1090                                 code = FULL;
1091                                 actcell = tabular->GetCellBelow(first_visible_cell) + column;
1092                         } else {
1093                                 actcell = tabular->GetFirstCellInRow(tabular->rows() - 1) + column;
1094                         }
1095                 resetPos(bv);
1096                 updateLocal(bv, code, false);
1097                 break;
1098         }
1099         case LFUN_PRIOR: {
1100                 UpdateCodes code = CURSOR;
1101                 if (hs) {
1102                         clearSelection();
1103                         code = SELECTION;
1104                 }
1105                 int column = actcol;
1106                 unlockInsetInInset(bv, the_locking_inset);
1107                 if (top_baseline < 0) {
1108                         bv->scrollDocView(bv->text->first_y - bv->painter().paperHeight());
1109                         code = FULL;
1110                         if (top_baseline > 0)
1111                                 actcell = column;
1112                         else
1113                                 actcell = tabular->GetCellBelow(first_visible_cell) + column;
1114                 } else {
1115                         actcell = column;
1116                 }
1117                 resetPos(bv);
1118                 updateLocal(bv, code, false);
1119                 break;
1120         }
1121         // none of these make sense for insettabular,
1122         // but we must catch them to prevent any
1123         // selection from being confused
1124         case LFUN_PRIORSEL:
1125         case LFUN_NEXTSEL:
1126         case LFUN_WORDLEFT:
1127         case LFUN_WORDLEFTSEL:
1128         case LFUN_WORDRIGHT:
1129         case LFUN_WORDRIGHTSEL:
1130         case LFUN_WORDSEL:
1131         case LFUN_DOWN_PARAGRAPH:
1132         case LFUN_DOWN_PARAGRAPHSEL:
1133         case LFUN_UP_PARAGRAPH:
1134         case LFUN_UP_PARAGRAPHSEL:
1135         case LFUN_BACKSPACE:
1136         case LFUN_HOME:
1137         case LFUN_HOMESEL:
1138         case LFUN_END:
1139         case LFUN_ENDSEL:
1140         case LFUN_BEGINNINGBUF:
1141         case LFUN_BEGINNINGBUFSEL:
1142         case LFUN_ENDBUF:
1143         case LFUN_ENDBUFSEL:
1144                 break;
1145         case LFUN_LAYOUT_TABULAR:
1146                 bv->owner()->getDialogs().showTabular(this);
1147                 break;
1148         case LFUN_TABULAR_FEATURE:
1149                 if (!tabularFeatures(bv, arg))
1150                         result = UNDISPATCHED;
1151                 break;
1152                 // insert file functions
1153         case LFUN_FILE_INSERT_ASCII_PARA:
1154         case LFUN_FILE_INSERT_ASCII:
1155         {
1156                 string tmpstr = getContentsOfAsciiFile(bv, arg, false);
1157                 if (tmpstr.empty())
1158                         break;
1159                 if (insertAsciiString(bv, tmpstr, false))
1160                         updateLocal(bv, INIT, true);
1161                 else
1162                         result = UNDISPATCHED;
1163                 break;
1164         }
1165         // cut and paste functions
1166         case LFUN_CUT:
1167                 if (!copySelection(bv))
1168                         break;
1169                 // no break here!
1170         case LFUN_DELETE:
1171                 setUndo(bv, Undo::DELETE,
1172                         bv->text->cursor.par(),
1173                         bv->text->cursor.par()->next());
1174                 cutSelection();
1175                 updateLocal(bv, INIT, true);
1176                 break;
1177         case LFUN_COPY:
1178                 if (!hasSelection())
1179                         break;
1180                 finishUndo();
1181                 copySelection(bv);
1182                 break;
1183         case LFUN_PASTESELECTION:
1184         {
1185                 string const clip(bv->getClipboard());
1186                         if (clip.empty())
1187                         break;
1188 #if 0
1189                 if (clip.find('\t') != string::npos) {
1190                         int cols = 1;
1191                         int rows = 1;
1192                         int maxCols = 1;
1193                         string::size_type len = clip.length();
1194                         string::size_type p = 0;
1195
1196                         while (p < len &&
1197                               ((p = clip.find_first_of("\t\n", p)) != string::npos)) {
1198                                 switch (clip[p]) {
1199                                 case '\t':
1200                                         ++cols;
1201                                         break;
1202                                 case '\n':
1203                                         if ((p+1) < len)
1204                                                 ++rows;
1205                                         maxCols = max(cols, maxCols);
1206                                         cols = 1;
1207                                         break;
1208                                 }
1209                                 ++p;
1210                         }
1211                         maxCols = max(cols, maxCols);
1212                         delete paste_tabular;
1213                         paste_tabular = new LyXTabular(bv->buffer()->params,
1214                                                        this, rows, maxCols);
1215                         string::size_type op = 0;
1216                         int cell = 0;
1217                         int cells = paste_tabular->GetNumberOfCells();
1218                         p = cols = 0;
1219                         while ((cell < cells) && (p < len) &&
1220                               (p = clip.find_first_of("\t\n", p)) != string::npos) {
1221                                 if (p >= len)
1222                                         break;
1223                                 switch (clip[p]) {
1224                                 case '\t':
1225                                         paste_tabular->GetCellInset(cell)->setText(clip.substr(op, p-op));
1226                                         ++cols;
1227                                         ++cell;
1228                                         break;
1229                                 case '\n':
1230                                         paste_tabular->GetCellInset(cell)->setText(clip.substr(op, p-op));
1231                                         while (cols++ < maxCols)
1232                                                 ++cell;
1233                                         cols = 0;
1234                                         break;
1235                                 }
1236                                 ++p;
1237                                 op = p;
1238                         }
1239                         // check for the last cell if there is no trailing '\n'
1240                         if ((cell < cells) && (op < len))
1241                                 paste_tabular->GetCellInset(cell)->setText(clip.substr(op, len-op));
1242                 } else
1243 #else
1244                 if (!insertAsciiString(bv, clip, true))
1245 #endif
1246                 {
1247                         // so that the clipboard is used and it goes on
1248                         // to default
1249                         // and executes LFUN_PASTESELECTION in insettext!
1250                         delete paste_tabular;
1251                         paste_tabular = 0;
1252                 }
1253         }
1254         case LFUN_PASTE:
1255                 if (hasPasteBuffer()) {
1256                         setUndo(bv, Undo::INSERT,
1257                                 bv->text->cursor.par(),
1258                                 bv->text->cursor.par()->next());
1259                         pasteSelection(bv);
1260                         updateLocal(bv, INIT, true);
1261                         break;
1262                 }
1263                 // ATTENTION: the function above has to be PASTE and PASTESELECTION!!!
1264         default:
1265                 // handle font changing stuff on selection before we lock the inset
1266                 // in the default part!
1267                 result = UNDISPATCHED;
1268                 if (hs) {
1269                         switch(action) {
1270                         case LFUN_LANGUAGE:
1271                         case LFUN_EMPH:
1272                         case LFUN_BOLD:
1273                         case LFUN_NOUN:
1274                         case LFUN_CODE:
1275                         case LFUN_SANS:
1276                         case LFUN_ROMAN:
1277                         case LFUN_DEFAULT:
1278                         case LFUN_UNDERLINE:
1279                         case LFUN_FONT_SIZE:
1280                                 if (bv->dispatch(FuncRequest(bv, action, arg)))
1281                                         result = DISPATCHED;
1282                                 break;
1283                         default:
1284                                 break;
1285                         }
1286                 }
1287                 // we try to activate the actual inset and put this event down to
1288                 // the insets dispatch function.
1289                 if ((result == DISPATCHED) || the_locking_inset)
1290                         break;
1291                 nodraw(true);
1292                 if (activateCellInset(bv)) {
1293                         // reset need_update setted in above function!
1294                         need_update = NONE;
1295                         result = the_locking_inset->localDispatch(FuncRequest(bv, action, arg));
1296                         if ((result == UNDISPATCHED) || (result >= FINISHED)) {
1297                                 unlockInsetInInset(bv, the_locking_inset);
1298                                 nodraw(false);
1299                                 // we need to update if this was requested before
1300                                 updateLocal(bv, NONE, false);
1301                                 return UNDISPATCHED;
1302                         } else if (hs) {
1303                                 clearSelection();
1304                                 // so the below CELL is not set because this is higher
1305                                 // priority and we get a full redraw
1306                                 need_update = SELECTION;
1307                         }
1308                         nodraw(false);
1309                         updateLocal(bv, CELL, false);
1310                         return result;
1311                 }
1312                 break;
1313         }
1314         if (result < FINISHED) {
1315                 if (!the_locking_inset) {
1316                         if (bv->fitCursor())
1317                                 updateLocal(bv, FULL, false);
1318                         if (locked)
1319                                 showInsetCursor(bv);
1320                 }
1321         } else
1322                 bv->unlockInset(this);
1323         return result;
1324 }
1325
1326
1327 int InsetTabular::latex(Buffer const * buf, ostream & os,
1328                         bool fragile, bool fp) const
1329 {
1330         return tabular->latex(buf, os, fragile, fp);
1331 }
1332
1333
1334 int InsetTabular::ascii(Buffer const * buf, ostream & os, int ll) const
1335 {
1336         if (ll > 0)
1337                 return tabular->ascii(buf, os, (int)parOwner()->params().depth(),
1338                                       false,0);
1339         return tabular->ascii(buf, os, 0, false,0);
1340 }
1341
1342
1343 int InsetTabular::linuxdoc(Buffer const * buf, ostream & os) const
1344 {
1345         os << "<![CDATA[";
1346         int const ret = tabular->ascii(buf,os,
1347                                        (int)parOwner()->params().depth(),
1348                                        false, 0);
1349         os << "]]>";
1350         return ret;
1351 }
1352
1353
1354 int InsetTabular::docbook(Buffer const * buf, ostream & os, bool mixcont) const
1355 {
1356         int ret = 0;
1357         Inset * master;
1358
1359         // if the table is inside a float it doesn't need the informaltable
1360         // wrapper. Search for it.
1361         for(master = owner();
1362             master && master->lyxCode() != Inset::FLOAT_CODE;
1363             master = master->owner());
1364
1365         if (!master) {
1366                 os << "<informaltable>";
1367                 if (mixcont)
1368                         os << endl;
1369                 ret++;
1370         }
1371         ret+= tabular->docbook(buf, os, mixcont);
1372         if (!master) {
1373                 os << "</informaltable>";
1374                 if (mixcont)
1375                         os << endl;
1376                 ret++;
1377         }
1378         return ret;
1379 }
1380
1381
1382 void InsetTabular::validate(LaTeXFeatures & features) const
1383 {
1384         tabular->Validate(features);
1385 }
1386
1387
1388 bool InsetTabular::calculate_dimensions_of_cells(BufferView * bv,
1389                                                  LyXFont const & font,
1390                                                  bool reinit) const
1391 {
1392         int cell = -1;
1393         int maxAsc = 0;
1394         int maxDesc = 0;
1395         InsetText * inset;
1396         bool changed = false;
1397
1398         // if we have a locking_inset we should have to check only this cell for
1399         // change so I'll try this to have a boost, but who knows ;)
1400         if ((need_update != INIT) &&
1401             (the_locking_inset == tabular->GetCellInset(actcell))) {
1402                 for(int i = 0; i < tabular->columns(); ++i) {
1403                         maxAsc = max(tabular->GetCellInset(actrow, i)->ascent(bv, font),
1404                                      maxAsc);
1405                         maxDesc = max(tabular->GetCellInset(actrow, i)->descent(bv, font),
1406                                       maxDesc);
1407                 }
1408                 changed = tabular->SetWidthOfCell(actcell, the_locking_inset->width(bv, font));
1409                 changed = tabular->SetAscentOfRow(actrow, maxAsc + ADD_TO_HEIGHT) || changed;
1410                 changed = tabular->SetDescentOfRow(actrow, maxDesc + ADD_TO_HEIGHT) || changed;
1411                 return changed;
1412         }
1413         for (int i = 0; i < tabular->rows(); ++i) {
1414                 maxAsc = 0;
1415                 maxDesc = 0;
1416                 for (int j = 0; j < tabular->columns(); ++j) {
1417                         if (tabular->IsPartOfMultiColumn(i,j))
1418                                 continue;
1419                         ++cell;
1420                         inset = tabular->GetCellInset(cell);
1421                         if (!reinit && !tabular->GetPWidth(cell).zero())
1422                                 inset->update(bv, font, false);
1423                         maxAsc = max(maxAsc, inset->ascent(bv, font));
1424                         maxDesc = max(maxDesc, inset->descent(bv, font));
1425                         changed = tabular->SetWidthOfCell(cell, inset->width(bv, font)) || changed;
1426                 }
1427                 changed = tabular->SetAscentOfRow(i, maxAsc + ADD_TO_HEIGHT) || changed;
1428                 changed = tabular->SetDescentOfRow(i, maxDesc + ADD_TO_HEIGHT) || changed;
1429         }
1430         if (changed)
1431                 tabular->reinit();
1432         return changed;
1433 }
1434
1435
1436 void InsetTabular::getCursorPos(BufferView * bv, int & x, int & y) const
1437 {
1438         if (the_locking_inset) {
1439                 the_locking_inset->getCursorPos(bv, x, y);
1440                 return;
1441         }
1442         x = cursor_.x() - top_x;
1443         y = cursor_.y();
1444 }
1445
1446
1447 void InsetTabular::toggleInsetCursor(BufferView * bv)
1448 {
1449         if (nodraw()) {
1450                 if (isCursorVisible())
1451                         bv->hideLockedInsetCursor();
1452                 return;
1453         }
1454         if (the_locking_inset) {
1455                 the_locking_inset->toggleInsetCursor(bv);
1456                 return;
1457         }
1458
1459         LyXFont font; // = the_locking_inset->GetFont(par, cursor.pos);
1460
1461         int const asc = font_metrics::maxAscent(font);
1462         int const desc = font_metrics::maxDescent(font);
1463
1464         if (isCursorVisible())
1465                 bv->hideLockedInsetCursor();
1466         else
1467                 bv->showLockedInsetCursor(cursor_.x(), cursor_.y(), asc, desc);
1468         toggleCursorVisible();
1469 }
1470
1471
1472 void InsetTabular::showInsetCursor(BufferView * bv, bool show)
1473 {
1474         if (nodraw())
1475                 return;
1476         if (!isCursorVisible()) {
1477                 LyXFont font; // = GetFont(par, cursor.pos);
1478
1479                 int const asc = font_metrics::maxAscent(font);
1480                 int const desc = font_metrics::maxDescent(font);
1481                 bv->fitLockedInsetCursor(cursor_.x(), cursor_.y(), asc, desc);
1482                 if (show)
1483                         bv->showLockedInsetCursor(cursor_.x(), cursor_.y(), asc, desc);
1484                 setCursorVisible(true);
1485         }
1486 }
1487
1488
1489 void InsetTabular::hideInsetCursor(BufferView * bv)
1490 {
1491         if (isCursorVisible()) {
1492                 bv->hideLockedInsetCursor();
1493                 setCursorVisible(false);
1494         }
1495 }
1496
1497
1498 void InsetTabular::fitInsetCursor(BufferView * bv) const
1499 {
1500         if (the_locking_inset) {
1501                 int old_first_y = bv->text->first_y;
1502                 the_locking_inset->fitInsetCursor(bv);
1503                 if (old_first_y != bv->text->first_y)
1504                         need_update = FULL;
1505                 return;
1506         }
1507         LyXFont font;
1508
1509         int const asc = font_metrics::maxAscent(font);
1510         int const desc = font_metrics::maxDescent(font);
1511         resetPos(bv);
1512
1513         if (bv->fitLockedInsetCursor(cursor_.x(), cursor_.y(), asc, desc))
1514                 need_update = FULL;
1515 }
1516
1517
1518 void InsetTabular::setPos(BufferView * bv, int x, int y) const
1519 {
1520         cursor_.y(0);
1521
1522         actcell = actrow = actcol = 0;
1523         int ly = tabular->GetDescentOfRow(actrow);
1524
1525         // first search the right row
1526         while ((ly < y) && ((actrow+1) < tabular->rows())) {
1527                 cursor_.y(cursor_.y() + tabular->GetDescentOfRow(actrow) +
1528                                  tabular->GetAscentOfRow(actrow + 1) +
1529                                  tabular->GetAdditionalHeight(actrow + 1));
1530                 ++actrow;
1531                 ly = cursor_.y() + tabular->GetDescentOfRow(actrow);
1532         }
1533         actcell = tabular->GetCellNumber(actrow, actcol);
1534
1535         // now search the right column
1536         int lx = tabular->GetWidthOfColumn(actcell) -
1537                 tabular->GetAdditionalWidth(actcell);
1538         for (; !tabular->IsLastCellInRow(actcell) && lx < x; ++actcell) {
1539                 lx += tabular->GetWidthOfColumn(actcell + 1)
1540                         + tabular->GetAdditionalWidth(actcell);
1541         }
1542         cursor_.x(lx - tabular->GetWidthOfColumn(actcell) + top_x + 2);
1543         resetPos(bv);
1544 }
1545
1546
1547 int InsetTabular::getCellXPos(int cell) const
1548 {
1549         int c = cell;
1550
1551         for (; !tabular->IsFirstCellInRow(c); --c)
1552                 ;
1553         int lx = tabular->GetWidthOfColumn(cell);
1554         for (; c < cell; ++c) {
1555                 lx += tabular->GetWidthOfColumn(c);
1556         }
1557         return (lx - tabular->GetWidthOfColumn(cell) + top_x);
1558 }
1559
1560
1561 void InsetTabular::resetPos(BufferView * bv) const
1562 {
1563 #ifdef WITH_WARNINGS
1564 #warning This should be fixed in the right manner (20011128 Jug)
1565 #endif
1566         // fast hack to fix infinite repaintings!
1567         if (in_reset_pos > 0)
1568                 return;
1569
1570         int cell = 0;
1571         actcol = tabular->column_of_cell(actcell);
1572         actrow = 0;
1573         cursor_.y(0);
1574         for (; (cell < actcell) && !tabular->IsLastRow(cell); ++cell) {
1575                 if (tabular->IsLastCellInRow(cell)) {
1576                         cursor_.y(cursor_.y() + tabular->GetDescentOfRow(actrow) +
1577                                          tabular->GetAscentOfRow(actrow + 1) +
1578                                          tabular->GetAdditionalHeight(actrow + 1));
1579                         ++actrow;
1580                 }
1581         }
1582         if (!locked || nodraw()) {
1583                 if (the_locking_inset)
1584                         inset_y = cursor_.y();
1585                 return;
1586         }
1587         // we need this only from here on!!!
1588         ++in_reset_pos;
1589         static int const offset = ADD_TO_TABULAR_WIDTH + 2;
1590         int new_x = getCellXPos(actcell);
1591         int old_x = cursor_.x();
1592         new_x += offset;
1593         cursor_.x(new_x);
1594 //    cursor.x(getCellXPos(actcell) + offset);
1595         if ((actcol < tabular->columns() - 1) && scroll(false) &&
1596                 (tabular->GetWidthOfTabular() < bv->workWidth()-20))
1597         {
1598                 scroll(bv, 0.0F);
1599                 updateLocal(bv, FULL, false);
1600         } else if (the_locking_inset &&
1601                  (tabular->GetWidthOfColumn(actcell) > bv->workWidth()-20))
1602         {
1603                 int xx = cursor_.x() - offset + bv->text->getRealCursorX(bv);
1604                 if (xx > (bv->workWidth()-20)) {
1605                         scroll(bv, -(xx - bv->workWidth() + 60));
1606                         updateLocal(bv, FULL, false);
1607                 } else if (xx < 20) {
1608                         if (xx < 0)
1609                                 xx = -xx + 60;
1610                         else
1611                                 xx = 60;
1612                         scroll(bv, xx);
1613                         updateLocal(bv, FULL, false);
1614                 }
1615         } else if ((cursor_.x() - offset) > 20 &&
1616                    (cursor_.x() - offset + tabular->GetWidthOfColumn(actcell))
1617                    > (bv->workWidth() - 20)) {
1618                 scroll(bv, -tabular->GetWidthOfColumn(actcell) - 20);
1619                 updateLocal(bv, FULL, false);
1620         } else if ((cursor_.x() - offset) < 20) {
1621                 scroll(bv, 20 - cursor_.x() + offset);
1622                 updateLocal(bv, FULL, false);
1623         } else if (scroll() && top_x > 20 &&
1624                    (top_x + tabular->GetWidthOfTabular()) > (bv->workWidth() - 20)) {
1625                 scroll(bv, old_x - cursor_.x());
1626                 updateLocal(bv, FULL, false);
1627         }
1628         if (the_locking_inset) {
1629                 inset_x = cursor_.x() - top_x + tabular->GetBeginningOfTextInCell(actcell);
1630                 inset_y = cursor_.y();
1631         }
1632         if ((!the_locking_inset ||
1633              !the_locking_inset->getFirstLockingInsetOfType(TABULAR_CODE)) &&
1634             actcell != oldcell) {
1635                 InsetTabular * inset = const_cast<InsetTabular *>(this);
1636                 bv->owner()->getDialogs().updateTabular(inset);
1637                 oldcell = actcell;
1638         }
1639         in_reset_pos = 0;
1640 }
1641
1642
1643 Inset::RESULT InsetTabular::moveRight(BufferView * bv, bool lock)
1644 {
1645         if (lock && !old_locking_inset) {
1646                 if (activateCellInset(bv))
1647                         return DISPATCHED;
1648         } else {
1649                 bool moved = isRightToLeft(bv)
1650                         ? movePrevCell(bv) : moveNextCell(bv);
1651                 if (!moved)
1652                         return FINISHED_RIGHT;
1653                 if (lock && activateCellInset(bv))
1654                         return DISPATCHED;
1655         }
1656         resetPos(bv);
1657         return DISPATCHED_NOUPDATE;
1658 }
1659
1660
1661 Inset::RESULT InsetTabular::moveLeft(BufferView * bv, bool lock)
1662 {
1663         bool moved = isRightToLeft(bv) ? moveNextCell(bv) : movePrevCell(bv);
1664         if (!moved)
1665                 return FINISHED;
1666         if (lock) {       // behind the inset
1667                 if (activateCellInset(bv, 0, 0, mouse_button::none, true))
1668                         return DISPATCHED;
1669         }
1670         resetPos(bv);
1671         return DISPATCHED_NOUPDATE;
1672 }
1673
1674
1675 Inset::RESULT InsetTabular::moveUp(BufferView * bv, bool lock)
1676 {
1677         int const ocell = actcell;
1678         actcell = tabular->GetCellAbove(actcell);
1679         if (actcell == ocell) // we moved out of the inset
1680                 return FINISHED_UP;
1681         resetPos(bv);
1682         if (lock) {
1683                 int x = 0;
1684                 int y = 0;
1685                 if (old_locking_inset) {
1686                         old_locking_inset->getCursorPos(bv, x, y);
1687                         x -= cursor_.x() + tabular->GetBeginningOfTextInCell(actcell);
1688                 }
1689                 if (activateCellInset(bv, x, 0))
1690                         return DISPATCHED;
1691         }
1692         return DISPATCHED_NOUPDATE;
1693 }
1694
1695
1696 Inset::RESULT InsetTabular::moveDown(BufferView * bv, bool lock)
1697 {
1698         int const ocell = actcell;
1699         actcell = tabular->GetCellBelow(actcell);
1700         if (actcell == ocell) // we moved out of the inset
1701                 return FINISHED_DOWN;
1702         resetPos(bv);
1703         if (lock) {
1704                 int x = 0;
1705                 int y = 0;
1706                 if (old_locking_inset) {
1707                         old_locking_inset->getCursorPos(bv, x, y);
1708                         x -= cursor_.x() + tabular->GetBeginningOfTextInCell(actcell);
1709                 }
1710                 if (activateCellInset(bv, x, 0))
1711                         return DISPATCHED;
1712         }
1713         return DISPATCHED_NOUPDATE;
1714 }
1715
1716
1717 bool InsetTabular::moveNextCell(BufferView * bv, bool lock)
1718 {
1719         if (isRightToLeft(bv)) {
1720                 if (tabular->IsFirstCellInRow(actcell)) {
1721                         int row = tabular->row_of_cell(actcell);
1722                         if (row == tabular->rows() - 1)
1723                                 return false;
1724                         actcell = tabular->GetLastCellInRow(row);
1725                         actcell = tabular->GetCellBelow(actcell);
1726                 } else {
1727                         if (!actcell)
1728                                 return false;
1729                         --actcell;
1730                 }
1731         } else {
1732                 if (tabular->IsLastCell(actcell))
1733                         return false;
1734                 ++actcell;
1735         }
1736         if (lock) {
1737                 bool rtl = tabular->GetCellInset(actcell)->paragraph()->
1738                         isRightToLeftPar(bv->buffer()->params);
1739                 activateCellInset(bv, 0, 0, mouse_button::none, !rtl);
1740         }
1741         resetPos(bv);
1742         return true;
1743 }
1744
1745
1746 bool InsetTabular::movePrevCell(BufferView * bv, bool lock)
1747 {
1748         if (isRightToLeft(bv)) {
1749                 if (tabular->IsLastCellInRow(actcell)) {
1750                         int row = tabular->row_of_cell(actcell);
1751                         if (row == 0)
1752                                 return false;
1753                         actcell = tabular->GetFirstCellInRow(row);
1754                         actcell = tabular->GetCellAbove(actcell);
1755                 } else {
1756                         if (tabular->IsLastCell(actcell))
1757                                 return false;
1758                         ++actcell;
1759                 }
1760         } else {
1761                 if (!actcell) // first cell
1762                         return false;
1763                 --actcell;
1764         }
1765         if (lock) {
1766                 bool rtl = tabular->GetCellInset(actcell)->paragraph()->
1767                         isRightToLeftPar(bv->buffer()->params);
1768                 activateCellInset(bv, 0, 0, mouse_button::none, !rtl);
1769         }
1770         resetPos(bv);
1771         return true;
1772 }
1773
1774
1775 bool InsetTabular::deletable() const
1776 {
1777         return true;
1778 }
1779
1780
1781 void InsetTabular::setFont(BufferView * bv, LyXFont const & font, bool tall,
1782                            bool selectall)
1783 {
1784         if (selectall) {
1785                 setSelection(0, tabular->GetNumberOfCells() - 1);
1786         }
1787         if (hasSelection()) {
1788                 setUndo(bv, Undo::EDIT,
1789                         bv->text->cursor.par(),
1790                         bv->text->cursor.par()->next());
1791                 bool const frozen = undo_frozen;
1792                 if (!frozen)
1793                         freezeUndo();
1794                 // apply the fontchange on the whole selection
1795                 int sel_row_start;
1796                 int sel_row_end;
1797                 int sel_col_start;
1798                 int sel_col_end;
1799                 getSelection(sel_row_start, sel_row_end, sel_col_start, sel_col_end);
1800                 for(int i = sel_row_start; i <= sel_row_end; ++i) {
1801                         for(int j = sel_col_start; j <= sel_col_end; ++j) {
1802                                 tabular->GetCellInset(i, j)->setFont(bv, font, tall, true);
1803                         }
1804                 }
1805                 if (!frozen)
1806                         unFreezeUndo();
1807                 if (selectall)
1808                         clearSelection();
1809                 updateLocal(bv, INIT, true);
1810         }
1811         if (the_locking_inset)
1812                 the_locking_inset->setFont(bv, font, tall);
1813 }
1814
1815
1816 bool InsetTabular::tabularFeatures(BufferView * bv, string const & what)
1817 {
1818         LyXTabular::Feature action = LyXTabular::LAST_ACTION;
1819
1820         int i = 0;
1821         for (; tabularFeature[i].action != LyXTabular::LAST_ACTION; ++i) {
1822                 string const tmp = tabularFeature[i].feature;
1823
1824                 if (tmp == what.substr(0, tmp.length())) {
1825                         //if (!compare(tabularFeatures[i].feature.c_str(), what.c_str(),
1826                         //tabularFeatures[i].feature.length())) {
1827                         action = tabularFeature[i].action;
1828                         break;
1829                 }
1830         }
1831         if (action == LyXTabular::LAST_ACTION)
1832                 return false;
1833
1834         string const val =
1835                 ltrim(what.substr(tabularFeature[i].feature.length()));
1836         tabularFeatures(bv, action, val);
1837         return true;
1838 }
1839
1840 static void checkLongtableSpecial(LyXTabular::ltType & ltt,
1841                                   string const & special, bool & flag)
1842 {
1843         if (special == "dl_above") {
1844                 ltt.topDL = flag;
1845                 ltt.set = false;
1846         } else if (special == "dl_below") {
1847                 ltt.bottomDL = flag;
1848                 ltt.set = false;
1849         } else if (special == "empty") {
1850                 ltt.empty = flag;
1851                 ltt.set = false;
1852         } else if (flag) {
1853                 ltt.empty = false;
1854                 ltt.set = true;
1855         }
1856 }
1857
1858
1859 void InsetTabular::tabularFeatures(BufferView * bv,
1860                                    LyXTabular::Feature feature,
1861                                    string const & value)
1862 {
1863         int sel_col_start;
1864         int sel_col_end;
1865         int sel_row_start;
1866         int sel_row_end;
1867         bool setLines = false;
1868         LyXAlignment setAlign = LYX_ALIGN_LEFT;
1869         LyXTabular::VAlignment setVAlign = LyXTabular::LYX_VALIGN_TOP;
1870
1871         switch (feature) {
1872         case LyXTabular::M_ALIGN_LEFT:
1873         case LyXTabular::ALIGN_LEFT:
1874                 setAlign = LYX_ALIGN_LEFT;
1875                 break;
1876         case LyXTabular::M_ALIGN_RIGHT:
1877         case LyXTabular::ALIGN_RIGHT:
1878                 setAlign = LYX_ALIGN_RIGHT;
1879                 break;
1880         case LyXTabular::M_ALIGN_CENTER:
1881         case LyXTabular::ALIGN_CENTER:
1882                 setAlign = LYX_ALIGN_CENTER;
1883                 break;
1884         case LyXTabular::ALIGN_BLOCK:
1885                 setAlign = LYX_ALIGN_BLOCK;
1886                 break;
1887         case LyXTabular::M_VALIGN_TOP:
1888         case LyXTabular::VALIGN_TOP:
1889                 setVAlign = LyXTabular::LYX_VALIGN_TOP;
1890                 break;
1891         case LyXTabular::M_VALIGN_BOTTOM:
1892         case LyXTabular::VALIGN_BOTTOM:
1893                 setVAlign = LyXTabular::LYX_VALIGN_BOTTOM;
1894                 break;
1895         case LyXTabular::M_VALIGN_CENTER:
1896         case LyXTabular::VALIGN_CENTER:
1897                 setVAlign = LyXTabular::LYX_VALIGN_CENTER;
1898                 break;
1899         default:
1900                 break;
1901         }
1902         if (hasSelection()) {
1903                 getSelection(sel_row_start, sel_row_end, sel_col_start, sel_col_end);
1904         } else {
1905                 sel_col_start = sel_col_end = tabular->column_of_cell(actcell);
1906                 sel_row_start = sel_row_end = tabular->row_of_cell(actcell);
1907         }
1908         setUndo(bv, Undo::FINISH,
1909                 bv->text->cursor.par(),
1910                 bv->text->cursor.par()->next());
1911
1912         int row =  tabular->row_of_cell(actcell);
1913         int column = tabular->column_of_cell(actcell);
1914         bool flag = true;
1915         LyXTabular::ltType ltt;
1916
1917         switch (feature) {
1918         case LyXTabular::SET_PWIDTH:
1919         {
1920                 LyXLength const vallen(value);
1921                 LyXLength const & tmplen = tabular->GetColumnPWidth(actcell);
1922
1923                 bool const update = (tmplen != vallen);
1924                 tabular->SetColumnPWidth(actcell, vallen);
1925                 if (update) {
1926                         int cell;
1927                         for (int i = 0; i < tabular->rows(); ++i) {
1928                                 cell = tabular->GetCellNumber(i,column);
1929                                 tabular->GetCellInset(cell)->resizeLyXText(bv);
1930                         }
1931                         updateLocal(bv, INIT, true);
1932                 }
1933
1934                 if (vallen.zero()
1935                     && tabular->GetAlignment(actcell, true) == LYX_ALIGN_BLOCK)
1936                         tabularFeatures(bv, LyXTabular::ALIGN_CENTER, string());
1937                 else if (!vallen.zero()
1938                          && tabular->GetAlignment(actcell, true) != LYX_ALIGN_BLOCK)
1939                         tabularFeatures(bv, LyXTabular::ALIGN_BLOCK, string());
1940         }
1941         break;
1942         case LyXTabular::SET_MPWIDTH:
1943         {
1944                 LyXLength const vallen(value);
1945                 LyXLength const & tmplen = tabular->GetPWidth(actcell);
1946
1947                 bool const update = (tmplen != vallen);
1948                 tabular->SetMColumnPWidth(actcell, vallen);
1949                 if (update) {
1950                         for (int i = 0; i < tabular->rows(); ++i) {
1951                                 tabular->GetCellInset(tabular->GetCellNumber(i, column))->
1952                                         resizeLyXText(bv);
1953                         }
1954                         updateLocal(bv, INIT, true);
1955                 }
1956         }
1957         break;
1958         case LyXTabular::SET_SPECIAL_COLUMN:
1959         case LyXTabular::SET_SPECIAL_MULTI:
1960                 tabular->SetAlignSpecial(actcell,value,feature);
1961                 updateLocal(bv, FULL, true);
1962                 break;
1963         case LyXTabular::APPEND_ROW:
1964                 // append the row into the tabular
1965                 unlockInsetInInset(bv, the_locking_inset);
1966                 tabular->AppendRow(bv->buffer()->params, actcell);
1967                 updateLocal(bv, INIT, true);
1968                 break;
1969         case LyXTabular::APPEND_COLUMN:
1970                 // append the column into the tabular
1971                 unlockInsetInInset(bv, the_locking_inset);
1972                 tabular->AppendColumn(bv->buffer()->params, actcell);
1973                 actcell = tabular->GetCellNumber(row, column);
1974                 updateLocal(bv, INIT, true);
1975                 break;
1976         case LyXTabular::DELETE_ROW:
1977                 unlockInsetInInset(bv, the_locking_inset);
1978                 for(int i = sel_row_start; i <= sel_row_end; ++i) {
1979                         tabular->DeleteRow(sel_row_start);
1980                 }
1981                 if (sel_row_start >= tabular->rows())
1982                         --sel_row_start;
1983                 actcell = tabular->GetCellNumber(sel_row_start, column);
1984                 clearSelection();
1985                 updateLocal(bv, INIT, true);
1986                 break;
1987         case LyXTabular::DELETE_COLUMN:
1988                 unlockInsetInInset(bv, the_locking_inset);
1989                 for(int i = sel_col_start; i <= sel_col_end; ++i) {
1990                         tabular->DeleteColumn(sel_col_start);
1991                 }
1992                 if (sel_col_start >= tabular->columns())
1993                         --sel_col_start;
1994                 actcell = tabular->GetCellNumber(row, sel_col_start);
1995                 clearSelection();
1996                 updateLocal(bv, INIT, true);
1997                 break;
1998         case LyXTabular::M_TOGGLE_LINE_TOP:
1999                 flag = false;
2000         case LyXTabular::TOGGLE_LINE_TOP:
2001         {
2002                 bool lineSet = !tabular->TopLine(actcell, flag);
2003                 for (int i = sel_row_start; i <= sel_row_end; ++i)
2004                         for (int j = sel_col_start; j <= sel_col_end; ++j)
2005                                 tabular->SetTopLine(
2006                                         tabular->GetCellNumber(i, j),
2007                                         lineSet, flag);
2008                 updateLocal(bv, INIT, true);
2009                 break;
2010         }
2011
2012         case LyXTabular::M_TOGGLE_LINE_BOTTOM:
2013                 flag = false;
2014         case LyXTabular::TOGGLE_LINE_BOTTOM:
2015         {
2016                 bool lineSet = !tabular->BottomLine(actcell, flag);
2017                 for (int i = sel_row_start; i <= sel_row_end; ++i)
2018                         for (int j = sel_col_start; j <= sel_col_end; ++j)
2019                                 tabular->SetBottomLine(
2020                                         tabular->GetCellNumber(i, j),
2021                                         lineSet,
2022                                         flag);
2023                 updateLocal(bv, INIT, true);
2024                 break;
2025         }
2026
2027         case LyXTabular::M_TOGGLE_LINE_LEFT:
2028                 flag = false;
2029         case LyXTabular::TOGGLE_LINE_LEFT:
2030         {
2031                 bool lineSet = !tabular->LeftLine(actcell, flag);
2032                 for (int i = sel_row_start; i <= sel_row_end; ++i)
2033                         for (int j = sel_col_start; j <= sel_col_end; ++j)
2034                                 tabular->SetLeftLine(
2035                                         tabular->GetCellNumber(i,j),
2036                                         lineSet,
2037                                         flag);
2038                 updateLocal(bv, INIT, true);
2039                 break;
2040         }
2041
2042         case LyXTabular::M_TOGGLE_LINE_RIGHT:
2043                 flag = false;
2044         case LyXTabular::TOGGLE_LINE_RIGHT:
2045         {
2046                 bool lineSet = !tabular->RightLine(actcell, flag);
2047                 for (int i = sel_row_start; i <= sel_row_end; ++i)
2048                         for (int j = sel_col_start; j <= sel_col_end; ++j)
2049                                 tabular->SetRightLine(
2050                                         tabular->GetCellNumber(i,j),
2051                                         lineSet,
2052                                         flag);
2053                 updateLocal(bv, INIT, true);
2054                 break;
2055         }
2056
2057         case LyXTabular::M_ALIGN_LEFT:
2058         case LyXTabular::M_ALIGN_RIGHT:
2059         case LyXTabular::M_ALIGN_CENTER:
2060                 flag = false;
2061         case LyXTabular::ALIGN_LEFT:
2062         case LyXTabular::ALIGN_RIGHT:
2063         case LyXTabular::ALIGN_CENTER:
2064         case LyXTabular::ALIGN_BLOCK:
2065                 for (int i = sel_row_start; i <= sel_row_end; ++i)
2066                         for (int j = sel_col_start; j <= sel_col_end; ++j)
2067                                 tabular->SetAlignment(
2068                                         tabular->GetCellNumber(i, j),
2069                                         setAlign,
2070                                         flag);
2071                 updateLocal(bv, INIT, true);
2072                 break;
2073         case LyXTabular::M_VALIGN_TOP:
2074         case LyXTabular::M_VALIGN_BOTTOM:
2075         case LyXTabular::M_VALIGN_CENTER:
2076                 flag = false;
2077         case LyXTabular::VALIGN_TOP:
2078         case LyXTabular::VALIGN_BOTTOM:
2079         case LyXTabular::VALIGN_CENTER:
2080                 for (int i = sel_row_start; i <= sel_row_end; ++i)
2081                         for (int j = sel_col_start; j <= sel_col_end; ++j)
2082                                 tabular->SetVAlignment(
2083                                         tabular->GetCellNumber(i, j),
2084                                         setVAlign, flag);
2085                 updateLocal(bv, INIT, true);
2086                 break;
2087         case LyXTabular::MULTICOLUMN:
2088         {
2089                 if (sel_row_start != sel_row_end) {
2090                         Alert::alert(_("Impossible Operation!"),
2091                                    _("Multicolumns can only be horizontally."),
2092                                    _("Sorry."));
2093                         return;
2094                 }
2095                 // just multicol for one Single Cell
2096                 if (!hasSelection()) {
2097                         // check wether we are completly in a multicol
2098                         if (tabular->IsMultiColumn(actcell)) {
2099                                 tabular->UnsetMultiColumn(actcell);
2100                                 updateLocal(bv, INIT, true);
2101                         } else {
2102                                 tabular->SetMultiColumn(bv->buffer(), actcell, 1);
2103                                 updateLocal(bv, CELL, true);
2104                         }
2105                         return;
2106                 }
2107                 // we have a selection so this means we just add all this
2108                 // cells to form a multicolumn cell
2109                 int s_start;
2110                 int s_end;
2111
2112                 if (sel_cell_start > sel_cell_end) {
2113                         s_start = sel_cell_end;
2114                         s_end = sel_cell_start;
2115                 } else {
2116                         s_start = sel_cell_start;
2117                         s_end = sel_cell_end;
2118                 }
2119                 tabular->SetMultiColumn(bv->buffer(), s_start, s_end - s_start + 1);
2120                 actcell = s_start;
2121                 clearSelection();
2122                 updateLocal(bv, INIT, true);
2123                 break;
2124         }
2125         case LyXTabular::SET_ALL_LINES:
2126                 setLines = true;
2127         case LyXTabular::UNSET_ALL_LINES:
2128                 for (int i = sel_row_start; i <= sel_row_end; ++i)
2129                         for (int j = sel_col_start; j <= sel_col_end; ++j)
2130                                 tabular->SetAllLines(
2131                                         tabular->GetCellNumber(i,j), setLines);
2132                 updateLocal(bv, INIT, true);
2133                 break;
2134         case LyXTabular::SET_LONGTABULAR:
2135                 tabular->SetLongTabular(true);
2136                 updateLocal(bv, INIT, true); // because this toggles displayed
2137                 break;
2138         case LyXTabular::UNSET_LONGTABULAR:
2139                 tabular->SetLongTabular(false);
2140                 updateLocal(bv, INIT, true); // because this toggles displayed
2141                 break;
2142         case LyXTabular::SET_ROTATE_TABULAR:
2143                 tabular->SetRotateTabular(true);
2144                 break;
2145         case LyXTabular::UNSET_ROTATE_TABULAR:
2146                 tabular->SetRotateTabular(false);
2147                 break;
2148         case LyXTabular::SET_ROTATE_CELL:
2149                 for (int i = sel_row_start; i <= sel_row_end; ++i)
2150                         for (int j = sel_col_start; j<=sel_col_end; ++j)
2151                                 tabular->SetRotateCell(
2152                                         tabular->GetCellNumber(i, j),
2153                                         true);
2154                 break;
2155         case LyXTabular::UNSET_ROTATE_CELL:
2156                 for (int i = sel_row_start; i <= sel_row_end; ++i)
2157                         for (int j = sel_col_start; j <= sel_col_end; ++j)
2158                                 tabular->SetRotateCell(
2159                                         tabular->GetCellNumber(i, j), false);
2160                 break;
2161         case LyXTabular::SET_USEBOX:
2162         {
2163                 LyXTabular::BoxType val = LyXTabular::BoxType(strToInt(value));
2164                 if (val == tabular->GetUsebox(actcell))
2165                         val = LyXTabular::BOX_NONE;
2166                 for (int i = sel_row_start; i <= sel_row_end; ++i)
2167                         for (int j = sel_col_start; j <= sel_col_end; ++j)
2168                                 tabular->SetUsebox(
2169                                         tabular->GetCellNumber(i, j), val);
2170                 break;
2171         }
2172         case LyXTabular::UNSET_LTFIRSTHEAD:
2173                 flag = false;
2174         case LyXTabular::SET_LTFIRSTHEAD:
2175                 (void)tabular->GetRowOfLTFirstHead(row, ltt);
2176                 checkLongtableSpecial(ltt, value, flag);
2177                 tabular->SetLTHead(row, flag, ltt, true);
2178                 break;
2179         case LyXTabular::UNSET_LTHEAD:
2180                 flag = false;
2181         case LyXTabular::SET_LTHEAD:
2182                 (void)tabular->GetRowOfLTHead(row, ltt);
2183                 checkLongtableSpecial(ltt, value, flag);
2184                 tabular->SetLTHead(row, flag, ltt, false);
2185                 break;
2186         case LyXTabular::UNSET_LTFOOT:
2187                 flag = false;
2188         case LyXTabular::SET_LTFOOT:
2189                 (void)tabular->GetRowOfLTFoot(row, ltt);
2190                 checkLongtableSpecial(ltt, value, flag);
2191                 tabular->SetLTFoot(row, flag, ltt, false);
2192                 break;
2193         case LyXTabular::UNSET_LTLASTFOOT:
2194                 flag = false;
2195         case LyXTabular::SET_LTLASTFOOT:
2196                 (void)tabular->GetRowOfLTLastFoot(row, ltt);
2197                 checkLongtableSpecial(ltt, value, flag);
2198                 tabular->SetLTFoot(row, flag, ltt, true);
2199                 break;
2200         case LyXTabular::SET_LTNEWPAGE:
2201         {
2202                 bool what = !tabular->GetLTNewPage(row);
2203                 tabular->SetLTNewPage(row, what);
2204                 break;
2205         }
2206         // dummy stuff just to avoid warnings
2207         case LyXTabular::LAST_ACTION:
2208                 break;
2209         }
2210 }
2211
2212
2213 bool InsetTabular::activateCellInset(BufferView * bv, int x, int y, mouse_button::state button,
2214                                      bool behind)
2215 {
2216         UpdatableInset * inset =
2217                 static_cast<UpdatableInset*>(tabular->GetCellInset(actcell));
2218         LyXFont font(LyXFont::ALL_SANE);
2219         if (behind) {
2220                 x = inset->x() + inset->width(bv, font);
2221                 y = inset->descent(bv, font);
2222         }
2223         //inset_x = cursor.x() - top_x + tabular->GetBeginningOfTextInCell(actcell);
2224         //inset_y = cursor.y();
2225         inset->edit(bv, x,  y, button);
2226         if (!the_locking_inset)
2227                 return false;
2228         updateLocal(bv, CELL, false);
2229         return (the_locking_inset != 0);
2230 }
2231
2232
2233 bool InsetTabular::activateCellInsetAbs(BufferView * bv, int x, int y,
2234                                         mouse_button::state button)
2235 {
2236         inset_x = cursor_.x()
2237                 - top_x + tabular->GetBeginningOfTextInCell(actcell);
2238         inset_y = cursor_.y();
2239         return activateCellInset(bv, x - inset_x, y - inset_y, button);
2240 }
2241
2242
2243 bool InsetTabular::insetHit(BufferView *, int x, int) const
2244 {
2245         return (x + top_x)
2246                 > (cursor_.x() + tabular->GetBeginningOfTextInCell(actcell));
2247 }
2248
2249
2250 // This returns paperWidth() if the cell-width is unlimited or the width
2251 // in pixels if we have a pwidth for this cell.
2252 int InsetTabular::getMaxWidthOfCell(BufferView * bv, int cell) const
2253 {
2254         LyXLength const len = tabular->GetPWidth(cell);
2255
2256         if (len.zero())
2257                 return -1;
2258         return len.inPixels(latexTextWidth(bv));
2259 }
2260
2261
2262 int InsetTabular::getMaxWidth(BufferView * bv,
2263                               UpdatableInset const * inset) const
2264 {
2265         int cell = tabular->GetCellFromInset(inset, actcell);
2266
2267         if (cell == -1) {
2268                 lyxerr << "Own inset not found, shouldn't really happen!"
2269                        << endl;
2270                 return -1;
2271         }
2272
2273         int w = getMaxWidthOfCell(bv, cell);
2274         if (w > 0) {
2275                 // because the inset then subtracts it's top_x and owner->x()
2276                 w += (inset->x() - top_x);
2277         }
2278
2279         return w;
2280 }
2281
2282
2283 void InsetTabular::deleteLyXText(BufferView * bv, bool recursive) const
2284 {
2285         resizeLyXText(bv, recursive);
2286 }
2287
2288
2289 void InsetTabular::resizeLyXText(BufferView * bv, bool force) const
2290 {
2291         if (force) {
2292                 for(int i = 0; i < tabular->rows(); ++i) {
2293                         for(int j = 0; j < tabular->columns(); ++j) {
2294                                 tabular->GetCellInset(i, j)->resizeLyXText(bv, true);
2295                         }
2296                 }
2297         }
2298         need_update = FULL;
2299 }
2300
2301
2302 LyXText * InsetTabular::getLyXText(BufferView const * bv,
2303                                    bool const recursive) const
2304 {
2305         if (the_locking_inset)
2306                 return the_locking_inset->getLyXText(bv, recursive);
2307 #if 0
2308         // if we're locked lock the actual insettext and return it's LyXText!!!
2309         if (locked) {
2310                 UpdatableInset * inset =
2311                         static_cast<UpdatableInset*>(tabular->GetCellInset(actcell));
2312                 inset->edit(const_cast<BufferView *>(bv), 0,  0, 0);
2313                 return the_locking_inset->getLyXText(bv, recursive);
2314         }
2315 #endif
2316         return Inset::getLyXText(bv, recursive);
2317 }
2318
2319
2320 bool InsetTabular::showInsetDialog(BufferView * bv) const
2321 {
2322         if (!the_locking_inset || !the_locking_inset->showInsetDialog(bv))
2323                 bv->owner()->getDialogs().
2324                         showTabular(const_cast<InsetTabular *>(this));
2325         return true;
2326 }
2327
2328
2329 void InsetTabular::openLayoutDialog(BufferView * bv) const
2330 {
2331         if (the_locking_inset) {
2332                 InsetTabular * i = static_cast<InsetTabular *>
2333                         (the_locking_inset->getFirstLockingInsetOfType(TABULAR_CODE));
2334                 if (i) {
2335                         i->openLayoutDialog(bv);
2336                         return;
2337                 }
2338         }
2339         bv->owner()->getDialogs().showTabular(
2340                 const_cast<InsetTabular *>(this));
2341 }
2342
2343
2344 //
2345 // function returns an object as defined in func_status.h:
2346 // states OK, Unknown, Disabled, On, Off.
2347 //
2348 FuncStatus InsetTabular::getStatus(string const & what) const
2349 {
2350         int action = LyXTabular::LAST_ACTION;
2351         FuncStatus status;
2352
2353         int i = 0;
2354         for (; tabularFeature[i].action != LyXTabular::LAST_ACTION; ++i) {
2355                 string const tmp = tabularFeature[i].feature;
2356                 if (tmp == what.substr(0, tmp.length())) {
2357                         //if (!compare(tabularFeatures[i].feature.c_str(), what.c_str(),
2358                         //   tabularFeatures[i].feature.length())) {
2359                         action = tabularFeature[i].action;
2360                         break;
2361                 }
2362         }
2363         if (action == LyXTabular::LAST_ACTION) {
2364                 status.clear();
2365                 return status.unknown(true);
2366         }
2367
2368         string const argument = ltrim(what.substr(tabularFeature[i].feature.length()));
2369
2370         int sel_row_start;
2371         int sel_row_end;
2372         int dummy;
2373         LyXTabular::ltType dummyltt;
2374         bool flag = true;
2375
2376         if (hasSelection()) {
2377                 getSelection(sel_row_start, sel_row_end, dummy, dummy);
2378         } else {
2379                 sel_row_start = sel_row_end = tabular->row_of_cell(actcell);
2380         }
2381
2382         switch (action) {
2383         case LyXTabular::SET_PWIDTH:
2384         case LyXTabular::SET_MPWIDTH:
2385         case LyXTabular::SET_SPECIAL_COLUMN:
2386         case LyXTabular::SET_SPECIAL_MULTI:
2387                 return status.disabled(true);
2388
2389         case LyXTabular::APPEND_ROW:
2390         case LyXTabular::APPEND_COLUMN:
2391         case LyXTabular::DELETE_ROW:
2392         case LyXTabular::DELETE_COLUMN:
2393         case LyXTabular::SET_ALL_LINES:
2394         case LyXTabular::UNSET_ALL_LINES:
2395                 return status.clear();
2396
2397         case LyXTabular::MULTICOLUMN:
2398                 status.setOnOff(tabular->IsMultiColumn(actcell));
2399                 break;
2400         case LyXTabular::M_TOGGLE_LINE_TOP:
2401                 flag = false;
2402         case LyXTabular::TOGGLE_LINE_TOP:
2403                 status.setOnOff(tabular->TopLine(actcell, flag));
2404                 break;
2405         case LyXTabular::M_TOGGLE_LINE_BOTTOM:
2406                 flag = false;
2407         case LyXTabular::TOGGLE_LINE_BOTTOM:
2408                 status.setOnOff(tabular->BottomLine(actcell, flag));
2409                 break;
2410         case LyXTabular::M_TOGGLE_LINE_LEFT:
2411                 flag = false;
2412         case LyXTabular::TOGGLE_LINE_LEFT:
2413                 status.setOnOff(tabular->LeftLine(actcell, flag));
2414                 break;
2415         case LyXTabular::M_TOGGLE_LINE_RIGHT:
2416                 flag = false;
2417         case LyXTabular::TOGGLE_LINE_RIGHT:
2418                 status.setOnOff(tabular->RightLine(actcell, flag));
2419                 break;
2420         case LyXTabular::M_ALIGN_LEFT:
2421                 flag = false;
2422         case LyXTabular::ALIGN_LEFT:
2423                 status.setOnOff(tabular->GetAlignment(actcell, flag) == LYX_ALIGN_LEFT);
2424                 break;
2425         case LyXTabular::M_ALIGN_RIGHT:
2426                 flag = false;
2427         case LyXTabular::ALIGN_RIGHT:
2428                 status.setOnOff(tabular->GetAlignment(actcell, flag) == LYX_ALIGN_RIGHT);
2429                 break;
2430         case LyXTabular::M_ALIGN_CENTER:
2431                 flag = false;
2432         case LyXTabular::ALIGN_CENTER:
2433                 status.setOnOff(tabular->GetAlignment(actcell, flag) == LYX_ALIGN_CENTER);
2434                 break;
2435         case LyXTabular::ALIGN_BLOCK:
2436                 status.disabled(tabular->GetPWidth(actcell).zero());
2437                 status.setOnOff(tabular->GetAlignment(actcell, flag) == LYX_ALIGN_BLOCK);
2438                 break;
2439         case LyXTabular::M_VALIGN_TOP:
2440                 flag = false;
2441         case LyXTabular::VALIGN_TOP:
2442                 status.setOnOff(tabular->GetVAlignment(actcell, flag) == LyXTabular::LYX_VALIGN_TOP);
2443                 break;
2444         case LyXTabular::M_VALIGN_BOTTOM:
2445                 flag = false;
2446         case LyXTabular::VALIGN_BOTTOM:
2447                 status.setOnOff(tabular->GetVAlignment(actcell, flag) == LyXTabular::LYX_VALIGN_BOTTOM);
2448                 break;
2449         case LyXTabular::M_VALIGN_CENTER:
2450                 flag = false;
2451         case LyXTabular::VALIGN_CENTER:
2452                 status.setOnOff(tabular->GetVAlignment(actcell, flag) == LyXTabular::LYX_VALIGN_CENTER);
2453                 break;
2454         case LyXTabular::SET_LONGTABULAR:
2455                 status.setOnOff(tabular->IsLongTabular());
2456                 break;
2457         case LyXTabular::UNSET_LONGTABULAR:
2458                 status.setOnOff(!tabular->IsLongTabular());
2459                 break;
2460         case LyXTabular::SET_ROTATE_TABULAR:
2461                 status.setOnOff(tabular->GetRotateTabular());
2462                 break;
2463         case LyXTabular::UNSET_ROTATE_TABULAR:
2464                 status.setOnOff(!tabular->GetRotateTabular());
2465                 break;
2466         case LyXTabular::SET_ROTATE_CELL:
2467                 status.setOnOff(tabular->GetRotateCell(actcell));
2468                 break;
2469         case LyXTabular::UNSET_ROTATE_CELL:
2470                 status.setOnOff(!tabular->GetRotateCell(actcell));
2471                 break;
2472         case LyXTabular::SET_USEBOX:
2473                 status.setOnOff(strToInt(argument) == tabular->GetUsebox(actcell));
2474                 break;
2475         case LyXTabular::SET_LTFIRSTHEAD:
2476                 status.setOnOff(tabular->GetRowOfLTHead(sel_row_start, dummyltt));
2477                 break;
2478         case LyXTabular::SET_LTHEAD:
2479                 status.setOnOff(tabular->GetRowOfLTHead(sel_row_start, dummyltt));
2480                 break;
2481         case LyXTabular::SET_LTFOOT:
2482                 status.setOnOff(tabular->GetRowOfLTFoot(sel_row_start, dummyltt));
2483                 break;
2484         case LyXTabular::SET_LTLASTFOOT:
2485                 status.setOnOff(tabular->GetRowOfLTFoot(sel_row_start, dummyltt));
2486                 break;
2487         case LyXTabular::SET_LTNEWPAGE:
2488                 status.setOnOff(tabular->GetLTNewPage(sel_row_start));
2489                 break;
2490         default:
2491                 status.clear();
2492                 status.disabled(true);
2493                 break;
2494         }
2495         return status;
2496 }
2497
2498
2499 vector<string> const InsetTabular::getLabelList() const
2500 {
2501         return tabular->getLabelList();
2502 }
2503
2504
2505 bool InsetTabular::copySelection(BufferView * bv)
2506 {
2507         if (!hasSelection())
2508                 return false;
2509
2510         int sel_col_start = tabular->column_of_cell(sel_cell_start);
2511         int sel_col_end = tabular->column_of_cell(sel_cell_end);
2512         if (sel_col_start > sel_col_end) {
2513                 sel_col_start = sel_col_end;
2514                 sel_col_end = tabular->right_column_of_cell(sel_cell_start);
2515         } else {
2516                 sel_col_end = tabular->right_column_of_cell(sel_cell_end);
2517         }
2518         int const columns = sel_col_end - sel_col_start + 1;
2519
2520         int sel_row_start = tabular->row_of_cell(sel_cell_start);
2521         int sel_row_end = tabular->row_of_cell(sel_cell_end);
2522         if (sel_row_start > sel_row_end) {
2523                 swap(sel_row_start, sel_row_end);
2524         }
2525         int const rows = sel_row_end - sel_row_start + 1;
2526
2527         delete paste_tabular;
2528         paste_tabular = new LyXTabular(bv->buffer()->params,
2529                                        this, *tabular); // rows, columns);
2530         for (int i = 0; i < sel_row_start; ++i)
2531                 paste_tabular->DeleteRow(0);
2532         while (paste_tabular->rows() > rows)
2533                 paste_tabular->DeleteRow(rows);
2534         paste_tabular->SetTopLine(0, true, true);
2535         paste_tabular->SetBottomLine(paste_tabular->GetFirstCellInRow(rows - 1),
2536                                      true, true);
2537         for (int i = 0; i < sel_col_start; ++i)
2538                 paste_tabular->DeleteColumn(0);
2539         while (paste_tabular->columns() > columns)
2540                 paste_tabular->DeleteColumn(columns);
2541         paste_tabular->SetLeftLine(0, true, true);
2542         paste_tabular->SetRightLine(paste_tabular->GetLastCellInRow(0),
2543                                     true, true);
2544
2545         ostringstream sstr;
2546         paste_tabular->ascii(bv->buffer(), sstr,
2547                              (int)parOwner()->params().depth(), true, '\t');
2548         bv->stuffClipboard(STRCONV(sstr.str()));
2549         return true;
2550 }
2551
2552
2553 bool InsetTabular::pasteSelection(BufferView * bv)
2554 {
2555         if (!paste_tabular)
2556                 return false;
2557
2558         for (int r1 = 0, r2 = actrow;
2559              (r1 < paste_tabular->rows()) && (r2 < tabular->rows());
2560              ++r1, ++r2) {
2561                 for(int c1 = 0, c2 = actcol;
2562                     (c1 < paste_tabular->columns()) && (c2 < tabular->columns());
2563                     ++c1, ++c2) {
2564                         if (paste_tabular->IsPartOfMultiColumn(r1,c1) &&
2565                             tabular->IsPartOfMultiColumn(r2,c2))
2566                                 continue;
2567                         if (paste_tabular->IsPartOfMultiColumn(r1,c1)) {
2568                                 --c2;
2569                                 continue;
2570                         }
2571                         if (tabular->IsPartOfMultiColumn(r2,c2)) {
2572                                 --c1;
2573                                 continue;
2574                         }
2575                         int const n1 = paste_tabular->GetCellNumber(r1, c1);
2576                         int const n2 = tabular->GetCellNumber(r2, c2);
2577                         *(tabular->GetCellInset(n2)) = *(paste_tabular->GetCellInset(n1));
2578                         tabular->GetCellInset(n2)->setOwner(this);
2579                         tabular->GetCellInset(n2)->deleteLyXText(bv);
2580                 }
2581         }
2582         return true;
2583 }
2584
2585
2586 bool InsetTabular::cutSelection()
2587 {
2588         if (!hasSelection())
2589                 return false;
2590
2591         int sel_col_start = tabular->column_of_cell(sel_cell_start);
2592         int sel_col_end = tabular->column_of_cell(sel_cell_end);
2593         if (sel_col_start > sel_col_end) {
2594                 sel_col_start = sel_col_end;
2595                 sel_col_end = tabular->right_column_of_cell(sel_cell_start);
2596         } else {
2597                 sel_col_end = tabular->right_column_of_cell(sel_cell_end);
2598         }
2599         int sel_row_start = tabular->row_of_cell(sel_cell_start);
2600         int sel_row_end = tabular->row_of_cell(sel_cell_end);
2601         if (sel_row_start > sel_row_end) {
2602                 swap(sel_row_start, sel_row_end);
2603         }
2604         if (sel_cell_start > sel_cell_end) {
2605                 swap(sel_cell_start, sel_cell_end);
2606         }
2607         for (int i = sel_row_start; i <= sel_row_end; ++i) {
2608                 for (int j = sel_col_start; j <= sel_col_end; ++j) {
2609                         tabular->GetCellInset(tabular->GetCellNumber(i, j))->clear();
2610                 }
2611         }
2612         return true;
2613 }
2614
2615
2616 bool InsetTabular::isRightToLeft(BufferView * bv)
2617 {
2618         return bv->getParentLanguage(this)->RightToLeft();
2619 }
2620
2621
2622 bool InsetTabular::nodraw() const
2623 {
2624         if (!UpdatableInset::nodraw() && the_locking_inset)
2625                 return the_locking_inset->nodraw();
2626         return UpdatableInset::nodraw();
2627 }
2628
2629
2630 int InsetTabular::scroll(bool recursive) const
2631 {
2632         int sx = UpdatableInset::scroll(false);
2633
2634         if (recursive && the_locking_inset)
2635                 sx += the_locking_inset->scroll(recursive);
2636
2637         return sx;
2638 }
2639
2640
2641 bool InsetTabular::doClearArea() const
2642 {
2643         return !locked || (need_update & (FULL|INIT));
2644 }
2645
2646
2647 void InsetTabular::getSelection(int & srow, int & erow,
2648                                 int & scol, int & ecol) const
2649 {
2650         int const start = hasSelection() ? sel_cell_start : actcell;
2651         int const end = hasSelection() ? sel_cell_end : actcell;
2652
2653         srow = tabular->row_of_cell(start);
2654         erow = tabular->row_of_cell(end);
2655         if (srow > erow) {
2656                 swap(srow, erow);
2657         }
2658
2659         scol = tabular->column_of_cell(start);
2660         ecol = tabular->column_of_cell(end);
2661         if (scol > ecol) {
2662                 swap(scol, ecol);
2663         } else {
2664                 ecol = tabular->right_column_of_cell(end);
2665         }
2666 }
2667
2668
2669 Paragraph * InsetTabular::getParFromID(int id) const
2670 {
2671         Paragraph * result;
2672         for(int i = 0; i < tabular->rows(); ++i) {
2673                 for(int j = 0; j < tabular->columns(); ++j) {
2674                         if ((result = tabular->GetCellInset(i, j)->getParFromID(id)))
2675                                 return result;
2676                 }
2677         }
2678         return 0;
2679 }
2680
2681
2682 Paragraph * InsetTabular::firstParagraph() const
2683 {
2684         if (the_locking_inset)
2685                 return the_locking_inset->firstParagraph();
2686         return 0;
2687 }
2688
2689
2690 Paragraph * InsetTabular::getFirstParagraph(int i) const
2691 {
2692         return (i < tabular->GetNumberOfCells())
2693                 ? tabular->GetCellInset(i)->getFirstParagraph(0)
2694                 : 0;
2695 }
2696
2697
2698 LyXCursor const & InsetTabular::cursor(BufferView * bv) const
2699 {
2700         if (the_locking_inset)
2701                 return the_locking_inset->cursor(bv);
2702         return Inset::cursor(bv);
2703 }
2704
2705
2706 Inset * InsetTabular::getInsetFromID(int id_arg) const
2707 {
2708         if (id_arg == id())
2709                 return const_cast<InsetTabular *>(this);
2710
2711         Inset * result;
2712         for(int i = 0; i < tabular->rows(); ++i) {
2713                 for(int j = 0; j < tabular->columns(); ++j) {
2714                         if ((result = tabular->GetCellInset(i, j)->getInsetFromID(id_arg)))
2715                                 return result;
2716                 }
2717         }
2718         return 0;
2719 }
2720
2721
2722 WordLangTuple const
2723 InsetTabular::selectNextWordToSpellcheck(BufferView * bv, float & value) const
2724 {
2725         nodraw(true);
2726         if (the_locking_inset) {
2727                 WordLangTuple word(the_locking_inset->selectNextWordToSpellcheck(bv, value));
2728                 if (!word.word().empty()) {
2729                         nodraw(false);
2730                         return word;
2731                 }
2732                 if (tabular->IsLastCell(actcell)) {
2733                         bv->unlockInset(const_cast<InsetTabular *>(this));
2734                         nodraw(false);
2735                         return WordLangTuple();
2736                 }
2737                 ++actcell;
2738         }
2739         // otherwise we have to lock the next inset and ask for it's selecttion
2740         UpdatableInset * inset =
2741                 static_cast<UpdatableInset*>(tabular->GetCellInset(actcell));
2742         inset->edit(bv, 0,  0, mouse_button::none);
2743         WordLangTuple word(selectNextWordInt(bv, value));
2744         nodraw(false);
2745         if (!word.word().empty())
2746                 resetPos(bv);
2747         return word;
2748 }
2749
2750
2751 WordLangTuple InsetTabular::selectNextWordInt(BufferView * bv, float & value) const
2752 {
2753         // when entering this function the inset should be ALWAYS locked!
2754         lyx::Assert(the_locking_inset);
2755
2756         WordLangTuple word(the_locking_inset->selectNextWordToSpellcheck(bv, value));
2757         if (!word.word().empty())
2758                 return word;
2759
2760         if (tabular->IsLastCell(actcell)) {
2761                 bv->unlockInset(const_cast<InsetTabular *>(this));
2762                 return WordLangTuple();
2763         }
2764
2765         // otherwise we have to lock the next inset and ask for it's selecttion
2766         UpdatableInset * inset =
2767                 static_cast<UpdatableInset*>(tabular->GetCellInset(++actcell));
2768         inset->edit(bv);
2769         return selectNextWordInt(bv, value);
2770 }
2771
2772
2773 void InsetTabular::selectSelectedWord(BufferView * bv)
2774 {
2775         if (the_locking_inset) {
2776                 the_locking_inset->selectSelectedWord(bv);
2777                 return;
2778         }
2779         return;
2780 }
2781
2782
2783 void InsetTabular::toggleSelection(BufferView * bv, bool kill_selection)
2784 {
2785         if (the_locking_inset) {
2786                 the_locking_inset->toggleSelection(bv, kill_selection);
2787         }
2788 }
2789
2790
2791 bool InsetTabular::searchForward(BufferView * bv, string const & str,
2792                                  bool cs, bool mw)
2793 {
2794         if (the_locking_inset) {
2795                 if (the_locking_inset->searchForward(bv, str, cs, mw)) {
2796                         updateLocal(bv, CELL, false);
2797                         return true;
2798                 }
2799                 if (tabular->IsLastCell(actcell))
2800                         return false;
2801                 ++actcell;
2802         }
2803         InsetText * inset = tabular->GetCellInset(actcell);
2804         if (inset->searchForward(bv, str, cs, mw)) {
2805                 updateLocal(bv, FULL, false);
2806                 return true;
2807         }
2808         while (!tabular->IsLastCell(actcell)) {
2809                 ++actcell;
2810                 inset = tabular->GetCellInset(actcell);
2811                 if (inset->searchForward(bv, str, cs, mw)) {
2812                         updateLocal(bv, FULL, false);
2813                         return true;
2814                 }
2815         }
2816         return false;
2817 }
2818
2819
2820 bool InsetTabular::searchBackward(BufferView * bv, string const & str,
2821                                bool cs, bool mw)
2822 {
2823         if (the_locking_inset) {
2824                 if (the_locking_inset->searchBackward(bv, str, cs, mw)) {
2825                         updateLocal(bv, CELL, false);
2826                         return true;
2827                 }
2828         }
2829         if (!locked)
2830                 actcell = tabular->GetNumberOfCells();
2831
2832         while (actcell) {
2833                 --actcell;
2834                 InsetText * inset = tabular->GetCellInset(actcell);
2835                 if (inset->searchBackward(bv, str, cs, mw)) {
2836                         updateLocal(bv, CELL, false);
2837                         return true;
2838                 }
2839         }
2840         return false;
2841 }
2842
2843
2844 bool InsetTabular::insetAllowed(Inset::Code code) const
2845 {
2846         if (the_locking_inset)
2847                 return the_locking_inset->insetAllowed(code);
2848         // we return true here because if the inset is not locked someone
2849         // wants to insert something in one of our insettexts and we generally
2850         // allow to do so.
2851         return true;
2852 }
2853
2854
2855 bool InsetTabular::forceDefaultParagraphs(Inset const * in) const
2856 {
2857         const int cell = tabular->GetCellFromInset(in, actcell);
2858
2859         if (cell != -1)
2860                 return tabular->GetPWidth(cell).zero();
2861
2862         // well we didn't obviously find it so maybe our owner knows more
2863         if (owner())
2864                 return owner()->forceDefaultParagraphs(in);
2865         // if we're here there is really something strange going on!!!
2866         return false;
2867 }
2868
2869 bool InsetTabular::insertAsciiString(BufferView * bv, string const & buf,
2870                                      bool usePaste)
2871 {
2872         if (buf.length() <= 0)
2873                 return true;
2874
2875         int cols = 1;
2876         int rows = 1;
2877         int maxCols = 1;
2878         string::size_type len = buf.length();
2879         string::size_type p = 0;
2880
2881         while (p < len &&
2882                ((p = buf.find_first_of("\t\n", p)) != string::npos))
2883         {
2884                 switch (buf[p]) {
2885                 case '\t':
2886                         ++cols;
2887                         break;
2888                 case '\n':
2889                         if ((p+1) < len)
2890                                 ++rows;
2891                         maxCols = max(cols, maxCols);
2892                         cols = 1;
2893                         break;
2894                 }
2895                 ++p;
2896         }
2897         maxCols = max(cols, maxCols);
2898         LyXTabular * loctab;
2899         int cell = 0;
2900         int ocol = 0;
2901         int row = 0;
2902         if (usePaste) {
2903                 delete paste_tabular;
2904                 paste_tabular = new LyXTabular(bv->buffer()->params,
2905                                                this, rows, maxCols);
2906                 loctab = paste_tabular;
2907                 cols = 0;
2908         } else {
2909                 loctab = tabular.get();
2910                 cell = actcell;
2911                 ocol = actcol;
2912                 row = actrow;
2913         }
2914         string::size_type op = 0;
2915         int cells = loctab->GetNumberOfCells();
2916         p = 0;
2917         cols = ocol;
2918         rows = loctab->rows();
2919         int const columns = loctab->columns();
2920         while ((cell < cells) && (p < len) && (row < rows) &&
2921                (p = buf.find_first_of("\t\n", p)) != string::npos)
2922         {
2923                 if (p >= len)
2924                         break;
2925                 switch (buf[p]) {
2926                 case '\t':
2927                         // we can only set this if we are not too far right
2928                         if (cols < columns) {
2929                                 InsetText * ti = loctab->GetCellInset(cell);
2930                                 LyXFont const font = ti->getLyXText(bv)->
2931                                         getFont(bv->buffer(), ti->paragraph(), 0);
2932                                 ti->setText(buf.substr(op, p-op), font);
2933                                 ++cols;
2934                                 ++cell;
2935                         }
2936                         break;
2937                 case '\n':
2938                         // we can only set this if we are not too far right
2939                         if (cols < columns) {
2940                                 InsetText * ti = loctab->GetCellInset(cell);
2941                                 LyXFont const font = ti->getLyXText(bv)->
2942                                         getFont(bv->buffer(), ti->paragraph(), 0);
2943                                 ti->setText(buf.substr(op, p-op), font);
2944                         }
2945                         cols = ocol;
2946                         ++row;
2947                         if (row < rows)
2948                                 cell = loctab->GetCellNumber(row, cols);
2949                         break;
2950                 }
2951                 ++p;
2952                 op = p;
2953         }
2954         // check for the last cell if there is no trailing '\n'
2955         if ((cell < cells) && (op < len)) {
2956                 InsetText * ti = loctab->GetCellInset(cell);
2957                 LyXFont const font = ti->getLyXText(bv)->
2958                         getFont(bv->buffer(), ti->paragraph(), 0);
2959                 ti->setText(buf.substr(op, len-op), font);
2960         }
2961
2962         return true;
2963 }
2964
2965
2966 void InsetTabular::addPreview(grfx::PreviewLoader & loader) const
2967 {
2968         int const rows = tabular->rows();
2969         int const columns = tabular->columns();
2970         for (int i = 0; i < rows; ++i) {
2971                 for (int j = 0; j < columns; ++j) {
2972                         tabular->GetCellInset(i,j)->addPreview(loader);
2973                 }
2974         }
2975 }