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