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