]> git.lyx.org Git - lyx.git/blob - src/insets/insettabular.C
Patch fdfix from Angus, using only the new tabular-layout, some fixes!
[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 "LaTeXFeatures.h"
27 #include "Painter.h"
28 #include "font.h"
29 #include "lyxtext.h"
30 #include "lyx_gui_misc.h"
31 #include "LyXView.h"
32 #include "lyxfunc.h"
33 #include "insets/insettext.h"
34 #include "frontends/Dialogs.h"
35
36 const int ADD_TO_HEIGHT = 2;
37 const int ADD_TO_TABULAR_WIDTH = 2;
38
39 using std::ostream;
40 using std::ifstream;
41 using std::max;
42 using std::endl;
43
44 #define cellstart(p) ((p % 2) == 0)
45
46 InsetTabular::InsetTabular(Buffer * buf, int rows, int columns)
47 {
48     if (rows <= 0)
49         rows = 1;
50     if (columns <= 0)
51         columns = 1;
52     buffer = buf; // set this first!!!
53     tabular = new LyXTabular(this, rows,columns);
54     // for now make it always display as display() inset
55     // just for test!!!
56     the_locking_inset = 0;
57     locked = no_selection = cursor_visible = false;
58     cursor.x_fix(-1);
59     oldcell = -1;
60     actcell = 0;
61     cursor.pos(0);
62     sel_pos_start = sel_pos_end = sel_cell_start = sel_cell_end = 0;
63     dialogs_ = 0;
64     need_update = INIT;
65 }
66
67
68 InsetTabular::InsetTabular(InsetTabular const & tab, Buffer * buf)
69 {
70     buffer = buf; // set this first
71     tabular = new LyXTabular(this, *(tab.tabular));
72     the_locking_inset = 0;
73     locked = no_selection = cursor_visible = false;
74     cursor.x_fix(-1);
75     oldcell = -1;
76     actcell = 0;
77     cursor.pos(0);
78     sel_pos_start = sel_pos_end = sel_cell_start = sel_cell_end = 0;
79     dialogs_ = 0;
80     need_update = INIT;
81 }
82
83
84 InsetTabular::~InsetTabular()
85 {
86     delete tabular;
87     if (dialogs_)
88         dialogs_->hideTabular(this);
89 }
90
91
92 Inset * InsetTabular::Clone() const
93 {
94     InsetTabular * t = new InsetTabular(*this, buffer);
95     delete t->tabular;
96     t->tabular = tabular->Clone(t);
97     return t;
98 }
99
100
101 void InsetTabular::Write(Buffer const * buf, ostream & os) const
102 {
103     os << " Tabular" << endl;
104     tabular->Write(buf, os);
105 }
106
107
108 void InsetTabular::Read(Buffer const * buf, LyXLex & lex)
109 {
110     bool old_format = (lex.GetString() == "\\LyXTable");
111     string token;
112
113     if (tabular)
114         delete tabular;
115     tabular = new LyXTabular(buf, this, lex);
116
117     need_update = INIT;
118
119     if (old_format)
120         return;
121
122     lex.nextToken();
123     token = lex.GetString();
124     while (lex.IsOK() && (token != "\\end_inset")) {
125         lex.nextToken();
126         token = lex.GetString();
127     }
128     if (token != "\\end_inset") {
129         lex.printError("Missing \\end_inset at this point. "
130                        "Read: `$$Token'");
131     }
132 }
133
134
135 int InsetTabular::ascent(BufferView *, LyXFont const &) const
136 {
137     return tabular->GetAscentOfRow(0);
138 }
139
140
141 int InsetTabular::descent(BufferView *, LyXFont const &) const
142 {
143     return tabular->GetHeightOfTabular() - tabular->GetAscentOfRow(0) + 1;
144 }
145
146
147 int InsetTabular::width(BufferView *, LyXFont const &) const
148 {
149     return tabular->GetWidthOfTabular() + (2 * ADD_TO_TABULAR_WIDTH);
150 }
151
152
153 void InsetTabular::draw(BufferView * bv, LyXFont const & font, int baseline,
154                         float & x, bool cleared) const
155 {
156     Painter & pain = bv->painter();
157     int i, j, cell=0;
158     int nx;
159     float cx;
160
161     UpdatableInset::draw(bv,font,baseline,x,cleared);
162     if (!cleared && ((need_update == INIT) || (need_update == FULL) ||
163                      (top_x != int(x)) || (top_baseline != baseline))) {
164         int h = ascent(bv, font) + descent(bv, font);
165         int tx = display()? 0:top_x;
166         int w =  tx? width(bv, font):pain.paperWidth();
167         int ty = baseline - ascent(bv, font);
168         
169         if (ty < 0)
170             ty = 0;
171         if ((ty + h) > pain.paperHeight())
172             h = pain.paperHeight();
173         if ((top_x + w) > pain.paperWidth())
174             w = pain.paperWidth();
175         pain.fillRectangle(tx, ty, w, h);
176         need_update = FULL;
177         cleared = true;
178     }
179     top_x = int(x);
180     top_baseline = baseline;
181     bool dodraw;
182     x += ADD_TO_TABULAR_WIDTH;
183     if (cleared || (need_update == FULL) || (need_update == CELL)) {
184         for(i=0;i<tabular->rows();++i) {
185             nx = int(x);
186             dodraw = ((baseline+tabular->GetDescentOfRow(i)) > 0) &&
187                     (baseline-tabular->GetAscentOfRow(i)) < pain.paperHeight();
188             for(j=0;j<tabular->columns();++j) {
189                 if (tabular->IsPartOfMultiColumn(i,j))
190                     continue;
191                 cx = nx + tabular->GetBeginningOfTextInCell(cell);
192                 if (hasSelection())
193                     DrawCellSelection(pain, nx, baseline, i, j, cell);
194                 if (dodraw && !cleared && locked && the_locking_inset) {
195                     if (the_locking_inset == tabular->GetCellInset(cell))
196                         tabular->GetCellInset(cell)->draw(bv, font,
197                                                           baseline, cx,
198                                                           cleared);
199                 } else if (dodraw) {
200                     tabular->GetCellInset(cell)->draw(bv, font, baseline, cx,
201                                                       cleared);
202                     DrawCellLines(pain, nx, baseline, i, cell);
203                 }
204                 nx += tabular->GetWidthOfColumn(cell);
205                 ++cell;
206             }
207             baseline += tabular->GetDescentOfRow(i) +
208                 tabular->GetAscentOfRow(i+1)+
209                 tabular->GetAdditionalHeight(cell+1);
210         }
211     }
212     x += width(bv, font);
213     need_update = NONE;
214 }
215
216
217 void InsetTabular::DrawCellLines(Painter & pain, int x, int baseline,
218                                  int row, int cell) const
219 {
220     int  x2 = x + tabular->GetWidthOfColumn(cell);
221     bool on_off;
222
223     if (!tabular->TopAlreadyDrawed(cell)) {
224         on_off = !tabular->TopLine(cell);
225         pain.line(x, baseline - tabular->GetAscentOfRow(row),
226                   x2, baseline -  tabular->GetAscentOfRow(row),
227                   on_off ? LColor::tabularonoffline:LColor::tabularline,
228                   on_off ? Painter::line_onoffdash:Painter::line_solid);
229     }
230     on_off = !tabular->BottomLine(cell);
231     pain.line(x,baseline +  tabular->GetDescentOfRow(row),
232               x2, baseline +  tabular->GetDescentOfRow(row),
233               on_off ? LColor::tabularonoffline:LColor::tabularline,
234               on_off ? Painter::line_onoffdash:Painter::line_solid);
235     if (!tabular->LeftAlreadyDrawed(cell)) {
236         on_off = !tabular->LeftLine(cell);
237         pain.line(x, baseline -  tabular->GetAscentOfRow(row),
238                   x, baseline +  tabular->GetDescentOfRow(row),
239                   on_off ? LColor::tabularonoffline:LColor::tabularline,
240                   on_off ? Painter::line_onoffdash:Painter::line_solid);
241     }
242     on_off = !tabular->RightLine(cell);
243     pain.line(x2 - tabular->GetAdditionalWidth(cell),
244               baseline -  tabular->GetAscentOfRow(row),
245               x2 - tabular->GetAdditionalWidth(cell),
246               baseline +  tabular->GetDescentOfRow(row),
247               on_off ? LColor::tabularonoffline:LColor::tabularline,
248               on_off ? Painter::line_onoffdash:Painter::line_solid);
249 }
250
251
252 void InsetTabular::DrawCellSelection(Painter & pain, int x, int baseline,
253                                      int row, int column, int cell) const
254 {
255     int tmp;
256
257     int cs = tabular->column_of_cell(sel_cell_start);
258     int ce = tabular->column_of_cell(sel_cell_end);
259     if (cs > ce) {
260         ce = cs;
261         cs = tabular->column_of_cell(sel_cell_end);
262     } else {
263         ce = tabular->right_column_of_cell(sel_cell_end);
264     }
265
266     int rs = tabular->row_of_cell(sel_cell_start);
267     int re = tabular->row_of_cell(sel_cell_end);
268     if (rs > re) {
269         tmp = rs;
270         rs = re;
271         re = tmp;
272     }
273
274     if ((column >= cs) && (column <= ce) && (row >= rs) && (row <= re)) {
275         int w = tabular->GetWidthOfColumn(cell);
276         int h = tabular->GetAscentOfRow(row) + tabular->GetDescentOfRow(row);
277         pain.fillRectangle(x, baseline - tabular->GetAscentOfRow(row),
278                            w, h, LColor::selection);
279     }
280 }
281
282
283 void InsetTabular::update(BufferView * bv, LyXFont const & font, bool reinit)
284 {
285     if (reinit) {
286         need_update = INIT;
287         calculate_dimensions_of_cells(bv, font, true);
288         if (owner())
289             owner()->update(bv, font, true);
290         return;
291     }
292     if (the_locking_inset)
293         the_locking_inset->update(bv, font, reinit);
294     switch(need_update) {
295     case INIT:
296     case FULL:
297     case CELL:
298         if (calculate_dimensions_of_cells(bv, font, false))
299             need_update = INIT;
300         break;
301     case SELECTION:
302         need_update = INIT;
303         break;
304     default:
305         break;
306     }
307 }
308
309
310 char const * InsetTabular::EditMessage() const
311 {
312     return _("Opened Tabular Inset");
313 }
314
315
316 void InsetTabular::Edit(BufferView * bv, int x, int y, unsigned int button)
317 {
318     UpdatableInset::Edit(bv, x, y, button);
319
320     if (!bv->lockInset(this)) {
321         lyxerr[Debug::INSETS] << "InsetTabular::Cannot lock inset" << endl;
322         return;
323     }
324     locked = true;
325     the_locking_inset = 0;
326     inset_pos = inset_x = inset_y = 0;
327     setPos(bv, x, y);
328     sel_pos_start = sel_pos_end = cursor.pos();
329     sel_cell_start = sel_cell_end = actcell;
330     bv->text->FinishUndo();
331     if (InsetHit(bv, x, y)) {
332         ActivateCellInset(bv, x, y, button);
333     }
334     UpdateLocal(bv, NONE, false);
335 //    bv->getOwner()->getPopups().updateFormTabular();
336 }
337
338
339 void InsetTabular::InsetUnlock(BufferView * bv)
340 {
341     if (the_locking_inset) {
342         the_locking_inset->InsetUnlock(bv);
343         the_locking_inset = 0;
344     }
345     HideInsetCursor(bv);
346     if (hasSelection()) {
347         sel_pos_start = sel_pos_end = 0;
348         sel_cell_start = sel_cell_end = 0;
349         UpdateLocal(bv, FULL, false);
350     }
351     no_selection = false;
352     oldcell = -1;
353     locked = false;
354 }
355
356 void InsetTabular::UpdateLocal(BufferView * bv, UpdateCodes what,
357                                bool mark_dirty)
358 {
359     need_update = what;
360     bv->updateInset(this, mark_dirty);
361     if (what != NONE)
362         resetPos(bv);
363 }
364
365 bool InsetTabular::LockInsetInInset(BufferView * bv, UpdatableInset * inset)
366 {
367     lyxerr[Debug::INSETS] << "InsetTabular::LockInsetInInset(" <<inset<< "): ";
368     if (!inset)
369         return false;
370     oldcell = -1;
371     if (inset == tabular->GetCellInset(actcell)) {
372         lyxerr[Debug::INSETS] << "OK" << endl;
373         the_locking_inset = tabular->GetCellInset(actcell);
374         resetPos(bv);
375         inset_x = cursor.x() - top_x + tabular->GetBeginningOfTextInCell(actcell);
376         inset_y = cursor.y();
377         inset_pos = cursor.pos();
378         return true;
379     } else if (the_locking_inset && (the_locking_inset == inset)) {
380         if (cursor.pos() == inset_pos) {
381             lyxerr[Debug::INSETS] << "OK" << endl;
382             resetPos(bv);
383             inset_x = cursor.x() - top_x + tabular->GetBeginningOfTextInCell(actcell);
384             inset_y = cursor.y();
385         } else {
386             lyxerr[Debug::INSETS] << "cursor.pos != inset_pos" << endl;
387         }
388     } else if (the_locking_inset) {
389         lyxerr[Debug::INSETS] << "MAYBE" << endl;
390         return the_locking_inset->LockInsetInInset(bv, inset);
391     }
392     lyxerr[Debug::INSETS] << "NOT OK" << endl;
393     return false;
394 }
395
396 bool InsetTabular::UnlockInsetInInset(BufferView * bv, UpdatableInset * inset,
397                                    bool lr)
398 {
399     if (!the_locking_inset)
400         return false;
401     if (the_locking_inset == inset) {
402         the_locking_inset->InsetUnlock(bv);
403         the_locking_inset = 0;
404         if (lr)
405             moveRight(bv, false);
406         UpdateLocal(bv, CELL, false);
407         return true;
408     }
409     if (the_locking_inset->UnlockInsetInInset(bv, inset, lr)) {
410         if ((inset->LyxCode() == TABULAR_CODE) &&
411             !the_locking_inset->GetFirstLockingInsetOfType(TABULAR_CODE))
412         {
413             dialogs_ = bv->owner()->getDialogs();
414             dialogs_->updateTabular(const_cast<InsetTabular *>(this));
415             oldcell = actcell;
416         }
417         return true;
418     }
419     return false;
420 }
421
422 bool InsetTabular::UpdateInsetInInset(BufferView * bv, Inset * inset)
423 {
424     if (!the_locking_inset)
425         return false;
426     if (the_locking_inset != inset)
427         return the_locking_inset->UpdateInsetInInset(bv, inset);
428     UpdateLocal(bv, CELL, false);
429     return true;
430 }
431
432
433 int InsetTabular::InsetInInsetY()
434 {
435     if (!the_locking_inset)
436         return 0;
437
438     return (inset_y + the_locking_inset->InsetInInsetY());
439 }
440
441
442 UpdatableInset * InsetTabular::GetLockingInset()
443 {
444     return the_locking_inset ? the_locking_inset->GetLockingInset() : this;
445 }
446
447
448 UpdatableInset * InsetTabular::GetFirstLockingInsetOfType(Inset::Code c)
449 {
450     if (c == LyxCode())
451         return this;
452     if (the_locking_inset)
453         return the_locking_inset->GetFirstLockingInsetOfType(c);
454     return 0;
455 }
456
457
458 bool InsetTabular::InsertInset(BufferView * bv, Inset * inset)
459 {
460     if (the_locking_inset)
461         return the_locking_inset->InsertInset(bv, inset);
462     return false;
463 }
464
465
466 void InsetTabular::InsetButtonPress(BufferView * bv, int x, int y, int button)
467 {
468     if (hasSelection()) {
469         sel_pos_start = sel_pos_end = sel_cell_start = sel_cell_end = 0;
470         UpdateLocal(bv, SELECTION, false);
471     }
472     no_selection = false;
473
474     int ocell = actcell;
475
476     setPos(bv, x, y);
477     sel_pos_start = sel_pos_end = cursor.pos();
478     sel_cell_start = sel_cell_end = actcell;
479
480     bool inset_hit = InsetHit(bv, x, y);
481
482     if ((ocell == actcell) && the_locking_inset && inset_hit) {
483         the_locking_inset->InsetButtonPress(bv, x-inset_x, y-inset_y, button);
484         return;
485     } else if (the_locking_inset) {
486         the_locking_inset->InsetUnlock(bv);
487     }
488     the_locking_inset = 0;
489     if (inset_hit && bv->the_locking_inset) {
490         ActivateCellInset(bv, x, y, button);
491         the_locking_inset->InsetButtonPress(bv, x-inset_x, y-inset_y, button);
492     }
493 }
494
495
496 void InsetTabular::InsetButtonRelease(BufferView * bv,
497                                       int x, int y, int button)
498 {
499     if (button == 3) {
500         if (the_locking_inset) {
501             UpdatableInset * i;
502             if ((i=the_locking_inset->GetFirstLockingInsetOfType(TABULAR_CODE))) {
503                 i->InsetButtonRelease(bv, x, y, button);
504                 return;
505             }
506         }
507         dialogs_ = bv->owner()->getDialogs();
508         dialogs_->showTabular(this);
509 #if 0
510         else if (ocell != actcell)
511                 bview->getOwner()->getPopups().updateTabular();
512 #endif
513         return;
514     }
515     if (the_locking_inset) {
516         the_locking_inset->InsetButtonRelease(bv, x-inset_x, y-inset_y,button);
517         return;
518     }
519     no_selection = false;
520 }
521
522
523 void InsetTabular::InsetMotionNotify(BufferView * bv, int x, int y, int button)
524 {
525     if (the_locking_inset) {
526         the_locking_inset->InsetMotionNotify(bv, x - inset_x,
527                                              y - inset_y, button);
528         return;
529     }
530     if (!no_selection) {
531             // int ocell = actcell,
532             int old = sel_pos_end;
533
534         setPos(bv, x, y);
535         sel_pos_end = cursor.pos();
536         sel_cell_end = actcell;
537         if (old != sel_pos_end)
538             UpdateLocal(bv, SELECTION, false);
539 #if 0
540         if (ocell != actcell)
541             bview->getOwner()->getPopups().updateFormTabular();
542 #endif
543     }
544     no_selection = false;
545 }
546
547
548 void InsetTabular::InsetKeyPress(XKeyEvent * xke)
549 {
550     if (the_locking_inset) {
551         the_locking_inset->InsetKeyPress(xke);
552         return;
553     }
554 }
555
556
557 UpdatableInset::RESULT InsetTabular::LocalDispatch(BufferView * bv, int action,
558                                                    string const & arg)
559 {
560     UpdatableInset::RESULT 
561         result;
562
563     no_selection = false;
564     if (((result=UpdatableInset::LocalDispatch(bv, action, arg)) == DISPATCHED)
565         || (result == DISPATCHED_NOUPDATE)) {
566
567         resetPos(bv);
568         return result;
569     }
570     result=DISPATCHED;
571
572     if ((action < 0) && arg.empty())
573         return FINISHED;
574
575     if ((action != LFUN_DOWN) && (action != LFUN_UP) &&
576         (action != LFUN_DOWNSEL) && (action != LFUN_UPSEL))
577         cursor.x_fix(-1);
578     if (the_locking_inset) {
579         result=the_locking_inset->LocalDispatch(bv, action, arg);
580         if (result == DISPATCHED_NOUPDATE)
581             return result;
582         else if (result == DISPATCHED) {
583             the_locking_inset->ToggleInsetCursor(bv);
584             UpdateLocal(bv, CELL, false);
585             the_locking_inset->ToggleInsetCursor(bv);
586             return result;
587         } else if (result == FINISHED) {
588             if ((action == LFUN_RIGHT) || (action == -1)) {
589                 cursor.pos(inset_pos + 1);
590                 resetPos(bv);
591             }
592             sel_pos_start = sel_pos_end = cursor.pos();
593             sel_cell_start = sel_cell_end = actcell;
594             the_locking_inset=0;
595             result = DISPATCHED;
596             return result;
597         }
598     }
599
600     bool hs = hasSelection();
601     HideInsetCursor(bv);
602     switch (action) {
603         // Normal chars not handled here
604     case -1:
605         break;
606         // --- Cursor Movements ---------------------------------------------
607     case LFUN_RIGHTSEL:
608         if (tabular->IsLastCellInRow(actcell) && !cellstart(cursor.pos()))
609             break;
610         moveRight(bv, false);
611         sel_pos_end = cursor.pos();
612         if (!cellstart(cursor.pos())) {
613             if (tabular->right_column_of_cell(sel_cell_start) >
614                 tabular->right_column_of_cell(actcell))
615                 sel_cell_end = actcell+1;
616             else
617                 sel_cell_end = actcell;
618         }
619         UpdateLocal(bv, SELECTION, false);
620         break;
621     case LFUN_RIGHT:
622         result = moveRight(bv);
623         sel_pos_start = sel_pos_end = cursor.pos();
624         sel_cell_start = sel_cell_end = actcell;
625         if (hs)
626             UpdateLocal(bv, CURSOR, false);
627         break;
628     case LFUN_LEFTSEL:
629         if (tabular->IsFirstCellInRow(actcell) && cellstart(cursor.pos()))
630             break;
631         moveLeft(bv, false);
632         sel_pos_end = cursor.pos();
633         if (cellstart(cursor.pos())) {
634             if (tabular->column_of_cell(sel_cell_start) >=
635                 tabular->column_of_cell(actcell))
636                 sel_cell_end = actcell;
637             else
638                 sel_cell_end = actcell-1;
639         }
640         UpdateLocal(bv, SELECTION, false);
641         break;
642     case LFUN_LEFT:
643         result = moveLeft(bv);
644         sel_pos_start = sel_pos_end = cursor.pos();
645         sel_cell_start = sel_cell_end = actcell;
646         if (hs)
647             UpdateLocal(bv, CURSOR, false);
648         break;
649     case LFUN_DOWNSEL:
650     {
651         int ocell = actcell;
652         moveDown(bv);
653         sel_pos_end = cursor.pos();
654         if ((ocell == sel_cell_end) ||
655             (tabular->column_of_cell(ocell)>tabular->column_of_cell(actcell)))
656             sel_cell_end = tabular->GetCellBelow(sel_cell_end);
657         else
658             sel_cell_end = tabular->GetLastCellBelow(sel_cell_end);
659         UpdateLocal(bv, SELECTION, false);
660     }
661     break;
662     case LFUN_DOWN:
663         result= moveDown(bv);
664         sel_pos_start = sel_pos_end = cursor.pos();
665         sel_cell_start = sel_cell_end = actcell;
666         if (hs)
667             UpdateLocal(bv, CURSOR, false);
668         break;
669     case LFUN_UPSEL:
670     {
671         int ocell = actcell;
672         moveUp(bv);
673         sel_pos_end = cursor.pos();
674         if ((ocell == sel_cell_end) ||
675             (tabular->column_of_cell(ocell)>tabular->column_of_cell(actcell)))
676             sel_cell_end = tabular->GetCellAbove(sel_cell_end);
677         else
678             sel_cell_end = tabular->GetLastCellAbove(sel_cell_end);
679         UpdateLocal(bv, SELECTION, false);
680     }
681     break;
682     case LFUN_UP:
683         result= moveUp(bv);
684         sel_pos_start = sel_pos_end = cursor.pos();
685         sel_cell_start = sel_cell_end = actcell;
686         if (hs)
687             UpdateLocal(bv, CURSOR, false);
688         break;
689     case LFUN_BACKSPACE:
690         break;
691     case LFUN_DELETE:
692         break;
693     case LFUN_HOME:
694         break;
695     case LFUN_END:
696         break;
697     case LFUN_SHIFT_TAB:
698     case LFUN_TAB:
699         if (the_locking_inset) {
700             the_locking_inset->InsetUnlock(bv);
701         }
702         the_locking_inset = 0;
703         if (action == LFUN_TAB)
704             moveNextCell(bv);
705         else
706             movePrevCell(bv);
707         sel_pos_start = sel_pos_end = cursor.pos();
708         sel_cell_start = sel_cell_end = actcell;
709         if (hs)
710             UpdateLocal(bv, CURSOR, false);
711         break;
712     case LFUN_LAYOUT_TABLE:
713     {
714         dialogs_ = bv->owner()->getDialogs();
715         dialogs_->showTabular(this);
716     }
717     break;
718     default:
719         result = UNDISPATCHED;
720         break;
721     }
722     if (result!=FINISHED) {
723         if (!the_locking_inset) {
724 #if 0       
725             if (ocell != actcell)
726                 bview->getOwner()->getPopups().updateFormTabular();
727 #endif
728             ShowInsetCursor(bv);
729         }
730     } else
731         bv->unlockInset(this);
732     return result;
733 }
734
735
736 int InsetTabular::Latex(Buffer const * buf, ostream & os, bool fragile, bool fp) const
737 {
738     return tabular->Latex(buf, os, fragile, fp);
739 }
740
741
742 int InsetTabular::Ascii(Buffer const *, ostream &) const
743 {
744     return 0;
745 }
746
747 int InsetTabular::Linuxdoc(Buffer const *, ostream &) const
748 {
749     return 0;
750 }
751
752
753 int InsetTabular::DocBook(Buffer const *, ostream &) const
754 {
755     return 0;
756 }
757
758
759 void InsetTabular::Validate(LaTeXFeatures & features) const
760 {
761     tabular->Validate(features);
762 }
763
764
765 bool InsetTabular::calculate_dimensions_of_cells(BufferView * bv,
766                                                  LyXFont const & font,
767                                                  bool reinit) const
768 {
769     int cell = -1;
770     int maxAsc, maxDesc;
771     InsetText * inset;
772     bool changed = false;
773     
774     for(int i = 0; i < tabular->rows(); ++i) {
775         maxAsc = maxDesc = 0;
776         for(int j= 0; j < tabular->columns(); ++j) {
777             if (tabular->IsPartOfMultiColumn(i,j))
778                 continue;
779             ++cell;
780             inset = tabular->GetCellInset(cell);
781             if (!reinit)
782                 inset->update(bv, font, false);
783             maxAsc = max(maxAsc, inset->ascent(bv, font));
784             maxDesc = max(maxDesc, inset->descent(bv, font));
785             changed = tabular->SetWidthOfCell(cell, inset->width(bv, font)) || changed;
786         }
787         changed = tabular->SetAscentOfRow(i, maxAsc + ADD_TO_HEIGHT) || changed;
788         changed = tabular->SetDescentOfRow(i, maxDesc + ADD_TO_HEIGHT) || changed;
789     }
790     return changed;
791 }
792
793
794 void InsetTabular::GetCursorPos(BufferView *, int & x, int & y) const
795 {
796     x = cursor.x() - top_x;
797     y = cursor.y();
798 }
799
800
801 void InsetTabular::ToggleInsetCursor(BufferView * bv)
802 {
803     if (the_locking_inset) {
804         the_locking_inset->ToggleInsetCursor(bv);
805         return;
806     }
807
808     LyXFont font; // = the_locking_inset->GetFont(par, cursor.pos);
809
810     int asc = lyxfont::maxAscent(font);
811     int desc = lyxfont::maxDescent(font);
812   
813     if (cursor_visible)
814         bv->hideLockedInsetCursor();
815     else
816         bv->showLockedInsetCursor(cursor.x(), cursor.y(), asc, desc);
817     cursor_visible = !cursor_visible;
818 }
819
820
821 void InsetTabular::ShowInsetCursor(BufferView * bv)
822 {
823     if (!cursor_visible) {
824         LyXFont font; // = GetFont(par, cursor.pos);
825     
826         int asc = lyxfont::maxAscent(font);
827         int desc = lyxfont::maxDescent(font);
828         bv->fitLockedInsetCursor(cursor.x(), cursor.y(), asc, desc);
829         bv->showLockedInsetCursor(cursor.x(), cursor.y(), asc, desc);
830         cursor_visible = true;
831     }
832 }
833
834
835 void InsetTabular::HideInsetCursor(BufferView * bv)
836 {
837     if (cursor_visible)
838         ToggleInsetCursor(bv);
839 }
840
841
842 void InsetTabular::setPos(BufferView * bv, int x, int y) const
843 {
844         cursor.y(0);
845         cursor.pos(0);
846         
847         actcell = actrow = actcol = 0;
848     int ly = tabular->GetDescentOfRow(actrow);
849
850     // first search the right row
851     while((ly < y) && (actrow < tabular->rows())) {
852         cursor.y(cursor.y() + tabular->GetDescentOfRow(actrow) +
853             tabular->GetAscentOfRow(actrow+1) +
854             tabular->GetAdditionalHeight(tabular->GetCellNumber(actrow + 1,
855                                                                 actcol)));
856         ++actrow;
857         ly = cursor.y() + tabular->GetDescentOfRow(actrow);
858     }
859     actcell = tabular->GetCellNumber(actrow, actcol);
860
861     // now search the right column
862     int lx = tabular->GetWidthOfColumn(actcell) -
863         tabular->GetAdditionalWidth(actcell);
864     for(; !tabular->IsLastCellInRow(actcell) && (lx < x);
865         ++actcell,lx += tabular->GetWidthOfColumn(actcell) +
866             tabular->GetAdditionalWidth(actcell - 1));
867     cursor.pos(((actcell+1) * 2) - 1);
868     resetPos(bv);
869     if ((lx - (tabular->GetWidthOfColumn(actcell)/2)) < x) {
870         cursor.x(lx + top_x - 2);
871     } else {
872         cursor.pos(cursor.pos() - 1);
873         cursor.x(lx - tabular->GetWidthOfColumn(actcell) + top_x + 2);
874     }
875     resetPos(bv);
876 }
877
878 int InsetTabular::getCellXPos(int cell) const
879 {
880     int c;
881
882     for(c=cell;!tabular->IsFirstCellInRow(c);--c)
883         ;
884     int lx = tabular->GetWidthOfColumn(cell);
885     for(; (c < cell); ++c) {
886         lx += tabular->GetWidthOfColumn(c);
887     }
888     return (lx - tabular->GetWidthOfColumn(cell) + top_x +
889             ADD_TO_TABULAR_WIDTH);
890 }
891
892 void InsetTabular::resetPos(BufferView * bv) const
893 {
894     if (!locked)
895         return;
896     actcol = tabular->column_of_cell(actcell);
897
898     int cell = 0;
899     actrow = 0;
900     cursor.y(0);
901     for(; (cell<actcell) && !tabular->IsLastRow(cell); ++cell) {
902         if (tabular->IsLastCellInRow(cell)) {
903             cursor.y(cursor.y() + tabular->GetDescentOfRow(actrow) +
904                 tabular->GetAscentOfRow(actrow + 1) +
905                 tabular->GetAdditionalHeight(cell + 1));
906             ++actrow;
907         }
908     }
909     cursor.x(getCellXPos(actcell) + 2);
910     if (cursor.pos() % 2) {
911         LyXFont font(LyXFont::ALL_SANE);
912         cursor.x(cursor.x() + tabular->GetCellInset(actcell)->width(bv,font) +
913                 tabular->GetBeginningOfTextInCell(actcell));
914     }
915     if ((!the_locking_inset ||
916          !the_locking_inset->GetFirstLockingInsetOfType(TABULAR_CODE)) &&
917         (actcell != oldcell)) {
918         dialogs_ = bv->owner()->getDialogs();
919         dialogs_->updateTabular(const_cast<InsetTabular *>(this));
920         oldcell = actcell;
921     }
922 }
923
924
925 UpdatableInset::RESULT InsetTabular::moveRight(BufferView * bv, bool lock)
926 {
927     if (!cellstart(cursor.pos())) {
928         if (tabular->IsLastCell(actcell))
929             return FINISHED;
930         ++actcell;
931         cursor.pos(cursor.pos() + 1);
932     } else if (lock) {
933         if (ActivateCellInset(bv))
934             return DISPATCHED;
935     } else {              // before the inset
936         cursor.pos(cursor.pos() + 1);
937     }
938     resetPos(bv);
939     return DISPATCHED_NOUPDATE;
940 }
941
942
943 UpdatableInset::RESULT InsetTabular::moveLeft(BufferView * bv, bool lock)
944 {
945     if (!cursor.pos()) {
946         if (!actcell)
947             return FINISHED;
948         cursor.pos(2);
949     }
950     cursor.pos(cursor.pos() - 1);
951     if (!cellstart(cursor.pos())) {
952         --actcell;
953     } else if (lock) {       // behind the inset
954         if (ActivateCellInset(bv, 0, 0, 0, true))
955             return DISPATCHED;
956     }
957     resetPos(bv);
958     return DISPATCHED_NOUPDATE;
959 }
960
961
962 UpdatableInset::RESULT InsetTabular::moveUp(BufferView * bv)
963 {
964     int ocell = actcell;
965     actcell = tabular->GetCellAbove(actcell);
966     if (actcell == ocell) // we moved out of the inset
967         return FINISHED;
968     resetPos(bv);
969     return DISPATCHED_NOUPDATE;
970 }
971
972
973 UpdatableInset::RESULT InsetTabular::moveDown(BufferView * bv)
974 {
975     int ocell = actcell;
976     actcell = tabular->GetCellBelow(actcell);
977     if (actcell == ocell) // we moved out of the inset
978         return FINISHED;
979     resetPos(bv);
980     return DISPATCHED_NOUPDATE;
981 }
982
983
984 bool InsetTabular::moveNextCell(BufferView * bv)
985 {
986     if (tabular->IsLastCell(actcell))
987         return false;
988     ++actcell;
989     cursor.pos(cursor.pos() + 1);
990     if (!cellstart(cursor.pos()))
991         cursor.pos(cursor.pos() + 1);
992     resetPos(bv);
993     return true;
994 }
995
996
997 bool InsetTabular::movePrevCell(BufferView * bv)
998 {
999     if (!actcell) // first cell
1000         return false;
1001     --actcell;
1002     cursor.pos(cursor.pos() - 1);
1003     if (cellstart(cursor.pos()))
1004         cursor.pos(cursor.pos() - 1);
1005     resetPos(bv);
1006     return true;
1007 }
1008
1009
1010 bool InsetTabular::Delete()
1011 {
1012     return true;
1013 }
1014
1015
1016 void InsetTabular::SetFont(BufferView * bv, LyXFont const & font, bool tall)
1017 {
1018     if (the_locking_inset)
1019         the_locking_inset->SetFont(bv, font, tall);
1020 }
1021
1022
1023 void InsetTabular::TabularFeatures(BufferView * bv, int feature, string val)
1024 {
1025     int
1026         i, j,
1027         sel_col_start,
1028         sel_col_end,
1029         sel_row_start,
1030         sel_row_end,
1031         setLines = 0,
1032         setAlign = LYX_ALIGN_LEFT,
1033         lineSet;
1034     bool
1035         what;
1036
1037     switch (feature) {
1038       case LyXTabular::ALIGN_LEFT:
1039           setAlign=LYX_ALIGN_LEFT;
1040           break;
1041       case LyXTabular::ALIGN_RIGHT:
1042           setAlign=LYX_ALIGN_RIGHT;
1043           break;
1044       case LyXTabular::ALIGN_CENTER:
1045           setAlign=LYX_ALIGN_CENTER;
1046           break;
1047       default:
1048           break;
1049     }
1050     if (hasSelection()) {
1051         int tmp;
1052         sel_col_start = tabular->column_of_cell(sel_cell_start);
1053         sel_col_end = tabular->column_of_cell(sel_cell_end);
1054         if (sel_col_start > sel_col_end) {
1055             sel_col_end = sel_col_start;
1056             sel_col_start = tabular->column_of_cell(sel_cell_end);
1057         } else {
1058             sel_col_end = tabular->right_column_of_cell(sel_cell_end);
1059         }
1060         
1061         sel_row_start = tabular->row_of_cell(sel_cell_start);
1062         sel_row_end = tabular->row_of_cell(sel_cell_end);
1063         if (sel_row_start > sel_row_end) {
1064             tmp = sel_row_start;
1065             sel_row_start = sel_row_end;
1066             sel_row_end = tmp;
1067         }
1068     } else {
1069         sel_col_start = sel_col_end = tabular->column_of_cell(actcell);
1070         sel_row_start = sel_row_end = tabular->row_of_cell(actcell);
1071     }
1072     bv->text->SetUndo(bv->buffer(), Undo::FINISH, 
1073               bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->previous,
1074               bv->text->cursor.par()->ParFromPos(bv->text->cursor.pos())->next);
1075
1076     int row = tabular->row_of_cell(actcell);
1077     int column = tabular->column_of_cell(actcell);
1078
1079     switch (feature) {
1080     case LyXTabular::SET_PWIDTH:
1081     {
1082         bool update = (tabular->GetPWidth(actcell) != val);
1083         tabular->SetPWidth(actcell,val);
1084         if (update) {
1085             for (int i=0; i < tabular->rows(); ++i) {
1086                 tabular->GetCellInset(tabular->GetCellNumber(i, column))->
1087                     deleteLyXText(bv);
1088             }
1089             UpdateLocal(bv, INIT, true);
1090         }
1091     }
1092     break;
1093     case LyXTabular::SET_SPECIAL_COLUMN:
1094     case LyXTabular::SET_SPECIAL_MULTI:
1095         tabular->SetAlignSpecial(actcell,val,feature);
1096         break;
1097     case LyXTabular::APPEND_ROW:
1098         // append the row into the tabular
1099         UnlockInsetInInset(bv, the_locking_inset);
1100         tabular->AppendRow(actcell);
1101         UpdateLocal(bv, INIT, true);
1102         break;
1103     case LyXTabular::APPEND_COLUMN:
1104         // append the column into the tabular
1105         tabular->AppendColumn(actcell);
1106         actcell = tabular->GetCellNumber(row, column);
1107         UpdateLocal(bv, INIT, true);
1108         break;
1109     case LyXTabular::DELETE_ROW:
1110         tabular->DeleteRow(tabular->row_of_cell(actcell));
1111         if ((row+1) > tabular->rows())
1112             --row;
1113         actcell = tabular->GetCellNumber(row, column);
1114         UpdateLocal(bv, INIT, true);
1115         break;
1116     case LyXTabular::DELETE_COLUMN:
1117         tabular->DeleteColumn(tabular->column_of_cell(actcell));
1118         if ((column+1) > tabular->columns())
1119             --column;
1120         actcell = tabular->GetCellNumber(row, column);
1121         UpdateLocal(bv, INIT, true);
1122         break;
1123     case LyXTabular::TOGGLE_LINE_TOP:
1124         lineSet = !tabular->TopLine(actcell);
1125         for(i=sel_row_start; i<=sel_row_end; ++i)
1126             for(j=sel_col_start; j<=sel_col_end; ++j)
1127                 tabular->SetTopLine(tabular->GetCellNumber(i,j),lineSet);
1128         UpdateLocal(bv, INIT, true);
1129         break;
1130     
1131     case LyXTabular::TOGGLE_LINE_BOTTOM:
1132         lineSet = !tabular->BottomLine(actcell); 
1133         for(i=sel_row_start; i<=sel_row_end; ++i)
1134             for(j=sel_col_start; j<=sel_col_end; ++j)
1135                 tabular->SetBottomLine(tabular->GetCellNumber(i,j),lineSet);
1136         UpdateLocal(bv, INIT, true);
1137         break;
1138                 
1139     case LyXTabular::TOGGLE_LINE_LEFT:
1140         lineSet = !tabular->LeftLine(actcell);
1141         for(i=sel_row_start; i<=sel_row_end; ++i)
1142             for(j=sel_col_start; j<=sel_col_end; ++j)
1143                 tabular->SetLeftLine(tabular->GetCellNumber(i,j),lineSet);
1144         UpdateLocal(bv, INIT, true);
1145         break;
1146
1147     case LyXTabular::TOGGLE_LINE_RIGHT:
1148         lineSet = !tabular->RightLine(actcell);
1149         for(i=sel_row_start; i<=sel_row_end; ++i)
1150             for(j=sel_col_start; j<=sel_col_end; ++j)
1151                 tabular->SetRightLine(tabular->GetCellNumber(i,j),lineSet);
1152         UpdateLocal(bv, INIT, true);
1153         break;
1154     case LyXTabular::ALIGN_LEFT:
1155     case LyXTabular::ALIGN_RIGHT:
1156     case LyXTabular::ALIGN_CENTER:
1157         for(i=sel_row_start; i<=sel_row_end; ++i)
1158             for(j=sel_col_start; j<=sel_col_end; ++j)
1159                 tabular->SetAlignment(tabular->GetCellNumber(i,j),setAlign);
1160         if (hasSelection())
1161             UpdateLocal(bv, INIT, true);
1162         else
1163             UpdateLocal(bv, CELL, true);
1164         break;
1165     case LyXTabular::MULTICOLUMN:
1166     {
1167         if (sel_row_start != sel_row_end) {
1168             WriteAlert(_("Impossible Operation!"), 
1169                        _("Multicolumns can only be horizontally."), 
1170                        _("Sorry."));
1171             return;
1172         }
1173         // just multicol for one Single Cell
1174         if (!hasSelection()) {
1175             // check wether we are completly in a multicol
1176             if (tabular->IsMultiColumn(actcell)) {
1177                 tabular->UnsetMultiColumn(actcell);
1178                 UpdateLocal(bv, INIT, true);
1179             } else {
1180                 tabular->SetMultiColumn(actcell, 1);
1181                 UpdateLocal(bv, CELL, true);
1182             }
1183             return;
1184         }
1185         // we have a selection so this means we just add all this
1186         // cells to form a multicolumn cell
1187         int
1188             s_start, s_end;
1189
1190         if (sel_cell_start > sel_cell_end) {
1191             s_start = sel_cell_end;
1192             s_end = sel_cell_start;
1193         } else {
1194             s_start = sel_cell_start;
1195             s_end = sel_cell_end;
1196         }
1197         tabular->SetMultiColumn(s_start, s_end - s_start + 1);
1198         actcell = s_start;
1199         cursor.pos(0);
1200         sel_cell_end = sel_cell_start;
1201         sel_pos_end = sel_pos_start;
1202         UpdateLocal(bv, INIT, true);
1203         break;
1204     }
1205     case LyXTabular::SET_ALL_LINES:
1206         setLines = 1;
1207     case LyXTabular::UNSET_ALL_LINES:
1208         for(i=sel_row_start; i<=sel_row_end; ++i)
1209             for(j=sel_col_start; j<=sel_col_end; ++j)
1210                 tabular->SetAllLines(tabular->GetCellNumber(i,j), setLines);
1211         UpdateLocal(bv, INIT, true);
1212         break;
1213     case LyXTabular::SET_LONGTABULAR:
1214         tabular->SetLongTabular(true);
1215         UpdateLocal(bv, INIT, true); // because this toggles displayed
1216         break;
1217     case LyXTabular::UNSET_LONGTABULAR:
1218         tabular->SetLongTabular(false);
1219         UpdateLocal(bv, INIT, true); // because this toggles displayed
1220         break;
1221     case LyXTabular::SET_ROTATE_TABULAR:
1222         tabular->SetRotateTabular(true);
1223         break;
1224     case LyXTabular::UNSET_ROTATE_TABULAR:
1225         tabular->SetRotateTabular(false);
1226         break;
1227     case LyXTabular::SET_ROTATE_CELL:
1228         for(i=sel_row_start; i<=sel_row_end; ++i)
1229             for(j=sel_col_start; j<=sel_col_end; ++j)
1230                 tabular->SetRotateCell(tabular->GetCellNumber(i,j),true);
1231         break;
1232     case LyXTabular::UNSET_ROTATE_CELL:
1233         for(i=sel_row_start; i<=sel_row_end; ++i)
1234             for(j=sel_col_start; j<=sel_col_end; ++j)
1235                 tabular->SetRotateCell(tabular->GetCellNumber(i,j),false);
1236         break;
1237     case LyXTabular::SET_LINEBREAKS:
1238         what = !tabular->GetLinebreaks(actcell);
1239         for(i=sel_row_start; i<=sel_row_end; ++i)
1240             for(j=sel_col_start; j<=sel_col_end; ++j)
1241                 tabular->SetLinebreaks(tabular->GetCellNumber(i,j),what);
1242         break;
1243     case LyXTabular::SET_LTFIRSTHEAD:
1244         tabular->SetLTHead(actcell,true);
1245         break;
1246     case LyXTabular::SET_LTHEAD:
1247         tabular->SetLTHead(actcell,false);
1248         break;
1249     case LyXTabular::SET_LTFOOT:
1250         tabular->SetLTFoot(actcell,false);
1251         break;
1252     case LyXTabular::SET_LTLASTFOOT:
1253         tabular->SetLTFoot(actcell,true);
1254         break;
1255     case LyXTabular::SET_LTNEWPAGE:
1256         what = !tabular->GetLTNewPage(actcell);
1257         tabular->SetLTNewPage(actcell,what);
1258         break;
1259     }
1260 }
1261
1262 bool InsetTabular::ActivateCellInset(BufferView * bv, int x, int y, int button,
1263                                      bool behind)
1264 {
1265     // the cursor.pos has to be before the inset so if it isn't now just
1266     // reset the curor pos first!
1267     if (cursor.pos() % 2) { // behind the inset
1268         cursor.pos(cursor.pos() - 1);
1269         resetPos(bv);
1270     }
1271     UpdatableInset * inset =
1272         static_cast<UpdatableInset*>(tabular->GetCellInset(actcell));
1273     LyXFont font(LyXFont::ALL_SANE);
1274     if (behind) {
1275         x = inset->x() + inset->width(bv, font);
1276         y = inset->descent(bv, font);
1277     }
1278     inset_x = cursor.x() - top_x + tabular->GetBeginningOfTextInCell(actcell);
1279     inset_y = cursor.y();
1280     inset->Edit(bv, x - inset_x, y - inset_y, button);
1281     if (!the_locking_inset)
1282         return false;
1283     UpdateLocal(bv, CELL, false);
1284     return true;
1285 }
1286
1287 bool InsetTabular::InsetHit(BufferView * bv, int x, int ) const
1288 {
1289     InsetText * inset = tabular->GetCellInset(actcell);
1290     int x1 = x + top_x;
1291
1292     if (cursor.pos() % 2) { // behind the inset
1293         return (((x + top_x) < cursor.x()) &&
1294                 ((x + top_x) > (cursor.x() - inset->width(bv,
1295                                                       LyXFont(LyXFont::ALL_SANE)))));
1296     } else {
1297         int x2 = cursor.x() + tabular->GetBeginningOfTextInCell(actcell);
1298         return ((x1 > x2) &&
1299                 (x1 < (x2 + inset->width(bv, LyXFont(LyXFont::ALL_SANE)))));
1300     }
1301 }
1302
1303 // This returns paperWidth() if the cell-width is unlimited or the width
1304 // in pixels if we have a pwidth for this cell.
1305 int InsetTabular::GetMaxWidthOfCell(Painter &, int cell) const
1306 {
1307     string s = tabular->GetPWidth(cell);
1308
1309     if (s.empty())
1310         return -1;
1311     return VSpace(s).inPixels( 0, 0);
1312 }
1313
1314 int InsetTabular::getMaxWidth(Painter & pain,
1315                               UpdatableInset const * inset) const
1316 {
1317     int cell;
1318     int n = tabular->GetNumberOfCells();
1319     for(cell=0; cell < n; ++cell) {
1320         if (tabular->GetCellInset(cell) == inset)
1321             break;
1322     }
1323     if (cell >= n)
1324         return -1;
1325     int w = GetMaxWidthOfCell(pain, cell);
1326     // this because text insets remove the xpos from the maxwidth because
1327     // otherwise the would not break good!!!
1328 //    w += getCellXPos(cell) + tabular->GetBeginningOfTextInCell(cell);
1329 //    w += inset->x();
1330     return w;
1331 }
1332
1333 void InsetTabular::recomputeTextInsets(BufferView * bv, const LyXFont & font) const
1334 {
1335     InsetText * inset;
1336     int cell;
1337
1338 //    cx = top_x;
1339     for(int j= 0; j < tabular->columns(); ++j) {
1340         for(int i = 0; i < tabular->rows(); ++i) {
1341             if (tabular->IsPartOfMultiColumn(i,j))
1342                 continue;
1343             cell = tabular->GetCellNumber(i,j);
1344             inset = tabular->GetCellInset(cell);
1345             inset->update(bv, font);
1346             tabular->SetWidthOfCell(cell, inset->width(bv, font));
1347         }
1348 //      cell = tabular->GetCellNumber(0, j);
1349 //      cx += tabular->GetWidthOfColumn(cell);
1350     }
1351 }