]> git.lyx.org Git - features.git/blob - src/insets/insettabular.C
Some small fixes and the mouse now works for minipages again.
[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     // 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     bool hs = hasSelection();
744
745     result=DISPATCHED;
746     // this one have priority over the locked InsetText!
747     switch (action) {
748     case LFUN_SHIFT_TAB:
749     case LFUN_TAB:
750     {
751         HideInsetCursor(bv);
752         if (the_locking_inset) {
753             UnlockInsetInInset(bv, the_locking_inset);
754             the_locking_inset = 0;
755         }
756         if (action == LFUN_TAB)
757             moveNextCell(bv, old_locking_inset != 0);
758         else
759             movePrevCell(bv, old_locking_inset != 0);
760         sel_cell_start = sel_cell_end = actcell;
761         if (hs)
762             UpdateLocal(bv, SELECTION, false);
763         ShowInsetCursor(bv);
764         return result;
765     }
766     }
767
768     if (the_locking_inset) {
769         result=the_locking_inset->LocalDispatch(bv, action, arg);
770         if (result == DISPATCHED_NOUPDATE) {
771             int sc = scroll();
772             resetPos(bv);
773             if (sc != scroll()) { // inset has been scrolled
774                 the_locking_inset->ToggleInsetCursor(bv);
775                 UpdateLocal(bv, FULL, false);
776                 the_locking_inset->ToggleInsetCursor(bv);
777             }
778             return result;
779         } else if (result == DISPATCHED) {
780             the_locking_inset->ToggleInsetCursor(bv);
781             UpdateLocal(bv, CELL, false);
782             the_locking_inset->ToggleInsetCursor(bv);
783             return result;
784         } else if (result == FINISHED) {
785         }
786     }
787
788     HideInsetCursor(bv);
789     result=DISPATCHED;
790     switch (action) {
791         // --- Cursor Movements ---------------------------------------------
792     case LFUN_RIGHTSEL:
793         if (tabular->IsLastCellInRow(actcell))
794             break;
795         moveRight(bv, false);
796         sel_cell_end = actcell;
797         UpdateLocal(bv, SELECTION, false);
798         break;
799     case LFUN_RIGHT:
800         result = moveRight(bv);
801         sel_cell_start = sel_cell_end = actcell;
802         if (hs)
803             UpdateLocal(bv, SELECTION, false);
804         break;
805     case LFUN_LEFTSEL:
806         if (tabular->IsFirstCellInRow(actcell))
807             break;
808         moveLeft(bv, false);
809         sel_cell_end = actcell;
810         UpdateLocal(bv, SELECTION, false);
811         break;
812     case LFUN_LEFT:
813         result = moveLeft(bv);
814         sel_cell_start = sel_cell_end = actcell;
815         if (hs)
816             UpdateLocal(bv, SELECTION, false);
817         break;
818     case LFUN_DOWNSEL:
819     {
820         int const ocell = actcell;
821         moveDown(bv, false);
822         if ((ocell == sel_cell_end) ||
823             (tabular->column_of_cell(ocell)>tabular->column_of_cell(actcell)))
824             sel_cell_end = tabular->GetCellBelow(sel_cell_end);
825         else
826             sel_cell_end = tabular->GetLastCellBelow(sel_cell_end);
827         UpdateLocal(bv, SELECTION, false);
828     }
829     break;
830     case LFUN_DOWN:
831         result = moveDown(bv, old_locking_inset != 0);
832         sel_cell_start = sel_cell_end = actcell;
833         if (hs)
834             UpdateLocal(bv, SELECTION, false);
835         break;
836     case LFUN_UPSEL:
837     {
838         int const ocell = actcell;
839         moveUp(bv, false);
840         if ((ocell == sel_cell_end) ||
841             (tabular->column_of_cell(ocell)>tabular->column_of_cell(actcell)))
842             sel_cell_end = tabular->GetCellAbove(sel_cell_end);
843         else
844             sel_cell_end = tabular->GetLastCellAbove(sel_cell_end);
845         UpdateLocal(bv, SELECTION, false);
846     }
847     break;
848     case LFUN_UP:
849         result = moveUp(bv, old_locking_inset != 0);
850         sel_cell_start = sel_cell_end = actcell;
851         if (hs)
852             UpdateLocal(bv, SELECTION, false);
853         break;
854     case LFUN_NEXT: {
855         int column = actcol;
856         if (the_locking_inset) {
857             UnlockInsetInInset(bv, the_locking_inset);
858             the_locking_inset = 0;
859         }
860         if (bv->text->first + bv->painter().paperHeight() <
861             (top_baseline + tabular->GetHeightOfTabular()))
862         {
863             bv->scrollCB(bv->text->first + bv->painter().paperHeight());
864             UpdateLocal(bv, FULL, false);
865             actcell = tabular->GetCellBelow(first_visible_cell) + column;
866         } else {
867             actcell = tabular->GetFirstCellInRow(tabular->rows() - 1) + column;
868         }
869         resetPos(bv);
870         UpdateLocal(bv, CURSOR, false);
871         break;
872     }
873     case LFUN_PRIOR: {
874         int column = actcol;
875         if (the_locking_inset) {
876             UnlockInsetInInset(bv, the_locking_inset);
877             the_locking_inset = 0;
878         }
879         if (top_baseline < 0) {
880             bv->scrollCB(bv->text->first - bv->painter().paperHeight());
881             UpdateLocal(bv, FULL, false);
882             if (top_baseline > 0)
883                 actcell = column;
884             else
885                 actcell = tabular->GetCellBelow(first_visible_cell) + column;
886         } else {
887             actcell = column;
888         }
889         resetPos(bv);
890         UpdateLocal(bv, CURSOR, false);
891         break;
892     }
893     case LFUN_BACKSPACE:
894         break;
895     case LFUN_DELETE:
896         break;
897     case LFUN_HOME:
898         break;
899     case LFUN_END:
900         break;
901     case LFUN_LAYOUT_TABULAR:
902     {
903         bv->owner()->getDialogs()->showTabular(this);
904     }
905     break;
906     case LFUN_TABULAR_FEATURE:
907         if (!TabularFeatures(bv, arg))
908             result = UNDISPATCHED;
909         break;
910     case LFUN_CUT:
911         if (!copySelection(bv))
912             break;
913         bv->text->SetUndo(bv->buffer(), Undo::DELETE,
914 #ifndef NEW_INSETS
915           bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous_,
916                           bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next_
917 #else
918           bv->text->cursor.par()->previous(),
919           bv->text->cursor.par()->next()
920 #endif
921                 );
922         cutSelection();
923         UpdateLocal(bv, INIT, true);
924         break;
925     case LFUN_COPY:
926         if (!hasSelection())
927             break;
928         bv->text->FinishUndo();
929         copySelection(bv);
930         break;
931     case LFUN_PASTESELECTION:
932     {
933         string clip(bv->workarea()->getClipboard());
934         
935         if (clip.empty())
936             break;
937         if (clip.find('\t') != string::npos) {
938             int cols = 1;
939             int rows = 1;
940             int maxCols = 1;
941             unsigned int len = clip.length();
942             string::size_type p = 0;
943
944             while((p < len) &&
945                   ((p = clip.find_first_of("\t\n", p)) != string::npos))
946             {
947                 switch(clip[p]) {
948                 case '\t':
949                     ++cols;
950                     break;
951                 case '\n':
952                     if ((p+1) < len)
953                         ++rows;
954                     maxCols = max(cols, maxCols);
955                     cols = 1;
956                     break;
957                 }
958                 ++p;
959             }
960             maxCols = max(cols, maxCols);
961             delete paste_tabular;
962             paste_tabular = new LyXTabular(this, rows, maxCols);
963             string::size_type op = 0;
964             int cell = 0;
965             int cells = paste_tabular->GetNumberOfCells();
966             p = cols = 0;
967             while((cell < cells) && (p < len) &&
968                   (p = clip.find_first_of("\t\n", p)) != string::npos)
969             {
970                 if (p >= len)
971                     break;
972                 switch(clip[p]) {
973                 case '\t':
974                     paste_tabular->GetCellInset(cell)->SetText(clip.substr(op, p-op));
975                     ++cols;
976                     ++cell;
977                     break;
978                 case '\n':
979                     paste_tabular->GetCellInset(cell)->SetText(clip.substr(op, p-op));
980                     while(cols++ < maxCols)
981                         ++cell;
982                     cols = 0;
983                     break;
984                 }
985                 ++p;
986                 op = p;
987             }
988             // check for the last cell if there is no trailing '\n'
989             if ((cell < cells) && (op < len))
990                 paste_tabular->GetCellInset(cell)->SetText(clip.substr(op, len-op));
991         } else {
992             // so that the clipboard is used and it goes on to default
993             // and executes LFUN_PASTESELECTION in insettext!
994             delete paste_tabular;
995             paste_tabular = 0;
996         }
997     }
998     case LFUN_PASTE:
999         if (hasPasteBuffer()) {
1000             bv->text->SetUndo(bv->buffer(), Undo::INSERT,
1001 #ifndef NEW_INSETS
1002               bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous_,
1003                               bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next_
1004 #else
1005               bv->text->cursor.par()->previous(),
1006               bv->text->cursor.par()->next()
1007 #endif
1008                 );
1009             pasteSelection(bv);
1010             UpdateLocal(bv, INIT, true);
1011             break;
1012         }
1013     // ATTENTION: the function above has to be PASTE and PASTESELECTION!!!
1014     default:
1015         // we try to activate the actual inset and put this event down to
1016         // the insets dispatch function.
1017         result = UNDISPATCHED;
1018         if (the_locking_inset)
1019             break;
1020         no_draw = true;
1021         if (ActivateCellInset(bv)) {
1022             result=the_locking_inset->LocalDispatch(bv, action, arg);
1023             if ((result == UNDISPATCHED) || (result == FINISHED)) {
1024                 UnlockInsetInInset(bv, the_locking_inset);
1025                 no_draw = false;
1026                 the_locking_inset = 0;
1027                 return UNDISPATCHED;
1028             }
1029             no_draw = false;
1030             the_locking_inset->ToggleInsetCursor(bv);
1031             UpdateLocal(bv, CELL, false);
1032             the_locking_inset->ToggleInsetCursor(bv);
1033             return result;
1034         }
1035         break;
1036     }
1037     if (result!=FINISHED) {
1038         if (!the_locking_inset) {
1039             ShowInsetCursor(bv);
1040         }
1041     } else
1042         bv->unlockInset(this);
1043     return result;
1044 }
1045
1046
1047 int InsetTabular::Latex(Buffer const * buf, ostream & os,
1048                         bool fragile, bool fp) const
1049 {
1050     return tabular->Latex(buf, os, fragile, fp);
1051 }
1052
1053
1054 int InsetTabular::Ascii(Buffer const * buf, ostream & os, int) const
1055 {
1056     // This should be changed to a real ascii export
1057     return tabular->Ascii(buf, os);
1058 }
1059
1060
1061 int InsetTabular::Linuxdoc(Buffer const *, ostream &) const
1062 {
1063     return 0;
1064 }
1065
1066
1067 int InsetTabular::DocBook(Buffer const * buf, ostream & os) const
1068 {
1069     return tabular->DocBook(buf,os);
1070 }
1071
1072
1073 void InsetTabular::Validate(LaTeXFeatures & features) const
1074 {
1075     tabular->Validate(features);
1076 }
1077
1078
1079 bool InsetTabular::calculate_dimensions_of_cells(BufferView * bv,
1080                                                  LyXFont const & font,
1081                                                  bool reinit) const
1082 {
1083     int cell = -1;
1084     int maxAsc = 0;
1085     int maxDesc = 0;
1086     InsetText * inset;
1087     bool changed = false;
1088     
1089     // if we have a locking_inset we should have to check only this cell for
1090     // change so I'll try this to have a boost, but who knows ;)
1091     if ((need_update != INIT) &&
1092         (the_locking_inset == tabular->GetCellInset(actcell))) {
1093         for(int i = 0; i < tabular->columns(); ++i) {
1094             maxAsc = max(tabular->GetCellInset(actrow, i)->ascent(bv, font),
1095                          maxAsc);
1096             maxDesc = max(tabular->GetCellInset(actrow, i)->descent(bv, font),
1097                           maxDesc);
1098         }
1099         changed = tabular->SetWidthOfCell(actcell, the_locking_inset->width(bv, font));
1100         changed = tabular->SetAscentOfRow(actrow, maxAsc + ADD_TO_HEIGHT) || changed;
1101         changed = tabular->SetDescentOfRow(actrow, maxDesc + ADD_TO_HEIGHT) || changed;
1102         return changed;
1103     }
1104     for (int i = 0; i < tabular->rows(); ++i) {
1105         maxAsc = 0;
1106         maxDesc = 0;
1107         for (int j= 0; j < tabular->columns(); ++j) {
1108             if (tabular->IsPartOfMultiColumn(i,j))
1109                 continue;
1110             ++cell;
1111             inset = tabular->GetCellInset(cell);
1112             if (!reinit)
1113                 inset->update(bv, font, false);
1114             maxAsc = max(maxAsc, inset->ascent(bv, font));
1115             maxDesc = max(maxDesc, inset->descent(bv, font));
1116             changed = tabular->SetWidthOfCell(cell, inset->width(bv, font)) || changed;
1117         }
1118         changed = tabular->SetAscentOfRow(i, maxAsc + ADD_TO_HEIGHT) || changed;
1119         changed = tabular->SetDescentOfRow(i, maxDesc + ADD_TO_HEIGHT) || changed;
1120     }
1121     return changed;
1122 }
1123
1124
1125 void InsetTabular::GetCursorPos(BufferView *,
1126                                 int & x, int & y) const
1127 {
1128     x = cursor.x() - top_x;
1129     y = cursor.y();
1130 }
1131
1132
1133 void InsetTabular::ToggleInsetCursor(BufferView * bv)
1134 {
1135     if (the_locking_inset) {
1136         the_locking_inset->ToggleInsetCursor(bv);
1137         return;
1138     }
1139
1140     LyXFont font; // = the_locking_inset->GetFont(par, cursor.pos);
1141
1142     int const asc = lyxfont::maxAscent(font);
1143     int const desc = lyxfont::maxDescent(font);
1144   
1145     if (cursor_visible)
1146         bv->hideLockedInsetCursor();
1147     else
1148         bv->showLockedInsetCursor(cursor.x(), cursor.y(), asc, desc);
1149     cursor_visible = !cursor_visible;
1150 }
1151
1152
1153 void InsetTabular::ShowInsetCursor(BufferView * bv, bool show)
1154 {
1155     if (!cursor_visible) {
1156         LyXFont font; // = GetFont(par, cursor.pos);
1157     
1158         int const asc = lyxfont::maxAscent(font);
1159         int const desc = lyxfont::maxDescent(font);
1160         bv->fitLockedInsetCursor(cursor.x(), cursor.y(), asc, desc);
1161         if (show)
1162             bv->showLockedInsetCursor(cursor.x(), cursor.y(), asc, desc);
1163         cursor_visible = true;
1164     }
1165 }
1166
1167
1168 void InsetTabular::HideInsetCursor(BufferView * bv)
1169 {
1170     if (cursor_visible) {
1171         bv->hideLockedInsetCursor();
1172         cursor_visible = false;
1173     }
1174 //    if (cursor_visible)
1175 //        ToggleInsetCursor(bv);
1176 }
1177
1178
1179 void InsetTabular::setPos(BufferView * bv, int x, int y) const
1180 {
1181     cursor.y(0);
1182         
1183     actcell = actrow = actcol = 0;
1184     int ly = tabular->GetDescentOfRow(actrow);
1185
1186     // first search the right row
1187     while((ly < y) && (actrow < tabular->rows())) {
1188         cursor.y(cursor.y() + tabular->GetDescentOfRow(actrow) +
1189             tabular->GetAscentOfRow(actrow + 1) +
1190             tabular->GetAdditionalHeight(tabular->GetCellNumber(actrow + 1,
1191                                                                 actcol)));
1192         ++actrow;
1193         ly = cursor.y() + tabular->GetDescentOfRow(actrow);
1194     }
1195     actcell = tabular->GetCellNumber(actrow, actcol);
1196
1197     // now search the right column
1198     int lx = tabular->GetWidthOfColumn(actcell) -
1199         tabular->GetAdditionalWidth(actcell);
1200 #if 0
1201 #warning Jürgen, can you rewrite this to _not_ use the sequencing operator. (Lgb)
1202     for (; !tabular->IsLastCellInRow(actcell) && (lx < x);
1203         ++actcell,lx += tabular->GetWidthOfColumn(actcell) +
1204             tabular->GetAdditionalWidth(actcell - 1));
1205 #else
1206     // Jürgen, you should check that this is correct. (Lgb)
1207     for (; !tabular->IsLastCellInRow(actcell) && lx < x; ++actcell) {
1208             lx += tabular->GetWidthOfColumn(actcell + 1)
1209                     + tabular->GetAdditionalWidth(actcell);
1210     }
1211     
1212 #endif
1213     cursor.x(lx - tabular->GetWidthOfColumn(actcell) + top_x + 2);
1214     resetPos(bv);
1215 }
1216
1217
1218 int InsetTabular::getCellXPos(int cell) const
1219 {
1220     int c = cell;
1221
1222     for (; !tabular->IsFirstCellInRow(c); --c)
1223         ;
1224     int lx = tabular->GetWidthOfColumn(cell);
1225     for (; c < cell; ++c) {
1226         lx += tabular->GetWidthOfColumn(c);
1227     }
1228     return (lx - tabular->GetWidthOfColumn(cell) + top_x);
1229 }
1230
1231
1232 void InsetTabular::resetPos(BufferView * bv) const
1233 {
1234     if (!locked)
1235         return;
1236     actcol = tabular->column_of_cell(actcell);
1237
1238     int cell = 0;
1239     actrow = 0;
1240     cursor.y(0);
1241     for (; (cell < actcell) && !tabular->IsLastRow(cell); ++cell) {
1242         if (tabular->IsLastCellInRow(cell)) {
1243             cursor.y(cursor.y() + tabular->GetDescentOfRow(actrow) +
1244                 tabular->GetAscentOfRow(actrow + 1) +
1245                 tabular->GetAdditionalHeight(cell + 1));
1246             ++actrow;
1247         }
1248     }
1249     static int const offset = ADD_TO_TABULAR_WIDTH + 2;
1250     int new_x = getCellXPos(actcell);
1251     int old_x = cursor.x();
1252     new_x += offset;
1253     cursor.x(new_x);
1254 //    cursor.x(getCellXPos(actcell) + offset);
1255     if (scroll() && (tabular->GetWidthOfTabular() < bv->workWidth()-20))
1256         scroll(bv, 0.0F);
1257     else if (the_locking_inset &&
1258              (tabular->GetWidthOfColumn(actcell) > bv->workWidth()-20))
1259     {
1260             int xx = cursor.x() - offset + bv->text->GetRealCursorX(bv);
1261             if (xx > (bv->workWidth()-20))
1262                 scroll(bv, -(xx - bv->workWidth() + 60));
1263             else if (xx < 20) {
1264                 if (xx < 0)
1265                     xx = -xx + 60;
1266                 else
1267                     xx = 60;
1268                 scroll(bv, xx);
1269             }
1270     } else if (((cursor.x() - offset) > 20) &&
1271                ((cursor.x()-offset+tabular->GetWidthOfColumn(actcell)) >
1272                 (bv->workWidth()-20)))
1273     {
1274         scroll(bv, -tabular->GetWidthOfColumn(actcell)-20);
1275         UpdateLocal(bv, FULL, false);
1276     } else if ((cursor.x() - offset) < 20) {
1277         scroll(bv, 20 - cursor.x() + offset);
1278         UpdateLocal(bv, FULL, false);
1279     } else if (scroll() && (top_x > 20) &&
1280                ((top_x+tabular->GetWidthOfTabular()) > (bv->workWidth()-20))) {
1281         scroll(bv, old_x - cursor.x());
1282     }
1283     if ((!the_locking_inset ||
1284          !the_locking_inset->GetFirstLockingInsetOfType(TABULAR_CODE)) &&
1285         (actcell != oldcell)) {
1286         InsetTabular * inset = const_cast<InsetTabular *>(this);
1287         bv->owner()->getDialogs()->updateTabular(inset);
1288         oldcell = actcell;
1289     }
1290 }
1291
1292
1293 UpdatableInset::RESULT InsetTabular::moveRight(BufferView * bv, bool lock)
1294 {
1295     if (lock && !old_locking_inset) {
1296         if (ActivateCellInset(bv))
1297             return DISPATCHED;
1298     } else {
1299         bool moved = isRightToLeft(bv) ? movePrevCell(bv) : moveNextCell(bv);
1300         if (!moved)
1301             return FINISHED;
1302         if (lock && ActivateCellInset(bv))
1303             return DISPATCHED;
1304     }
1305     resetPos(bv);
1306     return DISPATCHED_NOUPDATE;
1307 }
1308
1309
1310 UpdatableInset::RESULT InsetTabular::moveLeft(BufferView * bv, bool lock)
1311 {
1312     bool moved = isRightToLeft(bv) ? moveNextCell(bv) : movePrevCell(bv);
1313     if (!moved)
1314         return FINISHED;
1315     if (lock) {       // behind the inset
1316         if (ActivateCellInset(bv, 0, 0, 0, true))
1317             return DISPATCHED;
1318     }
1319     resetPos(bv);
1320     return DISPATCHED_NOUPDATE;
1321 }
1322
1323
1324 UpdatableInset::RESULT InsetTabular::moveUp(BufferView * bv, bool lock)
1325 {
1326     int const ocell = actcell;
1327     actcell = tabular->GetCellAbove(actcell);
1328     if (actcell == ocell) // we moved out of the inset
1329         return FINISHED;
1330     resetPos(bv);
1331    if (lock) {
1332         int x = 0;
1333         int y = 0;
1334         if (old_locking_inset) {
1335             old_locking_inset->GetCursorPos(bv, x, y);
1336             x -= cursor.x() + tabular->GetBeginningOfTextInCell(actcell);
1337         }
1338         if (ActivateCellInset(bv, x, 0))
1339             return DISPATCHED;
1340     }
1341     return DISPATCHED_NOUPDATE;
1342 }
1343
1344
1345 UpdatableInset::RESULT InsetTabular::moveDown(BufferView * bv, bool lock)
1346 {
1347     int const ocell = actcell;
1348     actcell = tabular->GetCellBelow(actcell);
1349     if (actcell == ocell) // we moved out of the inset
1350         return FINISHED;
1351     resetPos(bv);
1352     if (lock) {
1353         int x = 0;
1354         int y = 0;
1355         if (old_locking_inset) {
1356             old_locking_inset->GetCursorPos(bv, x, y);
1357             x -= cursor.x() + tabular->GetBeginningOfTextInCell(actcell);
1358         }
1359         if (ActivateCellInset(bv, x, 0))
1360             return DISPATCHED;
1361     }
1362     return DISPATCHED_NOUPDATE;
1363 }
1364
1365
1366 bool InsetTabular::moveNextCell(BufferView * bv, bool lock)
1367 {
1368     if (isRightToLeft(bv)) {
1369         if (tabular->IsFirstCellInRow(actcell)) {
1370             int row = tabular->row_of_cell(actcell);
1371             if (row == tabular->rows() - 1)
1372                 return false;
1373             actcell = tabular->GetLastCellInRow(row);
1374             actcell = tabular->GetCellBelow(actcell);
1375         } else {
1376             if (!actcell)
1377                 return false;
1378             --actcell;
1379         }
1380     } else {
1381         if (tabular->IsLastCell(actcell))
1382             return false;
1383         ++actcell;
1384     }
1385     if (lock) {
1386         bool rtl = tabular->GetCellInset(actcell)->par->
1387                 isRightToLeftPar(bv->buffer()->params);
1388         ActivateCellInset(bv, 0, 0, 0, !rtl);
1389     }
1390     resetPos(bv);
1391     return true;
1392 }
1393
1394
1395 bool InsetTabular::movePrevCell(BufferView * bv, bool lock)
1396 {
1397     if (isRightToLeft(bv)) {
1398         if (tabular->IsLastCellInRow(actcell)) {
1399             int row = tabular->row_of_cell(actcell);
1400             if (row == 0)
1401                 return false;
1402             actcell = tabular->GetFirstCellInRow(row);
1403             actcell = tabular->GetCellAbove(actcell);
1404         } else {
1405             if (tabular->IsLastCell(actcell))
1406                 return false;
1407             ++actcell;
1408         }
1409     } else {
1410         if (!actcell) // first cell
1411             return false;
1412         --actcell;
1413     }
1414     if (lock) {
1415         bool rtl = tabular->GetCellInset(actcell)->par->
1416                 isRightToLeftPar(bv->buffer()->params);
1417         ActivateCellInset(bv, 0, 0, 0, !rtl);
1418     }
1419     resetPos(bv);
1420     return true;
1421 }
1422
1423
1424 bool InsetTabular::Delete()
1425 {
1426     return true;
1427 }
1428
1429
1430 void InsetTabular::SetFont(BufferView * bv, LyXFont const & font, bool tall)
1431 {
1432     if (the_locking_inset)
1433         the_locking_inset->SetFont(bv, font, tall);
1434 }
1435
1436
1437 bool InsetTabular::TabularFeatures(BufferView * bv, string const & what)
1438 {
1439     LyXTabular::Feature action = LyXTabular::LAST_ACTION;
1440
1441     int i = 0;
1442     for (; tabularFeatures[i].action != LyXTabular::LAST_ACTION; ++i) {
1443         string const tmp = tabularFeatures[i].feature;
1444             
1445         if (tmp == what.substr(0, tmp.length())) {
1446         //if (!compare(tabularFeatures[i].feature.c_str(), what.c_str(),
1447               //tabularFeatures[i].feature.length())) {
1448             action = tabularFeatures[i].action;
1449             break;
1450         }
1451     }
1452     if (action == LyXTabular::LAST_ACTION)
1453         return false;
1454
1455     string const val =
1456             frontStrip(what.substr(tabularFeatures[i].feature.length()));
1457     TabularFeatures(bv, action, val);
1458     return true;
1459 }
1460
1461
1462 void InsetTabular::TabularFeatures(BufferView * bv,
1463                                    LyXTabular::Feature feature,
1464                                    string const & value)
1465 {
1466     int i;
1467     int j;
1468     int sel_col_start;
1469     int sel_col_end;
1470     int sel_row_start;
1471     int sel_row_end;
1472     int setLines = 0;
1473     LyXAlignment setAlign = LYX_ALIGN_LEFT;
1474     LyXTabular::VAlignment setVAlign = LyXTabular::LYX_VALIGN_TOP;
1475     int lineSet;
1476     bool what;
1477
1478     switch (feature) {
1479       case LyXTabular::M_ALIGN_LEFT:
1480       case LyXTabular::ALIGN_LEFT:
1481           setAlign=LYX_ALIGN_LEFT;
1482           break;
1483       case LyXTabular::M_ALIGN_RIGHT:
1484       case LyXTabular::ALIGN_RIGHT:
1485           setAlign=LYX_ALIGN_RIGHT;
1486           break;
1487       case LyXTabular::M_ALIGN_CENTER:
1488       case LyXTabular::ALIGN_CENTER:
1489           setAlign=LYX_ALIGN_CENTER;
1490           break;
1491       case LyXTabular::M_VALIGN_TOP:
1492       case LyXTabular::VALIGN_TOP:
1493           setVAlign=LyXTabular::LYX_VALIGN_TOP;
1494           break;
1495       case LyXTabular::M_VALIGN_BOTTOM:
1496       case LyXTabular::VALIGN_BOTTOM:
1497           setVAlign=LyXTabular::LYX_VALIGN_BOTTOM;
1498           break;
1499       case LyXTabular::M_VALIGN_CENTER:
1500       case LyXTabular::VALIGN_CENTER:
1501           setVAlign=LyXTabular::LYX_VALIGN_CENTER;
1502           break;
1503       default:
1504           break;
1505     }
1506     if (hasSelection()) {
1507         sel_col_start = tabular->column_of_cell(sel_cell_start);
1508         sel_col_end = tabular->column_of_cell(sel_cell_end);
1509         if (sel_col_start > sel_col_end) {
1510             sel_col_end = sel_col_start;
1511             sel_col_start = tabular->column_of_cell(sel_cell_end);
1512         } else {
1513             sel_col_end = tabular->right_column_of_cell(sel_cell_end);
1514         }
1515         
1516         sel_row_start = tabular->row_of_cell(sel_cell_start);
1517         sel_row_end = tabular->row_of_cell(sel_cell_end);
1518         if (sel_row_start > sel_row_end) {
1519                 //int tmp = sel_row_start;
1520                 //sel_row_start = sel_row_end;
1521                 //sel_row_end = tmp;
1522             swap(sel_row_start, sel_row_end);
1523         }
1524     } else {
1525         sel_col_start = sel_col_end = tabular->column_of_cell(actcell);
1526         sel_row_start = sel_row_end = tabular->row_of_cell(actcell);
1527     }
1528     bv->text->SetUndo(bv->buffer(), Undo::FINISH,
1529 #ifndef NEW_INSETS
1530               bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous_,
1531                       bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next_
1532 #else
1533               bv->text->cursor.par()->previous(),
1534               bv->text->cursor.par()->next()
1535 #endif
1536             );
1537
1538     int row = tabular->row_of_cell(actcell);
1539     int column = tabular->column_of_cell(actcell);
1540     bool flag = true;
1541     
1542     switch (feature) {
1543     case LyXTabular::SET_PWIDTH:
1544     {
1545         bool const update = (tabular->GetColumnPWidth(actcell) != value);
1546         tabular->SetColumnPWidth(actcell,value);
1547         if (update) {
1548             for (int i=0; i < tabular->rows(); ++i) {
1549                 tabular->GetCellInset(tabular->GetCellNumber(i, column))->
1550                     resizeLyXText(bv);
1551             }
1552             UpdateLocal(bv, INIT, true);
1553         }
1554     }
1555     break;
1556     case LyXTabular::SET_MPWIDTH:
1557     {
1558         bool const update = (tabular->GetPWidth(actcell) != value);
1559         tabular->SetMColumnPWidth(actcell,value);
1560         if (update) {
1561             for (int i=0; i < tabular->rows(); ++i) {
1562                 tabular->GetCellInset(tabular->GetCellNumber(i, column))->
1563                     resizeLyXText(bv);
1564             }
1565             UpdateLocal(bv, INIT, true);
1566         }
1567     }
1568     break;
1569     case LyXTabular::SET_SPECIAL_COLUMN:
1570     case LyXTabular::SET_SPECIAL_MULTI:
1571         tabular->SetAlignSpecial(actcell,value,feature);
1572         break;
1573     case LyXTabular::APPEND_ROW:
1574         // append the row into the tabular
1575         UnlockInsetInInset(bv, the_locking_inset);
1576         tabular->AppendRow(actcell);
1577         UpdateLocal(bv, INIT, true);
1578         break;
1579     case LyXTabular::APPEND_COLUMN:
1580         // append the column into the tabular
1581         UnlockInsetInInset(bv, the_locking_inset);
1582         tabular->AppendColumn(actcell);
1583         actcell = tabular->GetCellNumber(row, column);
1584         UpdateLocal(bv, INIT, true);
1585         break;
1586     case LyXTabular::DELETE_ROW:
1587         UnlockInsetInInset(bv, the_locking_inset);
1588         tabular->DeleteRow(tabular->row_of_cell(actcell));
1589         if ((row+1) > tabular->rows())
1590             --row;
1591         actcell = tabular->GetCellNumber(row, column);
1592         clearSelection();
1593         UpdateLocal(bv, INIT, true);
1594         break;
1595     case LyXTabular::DELETE_COLUMN:
1596         UnlockInsetInInset(bv, the_locking_inset);
1597         tabular->DeleteColumn(tabular->column_of_cell(actcell));
1598         if ((column+1) > tabular->columns())
1599             --column;
1600         actcell = tabular->GetCellNumber(row, column);
1601         clearSelection();
1602         UpdateLocal(bv, INIT, true);
1603         break;
1604     case LyXTabular::M_TOGGLE_LINE_TOP:
1605         flag = false;
1606     case LyXTabular::TOGGLE_LINE_TOP:
1607         lineSet = !tabular->TopLine(actcell, flag);
1608         for (i=sel_row_start; i<=sel_row_end; ++i)
1609             for (j=sel_col_start; j<=sel_col_end; ++j)
1610                 tabular->SetTopLine(tabular->GetCellNumber(i,j),lineSet, flag);
1611         UpdateLocal(bv, INIT, true);
1612         break;
1613     
1614     case LyXTabular::M_TOGGLE_LINE_BOTTOM:
1615         flag = false;
1616     case LyXTabular::TOGGLE_LINE_BOTTOM:
1617         lineSet = !tabular->BottomLine(actcell, flag); 
1618         for (i=sel_row_start; i<=sel_row_end; ++i)
1619             for (j=sel_col_start; j<=sel_col_end; ++j)
1620                 tabular->SetBottomLine(tabular->GetCellNumber(i,j),lineSet,
1621                                        flag);
1622         UpdateLocal(bv, INIT, true);
1623         break;
1624                 
1625     case LyXTabular::M_TOGGLE_LINE_LEFT:
1626         flag = false;
1627     case LyXTabular::TOGGLE_LINE_LEFT:
1628         lineSet = !tabular->LeftLine(actcell, flag);
1629         for (i=sel_row_start; i<=sel_row_end; ++i)
1630             for (j=sel_col_start; j<=sel_col_end; ++j)
1631                 tabular->SetLeftLine(tabular->GetCellNumber(i,j),lineSet,
1632                                      flag);
1633         UpdateLocal(bv, INIT, true);
1634         break;
1635
1636     case LyXTabular::M_TOGGLE_LINE_RIGHT:
1637         flag = false;
1638     case LyXTabular::TOGGLE_LINE_RIGHT:
1639         lineSet = !tabular->RightLine(actcell, flag);
1640         for (i=sel_row_start; i<=sel_row_end; ++i)
1641             for (j=sel_col_start; j<=sel_col_end; ++j)
1642                 tabular->SetRightLine(tabular->GetCellNumber(i,j),lineSet,
1643                                       flag);
1644         UpdateLocal(bv, INIT, true);
1645         break;
1646     case LyXTabular::M_ALIGN_LEFT:
1647     case LyXTabular::M_ALIGN_RIGHT:
1648     case LyXTabular::M_ALIGN_CENTER:
1649         flag = false;
1650     case LyXTabular::ALIGN_LEFT:
1651     case LyXTabular::ALIGN_RIGHT:
1652     case LyXTabular::ALIGN_CENTER:
1653         for (i = sel_row_start; i <= sel_row_end; ++i)
1654             for (j = sel_col_start; j <= sel_col_end; ++j)
1655                 tabular->SetAlignment(tabular->GetCellNumber(i, j), setAlign,
1656                                       flag);
1657         UpdateLocal(bv, INIT, true);
1658         break;
1659     case LyXTabular::M_VALIGN_TOP:
1660     case LyXTabular::M_VALIGN_BOTTOM:
1661     case LyXTabular::M_VALIGN_CENTER:
1662         flag = false;
1663     case LyXTabular::VALIGN_TOP:
1664     case LyXTabular::VALIGN_BOTTOM:
1665     case LyXTabular::VALIGN_CENTER:
1666         for (i = sel_row_start; i <= sel_row_end; ++i)
1667             for (j = sel_col_start; j <= sel_col_end; ++j)
1668                 tabular->SetVAlignment(tabular->GetCellNumber(i, j),
1669                                        setVAlign, flag);
1670         UpdateLocal(bv, INIT, true);
1671         break;
1672     case LyXTabular::MULTICOLUMN:
1673     {
1674         if (sel_row_start != sel_row_end) {
1675             WriteAlert(_("Impossible Operation!"), 
1676                        _("Multicolumns can only be horizontally."), 
1677                        _("Sorry."));
1678             return;
1679         }
1680         // just multicol for one Single Cell
1681         if (!hasSelection()) {
1682             // check wether we are completly in a multicol
1683             if (tabular->IsMultiColumn(actcell)) {
1684                 tabular->UnsetMultiColumn(actcell);
1685                 UpdateLocal(bv, INIT, true);
1686             } else {
1687                 tabular->SetMultiColumn(actcell, 1);
1688                 UpdateLocal(bv, CELL, true);
1689             }
1690             return;
1691         }
1692         // we have a selection so this means we just add all this
1693         // cells to form a multicolumn cell
1694         int s_start;
1695         int s_end;
1696
1697         if (sel_cell_start > sel_cell_end) {
1698             s_start = sel_cell_end;
1699             s_end = sel_cell_start;
1700         } else {
1701             s_start = sel_cell_start;
1702             s_end = sel_cell_end;
1703         }
1704         tabular->SetMultiColumn(s_start, s_end - s_start + 1);
1705         actcell = s_start;
1706         sel_cell_end = sel_cell_start;
1707         UpdateLocal(bv, INIT, true);
1708         break;
1709     }
1710     case LyXTabular::SET_ALL_LINES:
1711         setLines = 1;
1712     case LyXTabular::UNSET_ALL_LINES:
1713         for (i=sel_row_start; i<=sel_row_end; ++i)
1714             for (j=sel_col_start; j<=sel_col_end; ++j)
1715                 tabular->SetAllLines(tabular->GetCellNumber(i,j), setLines);
1716         UpdateLocal(bv, INIT, true);
1717         break;
1718     case LyXTabular::SET_LONGTABULAR:
1719         tabular->SetLongTabular(true);
1720         UpdateLocal(bv, INIT, true); // because this toggles displayed
1721         break;
1722     case LyXTabular::UNSET_LONGTABULAR:
1723         tabular->SetLongTabular(false);
1724         UpdateLocal(bv, INIT, true); // because this toggles displayed
1725         break;
1726     case LyXTabular::SET_ROTATE_TABULAR:
1727         tabular->SetRotateTabular(true);
1728         break;
1729     case LyXTabular::UNSET_ROTATE_TABULAR:
1730         tabular->SetRotateTabular(false);
1731         break;
1732     case LyXTabular::SET_ROTATE_CELL:
1733         for (i=sel_row_start; i<=sel_row_end; ++i)
1734             for (j=sel_col_start; j<=sel_col_end; ++j)
1735                 tabular->SetRotateCell(tabular->GetCellNumber(i,j),true);
1736         break;
1737     case LyXTabular::UNSET_ROTATE_CELL:
1738         for (i = sel_row_start; i <= sel_row_end; ++i)
1739             for (j = sel_col_start; j <= sel_col_end; ++j)
1740                 tabular->SetRotateCell(tabular->GetCellNumber(i, j), false);
1741         break;
1742     case LyXTabular::SET_USEBOX:
1743     {
1744         LyXTabular::BoxType val = LyXTabular::BoxType(strToInt(value));
1745         if (val == tabular->GetUsebox(actcell))
1746             val = LyXTabular::BOX_NONE;
1747         for (i = sel_row_start; i <= sel_row_end; ++i)
1748             for (j = sel_col_start; j <= sel_col_end; ++j)
1749                 tabular->SetUsebox(tabular->GetCellNumber(i, j), val);
1750         break;
1751     }
1752     case LyXTabular::SET_LTFIRSTHEAD:
1753         tabular->SetLTHead(actcell, true);
1754         break;
1755     case LyXTabular::SET_LTHEAD:
1756         tabular->SetLTHead(actcell, false);
1757         break;
1758     case LyXTabular::SET_LTFOOT:
1759         tabular->SetLTFoot(actcell, false);
1760         break;
1761     case LyXTabular::SET_LTLASTFOOT:
1762         tabular->SetLTFoot(actcell, true);
1763         break;
1764     case LyXTabular::SET_LTNEWPAGE:
1765         what = !tabular->GetLTNewPage(actcell);
1766         tabular->SetLTNewPage(actcell, what);
1767         break;
1768     // dummy stuff just to avoid warnings
1769     case LyXTabular::LAST_ACTION:
1770         break;
1771     }
1772 }
1773
1774
1775 bool InsetTabular::ActivateCellInset(BufferView * bv, int x, int y, int button,
1776                                      bool behind)
1777 {
1778     UpdatableInset * inset =
1779         static_cast<UpdatableInset*>(tabular->GetCellInset(actcell));
1780     LyXFont font(LyXFont::ALL_SANE);
1781     if (behind) {
1782         x = inset->x() + inset->width(bv, font);
1783         y = inset->descent(bv, font);
1784     }
1785     //inset_x = cursor.x() - top_x + tabular->GetBeginningOfTextInCell(actcell);
1786     //inset_y = cursor.y();
1787     inset->Edit(bv, x,  y, button);
1788     if (!the_locking_inset)
1789         return false;
1790     UpdateLocal(bv, CELL, false);
1791     return (the_locking_inset != 0);
1792 }
1793
1794
1795 bool InsetTabular::ActivateCellInsetAbs(BufferView * bv, int x, int y,
1796                                         int button)
1797 {
1798         inset_x = cursor.x() - top_x + tabular->GetBeginningOfTextInCell(actcell);
1799         inset_y = cursor.y();
1800         return ActivateCellInset(bv, x - inset_x, y - inset_y, button);
1801 }
1802
1803
1804 bool InsetTabular::InsetHit(BufferView *, int x, int) const
1805 {
1806     return x + top_x > cursor.x() + tabular->GetBeginningOfTextInCell(actcell);
1807 }
1808
1809
1810 // This returns paperWidth() if the cell-width is unlimited or the width
1811 // in pixels if we have a pwidth for this cell.
1812 int InsetTabular::GetMaxWidthOfCell(Painter &, int cell) const
1813 {
1814     string const s = tabular->GetPWidth(cell);
1815
1816     if (s.empty())
1817         return -1;
1818     return VSpace(s).inPixels(0, 0);
1819 }
1820
1821
1822 int InsetTabular::getMaxWidth(Painter & pain,
1823                               UpdatableInset const * inset) const
1824 {
1825     int const n = tabular->GetNumberOfCells();
1826     int cell = 0;
1827     for (; cell < n; ++cell) {
1828         if (tabular->GetCellInset(cell) == inset)
1829             break;
1830     }
1831     if (cell >= n)
1832         return -1;
1833     int w = GetMaxWidthOfCell(pain, cell);
1834     if (w > 0)
1835         // because the inset then subtracts it's top_x and owner->x()
1836         w += (inset->x() - top_x);
1837     return w;
1838 }
1839
1840
1841 void InsetTabular::resizeLyXText(BufferView *) const
1842 {
1843     need_update = FULL;
1844 }
1845
1846
1847 LyXText * InsetTabular::getLyXText(BufferView const * bv, bool const recursive) const
1848 {
1849     if (the_locking_inset)
1850         return the_locking_inset->getLyXText(bv, recursive);
1851     return Inset::getLyXText(bv, recursive);
1852 }
1853
1854
1855 void InsetTabular::OpenLayoutDialog(BufferView * bv) const
1856 {
1857     if (the_locking_inset) {
1858         InsetTabular * i = static_cast<InsetTabular *>
1859             (the_locking_inset->GetFirstLockingInsetOfType(TABULAR_CODE));
1860         if (i) {
1861             i->OpenLayoutDialog(bv);
1862             return;
1863         }
1864     }
1865     bv->owner()->getDialogs()->showTabular(const_cast<InsetTabular *>(this));
1866 }
1867
1868 //
1869 // functions returns:
1870 // 0 ... disabled
1871 // 1 ... enabled
1872 // 2 ... toggled on
1873 // 3 ... toggled off
1874 //
1875 LyXFunc::func_status InsetTabular::getStatus(string const & what) const
1876 {
1877     int action = LyXTabular::LAST_ACTION;
1878     LyXFunc::func_status status = LyXFunc::OK;
1879     
1880     int i = 0;
1881     for (; tabularFeatures[i].action != LyXTabular::LAST_ACTION; ++i) {
1882         string const tmp = tabularFeatures[i].feature;
1883         if (tmp == what.substr(0, tmp.length())) {                  
1884         //if (!compare(tabularFeatures[i].feature.c_str(), what.c_str(),
1885         //   tabularFeatures[i].feature.length())) {
1886             action = tabularFeatures[i].action;
1887             break;
1888         }
1889     }
1890     if (action == LyXTabular::LAST_ACTION)
1891         return LyXFunc::Unknown;
1892
1893     string const argument = frontStrip(what.substr(tabularFeatures[i].feature.length()));
1894
1895     int sel_row_start;
1896     int sel_row_end;
1897     int dummy;
1898     bool flag = true;
1899
1900     if (hasSelection()) {
1901         sel_row_start = tabular->row_of_cell(sel_cell_start);
1902         sel_row_end = tabular->row_of_cell(sel_cell_end);
1903         if (sel_row_start > sel_row_end) {
1904                 //int tmp = sel_row_start;
1905                 //sel_row_start = sel_row_end;
1906                 //sel_row_end = tmp;
1907             swap(sel_row_start, sel_row_end);
1908         }
1909     } else {
1910         sel_row_start = sel_row_end = tabular->row_of_cell(actcell);
1911     }
1912
1913     switch (action) {
1914     case LyXTabular::SET_PWIDTH:
1915     case LyXTabular::SET_MPWIDTH:
1916     case LyXTabular::SET_SPECIAL_COLUMN:
1917     case LyXTabular::SET_SPECIAL_MULTI:
1918         status |= LyXFunc::Disabled;
1919         return status;
1920
1921     case LyXTabular::APPEND_ROW:
1922     case LyXTabular::APPEND_COLUMN:
1923     case LyXTabular::DELETE_ROW:
1924     case LyXTabular::DELETE_COLUMN:
1925     case LyXTabular::SET_ALL_LINES:
1926     case LyXTabular::UNSET_ALL_LINES:
1927         status |= LyXFunc::OK;
1928         return status;
1929
1930     case LyXTabular::MULTICOLUMN:
1931         if (tabular->IsMultiColumn(actcell))
1932             status |= LyXFunc::ToggleOn;
1933         else
1934             status |= LyXFunc::ToggleOff;
1935         break;
1936     case LyXTabular::M_TOGGLE_LINE_TOP:
1937         flag = false;
1938     case LyXTabular::TOGGLE_LINE_TOP:
1939         if (tabular->TopLine(actcell, flag))
1940             status |= LyXFunc::ToggleOn;
1941         else
1942             status |= LyXFunc::ToggleOff;
1943         break;
1944     case LyXTabular::M_TOGGLE_LINE_BOTTOM:
1945         flag = false;
1946     case LyXTabular::TOGGLE_LINE_BOTTOM:
1947         if (tabular->BottomLine(actcell, flag))
1948             status |= LyXFunc::ToggleOn;
1949         else
1950             status |= LyXFunc::ToggleOff;
1951         break;
1952     case LyXTabular::M_TOGGLE_LINE_LEFT:
1953         flag = false;
1954     case LyXTabular::TOGGLE_LINE_LEFT:
1955         if (tabular->LeftLine(actcell, flag))
1956             status |= LyXFunc::ToggleOn;
1957         else
1958             status |= LyXFunc::ToggleOff;
1959         break;
1960     case LyXTabular::M_TOGGLE_LINE_RIGHT:
1961         flag = false;
1962     case LyXTabular::TOGGLE_LINE_RIGHT:
1963         if (tabular->RightLine(actcell, flag))
1964             status |= LyXFunc::ToggleOn;
1965         else
1966             status |= LyXFunc::ToggleOff;
1967         break;
1968     case LyXTabular::M_ALIGN_LEFT:
1969         flag = false;
1970     case LyXTabular::ALIGN_LEFT:
1971         if (tabular->GetAlignment(actcell, flag) == LYX_ALIGN_LEFT)
1972             status |= LyXFunc::ToggleOn;
1973         else
1974             status |= LyXFunc::ToggleOff;
1975         break;
1976     case LyXTabular::M_ALIGN_RIGHT:
1977         flag = false;
1978     case LyXTabular::ALIGN_RIGHT:
1979         if (tabular->GetAlignment(actcell, flag) == LYX_ALIGN_RIGHT)
1980             status |= LyXFunc::ToggleOn;
1981         else
1982             status |= LyXFunc::ToggleOff;
1983         break;
1984     case LyXTabular::M_ALIGN_CENTER:
1985         flag = false;
1986     case LyXTabular::ALIGN_CENTER:
1987         if (tabular->GetAlignment(actcell, flag) == LYX_ALIGN_CENTER)
1988             status |= LyXFunc::ToggleOn;
1989         else
1990             status |= LyXFunc::ToggleOff;
1991         break;
1992     case LyXTabular::M_VALIGN_TOP:
1993         flag = false;
1994     case LyXTabular::VALIGN_TOP:
1995         if (tabular->GetVAlignment(actcell, flag) == LyXTabular::LYX_VALIGN_TOP)
1996             status |= LyXFunc::ToggleOn;
1997         else
1998             status |= LyXFunc::ToggleOff;
1999         break;
2000     case LyXTabular::M_VALIGN_BOTTOM:
2001         flag = false;
2002     case LyXTabular::VALIGN_BOTTOM:
2003         if (tabular->GetVAlignment(actcell, flag) == LyXTabular::LYX_VALIGN_BOTTOM)
2004             status |= LyXFunc::ToggleOn;
2005         else
2006             status |= LyXFunc::ToggleOff;
2007         break;
2008     case LyXTabular::M_VALIGN_CENTER:
2009         flag = false;
2010     case LyXTabular::VALIGN_CENTER:
2011         if (tabular->GetVAlignment(actcell, flag) == LyXTabular::LYX_VALIGN_CENTER)
2012             status |= LyXFunc::ToggleOn;
2013         else
2014             status |= LyXFunc::ToggleOff;
2015         break;
2016     case LyXTabular::SET_LONGTABULAR:
2017         if (tabular->IsLongTabular())
2018             status |= LyXFunc::ToggleOn;
2019         else
2020             status |= LyXFunc::ToggleOff;
2021         break;
2022     case LyXTabular::UNSET_LONGTABULAR:
2023         if (!tabular->IsLongTabular())
2024             status |= LyXFunc::ToggleOn;
2025         else
2026             status |= LyXFunc::ToggleOff;
2027         break;
2028     case LyXTabular::SET_ROTATE_TABULAR:
2029         if (tabular->GetRotateTabular())
2030             status |= LyXFunc::ToggleOn;
2031         else
2032             status |= LyXFunc::ToggleOff;
2033         break;
2034     case LyXTabular::UNSET_ROTATE_TABULAR:
2035         if (!tabular->GetRotateTabular())
2036             status |= LyXFunc::ToggleOn;
2037         else
2038             status |= LyXFunc::ToggleOff;
2039         break;
2040     case LyXTabular::SET_ROTATE_CELL:
2041         if (tabular->GetRotateCell(actcell))
2042             status |= LyXFunc::ToggleOn;
2043         else
2044             status |= LyXFunc::ToggleOff;
2045         break;
2046     case LyXTabular::UNSET_ROTATE_CELL:
2047         if (!tabular->GetRotateCell(actcell))
2048             status |= LyXFunc::ToggleOn;
2049         else
2050             status |= LyXFunc::ToggleOff;
2051         break;
2052     case LyXTabular::SET_USEBOX:
2053         if (strToInt(argument) == tabular->GetUsebox(actcell))
2054             status |= LyXFunc::ToggleOn;
2055         else
2056             status |= LyXFunc::ToggleOff;
2057         break;
2058     case LyXTabular::SET_LTFIRSTHEAD:
2059         if (tabular->GetRowOfLTHead(actcell, dummy))
2060             status |= LyXFunc::ToggleOn;
2061         else
2062             status |= LyXFunc::ToggleOff;
2063         break;
2064     case LyXTabular::SET_LTHEAD:
2065         if (tabular->GetRowOfLTHead(actcell, dummy))
2066             status |= LyXFunc::ToggleOn;
2067         else
2068             status |= LyXFunc::ToggleOff;
2069         break;
2070     case LyXTabular::SET_LTFOOT:
2071         if (tabular->GetRowOfLTFoot(actcell, dummy))
2072             status |= LyXFunc::ToggleOn;
2073         else
2074             status |= LyXFunc::ToggleOff;
2075         break;
2076     case LyXTabular::SET_LTLASTFOOT:
2077         if (tabular->GetRowOfLTFoot(actcell, dummy))
2078             status |= LyXFunc::ToggleOn;
2079         else
2080             status |= LyXFunc::ToggleOff;
2081         break;
2082     case LyXTabular::SET_LTNEWPAGE:
2083         if (tabular->GetLTNewPage(actcell))
2084             status |= LyXFunc::ToggleOn;
2085         else
2086             status |= LyXFunc::ToggleOff;
2087         break;
2088     default:
2089         status = LyXFunc::Disabled;
2090         break;
2091     }
2092     return status;
2093 }
2094
2095
2096 bool InsetTabular::copySelection(BufferView * bv)
2097 {
2098     if (!hasSelection())
2099         return false;
2100     delete paste_tabular;
2101
2102     int sel_col_start;
2103     int sel_col_end;
2104     int sel_row_start;
2105     int sel_row_end;
2106
2107     sel_col_start = tabular->column_of_cell(sel_cell_start);
2108     sel_col_end = tabular->column_of_cell(sel_cell_end);
2109     if (sel_col_start > sel_col_end) {
2110         sel_col_start = sel_col_end;
2111         sel_col_end = tabular->right_column_of_cell(sel_cell_start);
2112     } else {
2113         sel_col_end = tabular->right_column_of_cell(sel_cell_end);
2114     }
2115     int columns = sel_col_end - sel_col_start + 1;
2116
2117     sel_row_start = tabular->row_of_cell(sel_cell_start);
2118     sel_row_end = tabular->row_of_cell(sel_cell_end);
2119     if (sel_row_start > sel_row_end) {
2120             //int tmp tmp = sel_row_start;
2121             //sel_row_start = sel_row_end;
2122             //sel_row_end = tmp;
2123         swap(sel_row_start, sel_row_end);
2124     }
2125     int rows = sel_row_end - sel_row_start + 1;
2126
2127     paste_tabular = new LyXTabular(this, *tabular); // rows, columns);
2128     int i;
2129     for (i=0; i < sel_row_start; ++i)
2130         paste_tabular->DeleteRow(0);
2131     while(paste_tabular->rows() > rows)
2132         paste_tabular->DeleteRow(rows);
2133     paste_tabular->SetTopLine(0, true, true);
2134     paste_tabular->SetBottomLine(paste_tabular->GetFirstCellInRow(rows-1),
2135                                  true, true);
2136     for (i=0; i < sel_col_start; ++i)
2137         paste_tabular->DeleteColumn(0);
2138     while(paste_tabular->columns() > columns)
2139         paste_tabular->DeleteColumn(columns);
2140     paste_tabular->SetLeftLine(0, true, true);
2141     paste_tabular->SetRightLine(paste_tabular->GetLastCellInRow(0),true, true);
2142
2143     ostringstream sstr;
2144     paste_tabular->Ascii(bv->buffer(), sstr);
2145     bv->stuffClipboard(sstr.str().c_str());
2146     return true;
2147 }
2148
2149
2150 bool InsetTabular::pasteSelection(BufferView * bv)
2151 {
2152     if (!paste_tabular)
2153         return false;
2154
2155     for (int r1 = 0, r2 = actrow;
2156          (r1 < paste_tabular->rows()) && (r2 < tabular->rows());
2157          ++r1, ++r2)
2158     {
2159         for(int c1 = 0, c2 = actcol;
2160             (c1 < paste_tabular->columns()) && (c2 < tabular->columns());
2161             ++c1, ++c2)
2162         {
2163             if (paste_tabular->IsPartOfMultiColumn(r1,c1) &&
2164                 tabular->IsPartOfMultiColumn(r2,c2))
2165                 continue;
2166             if (paste_tabular->IsPartOfMultiColumn(r1,c1)) {
2167                 --c2;
2168                 continue;
2169             }
2170             if (tabular->IsPartOfMultiColumn(r2,c2)) {
2171                 --c1;
2172                 continue;
2173             }
2174             int n1 = paste_tabular->GetCellNumber(r1, c1);
2175             int n2 = tabular->GetCellNumber(r2, c2);
2176             *(tabular->GetCellInset(n2)) = *(paste_tabular->GetCellInset(n1));
2177             tabular->GetCellInset(n2)->setOwner(this);
2178             tabular->GetCellInset(n2)->deleteLyXText(bv);
2179         }
2180     }
2181     return true;
2182 }
2183
2184
2185 bool InsetTabular::cutSelection()
2186 {
2187     if (!hasSelection())
2188         return false;
2189
2190     int sel_col_start;
2191     int sel_col_end;
2192     int sel_row_start;
2193     int sel_row_end;
2194
2195     sel_col_start = tabular->column_of_cell(sel_cell_start);
2196     sel_col_end = tabular->column_of_cell(sel_cell_end);
2197     if (sel_col_start > sel_col_end) {
2198         sel_col_start = sel_col_end;
2199         sel_col_end = tabular->right_column_of_cell(sel_cell_start);
2200     } else {
2201         sel_col_end = tabular->right_column_of_cell(sel_cell_end);
2202     }
2203     sel_row_start = tabular->row_of_cell(sel_cell_start);
2204     sel_row_end = tabular->row_of_cell(sel_cell_end);
2205     if (sel_row_start > sel_row_end) {
2206             //int tmp = sel_row_start;
2207             //sel_row_start = sel_row_end;
2208             //sel_row_end = tmp;
2209         swap(sel_row_start, sel_row_end);
2210     }
2211     if (sel_cell_start > sel_cell_end) {
2212             //int tmp = sel_cell_start;
2213             //sel_cell_start = sel_cell_end;
2214             //sel_cell_end = tmp;
2215         swap(sel_cell_start, sel_cell_end);
2216     }
2217     for (int i = sel_row_start; i <= sel_row_end; ++i) {
2218         for (int j = sel_col_start; j <= sel_col_end; ++j) {
2219             tabular->GetCellInset(tabular->GetCellNumber(i, j))->clear();
2220         }
2221     }
2222     return true;
2223 }
2224
2225 bool InsetTabular::isRightToLeft(BufferView *bv )
2226 {
2227         return bv->getParentLanguage(this)->RightToLeft();
2228 }