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