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