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