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