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