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