]> git.lyx.org Git - lyx.git/blob - src/insets/insettabular.C
Angus insetindex patch + protect patch from Dekel
[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
38 const int ADD_TO_HEIGHT = 2;
39 const int ADD_TO_TABULAR_WIDTH = 2;
40
41 using std::ostream;
42 using std::ifstream;
43 using std::max;
44 using std::endl;
45 using std::swap;
46
47     
48 struct tabular_features {
49     int action;
50     string feature;
51 };
52
53 //static tabular_features * tabularFeatures = 0;
54
55 static tabular_features tabularFeatures[] =
56 {
57     { LyXTabular::APPEND_ROW, "append-row" },
58     { LyXTabular::APPEND_COLUMN, "append-column" },
59     { LyXTabular::DELETE_ROW, "delete-row" },
60     { LyXTabular::DELETE_COLUMN, "delete-column" },
61     { LyXTabular::TOGGLE_LINE_TOP, "toggle-line-top" },
62     { LyXTabular::TOGGLE_LINE_BOTTOM, "toggle-line-bottom" },
63     { LyXTabular::TOGGLE_LINE_LEFT, "toggle-line-left" },
64     { LyXTabular::TOGGLE_LINE_RIGHT, "toggle-line-right" },
65     { LyXTabular::ALIGN_LEFT, "align-left" },
66     { LyXTabular::ALIGN_RIGHT, "align-right" },
67     { LyXTabular::ALIGN_CENTER, "align-center" },
68     { LyXTabular::VALIGN_TOP, "valign-top" },
69     { LyXTabular::VALIGN_BOTTOM, "valign-bottom" },
70     { LyXTabular::VALIGN_CENTER, "valign-center" },
71     { LyXTabular::M_TOGGLE_LINE_TOP, "m-toggle-line-top" },
72     { LyXTabular::M_TOGGLE_LINE_BOTTOM, "m-toggle-line-bottom" },
73     { LyXTabular::M_TOGGLE_LINE_LEFT, "m-toggle-line-left" },
74     { LyXTabular::M_TOGGLE_LINE_RIGHT, "m-toggle-line-right" },
75     { LyXTabular::M_ALIGN_LEFT, "m-align-left" },
76     { LyXTabular::M_ALIGN_RIGHT, "m-align-right" },
77     { LyXTabular::M_ALIGN_CENTER, "m-align-center" },
78     { LyXTabular::M_VALIGN_TOP, "m-valign-top" },
79     { LyXTabular::M_VALIGN_BOTTOM, "m-valign-bottom" },
80     { LyXTabular::M_VALIGN_CENTER, "m-valign-center" },
81     { LyXTabular::DELETE_TABULAR, "delete-tabular" },
82     { LyXTabular::MULTICOLUMN, "multicolumn" },
83     { LyXTabular::SET_ALL_LINES, "set-all-lines" },
84     { LyXTabular::UNSET_ALL_LINES, "unset-all-lines" },
85     { LyXTabular::SET_LONGTABULAR, "set-longtabular" },
86     { LyXTabular::UNSET_LONGTABULAR, "unset-longtabular" },
87     { LyXTabular::SET_PWIDTH, "set-pwidth" },
88     { LyXTabular::SET_MPWIDTH, "set-mpwidth" },
89     { LyXTabular::SET_ROTATE_TABULAR, "set-rotate-tabular" },
90     { LyXTabular::UNSET_ROTATE_TABULAR, "unset-rotate-tabular" },
91     { LyXTabular::SET_ROTATE_CELL, "set-rotate-cell" },
92     { LyXTabular::UNSET_ROTATE_CELL, "unset-rotate-cell" },
93     { LyXTabular::SET_USEBOX, "set-usebox" },
94     { LyXTabular::SET_LTHEAD, "set-lthead" },
95     { LyXTabular::SET_LTFIRSTHEAD, "set-ltfirsthead" },
96     { LyXTabular::SET_LTFOOT, "set-ltfoot" },
97     { LyXTabular::SET_LTLASTFOOT, "set-ltlastfoot" },
98     { LyXTabular::SET_LTNEWPAGE, "set-ltnewpage" },
99     { LyXTabular::SET_SPECIAL_COLUMN, "set-special-column" },
100     { LyXTabular::SET_SPECIAL_MULTI, "set-special-multi" },
101     { LyXTabular::LAST_ACTION, "" }
102 };
103
104 //#define cellstart(p) ((p % 2) == 0)
105 static inline
106 bool cellstart(LyXParagraph::size_type p) 
107 {
108         return ((p % 2) == 0);
109 }
110
111
112 InsetTabular::InsetTabular(Buffer * 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     actcell = 0;
127     cursor.pos(0);
128     sel_pos_start = sel_pos_end = sel_cell_start = sel_cell_end = 0;
129     dialogs_ = 0;
130     need_update = INIT;
131 }
132
133
134 InsetTabular::InsetTabular(InsetTabular const & tab, Buffer * buf)
135         : buffer(buf)
136 {
137     tabular = new LyXTabular(this, *(tab.tabular));
138     the_locking_inset = 0;
139     locked = no_selection = cursor_visible = false;
140     cursor.x_fix(-1);
141     oldcell = -1;
142     actcell = 0;
143     cursor.pos(0);
144     sel_pos_start = sel_pos_end = sel_cell_start = sel_cell_end = 0;
145     dialogs_ = 0;
146     need_update = INIT;
147 }
148
149
150 InsetTabular::~InsetTabular()
151 {
152     delete tabular;
153     if (dialogs_)
154         dialogs_->hideTabular(this);
155 }
156
157
158 Inset * InsetTabular::Clone() const
159 {
160     InsetTabular * t = new InsetTabular(*this, buffer);
161     delete t->tabular;
162     t->tabular = tabular->Clone(t);
163     return t;
164 }
165
166
167 void InsetTabular::Write(Buffer const * buf, ostream & os) const
168 {
169     os << " Tabular" << endl;
170     tabular->Write(buf, os);
171 }
172
173
174 void InsetTabular::Read(Buffer const * buf, LyXLex & lex)
175 {
176     bool old_format = (lex.GetString() == "\\LyXTable");
177     string token;
178
179     if (tabular)
180         delete tabular;
181     tabular = new LyXTabular(buf, this, lex);
182
183     need_update = INIT;
184
185     if (old_format)
186         return;
187
188     lex.nextToken();
189     token = lex.GetString();
190     while (lex.IsOK() && (token != "\\end_inset")) {
191         lex.nextToken();
192         token = lex.GetString();
193     }
194     if (token != "\\end_inset") {
195         lex.printError("Missing \\end_inset at this point. "
196                        "Read: `$$Token'");
197     }
198 }
199
200
201 int InsetTabular::ascent(BufferView *, LyXFont const &) const
202 {
203     return tabular->GetAscentOfRow(0);
204 }
205
206
207 int InsetTabular::descent(BufferView *, LyXFont const &) const
208 {
209     return tabular->GetHeightOfTabular() - tabular->GetAscentOfRow(0) + 1;
210 }
211
212
213 int InsetTabular::width(BufferView *, LyXFont const &) const
214 {
215     return tabular->GetWidthOfTabular() + (2 * ADD_TO_TABULAR_WIDTH);
216 }
217
218
219 void InsetTabular::draw(BufferView * bv, LyXFont const & font, int baseline,
220                         float & x, bool cleared) const
221 {
222     Painter & pain = bv->painter();
223     int i, j, cell = 0;
224     int nx;
225     float cx;
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     bool dodraw;
248     x += ADD_TO_TABULAR_WIDTH;
249     if (cleared || (need_update == FULL) || (need_update == CELL)) {
250         for(i=0;i<tabular->rows();++i) {
251             nx = int(x);
252             dodraw = ((baseline+tabular->GetDescentOfRow(i)) > 0) &&
253                     (baseline-tabular->GetAscentOfRow(i)) < pain.paperHeight();
254             for(j=0;j<tabular->columns();++j) {
255                 if (tabular->IsPartOfMultiColumn(i,j))
256                     continue;
257                 cx = nx + tabular->GetBeginningOfTextInCell(cell);
258                 if (hasSelection())
259                     DrawCellSelection(pain, nx, baseline, i, j, cell);
260                 if (dodraw && !cleared && locked && the_locking_inset) {
261                     if (the_locking_inset == tabular->GetCellInset(cell))
262                         tabular->GetCellInset(cell)->draw(bv, font,
263                                                           baseline, cx,
264                                                           cleared);
265                 } else if (dodraw) {
266                     tabular->GetCellInset(cell)->draw(bv, font, baseline, cx,
267                                                       cleared);
268                     DrawCellLines(pain, nx, baseline, i, cell);
269                 }
270                 nx += tabular->GetWidthOfColumn(cell);
271                 ++cell;
272             }
273             baseline += tabular->GetDescentOfRow(i) +
274                 tabular->GetAscentOfRow(i+1)+
275                 tabular->GetAdditionalHeight(cell+1);
276         }
277     }
278     x += width(bv, font);
279     need_update = NONE;
280 }
281
282
283 void InsetTabular::DrawCellLines(Painter & pain, int x, int baseline,
284                                  int row, int cell) const
285 {
286     int  x2 = x + tabular->GetWidthOfColumn(cell);
287     bool on_off;
288
289     if (!tabular->TopAlreadyDrawed(cell)) {
290         on_off = !tabular->TopLine(cell);
291         pain.line(x, baseline - tabular->GetAscentOfRow(row),
292                   x2, baseline -  tabular->GetAscentOfRow(row),
293                   on_off ? LColor::tabularonoffline:LColor::tabularline,
294                   on_off ? Painter::line_onoffdash:Painter::line_solid);
295     }
296     on_off = !tabular->BottomLine(cell);
297     pain.line(x,baseline +  tabular->GetDescentOfRow(row),
298               x2, baseline +  tabular->GetDescentOfRow(row),
299               on_off ? LColor::tabularonoffline:LColor::tabularline,
300               on_off ? Painter::line_onoffdash:Painter::line_solid);
301     if (!tabular->LeftAlreadyDrawed(cell)) {
302         on_off = !tabular->LeftLine(cell);
303         pain.line(x, baseline -  tabular->GetAscentOfRow(row),
304                   x, baseline +  tabular->GetDescentOfRow(row),
305                   on_off ? LColor::tabularonoffline:LColor::tabularline,
306                   on_off ? Painter::line_onoffdash:Painter::line_solid);
307     }
308     on_off = !tabular->RightLine(cell);
309     pain.line(x2 - tabular->GetAdditionalWidth(cell),
310               baseline -  tabular->GetAscentOfRow(row),
311               x2 - tabular->GetAdditionalWidth(cell),
312               baseline +  tabular->GetDescentOfRow(row),
313               on_off ? LColor::tabularonoffline:LColor::tabularline,
314               on_off ? Painter::line_onoffdash:Painter::line_solid);
315 }
316
317
318 void InsetTabular::DrawCellSelection(Painter & pain, int x, int baseline,
319                                      int row, int column, int cell) const
320 {
321     int cs = tabular->column_of_cell(sel_cell_start);
322     int ce = tabular->column_of_cell(sel_cell_end);
323     if (cs > ce) {
324         ce = cs;
325         cs = tabular->column_of_cell(sel_cell_end);
326     } else {
327         ce = tabular->right_column_of_cell(sel_cell_end);
328     }
329
330     int rs = tabular->row_of_cell(sel_cell_start);
331     int re = tabular->row_of_cell(sel_cell_end);
332     if (rs > re) swap(rs, re);
333
334     if ((column >= cs) && (column <= ce) && (row >= rs) && (row <= re)) {
335         int w = tabular->GetWidthOfColumn(cell);
336         int h = tabular->GetAscentOfRow(row) + tabular->GetDescentOfRow(row);
337         pain.fillRectangle(x, baseline - tabular->GetAscentOfRow(row),
338                            w, h, LColor::selection);
339     }
340 }
341
342
343 void InsetTabular::update(BufferView * bv, LyXFont const & font, bool reinit)
344 {
345     if (reinit) {
346         need_update = INIT;
347         calculate_dimensions_of_cells(bv, font, true);
348         if (owner())
349             owner()->update(bv, font, true);
350         return;
351     }
352     if (the_locking_inset)
353         the_locking_inset->update(bv, font, reinit);
354     switch(need_update) {
355     case INIT:
356     case FULL:
357     case CELL:
358         if (calculate_dimensions_of_cells(bv, font, false))
359             need_update = INIT;
360         break;
361     case SELECTION:
362         need_update = INIT;
363         break;
364     default:
365         break;
366     }
367 }
368
369
370 char const * InsetTabular::EditMessage() const
371 {
372     return _("Opened Tabular Inset");
373 }
374
375
376 void InsetTabular::Edit(BufferView * bv, int x, int y, unsigned int button)
377 {
378     UpdatableInset::Edit(bv, x, y, button);
379
380     if (!bv->lockInset(this)) {
381         lyxerr[Debug::INSETS] << "InsetTabular::Cannot lock inset" << endl;
382         return;
383     }
384     locked = true;
385     the_locking_inset = 0;
386     inset_pos = inset_x = inset_y = 0;
387     setPos(bv, x, y);
388     sel_pos_start = sel_pos_end = cursor.pos();
389     sel_cell_start = sel_cell_end = actcell;
390     bv->text->FinishUndo();
391     if (InsetHit(bv, x, y)) {
392         ActivateCellInset(bv, x, y, button);
393     }
394     UpdateLocal(bv, NONE, false);
395 //    bv->getOwner()->getPopups().updateFormTabular();
396 }
397
398
399 void InsetTabular::InsetUnlock(BufferView * bv)
400 {
401     if (the_locking_inset) {
402         the_locking_inset->InsetUnlock(bv);
403         the_locking_inset = 0;
404     }
405     HideInsetCursor(bv);
406     if (hasSelection()) {
407         sel_pos_start = sel_pos_end = 0;
408         sel_cell_start = sel_cell_end = 0;
409         UpdateLocal(bv, FULL, false);
410     }
411     no_selection = false;
412     oldcell = -1;
413     locked = false;
414 }
415
416
417 void InsetTabular::UpdateLocal(BufferView * bv, UpdateCodes what,
418                                bool mark_dirty)
419 {
420     need_update = what;
421     bv->updateInset(this, mark_dirty);
422     if (what != NONE)
423         resetPos(bv);
424 }
425
426
427 bool InsetTabular::LockInsetInInset(BufferView * bv, UpdatableInset * inset)
428 {
429     lyxerr[Debug::INSETS] << "InsetTabular::LockInsetInInset(" <<inset<< "): ";
430     if (!inset)
431         return false;
432     oldcell = -1;
433     if (inset == tabular->GetCellInset(actcell)) {
434         lyxerr[Debug::INSETS] << "OK" << endl;
435         the_locking_inset = tabular->GetCellInset(actcell);
436         resetPos(bv);
437         inset_x = cursor.x() - top_x + tabular->GetBeginningOfTextInCell(actcell);
438         inset_y = cursor.y();
439         inset_pos = cursor.pos();
440         return true;
441     } else if (the_locking_inset && (the_locking_inset == inset)) {
442         if (cursor.pos() == inset_pos) {
443             lyxerr[Debug::INSETS] << "OK" << endl;
444             resetPos(bv);
445             inset_x = cursor.x() - top_x + tabular->GetBeginningOfTextInCell(actcell);
446             inset_y = cursor.y();
447         } else {
448             lyxerr[Debug::INSETS] << "cursor.pos != inset_pos" << endl;
449         }
450     } else if (the_locking_inset) {
451         lyxerr[Debug::INSETS] << "MAYBE" << endl;
452         return the_locking_inset->LockInsetInInset(bv, inset);
453     }
454     lyxerr[Debug::INSETS] << "NOT OK" << endl;
455     return false;
456 }
457
458
459 bool InsetTabular::UnlockInsetInInset(BufferView * bv, UpdatableInset * inset,
460                                    bool lr)
461 {
462     if (!the_locking_inset)
463         return false;
464     if (the_locking_inset == inset) {
465         the_locking_inset->InsetUnlock(bv);
466         the_locking_inset = 0;
467         if (lr)
468             moveRight(bv, false);
469         UpdateLocal(bv, CELL, false);
470         return true;
471     }
472     if (the_locking_inset->UnlockInsetInInset(bv, inset, lr)) {
473         if ((inset->LyxCode() == TABULAR_CODE) &&
474             !the_locking_inset->GetFirstLockingInsetOfType(TABULAR_CODE))
475         {
476             dialogs_ = bv->owner()->getDialogs();
477             dialogs_->updateTabular(const_cast<InsetTabular *>(this));
478             oldcell = actcell;
479         }
480         return true;
481     }
482     return false;
483 }
484
485
486 bool InsetTabular::UpdateInsetInInset(BufferView * bv, Inset * inset)
487 {
488     if (!the_locking_inset)
489         return false;
490     if (the_locking_inset != inset)
491         return the_locking_inset->UpdateInsetInInset(bv, inset);
492     UpdateLocal(bv, CELL, false);
493     return true;
494 }
495
496
497 int InsetTabular::InsetInInsetY()
498 {
499     if (!the_locking_inset)
500         return 0;
501
502     return (inset_y + the_locking_inset->InsetInInsetY());
503 }
504
505
506 UpdatableInset * InsetTabular::GetLockingInset()
507 {
508     return the_locking_inset ? the_locking_inset->GetLockingInset() : this;
509 }
510
511
512 UpdatableInset * InsetTabular::GetFirstLockingInsetOfType(Inset::Code c)
513 {
514     if (c == LyxCode())
515         return this;
516     if (the_locking_inset)
517         return the_locking_inset->GetFirstLockingInsetOfType(c);
518     return 0;
519 }
520
521
522 bool InsetTabular::InsertInset(BufferView * bv, Inset * inset)
523 {
524     if (the_locking_inset)
525         return the_locking_inset->InsertInset(bv, inset);
526     return false;
527 }
528
529
530 void InsetTabular::InsetButtonPress(BufferView * bv, int x, int y, int button)
531 {
532     if (hasSelection()) {
533         sel_pos_start = sel_pos_end = sel_cell_start = sel_cell_end = 0;
534         UpdateLocal(bv, SELECTION, false);
535     }
536     no_selection = false;
537
538     int ocell = actcell;
539
540     setPos(bv, x, y);
541     sel_pos_start = sel_pos_end = cursor.pos();
542     sel_cell_start = sel_cell_end = actcell;
543
544     bool inset_hit = InsetHit(bv, x, y);
545
546     if ((ocell == actcell) && the_locking_inset && inset_hit) {
547         the_locking_inset->InsetButtonPress(bv, x-inset_x, y-inset_y, button);
548         return;
549     } else if (the_locking_inset) {
550         the_locking_inset->InsetUnlock(bv);
551     }
552     the_locking_inset = 0;
553     if (inset_hit && bv->the_locking_inset) {
554         ActivateCellInset(bv, x, y, button);
555         the_locking_inset->InsetButtonPress(bv, x-inset_x, y-inset_y, button);
556     }
557 }
558
559
560 void InsetTabular::InsetButtonRelease(BufferView * bv,
561                                       int x, int y, int button)
562 {
563     if (button == 3) {
564         if (the_locking_inset) {
565             UpdatableInset * i;
566             if ((i=the_locking_inset->GetFirstLockingInsetOfType(TABULAR_CODE))) {
567                 i->InsetButtonRelease(bv, x, y, button);
568                 return;
569             }
570         }
571         dialogs_ = bv->owner()->getDialogs();
572         dialogs_->showTabular(this);
573 #if 0
574         else if (ocell != actcell)
575                 bview->getOwner()->getPopups().updateTabular();
576 #endif
577         return;
578     }
579     if (the_locking_inset) {
580         the_locking_inset->InsetButtonRelease(bv, x-inset_x, y-inset_y,button);
581         return;
582     }
583     no_selection = false;
584 }
585
586
587 void InsetTabular::InsetMotionNotify(BufferView * bv, int x, int y, int button)
588 {
589     if (the_locking_inset) {
590         the_locking_inset->InsetMotionNotify(bv, x - inset_x,
591                                              y - inset_y, button);
592         return;
593     }
594     if (!no_selection) {
595             // int ocell = actcell,
596             int old = sel_pos_end;
597
598         setPos(bv, x, y);
599         sel_pos_end = cursor.pos();
600         sel_cell_end = actcell;
601         if (old != sel_pos_end)
602             UpdateLocal(bv, SELECTION, false);
603 #if 0
604         if (ocell != actcell)
605             bview->getOwner()->getPopups().updateFormTabular();
606 #endif
607     }
608     no_selection = false;
609 }
610
611
612 void InsetTabular::InsetKeyPress(XKeyEvent * xke)
613 {
614     if (the_locking_inset) {
615         the_locking_inset->InsetKeyPress(xke);
616         return;
617     }
618 }
619
620
621 UpdatableInset::RESULT InsetTabular::LocalDispatch(BufferView * bv, int action,
622                                                    string const & arg)
623 {
624     UpdatableInset::RESULT 
625         result;
626
627     no_selection = false;
628     if (((result=UpdatableInset::LocalDispatch(bv, action, arg)) == DISPATCHED)
629         || (result == DISPATCHED_NOUPDATE)) {
630
631         resetPos(bv);
632         return result;
633     }
634
635     if ((action < 0) && arg.empty())
636         return FINISHED;
637
638     if ((action != LFUN_DOWN) && (action != LFUN_UP) &&
639         (action != LFUN_DOWNSEL) && (action != LFUN_UPSEL))
640         cursor.x_fix(-1);
641     if (the_locking_inset) {
642         result=the_locking_inset->LocalDispatch(bv, action, arg);
643         if (result == DISPATCHED_NOUPDATE)
644             return result;
645         else if (result == DISPATCHED) {
646             the_locking_inset->ToggleInsetCursor(bv);
647             UpdateLocal(bv, CELL, false);
648             the_locking_inset->ToggleInsetCursor(bv);
649             return result;
650         } else if (result == FINISHED) {
651             if ((action == LFUN_RIGHT) || (action == -1)) {
652                 cursor.pos(inset_pos + 1);
653                 resetPos(bv);
654             }
655             sel_pos_start = sel_pos_end = cursor.pos();
656             sel_cell_start = sel_cell_end = actcell;
657             the_locking_inset=0;
658             result = DISPATCHED;
659             return result;
660         }
661     }
662
663     bool hs = hasSelection();
664     HideInsetCursor(bv);
665     result=DISPATCHED;
666     switch (action) {
667         // Normal chars not handled here
668     case -1:
669         break;
670         // --- Cursor Movements ---------------------------------------------
671     case LFUN_RIGHTSEL:
672         if (tabular->IsLastCellInRow(actcell) && !cellstart(cursor.pos()))
673             break;
674         moveRight(bv, false);
675         sel_pos_end = cursor.pos();
676         if (!cellstart(cursor.pos())) {
677             if (tabular->right_column_of_cell(sel_cell_start) >
678                 tabular->right_column_of_cell(actcell))
679                 sel_cell_end = actcell+1;
680             else
681                 sel_cell_end = actcell;
682         }
683         UpdateLocal(bv, SELECTION, false);
684         break;
685     case LFUN_RIGHT:
686         result = moveRight(bv);
687         sel_pos_start = sel_pos_end = cursor.pos();
688         sel_cell_start = sel_cell_end = actcell;
689         if (hs)
690             UpdateLocal(bv, SELECTION, false);
691         break;
692     case LFUN_LEFTSEL:
693         if (tabular->IsFirstCellInRow(actcell) && cellstart(cursor.pos()))
694             break;
695         moveLeft(bv, false);
696         sel_pos_end = cursor.pos();
697         if (cellstart(cursor.pos())) {
698             if (tabular->column_of_cell(sel_cell_start) >=
699                 tabular->column_of_cell(actcell))
700                 sel_cell_end = actcell;
701             else
702                 sel_cell_end = actcell-1;
703         }
704         UpdateLocal(bv, SELECTION, false);
705         break;
706     case LFUN_LEFT:
707         result = moveLeft(bv);
708         sel_pos_start = sel_pos_end = cursor.pos();
709         sel_cell_start = sel_cell_end = actcell;
710         if (hs)
711             UpdateLocal(bv, SELECTION, false);
712         break;
713     case LFUN_DOWNSEL:
714     {
715         int ocell = actcell;
716         moveDown(bv);
717         sel_pos_end = cursor.pos();
718         if ((ocell == sel_cell_end) ||
719             (tabular->column_of_cell(ocell)>tabular->column_of_cell(actcell)))
720             sel_cell_end = tabular->GetCellBelow(sel_cell_end);
721         else
722             sel_cell_end = tabular->GetLastCellBelow(sel_cell_end);
723         UpdateLocal(bv, SELECTION, false);
724     }
725     break;
726     case LFUN_DOWN:
727         result= moveDown(bv);
728         sel_pos_start = sel_pos_end = cursor.pos();
729         sel_cell_start = sel_cell_end = actcell;
730         if (hs)
731             UpdateLocal(bv, SELECTION, false);
732         break;
733     case LFUN_UPSEL:
734     {
735         int ocell = actcell;
736         moveUp(bv);
737         sel_pos_end = cursor.pos();
738         if ((ocell == sel_cell_end) ||
739             (tabular->column_of_cell(ocell)>tabular->column_of_cell(actcell)))
740             sel_cell_end = tabular->GetCellAbove(sel_cell_end);
741         else
742             sel_cell_end = tabular->GetLastCellAbove(sel_cell_end);
743         UpdateLocal(bv, SELECTION, false);
744     }
745     break;
746     case LFUN_UP:
747         result= moveUp(bv);
748         sel_pos_start = sel_pos_end = cursor.pos();
749         sel_cell_start = sel_cell_end = actcell;
750         if (hs)
751             UpdateLocal(bv, SELECTION, false);
752         break;
753     case LFUN_BACKSPACE:
754         break;
755     case LFUN_DELETE:
756         break;
757     case LFUN_HOME:
758         break;
759     case LFUN_END:
760         break;
761     case LFUN_SHIFT_TAB:
762     case LFUN_TAB:
763         if (the_locking_inset) {
764             UnlockInsetInInset(bv, the_locking_inset);
765             the_locking_inset = 0;
766         }
767         if (action == LFUN_TAB)
768             moveNextCell(bv);
769         else
770             movePrevCell(bv);
771         sel_pos_start = sel_pos_end = cursor.pos();
772         sel_cell_start = sel_cell_end = actcell;
773         if (hs)
774             UpdateLocal(bv, SELECTION, false);
775         break;
776     case LFUN_LAYOUT_TABLE:
777     {
778         dialogs_ = bv->owner()->getDialogs();
779         dialogs_->showTabular(this);
780     }
781     break;
782     case LFUN_TABULAR_FEATURE:
783         if (!TabularFeatures(bv, arg))
784             result = UNDISPATCHED;
785         break;
786
787     default:
788         result = UNDISPATCHED;
789         break;
790     }
791     if (result!=FINISHED) {
792         if (!the_locking_inset) {
793 #if 0       
794             if (ocell != actcell)
795                 bview->getOwner()->getPopups().updateFormTabular();
796 #endif
797             ShowInsetCursor(bv);
798         }
799     } else
800         bv->unlockInset(this);
801     return result;
802 }
803
804
805 int InsetTabular::Latex(Buffer const * buf, ostream & os,
806                         bool fragile, bool fp) const
807 {
808     return tabular->Latex(buf, os, fragile, fp);
809 }
810
811
812 int InsetTabular::Ascii(Buffer const *, ostream &) const
813 {
814     return 0;
815 }
816
817
818 int InsetTabular::Linuxdoc(Buffer const *, ostream &) const
819 {
820     return 0;
821 }
822
823
824 int InsetTabular::DocBook(Buffer const *, ostream &) const
825 {
826     return 0;
827 }
828
829
830 void InsetTabular::Validate(LaTeXFeatures & features) const
831 {
832     tabular->Validate(features);
833 }
834
835
836 bool InsetTabular::calculate_dimensions_of_cells(BufferView * bv,
837                                                  LyXFont const & font,
838                                                  bool reinit) const
839 {
840     int cell = -1;
841     int maxAsc, maxDesc;
842     InsetText * inset;
843     bool changed = false;
844     
845     for(int i = 0; i < tabular->rows(); ++i) {
846         maxAsc = maxDesc = 0;
847         for(int j= 0; j < tabular->columns(); ++j) {
848             if (tabular->IsPartOfMultiColumn(i,j))
849                 continue;
850             ++cell;
851             inset = tabular->GetCellInset(cell);
852             if (!reinit)
853                 inset->update(bv, font, false);
854             maxAsc = max(maxAsc, inset->ascent(bv, font));
855             maxDesc = max(maxDesc, inset->descent(bv, font));
856             changed = tabular->SetWidthOfCell(cell, inset->width(bv, font)) || changed;
857         }
858         changed = tabular->SetAscentOfRow(i, maxAsc + ADD_TO_HEIGHT) || changed;
859         changed = tabular->SetDescentOfRow(i, maxDesc + ADD_TO_HEIGHT) || changed;
860     }
861     return changed;
862 }
863
864
865 void InsetTabular::GetCursorPos(BufferView *, int & x, int & y) const
866 {
867     x = cursor.x() - top_x;
868     y = cursor.y();
869 }
870
871
872 void InsetTabular::ToggleInsetCursor(BufferView * bv)
873 {
874     if (the_locking_inset) {
875         the_locking_inset->ToggleInsetCursor(bv);
876         return;
877     }
878
879     LyXFont font; // = the_locking_inset->GetFont(par, cursor.pos);
880
881     int asc = lyxfont::maxAscent(font);
882     int desc = lyxfont::maxDescent(font);
883   
884     if (cursor_visible)
885         bv->hideLockedInsetCursor();
886     else
887         bv->showLockedInsetCursor(cursor.x(), cursor.y(), asc, desc);
888     cursor_visible = !cursor_visible;
889 }
890
891
892 void InsetTabular::ShowInsetCursor(BufferView * bv)
893 {
894     if (!cursor_visible) {
895         LyXFont font; // = GetFont(par, cursor.pos);
896     
897         int asc = lyxfont::maxAscent(font);
898         int desc = lyxfont::maxDescent(font);
899         bv->fitLockedInsetCursor(cursor.x(), cursor.y(), asc, desc);
900         bv->showLockedInsetCursor(cursor.x(), cursor.y(), asc, desc);
901         cursor_visible = true;
902     }
903 }
904
905
906 void InsetTabular::HideInsetCursor(BufferView * bv)
907 {
908     if (cursor_visible)
909         ToggleInsetCursor(bv);
910 }
911
912
913 void InsetTabular::setPos(BufferView * bv, int x, int y) const
914 {
915         cursor.y(0);
916         cursor.pos(0);
917         
918         actcell = actrow = actcol = 0;
919     int ly = tabular->GetDescentOfRow(actrow);
920
921     // first search the right row
922     while((ly < y) && (actrow < tabular->rows())) {
923         cursor.y(cursor.y() + tabular->GetDescentOfRow(actrow) +
924             tabular->GetAscentOfRow(actrow+1) +
925             tabular->GetAdditionalHeight(tabular->GetCellNumber(actrow + 1,
926                                                                 actcol)));
927         ++actrow;
928         ly = cursor.y() + tabular->GetDescentOfRow(actrow);
929     }
930     actcell = tabular->GetCellNumber(actrow, actcol);
931
932     // now search the right column
933     int lx = tabular->GetWidthOfColumn(actcell) -
934         tabular->GetAdditionalWidth(actcell);
935     for(; !tabular->IsLastCellInRow(actcell) && (lx < x);
936         ++actcell,lx += tabular->GetWidthOfColumn(actcell) +
937             tabular->GetAdditionalWidth(actcell - 1));
938     cursor.pos(((actcell+1) * 2) - 1);
939     resetPos(bv);
940     if ((lx - (tabular->GetWidthOfColumn(actcell)/2)) < x) {
941         cursor.x(lx + top_x - 2);
942     } else {
943         cursor.pos(cursor.pos() - 1);
944         cursor.x(lx - tabular->GetWidthOfColumn(actcell) + top_x + 2);
945     }
946     resetPos(bv);
947 }
948
949
950 int InsetTabular::getCellXPos(int cell) const
951 {
952     int c;
953
954     for(c=cell;!tabular->IsFirstCellInRow(c);--c)
955         ;
956     int lx = tabular->GetWidthOfColumn(cell);
957     for(; (c < cell); ++c) {
958         lx += tabular->GetWidthOfColumn(c);
959     }
960     return (lx - tabular->GetWidthOfColumn(cell) + top_x +
961             ADD_TO_TABULAR_WIDTH);
962 }
963
964
965 void InsetTabular::resetPos(BufferView * bv) const
966 {
967     if (!locked)
968         return;
969     actcol = tabular->column_of_cell(actcell);
970
971     int cell = 0;
972     actrow = 0;
973     cursor.y(0);
974     for(; (cell<actcell) && !tabular->IsLastRow(cell); ++cell) {
975         if (tabular->IsLastCellInRow(cell)) {
976             cursor.y(cursor.y() + tabular->GetDescentOfRow(actrow) +
977                 tabular->GetAscentOfRow(actrow + 1) +
978                 tabular->GetAdditionalHeight(cell + 1));
979             ++actrow;
980         }
981     }
982     cursor.x(getCellXPos(actcell) + 2);
983     if (cursor.pos() % 2) {
984         LyXFont font(LyXFont::ALL_SANE);
985         cursor.x(cursor.x() + tabular->GetCellInset(actcell)->width(bv,font) +
986                 tabular->GetBeginningOfTextInCell(actcell));
987     }
988     if ((!the_locking_inset ||
989          !the_locking_inset->GetFirstLockingInsetOfType(TABULAR_CODE)) &&
990         (actcell != oldcell)) {
991         dialogs_ = bv->owner()->getDialogs();
992         dialogs_->updateTabular(const_cast<InsetTabular *>(this));
993         oldcell = actcell;
994     }
995 }
996
997
998 UpdatableInset::RESULT InsetTabular::moveRight(BufferView * bv, bool lock)
999 {
1000     if (!cellstart(cursor.pos())) {
1001         if (tabular->IsLastCell(actcell))
1002             return FINISHED;
1003         ++actcell;
1004         cursor.pos(cursor.pos() + 1);
1005     } else if (lock) {
1006         if (ActivateCellInset(bv))
1007             return DISPATCHED;
1008     } else {              // before the inset
1009         cursor.pos(cursor.pos() + 1);
1010     }
1011     resetPos(bv);
1012     return DISPATCHED_NOUPDATE;
1013 }
1014
1015
1016 UpdatableInset::RESULT InsetTabular::moveLeft(BufferView * bv, bool lock)
1017 {
1018     if (!cursor.pos()) {
1019         if (!actcell)
1020             return FINISHED;
1021         cursor.pos(2);
1022     }
1023     cursor.pos(cursor.pos() - 1);
1024     if (!cellstart(cursor.pos())) {
1025         --actcell;
1026     } else if (lock) {       // behind the inset
1027         if (ActivateCellInset(bv, 0, 0, 0, true))
1028             return DISPATCHED;
1029     }
1030     resetPos(bv);
1031     return DISPATCHED_NOUPDATE;
1032 }
1033
1034
1035 UpdatableInset::RESULT InsetTabular::moveUp(BufferView * bv)
1036 {
1037     int ocell = actcell;
1038     actcell = tabular->GetCellAbove(actcell);
1039     if (actcell == ocell) // we moved out of the inset
1040         return FINISHED;
1041     resetPos(bv);
1042     return DISPATCHED_NOUPDATE;
1043 }
1044
1045
1046 UpdatableInset::RESULT InsetTabular::moveDown(BufferView * bv)
1047 {
1048     int ocell = actcell;
1049     actcell = tabular->GetCellBelow(actcell);
1050     if (actcell == ocell) // we moved out of the inset
1051         return FINISHED;
1052     resetPos(bv);
1053     return DISPATCHED_NOUPDATE;
1054 }
1055
1056
1057 bool InsetTabular::moveNextCell(BufferView * bv)
1058 {
1059     if (tabular->IsLastCell(actcell))
1060         return false;
1061     ++actcell;
1062     cursor.pos(cursor.pos() + 1);
1063     if (!cellstart(cursor.pos()))
1064         cursor.pos(cursor.pos() + 1);
1065     resetPos(bv);
1066     return true;
1067 }
1068
1069
1070 bool InsetTabular::movePrevCell(BufferView * bv)
1071 {
1072     if (!actcell) // first cell
1073         return false;
1074     --actcell;
1075     cursor.pos(cursor.pos() - 1);
1076     if (cellstart(cursor.pos()))
1077         cursor.pos(cursor.pos() - 1);
1078     resetPos(bv);
1079     return true;
1080 }
1081
1082
1083 bool InsetTabular::Delete()
1084 {
1085     return true;
1086 }
1087
1088
1089 void InsetTabular::SetFont(BufferView * bv, LyXFont const & font, bool tall)
1090 {
1091     if (the_locking_inset)
1092         the_locking_inset->SetFont(bv, font, tall);
1093 }
1094
1095
1096 bool InsetTabular::TabularFeatures(BufferView * bv, string what)
1097 {
1098     int action = LyXTabular::LAST_ACTION;
1099     string val;
1100     int i;
1101     
1102     for(i=0; tabularFeatures[i].action != LyXTabular::LAST_ACTION; ++i) {
1103         if (!strncmp(tabularFeatures[i].feature.c_str(), what.c_str(),
1104                      tabularFeatures[i].feature.length())) {
1105             action = tabularFeatures[i].action;
1106             break;
1107         }
1108     }
1109     if (action == LyXTabular::LAST_ACTION)
1110         return false;
1111
1112     val = frontStrip(what.substr(tabularFeatures[i].feature.length()));
1113     TabularFeatures(bv, action, val);
1114     return true;
1115 }
1116
1117
1118 void InsetTabular::TabularFeatures(BufferView * bv, int feature, string value)
1119 {
1120     int
1121         i, j,
1122         sel_col_start,
1123         sel_col_end,
1124         sel_row_start,
1125         sel_row_end,
1126         setLines = 0,
1127         setAlign = LYX_ALIGN_LEFT,
1128         lineSet;
1129     bool
1130         what;
1131
1132     switch (feature) {
1133       case LyXTabular::M_ALIGN_LEFT:
1134       case LyXTabular::ALIGN_LEFT:
1135           setAlign=LYX_ALIGN_LEFT;
1136           break;
1137       case LyXTabular::M_ALIGN_RIGHT:
1138       case LyXTabular::ALIGN_RIGHT:
1139           setAlign=LYX_ALIGN_RIGHT;
1140           break;
1141       case LyXTabular::M_ALIGN_CENTER:
1142       case LyXTabular::ALIGN_CENTER:
1143           setAlign=LYX_ALIGN_CENTER;
1144           break;
1145       case LyXTabular::M_VALIGN_TOP:
1146       case LyXTabular::VALIGN_TOP:
1147           setAlign=LyXTabular::LYX_VALIGN_TOP;
1148           break;
1149       case LyXTabular::M_VALIGN_BOTTOM:
1150       case LyXTabular::VALIGN_BOTTOM:
1151           setAlign=LyXTabular::LYX_VALIGN_BOTTOM;
1152           break;
1153       case LyXTabular::M_VALIGN_CENTER:
1154       case LyXTabular::VALIGN_CENTER:
1155           setAlign=LyXTabular::LYX_VALIGN_CENTER;
1156           break;
1157       default:
1158           break;
1159     }
1160     if (hasSelection()) {
1161         int tmp;
1162         sel_col_start = tabular->column_of_cell(sel_cell_start);
1163         sel_col_end = tabular->column_of_cell(sel_cell_end);
1164         if (sel_col_start > sel_col_end) {
1165             sel_col_end = sel_col_start;
1166             sel_col_start = tabular->column_of_cell(sel_cell_end);
1167         } else {
1168             sel_col_end = tabular->right_column_of_cell(sel_cell_end);
1169         }
1170         
1171         sel_row_start = tabular->row_of_cell(sel_cell_start);
1172         sel_row_end = tabular->row_of_cell(sel_cell_end);
1173         if (sel_row_start > sel_row_end) {
1174             tmp = sel_row_start;
1175             sel_row_start = sel_row_end;
1176             sel_row_end = tmp;
1177         }
1178     } else {
1179         sel_col_start = sel_col_end = tabular->column_of_cell(actcell);
1180         sel_row_start = sel_row_end = tabular->row_of_cell(actcell);
1181     }
1182     bv->text->SetUndo(bv->buffer(), Undo::FINISH,
1183 #ifndef NEW_INSETS
1184               bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous,
1185               bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next
1186 #else
1187               bv->text->cursor.par()->previous,
1188               bv->text->cursor.par()->next
1189 #endif
1190             );
1191
1192     int row = tabular->row_of_cell(actcell);
1193     int column = tabular->column_of_cell(actcell);
1194     bool flag = true;
1195     
1196     switch (feature) {
1197     case LyXTabular::SET_PWIDTH:
1198     {
1199         bool update = (tabular->GetColumnPWidth(actcell) != value);
1200         tabular->SetColumnPWidth(actcell,value);
1201         if (update) {
1202             for (int i=0; i < tabular->rows(); ++i) {
1203                 tabular->GetCellInset(tabular->GetCellNumber(i, column))->
1204                     resizeLyXText(bv);
1205             }
1206             UpdateLocal(bv, INIT, true);
1207         }
1208     }
1209     break;
1210     case LyXTabular::SET_MPWIDTH:
1211     {
1212         bool update = (tabular->GetPWidth(actcell) != value);
1213         tabular->SetMColumnPWidth(actcell,value);
1214         if (update) {
1215             for (int i=0; i < tabular->rows(); ++i) {
1216                 tabular->GetCellInset(tabular->GetCellNumber(i, column))->
1217                     resizeLyXText(bv);
1218             }
1219             UpdateLocal(bv, INIT, true);
1220         }
1221     }
1222     break;
1223     case LyXTabular::SET_SPECIAL_COLUMN:
1224     case LyXTabular::SET_SPECIAL_MULTI:
1225         tabular->SetAlignSpecial(actcell,value,feature);
1226         break;
1227     case LyXTabular::APPEND_ROW:
1228         // append the row into the tabular
1229         UnlockInsetInInset(bv, the_locking_inset);
1230         tabular->AppendRow(actcell);
1231         UpdateLocal(bv, INIT, true);
1232         break;
1233     case LyXTabular::APPEND_COLUMN:
1234         // append the column into the tabular
1235         tabular->AppendColumn(actcell);
1236         actcell = tabular->GetCellNumber(row, column);
1237         UpdateLocal(bv, INIT, true);
1238         break;
1239     case LyXTabular::DELETE_ROW:
1240         tabular->DeleteRow(tabular->row_of_cell(actcell));
1241         if ((row+1) > tabular->rows())
1242             --row;
1243         actcell = tabular->GetCellNumber(row, column);
1244         UpdateLocal(bv, INIT, true);
1245         break;
1246     case LyXTabular::DELETE_COLUMN:
1247         tabular->DeleteColumn(tabular->column_of_cell(actcell));
1248         if ((column+1) > tabular->columns())
1249             --column;
1250         actcell = tabular->GetCellNumber(row, column);
1251         UpdateLocal(bv, INIT, true);
1252         break;
1253     case LyXTabular::M_TOGGLE_LINE_TOP:
1254         flag = false;
1255     case LyXTabular::TOGGLE_LINE_TOP:
1256         lineSet = !tabular->TopLine(actcell, flag);
1257         for(i=sel_row_start; i<=sel_row_end; ++i)
1258             for(j=sel_col_start; j<=sel_col_end; ++j)
1259                 tabular->SetTopLine(tabular->GetCellNumber(i,j),lineSet, flag);
1260         UpdateLocal(bv, INIT, true);
1261         break;
1262     
1263     case LyXTabular::M_TOGGLE_LINE_BOTTOM:
1264         flag = false;
1265     case LyXTabular::TOGGLE_LINE_BOTTOM:
1266         lineSet = !tabular->BottomLine(actcell, flag); 
1267         for(i=sel_row_start; i<=sel_row_end; ++i)
1268             for(j=sel_col_start; j<=sel_col_end; ++j)
1269                 tabular->SetBottomLine(tabular->GetCellNumber(i,j),lineSet,
1270                                        flag);
1271         UpdateLocal(bv, INIT, true);
1272         break;
1273                 
1274     case LyXTabular::M_TOGGLE_LINE_LEFT:
1275         flag = false;
1276     case LyXTabular::TOGGLE_LINE_LEFT:
1277         lineSet = !tabular->LeftLine(actcell, flag);
1278         for(i=sel_row_start; i<=sel_row_end; ++i)
1279             for(j=sel_col_start; j<=sel_col_end; ++j)
1280                 tabular->SetLeftLine(tabular->GetCellNumber(i,j),lineSet,
1281                                      flag);
1282         UpdateLocal(bv, INIT, true);
1283         break;
1284
1285     case LyXTabular::M_TOGGLE_LINE_RIGHT:
1286         flag = false;
1287     case LyXTabular::TOGGLE_LINE_RIGHT:
1288         lineSet = !tabular->RightLine(actcell, flag);
1289         for(i=sel_row_start; i<=sel_row_end; ++i)
1290             for(j=sel_col_start; j<=sel_col_end; ++j)
1291                 tabular->SetRightLine(tabular->GetCellNumber(i,j),lineSet,
1292                                       flag);
1293         UpdateLocal(bv, INIT, true);
1294         break;
1295     case LyXTabular::M_ALIGN_LEFT:
1296     case LyXTabular::M_ALIGN_RIGHT:
1297     case LyXTabular::M_ALIGN_CENTER:
1298         flag = false;
1299     case LyXTabular::ALIGN_LEFT:
1300     case LyXTabular::ALIGN_RIGHT:
1301     case LyXTabular::ALIGN_CENTER:
1302         for(i=sel_row_start; i<=sel_row_end; ++i)
1303             for(j=sel_col_start; j<=sel_col_end; ++j)
1304                 tabular->SetAlignment(tabular->GetCellNumber(i,j),setAlign,
1305                                       flag);
1306         if (hasSelection())
1307             UpdateLocal(bv, INIT, true);
1308         else
1309             UpdateLocal(bv, CELL, true);
1310         break;
1311     case LyXTabular::M_VALIGN_TOP:
1312     case LyXTabular::M_VALIGN_BOTTOM:
1313     case LyXTabular::M_VALIGN_CENTER:
1314         flag = false;
1315     case LyXTabular::VALIGN_TOP:
1316     case LyXTabular::VALIGN_BOTTOM:
1317     case LyXTabular::VALIGN_CENTER:
1318         for(i=sel_row_start; i<=sel_row_end; ++i)
1319             for(j=sel_col_start; j<=sel_col_end; ++j)
1320                 tabular->SetVAlignment(tabular->GetCellNumber(i,j), setAlign,
1321                                        flag);
1322         if (hasSelection())
1323             UpdateLocal(bv, INIT, true);
1324         else
1325             UpdateLocal(bv, CELL, true);
1326         break;
1327     case LyXTabular::MULTICOLUMN:
1328     {
1329         if (sel_row_start != sel_row_end) {
1330             WriteAlert(_("Impossible Operation!"), 
1331                        _("Multicolumns can only be horizontally."), 
1332                        _("Sorry."));
1333             return;
1334         }
1335         // just multicol for one Single Cell
1336         if (!hasSelection()) {
1337             // check wether we are completly in a multicol
1338             if (tabular->IsMultiColumn(actcell)) {
1339                 tabular->UnsetMultiColumn(actcell);
1340                 UpdateLocal(bv, INIT, true);
1341             } else {
1342                 tabular->SetMultiColumn(actcell, 1);
1343                 UpdateLocal(bv, CELL, true);
1344             }
1345             return;
1346         }
1347         // we have a selection so this means we just add all this
1348         // cells to form a multicolumn cell
1349         int
1350             s_start, s_end;
1351
1352         if (sel_cell_start > sel_cell_end) {
1353             s_start = sel_cell_end;
1354             s_end = sel_cell_start;
1355         } else {
1356             s_start = sel_cell_start;
1357             s_end = sel_cell_end;
1358         }
1359         tabular->SetMultiColumn(s_start, s_end - s_start + 1);
1360         actcell = s_start;
1361         cursor.pos(0);
1362         sel_cell_end = sel_cell_start;
1363         sel_pos_end = sel_pos_start;
1364         UpdateLocal(bv, INIT, true);
1365         break;
1366     }
1367     case LyXTabular::SET_ALL_LINES:
1368         setLines = 1;
1369     case LyXTabular::UNSET_ALL_LINES:
1370         for(i=sel_row_start; i<=sel_row_end; ++i)
1371             for(j=sel_col_start; j<=sel_col_end; ++j)
1372                 tabular->SetAllLines(tabular->GetCellNumber(i,j), setLines);
1373         UpdateLocal(bv, INIT, true);
1374         break;
1375     case LyXTabular::SET_LONGTABULAR:
1376         tabular->SetLongTabular(true);
1377         UpdateLocal(bv, INIT, true); // because this toggles displayed
1378         break;
1379     case LyXTabular::UNSET_LONGTABULAR:
1380         tabular->SetLongTabular(false);
1381         UpdateLocal(bv, INIT, true); // because this toggles displayed
1382         break;
1383     case LyXTabular::SET_ROTATE_TABULAR:
1384         tabular->SetRotateTabular(true);
1385         break;
1386     case LyXTabular::UNSET_ROTATE_TABULAR:
1387         tabular->SetRotateTabular(false);
1388         break;
1389     case LyXTabular::SET_ROTATE_CELL:
1390         for(i=sel_row_start; i<=sel_row_end; ++i)
1391             for(j=sel_col_start; j<=sel_col_end; ++j)
1392                 tabular->SetRotateCell(tabular->GetCellNumber(i,j),true);
1393         break;
1394     case LyXTabular::UNSET_ROTATE_CELL:
1395         for(i=sel_row_start; i<=sel_row_end; ++i)
1396             for(j=sel_col_start; j<=sel_col_end; ++j)
1397                 tabular->SetRotateCell(tabular->GetCellNumber(i,j),false);
1398         break;
1399     case LyXTabular::SET_USEBOX:
1400     {
1401         int val = strToInt(value);
1402         if (val == tabular->GetUsebox(actcell))
1403             val = 0;
1404         for(i=sel_row_start; i<=sel_row_end; ++i)
1405             for(j=sel_col_start; j<=sel_col_end; ++j)
1406                 tabular->SetUsebox(tabular->GetCellNumber(i,j),val);
1407         break;
1408     }
1409     case LyXTabular::SET_LTFIRSTHEAD:
1410         tabular->SetLTHead(actcell,true);
1411         break;
1412     case LyXTabular::SET_LTHEAD:
1413         tabular->SetLTHead(actcell,false);
1414         break;
1415     case LyXTabular::SET_LTFOOT:
1416         tabular->SetLTFoot(actcell,false);
1417         break;
1418     case LyXTabular::SET_LTLASTFOOT:
1419         tabular->SetLTFoot(actcell,true);
1420         break;
1421     case LyXTabular::SET_LTNEWPAGE:
1422         what = !tabular->GetLTNewPage(actcell);
1423         tabular->SetLTNewPage(actcell,what);
1424         break;
1425     }
1426 }
1427
1428
1429 bool InsetTabular::ActivateCellInset(BufferView * bv, int x, int y, int button,
1430                                      bool behind)
1431 {
1432     // the cursor.pos has to be before the inset so if it isn't now just
1433     // reset the curor pos first!
1434     if (cursor.pos() % 2) { // behind the inset
1435         cursor.pos(cursor.pos() - 1);
1436         resetPos(bv);
1437     }
1438     UpdatableInset * inset =
1439         static_cast<UpdatableInset*>(tabular->GetCellInset(actcell));
1440     LyXFont font(LyXFont::ALL_SANE);
1441     if (behind) {
1442         x = inset->x() + inset->width(bv, font);
1443         y = inset->descent(bv, font);
1444     }
1445     inset_x = cursor.x() - top_x + tabular->GetBeginningOfTextInCell(actcell);
1446     inset_y = cursor.y();
1447     inset->Edit(bv, x - inset_x, y - inset_y, button);
1448     if (!the_locking_inset)
1449         return false;
1450     UpdateLocal(bv, CELL, false);
1451     return true;
1452 }
1453
1454
1455 bool InsetTabular::InsetHit(BufferView * bv, int x, int ) const
1456 {
1457     InsetText * inset = tabular->GetCellInset(actcell);
1458     int x1 = x + top_x;
1459
1460     if (cursor.pos() % 2) { // behind the inset
1461         return (((x + top_x) < cursor.x()) &&
1462                 ((x + top_x) > (cursor.x() - inset->width(bv,
1463                                                       LyXFont(LyXFont::ALL_SANE)))));
1464     } else {
1465         int x2 = cursor.x() + tabular->GetBeginningOfTextInCell(actcell);
1466         return ((x1 > x2) &&
1467                 (x1 < (x2 + inset->width(bv, LyXFont(LyXFont::ALL_SANE)))));
1468     }
1469 }
1470
1471
1472 // This returns paperWidth() if the cell-width is unlimited or the width
1473 // in pixels if we have a pwidth for this cell.
1474 int InsetTabular::GetMaxWidthOfCell(Painter &, int cell) const
1475 {
1476     string s = tabular->GetPWidth(cell);
1477
1478     if (s.empty())
1479         return -1;
1480     return VSpace(s).inPixels( 0, 0);
1481 }
1482
1483
1484 int InsetTabular::getMaxWidth(Painter & pain,
1485                               UpdatableInset const * inset) const
1486 {
1487     int cell;
1488     int n = tabular->GetNumberOfCells();
1489     for(cell=0; cell < n; ++cell) {
1490         if (tabular->GetCellInset(cell) == inset)
1491             break;
1492     }
1493     if (cell >= n)
1494         return -1;
1495     int w = GetMaxWidthOfCell(pain, cell);
1496     if (w > 0)
1497         // because the inset then subtracts it's top_x and owner->x()
1498         w += (inset->x() - top_x);
1499     return w;
1500 }
1501
1502
1503 void InsetTabular::recomputeTextInsets(BufferView * bv,
1504                                        LyXFont const & font) const
1505 {
1506     InsetText * inset;
1507     int cell;
1508
1509 //    cx = top_x;
1510     for(int j= 0; j < tabular->columns(); ++j) {
1511         for(int i = 0; i < tabular->rows(); ++i) {
1512             if (tabular->IsPartOfMultiColumn(i,j))
1513                 continue;
1514             cell = tabular->GetCellNumber(i,j);
1515             inset = tabular->GetCellInset(cell);
1516             inset->update(bv, font);
1517             tabular->SetWidthOfCell(cell, inset->width(bv, font));
1518         }
1519 //      cell = tabular->GetCellNumber(0, j);
1520 //      cx += tabular->GetWidthOfColumn(cell);
1521     }
1522 }
1523
1524
1525 void InsetTabular::resizeLyXText(BufferView *) const
1526 {
1527     need_update = FULL;
1528 }
1529
1530 LyXText * InsetTabular::getLyXText(BufferView * bv) const
1531 {
1532     if (the_locking_inset)
1533         return the_locking_inset->getLyXText(bv);
1534     return Inset::getLyXText(bv);
1535 }
1536
1537
1538 void InsetTabular::OpenLayoutDialog(BufferView * bv) const
1539 {
1540     if (the_locking_inset) {
1541         InsetTabular * i = static_cast<InsetTabular *>
1542             (the_locking_inset->GetFirstLockingInsetOfType(TABULAR_CODE));
1543         if (i) {
1544             i->OpenLayoutDialog(bv);
1545             return;
1546         }
1547     }
1548     dialogs_ = bv->owner()->getDialogs();
1549     dialogs_->showTabular(const_cast<InsetTabular *>(this));
1550 }
1551
1552 //
1553 // functions returns:
1554 // 0 ... disabled
1555 // 1 ... enabled
1556 // 2 ... toggled on
1557 // 3 ... toggled off
1558 //
1559 int InsetTabular::getStatus(string what) const
1560 {
1561     int action = LyXTabular::LAST_ACTION;
1562     string argument;
1563     int i;
1564     
1565     for(i=0; tabularFeatures[i].action != LyXTabular::LAST_ACTION; ++i) {
1566         if (!strncmp(tabularFeatures[i].feature.c_str(), what.c_str(),
1567                      tabularFeatures[i].feature.length())) {
1568             action = tabularFeatures[i].action;
1569             break;
1570         }
1571     }
1572     if (action == LyXTabular::LAST_ACTION)
1573         return 0;
1574
1575     argument = frontStrip(what.substr(tabularFeatures[i].feature.length()));
1576
1577     int sel_row_start, sel_row_end;
1578     int dummy;
1579     bool flag = true;
1580
1581     if (hasSelection()) {
1582         int tmp;
1583         sel_row_start = tabular->row_of_cell(sel_cell_start);
1584         sel_row_end = tabular->row_of_cell(sel_cell_end);
1585         if (sel_row_start > sel_row_end) {
1586             tmp = sel_row_start;
1587             sel_row_start = sel_row_end;
1588             sel_row_end = tmp;
1589         }
1590     } else {
1591         sel_row_start = sel_row_end = tabular->row_of_cell(actcell);
1592     }
1593
1594     switch (action) {
1595     case LyXTabular::SET_PWIDTH:
1596     case LyXTabular::SET_MPWIDTH:
1597     case LyXTabular::SET_SPECIAL_COLUMN:
1598     case LyXTabular::SET_SPECIAL_MULTI:
1599         return 0;
1600
1601     case LyXTabular::APPEND_ROW:
1602     case LyXTabular::APPEND_COLUMN:
1603     case LyXTabular::DELETE_ROW:
1604     case LyXTabular::DELETE_COLUMN:
1605     case LyXTabular::SET_ALL_LINES:
1606     case LyXTabular::UNSET_ALL_LINES:
1607         return 1;
1608
1609     case LyXTabular::MULTICOLUMN:
1610         if (tabular->IsMultiColumn(actcell))
1611             return 2;
1612         return 3;
1613
1614     case LyXTabular::M_TOGGLE_LINE_TOP:
1615         flag = false;
1616     case LyXTabular::TOGGLE_LINE_TOP:
1617         if (tabular->TopLine(actcell, flag))
1618             return 2;
1619         return 3;
1620     
1621     case LyXTabular::M_TOGGLE_LINE_BOTTOM:
1622         flag = false;
1623     case LyXTabular::TOGGLE_LINE_BOTTOM:
1624         if (tabular->BottomLine(actcell, flag))
1625             return 2;
1626         return 3;
1627                 
1628     case LyXTabular::M_TOGGLE_LINE_LEFT:
1629         flag = false;
1630     case LyXTabular::TOGGLE_LINE_LEFT:
1631         if (tabular->LeftLine(actcell, flag))
1632             return 2;
1633         return 3;
1634
1635     case LyXTabular::M_TOGGLE_LINE_RIGHT:
1636         flag = false;
1637     case LyXTabular::TOGGLE_LINE_RIGHT:
1638         if (tabular->RightLine(actcell, flag))
1639             return 2;
1640         return 3;
1641
1642     case LyXTabular::M_ALIGN_LEFT:
1643         flag = false;
1644     case LyXTabular::ALIGN_LEFT:
1645         if (tabular->GetAlignment(actcell, flag) == LYX_ALIGN_LEFT)
1646             return 2;
1647         return 3;
1648
1649     case LyXTabular::M_ALIGN_RIGHT:
1650         flag = false;
1651     case LyXTabular::ALIGN_RIGHT:
1652         if (tabular->GetAlignment(actcell, flag) == LYX_ALIGN_RIGHT)
1653             return 2;
1654         return 3;
1655
1656     case LyXTabular::M_ALIGN_CENTER:
1657         flag = false;
1658     case LyXTabular::ALIGN_CENTER:
1659         if (tabular->GetAlignment(actcell, flag) == LYX_ALIGN_CENTER)
1660             return 2;
1661         return 3;
1662
1663     case LyXTabular::M_VALIGN_TOP:
1664         flag = false;
1665     case LyXTabular::VALIGN_TOP:
1666         if (tabular->GetVAlignment(actcell, flag) == LyXTabular::LYX_VALIGN_TOP)
1667             return 2;
1668         return 3;
1669
1670     case LyXTabular::M_VALIGN_BOTTOM:
1671         flag = false;
1672     case LyXTabular::VALIGN_BOTTOM:
1673         if (tabular->GetVAlignment(actcell, flag) == LyXTabular::LYX_VALIGN_BOTTOM)
1674             return 2;
1675         return 3;
1676
1677     case LyXTabular::M_VALIGN_CENTER:
1678         flag = false;
1679     case LyXTabular::VALIGN_CENTER:
1680         if (tabular->GetVAlignment(actcell, flag) == LyXTabular::LYX_VALIGN_CENTER)
1681             return 2;
1682         return 3;
1683
1684     case LyXTabular::SET_LONGTABULAR:
1685         if (tabular->IsLongTabular())
1686             return 2;
1687         return 3;
1688
1689     case LyXTabular::UNSET_LONGTABULAR:
1690         if (!tabular->IsLongTabular())
1691             return 2;
1692         return 3;
1693
1694     case LyXTabular::SET_ROTATE_TABULAR:
1695         if (tabular->GetRotateTabular())
1696             return 2;
1697         return 3;
1698
1699     case LyXTabular::UNSET_ROTATE_TABULAR:
1700         if (!tabular->GetRotateTabular())
1701             return 2;
1702         return 3;
1703
1704     case LyXTabular::SET_ROTATE_CELL:
1705         if (tabular->GetRotateCell(actcell))
1706             return 2;
1707         return 3;
1708
1709     case LyXTabular::UNSET_ROTATE_CELL:
1710         if (!tabular->GetRotateCell(actcell))
1711             return 2;
1712         return 3;
1713
1714     case LyXTabular::SET_USEBOX:
1715         if (strToInt(argument) == tabular->GetUsebox(actcell))
1716             return 2;
1717         return 3;
1718
1719     case LyXTabular::SET_LTFIRSTHEAD:
1720         if (tabular->GetRowOfLTHead(actcell, dummy))
1721             return 2;
1722         return 3;
1723
1724     case LyXTabular::SET_LTHEAD:
1725         if (tabular->GetRowOfLTHead(actcell, dummy))
1726             return 2;
1727         return 3;
1728
1729     case LyXTabular::SET_LTFOOT:
1730         if (tabular->GetRowOfLTFoot(actcell, dummy))
1731             return 2;
1732         return 3;
1733
1734     case LyXTabular::SET_LTLASTFOOT:
1735         if (tabular->GetRowOfLTFoot(actcell, dummy))
1736             return 2;
1737         return 3;
1738
1739     case LyXTabular::SET_LTNEWPAGE:
1740         if (tabular->GetLTNewPage(actcell))
1741             return 2;
1742         return 3;
1743     }
1744     return 0;
1745 }