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