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