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