]> git.lyx.org Git - features.git/blob - src/insets/insettabular.C
Just some changes to be able to change TabularFeatures with the Table menu
[features.git] / src / insets / insettabular.C
1 /* This file is part of
2  * ======================================================
3  * 
4  *           LyX, The Document Processor
5  *
6  *           Copyright 2000 The LyX Team.
7  *
8  *======================================================
9  */
10
11 #include <config.h>
12
13 #include <fstream>
14 #include <algorithm>
15
16 #include <cstdlib>
17
18 #ifdef __GNUG__
19 #pragma implementation
20 #endif
21
22 #include "insettabular.h"
23
24 #include "buffer.h"
25 #include "commandtags.h"
26 #include "LaTeXFeatures.h"
27 #include "Painter.h"
28 #include "font.h"
29 #include "lyxtext.h"
30 #include "lyx_gui_misc.h"
31 #include "insets/insettext.h"
32
33 const int ADD_TO_HEIGHT = 2;
34 const int ADD_TO_TABULAR_WIDTH = 2;
35
36 using std::ostream;
37 using std::ifstream;
38 using std::max;
39 using std::endl;
40
41
42 InsetTabular::InsetTabular(Buffer * buf, int rows, int columns)
43 {
44     if (rows <= 0)
45         rows = 1;
46     if (columns <= 0)
47         columns = 1;
48     tabular = new LyXTabular(rows,columns,buf);
49     // for now make it always display as display() inset
50     // just for test!!!
51     tabular->SetLongTabular(true);
52     the_locking_inset = 0;
53     buffer = buf;
54     cursor_visible = false;
55     cursor.x_fix = -1;
56     actcell = cursor.pos = sel_pos_start = sel_pos_end = 0;
57     no_selection = false;
58     init = true;
59 }
60
61
62 InsetTabular::InsetTabular(InsetTabular const & tab, Buffer * buf)
63 {
64     tabular = new LyXTabular(*(tab.tabular), buf);
65     the_locking_inset = 0;
66     buffer = buf;
67     cursor_visible = false;
68     cursor.x_fix = -1;
69     actcell = cursor.pos = sel_pos_start = sel_pos_end = 0;
70     no_selection = false;
71     init = true;
72 }
73
74
75 InsetTabular::~InsetTabular()
76 {
77     delete tabular;
78 }
79
80
81 Inset * InsetTabular::Clone() const
82 {
83     InsetTabular * t = new InsetTabular(*this, buffer);
84     return t;
85 }
86
87
88 void InsetTabular::Write(ostream & os) const
89 {
90     os << " Tabular" << endl;
91     tabular->Write(os);
92 }
93
94
95 void InsetTabular::Read(LyXLex & lex)
96 {
97 //    bool old_format = (lex.GetString() == "\\LyXTable");
98     string token;
99
100     if (tabular)
101         delete tabular;
102     tabular = new LyXTabular(lex, buffer);
103
104     lex.nextToken();
105     token = lex.GetString();
106     while (lex.IsOK() && (token != "\\end_inset")) {
107         lex.nextToken();
108         token = lex.GetString();
109     }
110     if (token != "\\end_inset") {
111         lex.printError("Missing \\end_inset at this point. "
112                        "Read: `$$Token'");
113     }
114     tabular->SetLongTabular(true);
115     init = true;
116 }
117
118
119 int InsetTabular::ascent(Painter & pain, LyXFont const & font) const
120 {
121     if (init) {
122         calculate_width_of_cells(pain, font);
123         init = false;
124     }
125     return tabular->GetAscentOfRow(0);
126 }
127
128
129 int InsetTabular::descent(Painter & pain, LyXFont const & font) const
130 {
131     if (init) {
132         calculate_width_of_cells(pain, font);
133         init = false;
134     }
135     return tabular->GetHeightOfTabular() - tabular->GetAscentOfRow(0);
136 }
137
138
139 int InsetTabular::width(Painter & pain, LyXFont const & font) const
140 {
141     if (init) {
142         calculate_width_of_cells(pain, font);
143         init = false;
144     }
145     return tabular->GetWidthOfTabular() + (2 * ADD_TO_TABULAR_WIDTH);
146 }
147
148
149 void InsetTabular::draw(Painter & pain, const LyXFont & font, int baseline,
150                         float & x) const
151 {
152     int i, j, cell=0;
153     int nx;
154     float cx;
155
156     UpdatableInset::draw(pain,font,baseline,x);
157     if ((top_x != int(x)) || (top_baseline != baseline)) {
158         top_x = int(x);
159         top_baseline = baseline;
160         resetPos(pain);
161     }
162     for(i=0;i<tabular->rows();++i) {
163         nx = int(x);
164         for(j=0;j<tabular->columns();++j) {
165             cx = nx + tabular->GetBeginningOfTextInCell(cell);
166             tabular->GetCellInset(cell)->draw(pain, font, baseline, cx);
167             DrawCellLines(pain, nx, baseline, i, cell);
168             nx += tabular->GetWidthOfColumn(cell);
169             ++cell;
170         }
171         baseline += tabular->GetDescentOfRow(i) + tabular->GetAscentOfRow(i+1)
172             + tabular->GetAdditionalHeight(cell+1);
173     }
174 }
175
176
177 void InsetTabular::DrawCellLines(Painter & pain, int x, int baseline,
178                                  int row, int cell) const
179 {
180     int  x2 = x + tabular->GetWidthOfColumn(cell);
181     bool on_off;
182
183     if (!tabular->TopAlreadyDrawed(cell)) {
184         on_off = !tabular->TopLine(cell);
185         pain.line(x, baseline - tabular->GetAscentOfRow(row),
186                   x2, baseline -  tabular->GetAscentOfRow(row),
187                   on_off ? LColor::tabularonoffline:LColor::tabularline,
188                   on_off ? Painter::line_onoffdash:Painter::line_solid);
189     }
190     on_off = !tabular->BottomLine(cell);
191     pain.line(x,baseline +  tabular->GetDescentOfRow(row),
192               x2, baseline +  tabular->GetDescentOfRow(row),
193               on_off ? LColor::tabularonoffline:LColor::tabularline,
194               on_off ? Painter::line_onoffdash:Painter::line_solid);
195     if (!tabular->LeftAlreadyDrawed(cell)) {
196         on_off = !tabular->LeftLine(cell);
197         pain.line(x, baseline -  tabular->GetAscentOfRow(row),
198                   x, baseline +  tabular->GetDescentOfRow(row),
199                   on_off ? LColor::tabularonoffline:LColor::tabularline,
200                   on_off ? Painter::line_onoffdash:Painter::line_solid);
201     }
202     on_off = !tabular->RightLine(cell);
203     pain.line(x2 - tabular->GetAdditionalWidth(cell),
204               baseline -  tabular->GetAscentOfRow(row),
205               x2 - tabular->GetAdditionalWidth(cell),
206               baseline +  tabular->GetDescentOfRow(row),
207               on_off ? LColor::tabularonoffline:LColor::tabularline,
208               on_off ? Painter::line_onoffdash:Painter::line_solid);
209 }
210
211
212 char const * InsetTabular::EditMessage() const
213 {
214     return _("Opened Tabular Inset");
215 }
216
217
218 void InsetTabular::Edit(BufferView * bv, int x, int y, unsigned int button)
219 {
220     UpdatableInset::Edit(bv, x, y, button);
221
222     if (!bv->lockInset(this)) {
223         lyxerr[Debug::INSETS] << "InsetTabular::Cannot lock inset" << endl;
224         return;
225     }
226     the_locking_inset = 0;
227     sel_pos_start = sel_pos_end = inset_pos = inset_x = inset_y = 0;
228     setPos(bv->painter(), x, y);
229     sel_pos_start = sel_pos_end = cursor.pos;
230     bv->text->FinishUndo();
231     if (InsetHit(bv, x, y)) {
232         ActivateCellInset(bv, x, y, button);
233     }
234     UpdateLocal(bv, true);
235 //    bv->getOwner()->getPopups().updateFormTabular();
236 }
237
238
239 void InsetTabular::InsetUnlock(BufferView * bv)
240 {
241     if (the_locking_inset) {
242         the_locking_inset->InsetUnlock(bv);
243         the_locking_inset = 0;
244     }
245     HideInsetCursor(bv);
246     if (hasCharSelection()) {
247         sel_pos_start = sel_pos_end = cursor.pos;
248         UpdateLocal(bv, false);
249     } else
250         sel_pos_start = sel_pos_end = cursor.pos;
251     no_selection = false;
252 }
253
254 void InsetTabular::UpdateLocal(BufferView * bv, bool flag)
255 {
256     if (flag) {
257         calculate_width_of_cells(bv->painter(), LyXFont(LyXFont::ALL_SANE));
258         resetPos(bv->painter());
259     }
260     bv->updateInset(this, flag);
261 }
262
263 bool InsetTabular::LockInsetInInset(BufferView * bv, UpdatableInset * inset)
264 {
265     lyxerr[Debug::INSETS] << "InsetTabular::LockInsetInInset(" <<inset<< "): ";
266     if (!inset)
267         return false;
268     if (inset == tabular->GetCellInset(actcell)) {
269         lyxerr[Debug::INSETS] << "OK" << endl;
270         the_locking_inset = tabular->GetCellInset(actcell);
271         resetPos(bv->painter());
272         inset_x = cursor.x - top_x + tabular->GetBeginningOfTextInCell(actcell);
273         inset_y = cursor.y;
274         inset_pos = cursor.pos;
275         return true;
276     } else if (the_locking_inset && (the_locking_inset == inset)) {
277         if (cursor.pos == inset_pos) {
278             lyxerr[Debug::INSETS] << "OK" << endl;
279             resetPos(bv->painter());
280             inset_x = cursor.x - top_x + tabular->GetBeginningOfTextInCell(actcell);
281             inset_y = cursor.y;
282         } else {
283             lyxerr[Debug::INSETS] << "cursor.pos != inset_pos" << endl;
284         }
285     } else if (the_locking_inset) {
286         lyxerr[Debug::INSETS] << "MAYBE" << endl;
287         return the_locking_inset->LockInsetInInset(bv, inset);
288     }
289     lyxerr[Debug::INSETS] << "NOT OK" << endl;
290     return false;
291 }
292
293 bool InsetTabular::UnlockInsetInInset(BufferView * bv, UpdatableInset * inset,
294                                    bool lr)
295 {
296     if (!the_locking_inset)
297         return false;
298     if (the_locking_inset == inset) {
299         the_locking_inset->InsetUnlock(bv);
300         the_locking_inset = 0;
301         if (lr)
302             moveRight(bv, false);
303         return true;
304     }
305     return the_locking_inset->UnlockInsetInInset(bv, inset, lr);
306 }
307
308 bool InsetTabular::UpdateInsetInInset(BufferView * bv, Inset * inset)
309 {
310     if (!the_locking_inset)
311         return false;
312     if (the_locking_inset != inset)
313         return the_locking_inset->UpdateInsetInInset(bv, inset);
314     UpdateLocal(bv);
315     return true;
316 }
317
318
319 int InsetTabular::InsetInInsetY()
320 {
321     if (!the_locking_inset)
322         return 0;
323
324     return (inset_y + the_locking_inset->InsetInInsetY());
325 }
326
327 void InsetTabular::InsetButtonRelease(BufferView * bv,
328                                       int x, int y, int button)
329 {
330     if (the_locking_inset) {
331         the_locking_inset->InsetButtonRelease(bv, x-inset_x, y-inset_y,button);
332         return;
333     }
334     no_selection = false;
335 }
336
337
338 void InsetTabular::InsetButtonPress(BufferView * bv, int x, int y, int button)
339 {
340     if (hasCharSelection()) {
341         sel_pos_start = sel_pos_end = 0;
342         UpdateLocal(bv, false);
343     }
344     no_selection = false;
345
346     int oldcell = actcell;
347
348     setPos(bv->painter(), x, y);
349
350     bool inset_hit = InsetHit(bv, x, y);
351
352     if ((oldcell == actcell) && the_locking_inset && inset_hit) {
353         the_locking_inset->InsetButtonPress(bv, x-inset_x, y-inset_y, button);
354         return;
355     } else if (the_locking_inset) {
356         the_locking_inset->InsetUnlock(bv);
357     }
358     the_locking_inset = 0;
359     sel_pos_start = sel_pos_end = cursor.pos;
360     sel_cell_start = sel_cell_end = actcell;
361     if (inset_hit && bv->the_locking_inset) {
362         ActivateCellInset(bv, x, y, button);
363         the_locking_inset->InsetButtonPress(bv, x-inset_x, y-inset_y, button);
364     }
365     
366 #if 0
367     if (button == 3)
368         bview->getOwner()->getPopups().showFormTabular();
369     else if (oldcell != actcell)
370         bview->getOwner()->getPopups().updateFormTabular();
371 #endif
372 }
373
374
375 void InsetTabular::InsetMotionNotify(BufferView * bv, int x, int y, int button)
376 {
377     if (the_locking_inset) {
378         the_locking_inset->InsetMotionNotify(bv, x - inset_x,
379                                              y - inset_y, button);
380         return;
381     }
382     if (!no_selection) {
383             // int oldcell = actcell,
384             int old = sel_pos_end;
385
386         setPos(bv->painter(), x, y);
387         sel_pos_end = cursor.pos;
388         sel_cell_end = actcell;
389         if (old != sel_pos_end)
390             UpdateLocal(bv, false);
391 #if 0
392         if (oldcell != actcell)
393             bview->getOwner()->getPopups().updateFormTabular();
394 #endif
395     }
396     no_selection = false;
397 }
398
399
400 void InsetTabular::InsetKeyPress(XKeyEvent * xke)
401 {
402     if (the_locking_inset) {
403         the_locking_inset->InsetKeyPress(xke);
404         return;
405     }
406 }
407
408
409 UpdatableInset::RESULT InsetTabular::LocalDispatch(BufferView * bv, int action,
410                                                    string const & arg)
411 {
412     UpdatableInset::RESULT 
413         result;
414
415     no_selection = false;
416     if (((result=UpdatableInset::LocalDispatch(bv, action, arg)) == DISPATCHED)
417         || (result == DISPATCHED_NOUPDATE)) {
418
419         resetPos(bv->painter());
420         return result;
421     }
422     result=DISPATCHED;
423
424     if ((action < 0) && arg.empty())
425         return FINISHED;
426
427     if ((action != LFUN_DOWN) && (action != LFUN_UP) &&
428         (action != LFUN_DOWNSEL) && (action != LFUN_UPSEL))
429         cursor.x_fix = -1;
430     if (the_locking_inset) {
431         result=the_locking_inset->LocalDispatch(bv, action, arg);
432         if (result == DISPATCHED_NOUPDATE)
433             return result;
434         else if (result == DISPATCHED) {
435             bool upd = SetCellDimensions(bv->painter(), actcell, actrow);
436             the_locking_inset->ToggleInsetCursor(bv);
437             UpdateLocal(bv, upd);
438             the_locking_inset->ToggleInsetCursor(bv);
439             return result;
440         } else if (result == FINISHED) {
441             if ((action == LFUN_RIGHT) || (action == -1)) {
442                 cursor.pos = inset_pos + 1;
443                 resetPos(bv->painter());
444             }
445             the_locking_inset=0;
446             result = DISPATCHED;
447             return result;
448         }
449     }
450
451     HideInsetCursor(bv);
452     switch (action) {
453       // Normal chars not handled here
454       case -1:
455           break;
456       // --- Cursor Movements ---------------------------------------------
457       case LFUN_RIGHTSEL:
458           moveRight(bv, false);
459           sel_pos_end = cursor.pos;
460           UpdateLocal(bv, false);
461           break;
462       case LFUN_RIGHT:
463           result = moveRight(bv);
464           if (hasCharSelection()) {
465               sel_pos_start = sel_pos_end = cursor.pos;
466               UpdateLocal(bv, false);
467           } else
468               sel_pos_start = sel_pos_end = cursor.pos;
469           break;
470       case LFUN_LEFTSEL:
471           moveLeft(bv, false);
472           sel_pos_end = cursor.pos;
473           UpdateLocal(bv, false);
474           break;
475       case LFUN_LEFT:
476           result = moveLeft(bv);
477           if (hasCharSelection()) {
478               sel_pos_start = sel_pos_end = cursor.pos;
479               UpdateLocal(bv, false);
480           } else
481               sel_pos_start = sel_pos_end = cursor.pos;
482           break;
483       case LFUN_DOWNSEL:
484           moveDown();
485           sel_pos_end = cursor.pos;
486           UpdateLocal(bv, false);
487           break;
488       case LFUN_DOWN:
489           result= moveDown();
490           if (hasCharSelection()) {
491               sel_pos_start = sel_pos_end = cursor.pos;
492               UpdateLocal(bv, false);
493           } else
494               sel_pos_start = sel_pos_end = cursor.pos;
495           break;
496       case LFUN_UPSEL:
497           moveUp();
498           sel_pos_end = cursor.pos;
499           UpdateLocal(bv, false);
500           break;
501       case LFUN_UP:
502           result= moveUp();
503           if (hasCharSelection()) {
504               sel_pos_start = sel_pos_end = cursor.pos;
505               UpdateLocal(bv, false);
506           } else
507               sel_pos_start = sel_pos_end = cursor.pos;
508           break;
509       case LFUN_BACKSPACE:
510           break;
511       case LFUN_DELETE:
512           break;
513       case LFUN_HOME:
514           break;
515       case LFUN_END:
516           break;
517       case LFUN_TAB:
518           if (hasCharSelection()) {
519               sel_pos_start = sel_pos_end = cursor.pos;
520               UpdateLocal(bv, false);
521           }
522           sel_pos_start = sel_pos_end = cursor.pos;
523           moveNextCell();
524           break;
525       default:
526           result = UNDISPATCHED;
527           break;
528     }
529     if (result!=FINISHED) {
530         if (!the_locking_inset) {
531 #if 0       
532             if (oldcell != actcell)
533                 bview->getOwner()->getPopups().updateFormTabular();
534 #endif
535             ShowInsetCursor(bv);
536         }
537     } else
538         bv->unlockInset(this);
539     return result;
540 }
541
542
543 int InsetTabular::Latex(ostream & os, bool, bool) const
544 {
545     return tabular->Latex(os);
546 }
547
548
549 int InsetTabular::Ascii(ostream &) const
550 {
551     return 0;
552 }
553
554 int InsetTabular::Linuxdoc(ostream &) const
555 {
556     return 0;
557 }
558
559
560 int InsetTabular::DocBook(ostream &) const
561 {
562     return 0;
563 }
564
565
566 void InsetTabular::Validate(LaTeXFeatures & features) const
567 {
568     if (tabular->IsLongTabular())
569         features.longtable = true;
570 }
571
572
573 void InsetTabular::calculate_width_of_cells(Painter & pain,
574                                             LyXFont const & font) const
575 {
576     int cell = -1;
577     int maxAsc, maxDesc;
578     InsetText * inset;
579     
580     for(int i = 0; i < tabular->rows(); ++i) {
581         maxAsc = maxDesc = 0;
582         for(int j= 0; j < tabular->columns(); ++j) {
583             if (tabular->IsPartOfMultiColumn(i,j))
584                 continue;
585             ++cell;
586             inset = tabular->GetCellInset(cell);
587             maxAsc = max(maxAsc, inset->ascent(pain, font));
588             maxDesc = max(maxDesc, inset->descent(pain, font));
589             tabular->SetWidthOfCell(cell, inset->width(pain, font));
590         }
591         tabular->SetAscentOfRow(i, maxAsc + ADD_TO_HEIGHT);
592         tabular->SetDescentOfRow(i, maxDesc + ADD_TO_HEIGHT);
593     }
594 }
595
596
597 void InsetTabular::GetCursorPos(int & x, int & y) const
598 {
599     x = cursor.x-top_x;
600     y = cursor.y;
601 }
602
603
604 void InsetTabular::ToggleInsetCursor(BufferView * bv)
605 {
606     if (the_locking_inset) {
607         the_locking_inset->ToggleInsetCursor(bv);
608         return;
609     }
610
611     LyXFont font; // = the_locking_inset->GetFont(par, cursor.pos);
612
613     int asc = lyxfont::maxAscent(font);
614     int desc = lyxfont::maxDescent(font);
615   
616     if (cursor_visible)
617         bv->hideLockedInsetCursor();
618     else
619         bv->showLockedInsetCursor(cursor.x, cursor.y, asc, desc);
620     cursor_visible = !cursor_visible;
621 }
622
623
624 void InsetTabular::ShowInsetCursor(BufferView * bv)
625 {
626     if (!cursor_visible) {
627         LyXFont font; // = GetFont(par, cursor.pos);
628     
629         int asc = lyxfont::maxAscent(font);
630         int desc = lyxfont::maxDescent(font);
631         bv->fitLockedInsetCursor(cursor.x, cursor.y, asc, desc);
632         bv->showLockedInsetCursor(cursor.x, cursor.y, asc, desc);
633         cursor_visible = true;
634     }
635 }
636
637
638 void InsetTabular::HideInsetCursor(BufferView * bv)
639 {
640     if (cursor_visible)
641         ToggleInsetCursor(bv);
642 }
643
644
645 void InsetTabular::setPos(Painter & pain, int x, int y) const
646 {
647     cursor.y = cursor.pos = actcell = actrow = actcol = 0;
648     int ly = tabular->GetDescentOfRow(actrow);
649
650     // first search the right row
651     while((ly < y) && (actrow < tabular->rows())) {
652         cursor.y += tabular->GetDescentOfRow(actrow) +
653                 tabular->GetAscentOfRow(actrow+1) +
654             tabular->GetAdditionalHeight(tabular->GetCellNumber(actcol,actrow+1));
655         ++actrow;
656         ly = cursor.y + tabular->GetDescentOfRow(actrow);
657     }
658     actcell = tabular->GetCellNumber(actcol, actrow);
659
660     // now search the right column
661     int lx = tabular->GetWidthOfColumn(actcell) -
662         tabular->GetAdditionalWidth(actcell);
663     for(; !tabular->IsLastCellInRow(actcell) && (lx < x);
664         ++actcell,lx += tabular->GetWidthOfColumn(actcell) +
665             tabular->GetAdditionalWidth(actcell-1));
666     cursor.pos = ((actcell+1) * 2) - 1;
667     resetPos(pain);
668     if ((lx - (tabular->GetWidthOfColumn(actcell)/2)) < x) {
669         cursor.x = lx + top_x - 2;
670     } else {
671         --cursor.pos;
672         cursor.x = lx - tabular->GetWidthOfColumn(actcell) + top_x + 2;
673     }
674     resetPos(pain);
675 }
676
677
678 void InsetTabular::resetPos(Painter & pain) const
679 {
680     actrow = cursor.y = actcol = 0;
681
682     int cell = 0;
683     for(; (cell<actcell) && !tabular->IsLastRow(cell); ++cell) {
684         if (tabular->IsLastCellInRow(cell)) {
685             cursor.y += tabular->GetDescentOfRow(actrow) +
686                 tabular->GetAscentOfRow(actrow+1) +
687                 tabular->GetAdditionalHeight(cell+1);
688             ++actrow;
689         }
690     }
691     for(cell=actcell;!tabular->IsFirstCellInRow(cell);--cell)
692         ;
693     int lx = tabular->GetWidthOfColumn(actcell);
694     for(; (cell < actcell); ++cell) {
695         lx += tabular->GetWidthOfColumn(cell);
696         ++actcol;
697     }
698     cursor.x = lx - tabular->GetWidthOfColumn(actcell) + top_x + 2;
699     if (cursor.pos % 2) {
700         LyXFont font(LyXFont::ALL_SANE);
701         cursor.x += tabular->GetCellInset(actcell)->width(pain,font) +
702                 tabular->GetBeginningOfTextInCell(actcell);
703     }
704 }
705
706
707 bool InsetTabular::SetCellDimensions(Painter & pain, int cell, int row)
708 {
709     InsetText * inset = tabular->GetCellInset(cell);
710     LyXFont font(LyXFont::ALL_SANE);
711     int asc = inset->ascent(pain, font) + ADD_TO_HEIGHT;
712     int desc = inset->descent(pain, font) + ADD_TO_HEIGHT;
713     int maxAsc = tabular->GetAscentOfRow(row);
714     int maxDesc = tabular->GetDescentOfRow(row);
715     bool ret = tabular->SetWidthOfCell(cell, inset->width(pain, font));
716
717     if (maxAsc < asc) {
718         ret = true;
719         tabular->SetAscentOfRow(row, asc);
720     }
721     if (maxDesc < desc) {
722         ret = true;
723         tabular->SetDescentOfRow(row, desc);
724     }
725     return ret;
726 }
727
728
729 UpdatableInset::RESULT InsetTabular::moveRight(BufferView * bv, bool lock)
730 {
731     if (cursor.pos % 2) { // behind the inset
732         ++actcell;
733         if (actcell >= tabular->GetNumberOfCells())
734             return FINISHED;
735         ++cursor.pos;
736     } else if (lock) {
737         if (ActivateCellInset(bv))
738             return DISPATCHED;
739     } else {              // before the inset
740         ++cursor.pos;
741     }
742     resetPos(bv->painter());
743     return DISPATCHED_NOUPDATE;
744 }
745
746
747 UpdatableInset::RESULT InsetTabular::moveLeft(BufferView * bv, bool lock)
748 {
749     if (!cursor.pos)
750         return FINISHED;
751     --cursor.pos;
752     if (cursor.pos % 2) { // behind the inset
753         --actcell;
754     } else if (lock) {       // behind the inset
755         if (ActivateCellInset(bv, -1, -1))
756             return DISPATCHED;
757     }
758     resetPos(bv->painter());
759     return DISPATCHED_NOUPDATE;
760 }
761
762
763 UpdatableInset::RESULT InsetTabular::moveUp()
764 {
765     return DISPATCHED_NOUPDATE;
766 }
767
768
769 UpdatableInset::RESULT InsetTabular::moveDown()
770 {
771     return DISPATCHED_NOUPDATE;
772 }
773
774
775 bool InsetTabular::moveNextCell()
776 {
777     return false;
778 }
779
780
781 bool InsetTabular::movePrevCell()
782 {
783     return false;
784 }
785
786
787 bool InsetTabular::Delete()
788 {
789     return true;
790 }
791
792
793 void InsetTabular::SetFont(BufferView *, LyXFont const &, bool)
794 {
795 }
796
797
798 void InsetTabular::TabularFeatures(BufferView * bv, int feature, string val)
799 {
800     int
801         i,
802         sel_pos_start,
803         sel_pos_end,
804         setLines = 0,
805         setAlign = LYX_ALIGN_LEFT,
806         lineSet;
807     bool
808         what;
809
810     switch (feature) {
811       case LyXTabular::ALIGN_LEFT:
812           setAlign=LYX_ALIGN_LEFT;
813           break;
814       case LyXTabular::ALIGN_RIGHT:
815           setAlign=LYX_ALIGN_RIGHT;
816           break;
817       case LyXTabular::ALIGN_CENTER:
818           setAlign=LYX_ALIGN_CENTER;
819           break;
820       default:
821           break;
822     }
823     if (hasCellSelection()) {
824         if (sel_cell_start > sel_cell_end) {
825             sel_pos_start = sel_cell_end;
826             sel_pos_end = sel_cell_start;
827         } else {
828             sel_pos_start = sel_cell_start;
829             sel_pos_end = sel_cell_end;
830         }
831     } else
832         sel_pos_start = sel_pos_end = actcell;
833     switch (feature) {
834       case LyXTabular::SET_PWIDTH:
835           tabular->SetPWidth(actcell,val);
836           break;
837       case LyXTabular::SET_SPECIAL_COLUMN:
838       case LyXTabular::SET_SPECIAL_MULTI:
839           tabular->SetAlignSpecial(actcell,val,feature);
840           break;
841       case LyXTabular::APPEND_ROW:
842       {
843           // append the row into the tabular
844           tabular->AppendRow(actcell);
845           UpdateLocal(bv, true);
846           return;
847       }
848       case LyXTabular::APPEND_COLUMN:
849       { 
850           // append the column into the tabular
851           tabular->AppendColumn(actcell);
852           UpdateLocal(bv, true);
853           return;
854       }
855       case LyXTabular::DELETE_ROW:
856           RemoveTabularRow();
857           UpdateLocal(bv, true);
858           return;
859       case LyXTabular::DELETE_COLUMN:
860       {
861           /* delete the column from the tabular */ 
862           tabular->DeleteColumn(actcell);
863           UpdateLocal(bv, true);
864           return;
865       }
866       case LyXTabular::TOGGLE_LINE_TOP:
867           lineSet = !tabular->TopLine(actcell);
868           for(i=sel_pos_start; i<=sel_pos_end; ++i)
869               tabular->SetTopLine(i,lineSet);
870           UpdateLocal(bv, true);
871           return;
872     
873       case LyXTabular::TOGGLE_LINE_BOTTOM:
874           lineSet = !tabular->BottomLine(actcell); 
875           for(i=sel_pos_start; i<=sel_pos_end; ++i)
876               tabular->SetBottomLine(i,lineSet);
877           UpdateLocal(bv, true);
878           return;
879                 
880       case LyXTabular::TOGGLE_LINE_LEFT:
881           lineSet = !tabular->LeftLine(actcell);
882           for(i=sel_pos_start; i<=sel_pos_end; ++i)
883               tabular->SetLeftLine(i,lineSet);
884           UpdateLocal(bv, true);
885           return;
886
887       case LyXTabular::TOGGLE_LINE_RIGHT:
888           lineSet = !tabular->RightLine(actcell);
889           for(i=sel_pos_start; i<=sel_pos_end; ++i)
890               tabular->SetRightLine(i,lineSet);
891           UpdateLocal(bv, true);
892           return;
893       case LyXTabular::ALIGN_LEFT:
894       case LyXTabular::ALIGN_RIGHT:
895       case LyXTabular::ALIGN_CENTER:
896           for(i=sel_pos_start; i<=sel_pos_end; ++i)
897               tabular->SetAlignment(i,setAlign);
898           UpdateLocal(bv, true);
899           return;
900       case LyXTabular::MULTICOLUMN:
901       {
902           if (tabular->row_of_cell(sel_pos_start) !=
903               tabular->row_of_cell(sel_pos_end)) {
904               WriteAlert(_("Impossible Operation!"), 
905                          _("Multicolumns can only be horizontally."), 
906                          _("Sorry."));
907               return;
908           }
909           // just multicol for one Single Cell
910           if (!hasCellSelection()) {
911               // check wether we are completly in a multicol
912               if (tabular->IsMultiColumn(actcell)) {
913                   tabular->UnsetMultiColumn(actcell);
914                   UpdateLocal(bv, true);
915               } else {
916                   tabular->SetMultiColumn(actcell, 1);
917                   UpdateLocal(bv, false);
918               }
919               return;
920           }
921           // we have a selection so this means we just add all this
922           // cells to form a multicolumn cell
923           int
924               s_start, s_end;
925
926           if (sel_pos_start > sel_pos_end) {
927               s_start = sel_pos_end;
928               s_end = sel_pos_start;
929           } else {
930               s_start = sel_pos_start;
931               s_end = sel_pos_end;
932           }
933           tabular->SetMultiColumn(s_start, s_end);
934           cursor.pos = s_start;
935           sel_cell_end = sel_cell_start;
936           UpdateLocal(bv, true);
937           return;
938       }
939       case LyXTabular::SET_ALL_LINES:
940           setLines = 1;
941       case LyXTabular::UNSET_ALL_LINES:
942           for(i=sel_pos_start; i<=sel_pos_end; ++i)
943               tabular->SetAllLines(i, setLines);
944           UpdateLocal(bv, true);
945           return;
946       case LyXTabular::SET_LONGTABULAR:
947           tabular->SetLongTabular(true);
948           UpdateLocal(bv, true); // because this toggles displayed
949           return;
950       case LyXTabular::UNSET_LONGTABULAR:
951           tabular->SetLongTabular(false);
952           UpdateLocal(bv, true); // because this toggles displayed
953           return;
954       case LyXTabular::SET_ROTATE_TABULAR:
955           tabular->SetRotateTabular(true);
956           return;
957       case LyXTabular::UNSET_ROTATE_TABULAR:
958           tabular->SetRotateTabular(false);
959           return;
960       case LyXTabular::SET_ROTATE_CELL:
961           for(i=sel_pos_start; i<=sel_pos_end; ++i)
962               tabular->SetRotateCell(i,true);
963           return;
964       case LyXTabular::UNSET_ROTATE_CELL:
965           for(i=sel_pos_start; i<=sel_pos_end; ++i)
966               tabular->SetRotateCell(i,false);
967           return;
968       case LyXTabular::SET_LINEBREAKS:
969           what = !tabular->GetLinebreaks(actcell);
970           for(i=sel_pos_start; i<=sel_pos_end; ++i)
971               tabular->SetLinebreaks(i,what);
972           return;
973       case LyXTabular::SET_LTFIRSTHEAD:
974           tabular->SetLTHead(actcell,true);
975           return;
976       case LyXTabular::SET_LTHEAD:
977           tabular->SetLTHead(actcell,false);
978           return;
979       case LyXTabular::SET_LTFOOT:
980           tabular->SetLTFoot(actcell,false);
981           return;
982       case LyXTabular::SET_LTLASTFOOT:
983           tabular->SetLTFoot(actcell,true);
984           return;
985       case LyXTabular::SET_LTNEWPAGE:
986           what = !tabular->GetLTNewPage(actcell);
987           tabular->SetLTNewPage(actcell,what);
988           return;
989     }
990 }
991
992 void InsetTabular::RemoveTabularRow()
993 {
994 }
995
996 bool InsetTabular::ActivateCellInset(BufferView * bv, int x, int y, int button)
997 {
998     // the cursor.pos has to be before the inset so if it isn't now just
999     // reset the curor pos first!
1000     if (cursor.pos % 2) { // behind the inset
1001         --cursor.pos;
1002         resetPos(bv->painter());
1003     }
1004     UpdatableInset * inset =
1005         static_cast<UpdatableInset*>(tabular->GetCellInset(actcell));
1006     LyXFont font(LyXFont::ALL_SANE);
1007     if (x < 0)
1008         x = inset->width(bv->painter(), font) + top_x;
1009     if (y < 0)
1010         y = inset->descent(bv->painter(), font);
1011     inset_x = cursor.x - top_x + tabular->GetBeginningOfTextInCell(actcell);
1012     inset_y = cursor.y;
1013     inset->Edit(bv, x-inset_x, y-inset_y, button);
1014     if (!the_locking_inset)
1015         return false;
1016     UpdateLocal(bv, true);
1017     return true;
1018 }
1019
1020 bool InsetTabular::InsetHit(BufferView * bv, int x, int ) const
1021 {
1022     InsetText * inset = tabular->GetCellInset(actcell);
1023     int x1 = x + top_x;
1024
1025     if (cursor.pos % 2) { // behind the inset
1026         return (((x+top_x) < cursor.x) &&
1027                 ((x+top_x) > (cursor.x - inset->width(bv->painter(),
1028                                                       LyXFont(LyXFont::ALL_SANE)))));
1029     } else {
1030         int x2 = cursor.x + tabular->GetBeginningOfTextInCell(actcell);
1031         return ((x1 > x2) &&
1032                 (x1 < (x2 + inset->width(bv->painter(),
1033                                          LyXFont(LyXFont::ALL_SANE)))));
1034     }
1035 }