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