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