]> git.lyx.org Git - lyx.git/blob - src/insets/insettabular.C
39650ad2b60bbe641d37f7ccd20d0d25029df599
[lyx.git] / src / insets / insettabular.C
1 /* This file is part of
2  * ======================================================
3  * 
4  *           LyX, The Document Processor
5  *
6  *           Copyright 2001 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 "insets/insettext.h"
34 #include "frontends/Dialogs.h"
35 #include "debug.h"
36 #include "WorkArea.h"
37 #include "gettext.h"
38 #include "language.h"
39
40 using std::ostream;
41 using std::ifstream;
42 using std::max;
43 using std::endl;
44 using std::swap;
45 using std::max;
46
47
48 namespace {
49
50 const int ADD_TO_HEIGHT = 2;
51 const int ADD_TO_TABULAR_WIDTH = 2;
52 ///
53 LyXTabular * paste_tabular = 0;
54
55
56 struct tabular_features {
57         LyXTabular::Feature action;
58         string feature;
59 };
60
61 //tabular_features * tabularFeatures = 0;
62
63 tabular_features tabularFeatures[] =
64 {
65         { LyXTabular::APPEND_ROW, "append-row" },
66         { LyXTabular::APPEND_COLUMN, "append-column" },
67         { LyXTabular::DELETE_ROW, "delete-row" },
68         { LyXTabular::DELETE_COLUMN, "delete-column" },
69         { LyXTabular::TOGGLE_LINE_TOP, "toggle-line-top" },
70         { LyXTabular::TOGGLE_LINE_BOTTOM, "toggle-line-bottom" },
71         { LyXTabular::TOGGLE_LINE_LEFT, "toggle-line-left" },
72         { LyXTabular::TOGGLE_LINE_RIGHT, "toggle-line-right" },
73         { LyXTabular::ALIGN_LEFT, "align-left" },
74         { LyXTabular::ALIGN_RIGHT, "align-right" },
75         { LyXTabular::ALIGN_CENTER, "align-center" },
76         { LyXTabular::VALIGN_TOP, "valign-top" },
77         { LyXTabular::VALIGN_BOTTOM, "valign-bottom" },
78         { LyXTabular::VALIGN_CENTER, "valign-center" },
79         { LyXTabular::M_TOGGLE_LINE_TOP, "m-toggle-line-top" },
80         { LyXTabular::M_TOGGLE_LINE_BOTTOM, "m-toggle-line-bottom" },
81         { LyXTabular::M_TOGGLE_LINE_LEFT, "m-toggle-line-left" },
82         { LyXTabular::M_TOGGLE_LINE_RIGHT, "m-toggle-line-right" },
83         { LyXTabular::M_ALIGN_LEFT, "m-align-left" },
84         { LyXTabular::M_ALIGN_RIGHT, "m-align-right" },
85         { LyXTabular::M_ALIGN_CENTER, "m-align-center" },
86         { LyXTabular::M_VALIGN_TOP, "m-valign-top" },
87         { LyXTabular::M_VALIGN_BOTTOM, "m-valign-bottom" },
88         { LyXTabular::M_VALIGN_CENTER, "m-valign-center" },
89         { LyXTabular::MULTICOLUMN, "multicolumn" },
90         { LyXTabular::SET_ALL_LINES, "set-all-lines" },
91         { LyXTabular::UNSET_ALL_LINES, "unset-all-lines" },
92         { LyXTabular::SET_LONGTABULAR, "set-longtabular" },
93         { LyXTabular::UNSET_LONGTABULAR, "unset-longtabular" },
94         { LyXTabular::SET_PWIDTH, "set-pwidth" },
95         { LyXTabular::SET_MPWIDTH, "set-mpwidth" },
96         { LyXTabular::SET_ROTATE_TABULAR, "set-rotate-tabular" },
97         { LyXTabular::UNSET_ROTATE_TABULAR, "unset-rotate-tabular" },
98         { LyXTabular::SET_ROTATE_CELL, "set-rotate-cell" },
99         { LyXTabular::UNSET_ROTATE_CELL, "unset-rotate-cell" },
100         { LyXTabular::SET_USEBOX, "set-usebox" },
101         { LyXTabular::SET_LTHEAD, "set-lthead" },
102         { LyXTabular::SET_LTFIRSTHEAD, "set-ltfirsthead" },
103         { LyXTabular::SET_LTFOOT, "set-ltfoot" },
104         { LyXTabular::SET_LTLASTFOOT, "set-ltlastfoot" },
105         { LyXTabular::SET_LTNEWPAGE, "set-ltnewpage" },
106         { LyXTabular::SET_SPECIAL_COLUMN, "set-special-column" },
107         { LyXTabular::SET_SPECIAL_MULTI, "set-special-multi" },
108         { LyXTabular::LAST_ACTION, "" }
109 };
110
111 } // namespace anon
112
113
114 bool InsetTabular::hasPasteBuffer() const
115 {
116         return (paste_tabular != 0);
117 }
118
119
120 InsetTabular::InsetTabular(Buffer const & buf, int rows, int columns)
121         : buffer(&buf)
122 {
123         if (rows <= 0)
124                 rows = 1;
125         if (columns <= 0)
126                 columns = 1;
127         tabular.reset(new LyXTabular(this, rows,columns));
128         // for now make it always display as display() inset
129         // just for test!!!
130         the_locking_inset = 0;
131         locked = no_selection = false;
132         oldcell = -1;
133         actrow = actcell = 0;
134         clearSelection();
135         need_update = INIT;
136 }
137
138
139 InsetTabular::InsetTabular(InsetTabular const & tab, Buffer const & buf)
140         : buffer(&buf)
141 {
142         tabular.reset(new LyXTabular(this, *(tab.tabular)));
143         the_locking_inset = 0;
144         locked = no_selection = false;
145         oldcell = -1;
146         actrow = actcell = 0;
147         sel_cell_start = sel_cell_end = 0;
148         need_update = INIT;
149 }
150
151
152 InsetTabular::~InsetTabular()
153 {
154         //delete tabular;
155         hideDialog();
156 }
157
158
159 Inset * InsetTabular::Clone(Buffer const & buf) const
160 {
161         InsetTabular * t = new InsetTabular(*this, buf);
162         //delete t->tabular;
163         //t->tabular = tabular->Clone(t);
164         t->tabular.reset(tabular->Clone(t));
165         return t;
166 }
167
168
169 void InsetTabular::Write(Buffer const * buf, ostream & os) const
170 {
171         os << " Tabular" << endl;
172         tabular->Write(buf, os);
173 }
174
175
176 void InsetTabular::Read(Buffer const * buf, LyXLex & lex)
177 {
178         bool const old_format = (lex.GetString() == "\\LyXTable");
179
180         //if (tabular)
181         //delete tabular;
182         //tabular = new LyXTabular(buf, this, lex);
183         tabular.reset(new LyXTabular(buf, this, lex));
184
185         need_update = INIT;
186
187         if (old_format)
188                 return;
189
190         lex.nextToken();
191         string token = lex.GetString();
192         while (lex.IsOK() && (token != "\\end_inset")) {
193                 lex.nextToken();
194                 token = lex.GetString();
195         }
196         if (token != "\\end_inset") {
197                 lex.printError("Missing \\end_inset at this point. "
198                                "Read: `$$Token'");
199         }
200 }
201
202
203 int InsetTabular::ascent(BufferView *, LyXFont const &) const
204 {
205         return tabular->GetAscentOfRow(0);
206 }
207
208
209 int InsetTabular::descent(BufferView *, LyXFont const &) const
210 {
211         return tabular->GetHeightOfTabular() - tabular->GetAscentOfRow(0) + 1;
212 }
213
214
215 int InsetTabular::width(BufferView *, LyXFont const &) const
216 {
217         return tabular->GetWidthOfTabular() + (2 * ADD_TO_TABULAR_WIDTH);
218 }
219
220
221 void InsetTabular::draw(BufferView * bv, LyXFont const & font, int baseline,
222                         float & x, bool cleared) const
223 {
224         if (nodraw())
225                 return;
226 #if 0
227         if (need_update == INIT) {
228                 if (calculate_dimensions_of_cells(bv, font, true))
229                         bv->text->status = LyXText::CHANGED_IN_DRAW;
230                 need_update = FULL;
231         }
232 #endif
233
234         Painter & pain = bv->painter();
235         int i;
236         int j;
237         int nx;
238
239 #if 0
240         UpdatableInset::draw(bv, font, baseline, x, cleared);
241 #else
242         if (!owner())
243                 x += static_cast<float>(scroll());
244 #endif
245         if (!cleared && ((need_update == INIT) || (need_update == FULL) ||
246                          (top_x != int(x)) || (top_baseline != baseline))) {
247                 int h = ascent(bv, font) + descent(bv, font);
248                 int const tx = display() || !owner() ? 0 : top_x;
249                 int w =  tx ? width(bv, font) : pain.paperWidth();
250                 int ty = baseline - ascent(bv, font);
251         
252                 if (ty < 0)
253                         ty = 0;
254                 if ((ty + h) > pain.paperHeight())
255                         h = pain.paperHeight();
256                 if ((top_x + w) > pain.paperWidth())
257                         w = pain.paperWidth();
258                 pain.fillRectangle(tx, ty, w, h);
259                 need_update = FULL;
260                 cleared = true;
261         }
262         top_x = int(x);
263         top_baseline = baseline;
264         x += ADD_TO_TABULAR_WIDTH;
265         if (cleared) {
266                 int cell = 0;
267                 float cx;
268                 first_visible_cell = -1;
269                 for (i = 0; i < tabular->rows(); ++i) {
270                         nx = int(x);
271                         cell = tabular->GetCellNumber(i, 0);
272                         if (!((baseline + tabular->GetDescentOfRow(i)) > 0) &&
273                                 (baseline - tabular->GetAscentOfRow(i))<pain.paperHeight())
274                         {
275                                 baseline += tabular->GetDescentOfRow(i) +
276                                         tabular->GetAscentOfRow(i + 1) +
277                                         tabular->GetAdditionalHeight(i + 1);
278                                 continue;
279                         }
280                         for (j = 0; j < tabular->columns(); ++j) {
281                                 if (nx > bv->workWidth())
282                                         break;
283                                 if (tabular->IsPartOfMultiColumn(i, j))
284                                         continue;
285                                 cx = nx + tabular->GetBeginningOfTextInCell(cell);
286                                 if (first_visible_cell < 0)
287                                         first_visible_cell = cell;
288                                 if (hasSelection())
289                                         DrawCellSelection(pain, nx, baseline, i, j, cell);
290                                 tabular->GetCellInset(cell)->draw(bv, font, baseline, cx,
291                                                                                                   cleared);
292                                 DrawCellLines(pain, nx, baseline, i, cell);
293                                 nx += tabular->GetWidthOfColumn(cell);
294                                 ++cell;
295                         }
296                         baseline += tabular->GetDescentOfRow(i) +
297                                 tabular->GetAscentOfRow(i + 1) +
298                                 tabular->GetAdditionalHeight(i + 1);
299                 }
300         } else if (need_update == CELL) {
301                 int cell = 0;
302                 nx = int(x);
303                 if (the_locking_inset &&
304                         tabular->GetCellInset(actcell) != the_locking_inset)
305                 {
306                         Inset * inset = tabular->GetCellInset(cell);
307                         for (i = 0;
308                              inset != the_locking_inset && i < tabular->rows();
309                              ++i) {
310                                 for (j = 0;
311                                      inset != the_locking_inset
312                                              && j < tabular->columns();
313                                      ++j) {
314                                         if (tabular->IsPartOfMultiColumn(i, j))
315                                                 continue;
316                                         nx += tabular->GetWidthOfColumn(cell);
317                                         ++cell;
318                                         inset = tabular->GetCellInset(cell);
319                                 }
320                                 if (tabular->row_of_cell(cell) > i) {
321                                         nx = int(x);
322                                         baseline += tabular->GetDescentOfRow(i) +
323                                                 tabular->GetAscentOfRow(i + 1) +
324                                                 tabular->GetAdditionalHeight(i + 1);
325                                 }
326                         }
327                 } else {
328                         // copute baseline for actual row
329                         for (i = 0; i < actrow; ++i) {
330                                 baseline += tabular->GetDescentOfRow(i) +
331                                         tabular->GetAscentOfRow(i + 1) +
332                                         tabular->GetAdditionalHeight(i + 1);
333                         }
334                         // now compute the right x position
335                         cell = tabular->GetCellNumber(actrow, 0);
336                         for (j = 0; (cell < actcell) && (j < tabular->columns()); ++j) {
337                                         if (tabular->IsPartOfMultiColumn(actrow, j))
338                                                 continue;
339                                         nx += tabular->GetWidthOfColumn(cell);
340                                         ++cell;
341                         }
342                 }
343                 i = tabular->row_of_cell(cell);
344                 if (the_locking_inset != tabular->GetCellInset(cell)) {
345                         lyxerr[Debug::INSETS] << "ERROR this shouldn't happen\n";
346                         return;
347                 }
348                 float dx = nx + tabular->GetBeginningOfTextInCell(cell);
349                 float cx = dx;
350                 //cx = dx = nx + tabular->GetBeginningOfTextInCell(cell);
351                 tabular->GetCellInset(cell)->draw(bv,font,baseline, dx, false);
352 #if 0
353                 if (bv->text->status == LyXText::CHANGED_IN_DRAW)
354                         return;
355 #endif
356                 // clear only if we didn't have a change
357                 if (need_update == CELL) {
358                         // clear before the inset
359                         pain.fillRectangle(
360                                 nx + 1,
361                                 baseline - tabular->GetAscentOfRow(i) + 1,
362                                 int(cx - nx - 1),
363                                 tabular->GetAscentOfRow(i) +
364                                 tabular->GetDescentOfRow(i) - 1);
365                         // clear behind the inset
366                         pain.fillRectangle(
367                                 int(cx + the_locking_inset->width(bv,font) + 1),
368                                 baseline - tabular->GetAscentOfRow(i) + 1,
369                                 tabular->GetWidthOfColumn(cell) -
370                                 tabular->GetBeginningOfTextInCell(cell) -
371                                 the_locking_inset->width(bv,font) -
372                                 tabular->GetAdditionalWidth(cell) - 1,
373                                 tabular->GetAscentOfRow(i) +
374                                 tabular->GetDescentOfRow(i) - 1);
375                 }
376         }
377         x -= ADD_TO_TABULAR_WIDTH;
378         x += width(bv, font);
379         if (bv->text->status == LyXText::CHANGED_IN_DRAW) {
380                 int i=0;
381                 for(Inset * inset=owner();inset;++i)
382                         inset = inset->owner();
383                 if (calculate_dimensions_of_cells(bv, font, false))
384                         need_update = INIT;
385         } else {
386                 need_update = NONE;
387         }
388 }
389
390
391 void InsetTabular::DrawCellLines(Painter & pain, int x, int baseline,
392                                  int row, int cell) const
393 {
394         int x2 = x + tabular->GetWidthOfColumn(cell);
395         bool on_off;
396         
397         if (!tabular->TopAlreadyDrawed(cell)) {
398                 on_off = !tabular->TopLine(cell);
399                 pain.line(x, baseline - tabular->GetAscentOfRow(row),
400                           x2, baseline -  tabular->GetAscentOfRow(row),
401                           on_off ? LColor::tabularonoffline : LColor::tabularline,
402                           on_off ? Painter::line_onoffdash : Painter::line_solid);
403         }
404         on_off = !tabular->BottomLine(cell);
405         pain.line(x,baseline +  tabular->GetDescentOfRow(row),
406                   x2, baseline +  tabular->GetDescentOfRow(row),
407                   on_off ? LColor::tabularonoffline : LColor::tabularline,
408                   on_off ? Painter::line_onoffdash : Painter::line_solid);
409         if (!tabular->LeftAlreadyDrawed(cell)) {
410                 on_off = !tabular->LeftLine(cell);
411                 pain.line(x, baseline -  tabular->GetAscentOfRow(row),
412                           x, baseline +  tabular->GetDescentOfRow(row),
413                           on_off ? LColor::tabularonoffline : LColor::tabularline,
414                           on_off ? Painter::line_onoffdash : Painter::line_solid);
415         }
416         on_off = !tabular->RightLine(cell);
417         pain.line(x2 - tabular->GetAdditionalWidth(cell),
418                   baseline -  tabular->GetAscentOfRow(row),
419                   x2 - tabular->GetAdditionalWidth(cell),
420                   baseline +  tabular->GetDescentOfRow(row),
421                   on_off ? LColor::tabularonoffline : LColor::tabularline,
422                   on_off ? Painter::line_onoffdash : Painter::line_solid);
423 }
424
425
426 void InsetTabular::DrawCellSelection(Painter & pain, int x, int baseline,
427                                      int row, int column, int cell) const
428 {
429         int cs = tabular->column_of_cell(sel_cell_start);
430         int ce = tabular->column_of_cell(sel_cell_end);
431         if (cs > ce) {
432                 ce = cs;
433                 cs = tabular->column_of_cell(sel_cell_end);
434         } else {
435                 ce = tabular->right_column_of_cell(sel_cell_end);
436         }
437         
438         int rs = tabular->row_of_cell(sel_cell_start);
439         int re = tabular->row_of_cell(sel_cell_end);
440         if (rs > re) swap(rs, re);
441         
442         if ((column >= cs) && (column <= ce) && (row >= rs) && (row <= re)) {
443                 int w = tabular->GetWidthOfColumn(cell);
444                 int h = tabular->GetAscentOfRow(row) + tabular->GetDescentOfRow(row);
445                 pain.fillRectangle(x, baseline - tabular->GetAscentOfRow(row),
446                                    w, h, LColor::selection);
447         }
448 }
449
450
451 void InsetTabular::update(BufferView * bv, LyXFont const & font, bool reinit)
452 {
453         if (reinit) {
454                 need_update = INIT;
455                 calculate_dimensions_of_cells(bv, font, true);
456                 if (owner())
457                         owner()->update(bv, font, true);
458                 return;
459         }
460         if (the_locking_inset)
461                 the_locking_inset->update(bv, font, reinit);
462
463         switch (need_update) {
464         case INIT:
465         case FULL:
466         case CELL:
467                 if (calculate_dimensions_of_cells(bv, font, false))
468                         need_update = INIT;
469                 break;
470         case SELECTION:
471                 need_update = INIT;
472                 break;
473         default:
474                 break;
475         }
476 }
477
478
479 string const InsetTabular::EditMessage() const
480 {
481         return _("Opened Tabular Inset");
482 }
483
484
485 void InsetTabular::Edit(BufferView * bv, int x, int y, unsigned int button)
486 {
487         UpdatableInset::Edit(bv, x, y, button);
488         
489         if (!bv->lockInset(this)) {
490                 lyxerr[Debug::INSETS] << "InsetTabular::Cannot lock inset" << endl;
491                 return;
492         }
493         locked = true;
494         the_locking_inset = 0;
495         inset_x = 0;
496         inset_y = 0;
497         setPos(bv, x, y);
498         sel_cell_start = sel_cell_end = actcell;
499         bv->text->FinishUndo();
500         if (InsetHit(bv, x, y) && (button != 3)) {
501                 ActivateCellInsetAbs(bv, x, y, button);
502         }
503 //    UpdateLocal(bv, NONE, false);
504 //    bv->getOwner()->getPopups().updateFormTabular();
505 }
506
507
508 void InsetTabular::InsetUnlock(BufferView * bv)
509 {
510         if (the_locking_inset) {
511                 the_locking_inset->InsetUnlock(bv);
512                 the_locking_inset = 0;
513         }
514         HideInsetCursor(bv);
515         no_selection = false;
516         oldcell = -1;
517         locked = false;
518         if (scroll(false) || hasSelection()) {
519                 sel_cell_start = sel_cell_end = 0;
520                 if (scroll(false)) {
521                         scroll(bv, 0.0F);
522                 }
523                 UpdateLocal(bv, FULL, false);
524         }
525 }
526
527
528 void InsetTabular::UpdateLocal(BufferView * bv, UpdateCodes what,
529                                bool mark_dirty) const
530 {
531         if (need_update < what) // only set this if it has greater update
532                 need_update = what;
533         if ((what == INIT) && hasSelection())
534                 clearSelection();
535         // Dirty Cast! (Lgb)
536         if (need_update != NONE) {
537                 bv->updateInset(const_cast<InsetTabular *>(this), mark_dirty);
538                 if (locked) // && (what != NONE))
539                         resetPos(bv);
540         }
541 }
542
543
544 bool InsetTabular::LockInsetInInset(BufferView * bv, UpdatableInset * inset)
545 {
546         lyxerr[Debug::INSETS] << "InsetTabular::LockInsetInInset("
547                               << inset << "): ";
548         if (!inset)
549                 return false;
550         oldcell = -1;
551         if (inset == tabular->GetCellInset(actcell)) {
552                 lyxerr[Debug::INSETS] << "OK" << endl;
553                 the_locking_inset = tabular->GetCellInset(actcell);
554                 resetPos(bv);
555                 inset_x = cursor.x() - top_x + tabular->GetBeginningOfTextInCell(actcell);
556                 inset_y = cursor.y();
557                 return true;
558         } else if (the_locking_inset && (the_locking_inset == inset)) {
559                 lyxerr[Debug::INSETS] << "OK" << endl;
560                 resetPos(bv);
561                 inset_x = cursor.x() - top_x + tabular->GetBeginningOfTextInCell(actcell);
562                 inset_y = cursor.y();
563         } else if (the_locking_inset) {
564                 lyxerr[Debug::INSETS] << "MAYBE" << endl;
565                 return the_locking_inset->LockInsetInInset(bv, inset);
566         }
567         lyxerr[Debug::INSETS] << "NOT OK" << endl;
568         return false;
569 }
570
571
572 bool InsetTabular::UnlockInsetInInset(BufferView * bv, UpdatableInset * inset,
573                                       bool lr)
574 {
575         if (!the_locking_inset)
576                 return false;
577         if (the_locking_inset == inset) {
578                 the_locking_inset->InsetUnlock(bv);
579                 the_locking_inset = 0;
580 #warning fix scrolling when cellinset has requested a scroll (Jug)!!!
581 #if 0
582                 if (scroll(false))
583                         scroll(bv, 0.0F);
584 #endif
585                 UpdateLocal(bv, CELL, false);
586                 ShowInsetCursor(bv, false);
587                 return true;
588         }
589         if (the_locking_inset->UnlockInsetInInset(bv, inset, lr)) {
590                 if (inset->LyxCode() == TABULAR_CODE &&
591                     !the_locking_inset->GetFirstLockingInsetOfType(TABULAR_CODE)) {
592                         bv->owner()->getDialogs()->updateTabular(this);
593                         oldcell = actcell;
594                 }
595                 return true;
596         }
597         return false;
598 }
599
600
601 bool InsetTabular::UpdateInsetInInset(BufferView * bv, Inset * inset)
602 {
603         if (!the_locking_inset)
604                 return false;
605         if (the_locking_inset != inset) {
606                 if (!the_locking_inset->UpdateInsetInInset(bv, inset))
607                         return false;
608         }
609         UpdateLocal(bv, CELL, false);
610         return true;
611 }
612
613
614 unsigned int InsetTabular::InsetInInsetY()
615 {
616         if (!the_locking_inset)
617                 return 0;
618         
619         return inset_y + the_locking_inset->InsetInInsetY();
620 }
621
622
623 UpdatableInset * InsetTabular::GetLockingInset()
624 {
625         return the_locking_inset ? the_locking_inset->GetLockingInset() : this;
626 }
627
628
629 UpdatableInset * InsetTabular::GetFirstLockingInsetOfType(Inset::Code c)
630 {
631         if (c == LyxCode())
632                 return this;
633         if (the_locking_inset)
634                 return the_locking_inset->GetFirstLockingInsetOfType(c);
635         return 0;
636 }
637
638
639 bool InsetTabular::InsertInset(BufferView * bv, Inset * inset)
640 {
641         if (the_locking_inset)
642                 return the_locking_inset->InsertInset(bv, inset);
643         return false;
644 }
645
646
647 void InsetTabular::InsetButtonPress(BufferView * bv, int x, int y, int button)
648 {
649         if (hasSelection() && (button == 3))
650                 return;
651
652         if (hasSelection()) {
653                 clearSelection();
654                 UpdateLocal(bv, SELECTION, false);
655         }
656
657         no_selection = false;
658
659         int const ocell = actcell;
660         int const orow = actrow;
661
662         HideInsetCursor(bv);
663         setPos(bv, x, y);
664         if (actrow != orow)
665                 UpdateLocal(bv, NONE, false);
666         sel_cell_start = sel_cell_end = actcell;
667         if (button == 3) {
668                 if ((ocell != actcell) && the_locking_inset) {
669                         the_locking_inset->InsetUnlock(bv);
670                         the_locking_inset = 0;
671                 }
672                 ShowInsetCursor(bv);
673                 return;
674         }
675
676         bool const inset_hit = InsetHit(bv, x, y);
677
678         if ((ocell == actcell) && the_locking_inset && inset_hit) {
679                 resetPos(bv);
680                 the_locking_inset->InsetButtonPress(bv,
681                                                     x - inset_x, y - inset_y,
682                                                     button);
683                 return;
684         } else if (the_locking_inset) {
685                 the_locking_inset->InsetUnlock(bv);
686         }
687         the_locking_inset = 0;
688         if (button == 2) {
689                 LocalDispatch(bv, LFUN_PASTESELECTION, "paragraph");
690                 return;
691         }
692         if (inset_hit && bv->theLockingInset()) {
693                 if (ActivateCellInsetAbs(bv, x, y, button))
694                         the_locking_inset->InsetButtonPress(bv,
695                                                             x - inset_x,
696                                                             y - inset_y,
697                                                             button);
698                 return;
699         }
700         ShowInsetCursor(bv);
701 }
702
703
704 void InsetTabular::InsetButtonRelease(BufferView * bv,
705                                       int x, int y, int button)
706 {
707         if (button == 3) {
708                 if (the_locking_inset) {
709                         UpdatableInset * i;
710                         if ((i=the_locking_inset->GetFirstLockingInsetOfType(TABULAR_CODE))) {
711                                 i->InsetButtonRelease(bv, x, y, button);
712                                 return;
713                         }
714                 }
715                 bv->owner()->getDialogs()->showTabular(this);
716                 return;
717         }
718         if (the_locking_inset) {
719                 the_locking_inset->InsetButtonRelease(bv,
720                                                       x - inset_x, y - inset_y,
721                                                       button);
722                 return;
723         }
724         no_selection = false;
725 }
726
727
728 void InsetTabular::InsetMotionNotify(BufferView * bv, int x, int y, int button)
729 {
730         if (the_locking_inset) {
731                 the_locking_inset->InsetMotionNotify(bv,
732                                                      x - inset_x,
733                                                      y - inset_y,
734                                                      button);
735                 return;
736         }
737         if (!no_selection) {
738                 HideInsetCursor(bv);
739                 int const old_cell = actcell;
740                 
741                 setPos(bv, x, y);
742                 sel_cell_end = actcell;
743                 if (sel_cell_end != old_cell)
744                         UpdateLocal(bv, SELECTION, false);
745                 ShowInsetCursor(bv);
746         }
747         no_selection = false;
748 }
749
750
751 void InsetTabular::InsetKeyPress(XKeyEvent * xke)
752 {
753         if (the_locking_inset) {
754                 the_locking_inset->InsetKeyPress(xke);
755                 return;
756         }
757 }
758
759
760 UpdatableInset::RESULT
761 InsetTabular::LocalDispatch(BufferView * bv,
762                             kb_action action,
763                             string const & arg)
764 {
765         // We need to save the value of the_locking_inset as the call to 
766         // the_locking_inset->LocalDispatch might unlock it.
767         old_locking_inset = the_locking_inset;
768         no_selection = false;
769         UpdatableInset::RESULT result =
770                 UpdatableInset::LocalDispatch(bv, action, arg);
771         if (result == DISPATCHED || result == DISPATCHED_NOUPDATE) {
772                 resetPos(bv);
773                 return result;
774         }
775
776         if ((action < 0) && arg.empty())
777                 return FINISHED;
778
779         bool hs = hasSelection();
780
781         result=DISPATCHED;
782         // this one have priority over the locked InsetText!
783         switch (action) {
784         case LFUN_SHIFT_TAB:
785         case LFUN_TAB:
786         {
787                 if (GetFirstLockingInsetOfType(Inset::TABULAR_CODE) != this)
788                         break;
789                 HideInsetCursor(bv);
790                 if (the_locking_inset) {
791                         UnlockInsetInInset(bv, the_locking_inset);
792                         the_locking_inset = 0;
793                 }
794                 if (action == LFUN_TAB)
795                         moveNextCell(bv, old_locking_inset != 0);
796                 else
797                         movePrevCell(bv, old_locking_inset != 0);
798                 sel_cell_start = sel_cell_end = actcell;
799                 if (hs)
800                         UpdateLocal(bv, SELECTION, false);
801                 if (!the_locking_inset) {
802                         ShowInsetCursor(bv);
803                         return DISPATCHED_NOUPDATE;
804                 }
805                 return result;
806         }
807         // this to avoid compiler warnings.
808         default:
809                 break;
810         }
811
812         if (the_locking_inset) {
813                 result=the_locking_inset->LocalDispatch(bv, action, arg);
814                 if (result == DISPATCHED_NOUPDATE) {
815                         int sc = scroll();
816                         resetPos(bv);
817                         if (sc != scroll()) { // inset has been scrolled
818                                 the_locking_inset->ToggleInsetCursor(bv);
819                                 UpdateLocal(bv, FULL, false);
820                                 the_locking_inset->ToggleInsetCursor(bv);
821                         }
822                         return result;
823                 } else if (result == DISPATCHED) {
824                         the_locking_inset->ToggleInsetCursor(bv);
825                         UpdateLocal(bv, CELL, false);
826                         the_locking_inset->ToggleInsetCursor(bv);
827                         return result;
828                 } else if (result == FINISHED) {
829                 }
830         }
831
832         HideInsetCursor(bv);
833         result=DISPATCHED;
834         switch (action) {
835                 // --- Cursor Movements ----------------------------------
836         case LFUN_RIGHTSEL:
837                 if (tabular->IsLastCellInRow(actcell))
838                         break;
839                 moveRight(bv, false);
840                 sel_cell_end = actcell;
841                 UpdateLocal(bv, SELECTION, false);
842                 break;
843         case LFUN_RIGHT:
844                 result = moveRight(bv);
845                 sel_cell_start = sel_cell_end = actcell;
846                 if (hs)
847                         UpdateLocal(bv, SELECTION, false);
848                 break;
849         case LFUN_LEFTSEL:
850                 if (tabular->IsFirstCellInRow(actcell))
851                         break;
852                 moveLeft(bv, false);
853                 sel_cell_end = actcell;
854                 UpdateLocal(bv, SELECTION, false);
855                 break;
856         case LFUN_LEFT:
857                 result = moveLeft(bv);
858                 sel_cell_start = sel_cell_end = actcell;
859                 if (hs)
860                         UpdateLocal(bv, SELECTION, false);
861                 break;
862         case LFUN_DOWNSEL:
863         {
864                 int const ocell = actcell;
865                 moveDown(bv, false);
866                 if ((ocell == sel_cell_end) ||
867                     (tabular->column_of_cell(ocell)>tabular->column_of_cell(actcell)))
868                         sel_cell_end = tabular->GetCellBelow(sel_cell_end);
869                 else
870                         sel_cell_end = tabular->GetLastCellBelow(sel_cell_end);
871                 UpdateLocal(bv, SELECTION, false);
872         }
873         break;
874         case LFUN_DOWN:
875                 result = moveDown(bv, old_locking_inset != 0);
876                 sel_cell_start = sel_cell_end = actcell;
877                 if (hs)
878                         UpdateLocal(bv, SELECTION, false);
879                 break;
880         case LFUN_UPSEL:
881         {
882                 int const ocell = actcell;
883                 moveUp(bv, false);
884                 if ((ocell == sel_cell_end) ||
885                     (tabular->column_of_cell(ocell)>tabular->column_of_cell(actcell)))
886                         sel_cell_end = tabular->GetCellAbove(sel_cell_end);
887                 else
888                         sel_cell_end = tabular->GetLastCellAbove(sel_cell_end);
889                 UpdateLocal(bv, SELECTION, false);
890         }
891         break;
892         case LFUN_UP:
893                 result = moveUp(bv, old_locking_inset != 0);
894                 sel_cell_start = sel_cell_end = actcell;
895                 if (hs)
896                         UpdateLocal(bv, SELECTION, false);
897                 break;
898         case LFUN_NEXT: {
899                 int column = actcol;
900                 if (the_locking_inset) {
901                         UnlockInsetInInset(bv, the_locking_inset);
902                         the_locking_inset = 0;
903                 }
904                 if (bv->text->first + bv->painter().paperHeight() <
905                     (top_baseline + tabular->GetHeightOfTabular()))
906                         {
907                                 bv->scrollCB(bv->text->first + bv->painter().paperHeight());
908                                 UpdateLocal(bv, FULL, false);
909                                 actcell = tabular->GetCellBelow(first_visible_cell) + column;
910                         } else {
911                                 actcell = tabular->GetFirstCellInRow(tabular->rows() - 1) + column;
912                         }
913                 resetPos(bv);
914                 UpdateLocal(bv, CURSOR, false);
915                 break;
916         }
917         case LFUN_PRIOR: {
918                 int column = actcol;
919                 if (the_locking_inset) {
920                         UnlockInsetInInset(bv, the_locking_inset);
921                         the_locking_inset = 0;
922                 }
923                 if (top_baseline < 0) {
924                         bv->scrollCB(bv->text->first - bv->painter().paperHeight());
925                         UpdateLocal(bv, FULL, false);
926                         if (top_baseline > 0)
927                                 actcell = column;
928                         else
929                                 actcell = tabular->GetCellBelow(first_visible_cell) + column;
930                 } else {
931                         actcell = column;
932                 }
933                 resetPos(bv);
934                 UpdateLocal(bv, CURSOR, false);
935                 break;
936         }
937         case LFUN_BACKSPACE:
938                 break;
939         case LFUN_DELETE:
940                 break;
941         case LFUN_HOME:
942                 break;
943         case LFUN_END:
944                 break;
945         case LFUN_LAYOUT_TABULAR:
946         {
947                 bv->owner()->getDialogs()->showTabular(this);
948         }
949         break;
950         case LFUN_TABULAR_FEATURE:
951                 if (!TabularFeatures(bv, arg))
952                         result = UNDISPATCHED;
953                 break;
954         case LFUN_CUT:
955                 if (!copySelection(bv))
956                         break;
957                 bv->text->SetUndo(bv->buffer(), Undo::DELETE,
958                                   bv->text->cursor.par()->previous(),
959                                   bv->text->cursor.par()->next());
960                 cutSelection();
961                 UpdateLocal(bv, INIT, true);
962                 break;
963         case LFUN_COPY:
964                 if (!hasSelection())
965                         break;
966                 bv->text->FinishUndo();
967                 copySelection(bv);
968                 break;
969         case LFUN_PASTESELECTION:
970         {
971                 string clip(bv->getClipboard());
972         
973                 if (clip.empty())
974                         break;
975                 if (clip.find('\t') != string::npos) {
976                         int cols = 1;
977                         int rows = 1;
978                         int maxCols = 1;
979                         unsigned int len = clip.length();
980                         string::size_type p = 0;
981
982                         while(p < len &&
983                               ((p = clip.find_first_of("\t\n", p)) != string::npos)) {
984                                 switch(clip[p]) {
985                                 case '\t':
986                                         ++cols;
987                                         break;
988                                 case '\n':
989                                         if ((p+1) < len)
990                                                 ++rows;
991                                         maxCols = max(cols, maxCols);
992                                         cols = 1;
993                                         break;
994                                 }
995                                 ++p;
996                         }
997                         maxCols = max(cols, maxCols);
998                         delete paste_tabular;
999                         paste_tabular = new LyXTabular(this, rows, maxCols);
1000                         string::size_type op = 0;
1001                         int cell = 0;
1002                         int cells = paste_tabular->GetNumberOfCells();
1003                         p = cols = 0;
1004                         while((cell < cells) && (p < len) &&
1005                               (p = clip.find_first_of("\t\n", p)) != string::npos) {
1006                                 if (p >= len)
1007                                         break;
1008                                 switch(clip[p]) {
1009                                 case '\t':
1010                                         paste_tabular->GetCellInset(cell)->SetText(clip.substr(op, p-op));
1011                                         ++cols;
1012                                         ++cell;
1013                                         break;
1014                                 case '\n':
1015                                         paste_tabular->GetCellInset(cell)->SetText(clip.substr(op, p-op));
1016                                         while(cols++ < maxCols)
1017                                                 ++cell;
1018                                         cols = 0;
1019                                         break;
1020                                 }
1021                                 ++p;
1022                                 op = p;
1023                         }
1024                         // check for the last cell if there is no trailing '\n'
1025                         if ((cell < cells) && (op < len))
1026                                 paste_tabular->GetCellInset(cell)->SetText(clip.substr(op, len-op));
1027                 } else {
1028                         // so that the clipboard is used and it goes on
1029                         // to default
1030                         // and executes LFUN_PASTESELECTION in insettext!
1031                         delete paste_tabular;
1032                         paste_tabular = 0;
1033                 }
1034         }
1035         case LFUN_PASTE:
1036                 if (hasPasteBuffer()) {
1037                         bv->text->SetUndo(bv->buffer(), Undo::INSERT,
1038                                           bv->text->cursor.par()->previous(),
1039                                           bv->text->cursor.par()->next());
1040                         pasteSelection(bv);
1041                         UpdateLocal(bv, INIT, true);
1042                         break;
1043                 }
1044                 // ATTENTION: the function above has to be PASTE and PASTESELECTION!!!
1045         default:
1046                 // we try to activate the actual inset and put this event down to
1047                 // the insets dispatch function.
1048                 result = UNDISPATCHED;
1049                 if (the_locking_inset)
1050                         break;
1051                 nodraw(true);
1052                 if (ActivateCellInset(bv)) {
1053                         result = the_locking_inset->LocalDispatch(bv, action, arg);
1054                         if ((result == UNDISPATCHED) || (result == FINISHED)) {
1055                                 UnlockInsetInInset(bv, the_locking_inset);
1056                                 nodraw(false);
1057                                 the_locking_inset = 0;
1058                                 return UNDISPATCHED;
1059                         }
1060                         nodraw(false);
1061 //                      the_locking_inset->ToggleInsetCursor(bv);
1062                         UpdateLocal(bv, CELL, false);
1063 //                      the_locking_inset->ToggleInsetCursor(bv);
1064                         return result;
1065                 }
1066                 break;
1067         }
1068         if (result!=FINISHED) {
1069                 if (!the_locking_inset) {
1070                         ShowInsetCursor(bv);
1071                 }
1072         } else
1073                 bv->unlockInset(this);
1074         return result;
1075 }
1076
1077
1078 int InsetTabular::Latex(Buffer const * buf, ostream & os,
1079                         bool fragile, bool fp) const
1080 {
1081         return tabular->Latex(buf, os, fragile, fp);
1082 }
1083
1084
1085 int InsetTabular::Ascii(Buffer const * buf, ostream & os, int) const
1086 {
1087         // This should be changed to a real ascii export
1088         return tabular->Ascii(buf, os);
1089 }
1090
1091
1092 int InsetTabular::Linuxdoc(Buffer const *, ostream &) const
1093 {
1094         return 0;
1095 }
1096
1097
1098 int InsetTabular::DocBook(Buffer const * buf, ostream & os) const
1099 {
1100         return tabular->DocBook(buf,os);
1101 }
1102
1103
1104 void InsetTabular::Validate(LaTeXFeatures & features) const
1105 {
1106         tabular->Validate(features);
1107 }
1108
1109
1110 bool InsetTabular::calculate_dimensions_of_cells(BufferView * bv,
1111                                                  LyXFont const & font,
1112                                                  bool reinit) const
1113 {
1114         int cell = -1;
1115         int maxAsc = 0;
1116         int maxDesc = 0;
1117         InsetText * inset;
1118         bool changed = false;
1119         
1120         // if we have a locking_inset we should have to check only this cell for
1121         // change so I'll try this to have a boost, but who knows ;)
1122         if ((need_update != INIT) &&
1123             (the_locking_inset == tabular->GetCellInset(actcell))) {
1124                 for(int i = 0; i < tabular->columns(); ++i) {
1125                         maxAsc = max(tabular->GetCellInset(actrow, i)->ascent(bv, font),
1126                                      maxAsc);
1127                         maxDesc = max(tabular->GetCellInset(actrow, i)->descent(bv, font),
1128                                       maxDesc);
1129                 }
1130                 changed = tabular->SetWidthOfCell(actcell, the_locking_inset->width(bv, font));
1131                 changed = tabular->SetAscentOfRow(actrow, maxAsc + ADD_TO_HEIGHT) || changed;
1132                 changed = tabular->SetDescentOfRow(actrow, maxDesc + ADD_TO_HEIGHT) || changed;
1133                 return changed;
1134         }
1135         for (int i = 0; i < tabular->rows(); ++i) {
1136                 maxAsc = 0;
1137                 maxDesc = 0;
1138                 for (int j= 0; j < tabular->columns(); ++j) {
1139                         if (tabular->IsPartOfMultiColumn(i,j))
1140                                 continue;
1141                         ++cell;
1142                         inset = tabular->GetCellInset(cell);
1143                         if (!reinit)
1144                                 inset->update(bv, font, false);
1145                         maxAsc = max(maxAsc, inset->ascent(bv, font));
1146                         maxDesc = max(maxDesc, inset->descent(bv, font));
1147                         changed = tabular->SetWidthOfCell(cell, inset->width(bv, font)) || changed;
1148                 }
1149                 changed = tabular->SetAscentOfRow(i, maxAsc + ADD_TO_HEIGHT) || changed;
1150                 changed = tabular->SetDescentOfRow(i, maxDesc + ADD_TO_HEIGHT) || changed;
1151         }
1152         return changed;
1153 }
1154
1155
1156 void InsetTabular::GetCursorPos(BufferView *,
1157                                 int & x, int & y) const
1158 {
1159         x = cursor.x() - top_x;
1160         y = cursor.y();
1161 }
1162
1163
1164 void InsetTabular::ToggleInsetCursor(BufferView * bv)
1165 {
1166         if (the_locking_inset) {
1167                 the_locking_inset->ToggleInsetCursor(bv);
1168                 return;
1169         }
1170         
1171         LyXFont font; // = the_locking_inset->GetFont(par, cursor.pos);
1172         
1173         int const asc = lyxfont::maxAscent(font);
1174         int const desc = lyxfont::maxDescent(font);
1175         
1176         if (isCursorVisible())
1177                 bv->hideLockedInsetCursor();
1178         else
1179                 bv->showLockedInsetCursor(cursor.x(), cursor.y(), asc, desc);
1180         toggleCursorVisible();
1181 }
1182
1183
1184 void InsetTabular::ShowInsetCursor(BufferView * bv, bool show)
1185 {
1186         if (!isCursorVisible()) {
1187                 LyXFont font; // = GetFont(par, cursor.pos);
1188         
1189                 int const asc = lyxfont::maxAscent(font);
1190                 int const desc = lyxfont::maxDescent(font);
1191                 bv->fitLockedInsetCursor(cursor.x(), cursor.y(), asc, desc);
1192                 if (show)
1193                         bv->showLockedInsetCursor(cursor.x(), cursor.y(), asc, desc);
1194                 setCursorVisible(true);
1195         }
1196 }
1197
1198
1199 void InsetTabular::HideInsetCursor(BufferView * bv)
1200 {
1201         if (isCursorVisible()) {
1202                 bv->hideLockedInsetCursor();
1203                 setCursorVisible(false);
1204         }
1205 //    if (cursor_visible)
1206 //        ToggleInsetCursor(bv);
1207 }
1208
1209
1210 void InsetTabular::setPos(BufferView * bv, int x, int y) const
1211 {
1212         cursor.y(0);
1213         
1214         actcell = actrow = actcol = 0;
1215         int ly = tabular->GetDescentOfRow(actrow);
1216
1217         // first search the right row
1218         while((ly < y) && (actrow < tabular->rows())) {
1219                 cursor.y(cursor.y() + tabular->GetDescentOfRow(actrow) +
1220                                  tabular->GetAscentOfRow(actrow + 1) +
1221                                  tabular->GetAdditionalHeight(actrow + 1));
1222                 ++actrow;
1223                 ly = cursor.y() + tabular->GetDescentOfRow(actrow);
1224         }
1225         actcell = tabular->GetCellNumber(actrow, actcol);
1226
1227         // now search the right column
1228         int lx = tabular->GetWidthOfColumn(actcell) -
1229                 tabular->GetAdditionalWidth(actcell);
1230 #if 0
1231 #ifdef WITH_WARNINGS
1232 #warning Jürgen, can you rewrite this to _not_ use the sequencing operator. (Lgb)
1233 #endif
1234         for (; !tabular->IsLastCellInRow(actcell) && (lx < x);
1235              ++actcell,lx += tabular->GetWidthOfColumn(actcell) +
1236                      tabular->GetAdditionalWidth(actcell - 1));
1237 #else
1238         // Jürgen, you should check that this is correct. (Lgb)
1239         for (; !tabular->IsLastCellInRow(actcell) && lx < x; ++actcell) {
1240                 lx += tabular->GetWidthOfColumn(actcell + 1)
1241                         + tabular->GetAdditionalWidth(actcell);
1242         }
1243         
1244 #endif
1245         cursor.x(lx - tabular->GetWidthOfColumn(actcell) + top_x + 2);
1246         resetPos(bv);
1247 }
1248
1249
1250 int InsetTabular::getCellXPos(int cell) const
1251 {
1252         int c = cell;
1253         
1254         for (; !tabular->IsFirstCellInRow(c); --c)
1255                 ;
1256         int lx = tabular->GetWidthOfColumn(cell);
1257         for (; c < cell; ++c) {
1258                 lx += tabular->GetWidthOfColumn(c);
1259         }
1260         return (lx - tabular->GetWidthOfColumn(cell) + top_x);
1261 }
1262
1263
1264 void InsetTabular::resetPos(BufferView * bv) const
1265 {
1266         if (!locked)
1267                 return;
1268         actcol = tabular->column_of_cell(actcell);
1269
1270         int cell = 0;
1271         actrow = 0;
1272         cursor.y(0);
1273         for (; (cell < actcell) && !tabular->IsLastRow(cell); ++cell) {
1274                 if (tabular->IsLastCellInRow(cell)) {
1275                         cursor.y(cursor.y() + tabular->GetDescentOfRow(actrow) +
1276                                          tabular->GetAscentOfRow(actrow + 1) +
1277                                          tabular->GetAdditionalHeight(actrow + 1));
1278                         ++actrow;
1279                 }
1280         }
1281         static int const offset = ADD_TO_TABULAR_WIDTH + 2;
1282         int new_x = getCellXPos(actcell);
1283         int old_x = cursor.x();
1284         new_x += offset;
1285         cursor.x(new_x);
1286 //    cursor.x(getCellXPos(actcell) + offset);
1287         if ((actcol < tabular->columns()-1) && scroll(false) &&
1288                 (tabular->GetWidthOfTabular() < bv->workWidth()-20))
1289         {
1290                 scroll(bv, 0.0F);
1291                 UpdateLocal(bv, FULL, false);
1292         } else if (the_locking_inset &&
1293                  (tabular->GetWidthOfColumn(actcell) > bv->workWidth()-20))
1294         {
1295                 int xx = cursor.x() - offset + bv->text->GetRealCursorX(bv);
1296                 if (xx > (bv->workWidth()-20)) {
1297                         scroll(bv, -(xx - bv->workWidth() + 60));
1298                         UpdateLocal(bv, FULL, false);
1299                 } else if (xx < 20) {
1300                         if (xx < 0)
1301                                 xx = -xx + 60;
1302                         else
1303                                 xx = 60;
1304                         scroll(bv, xx);
1305                         UpdateLocal(bv, FULL, false);
1306                 }
1307         } else if ((cursor.x() - offset) > 20 &&
1308                    (cursor.x() - offset + tabular->GetWidthOfColumn(actcell))
1309                    > (bv->workWidth() - 20)) {
1310                 scroll(bv, -tabular->GetWidthOfColumn(actcell) - 20);
1311                 UpdateLocal(bv, FULL, false);
1312         } else if ((cursor.x() - offset) < 20) {
1313                 scroll(bv, 20 - cursor.x() + offset);
1314                 UpdateLocal(bv, FULL, false);
1315         } else if (scroll(false) && top_x > 20 &&
1316                    (top_x + tabular->GetWidthOfTabular()) > (bv->workWidth() - 20)) {
1317                 scroll(bv, old_x - cursor.x());
1318                 UpdateLocal(bv, FULL, false);
1319         }
1320         if ((!the_locking_inset ||
1321              !the_locking_inset->GetFirstLockingInsetOfType(TABULAR_CODE)) &&
1322             actcell != oldcell) {
1323                 InsetTabular * inset = const_cast<InsetTabular *>(this);
1324                 bv->owner()->getDialogs()->updateTabular(inset);
1325                 oldcell = actcell;
1326         }
1327 }
1328
1329
1330 UpdatableInset::RESULT InsetTabular::moveRight(BufferView * bv, bool lock)
1331 {
1332         if (lock && !old_locking_inset) {
1333                 if (ActivateCellInset(bv))
1334                         return DISPATCHED;
1335         } else {
1336                 bool moved = isRightToLeft(bv)
1337                         ? movePrevCell(bv) : moveNextCell(bv);
1338                 if (!moved)
1339                         return FINISHED;
1340                 if (lock && ActivateCellInset(bv))
1341                         return DISPATCHED;
1342         }
1343         resetPos(bv);
1344         return DISPATCHED_NOUPDATE;
1345 }
1346
1347
1348 UpdatableInset::RESULT InsetTabular::moveLeft(BufferView * bv, bool lock)
1349 {
1350         bool moved = isRightToLeft(bv) ? moveNextCell(bv) : movePrevCell(bv);
1351         if (!moved)
1352                 return FINISHED;
1353         if (lock) {       // behind the inset
1354                 if (ActivateCellInset(bv, 0, 0, 0, true))
1355                         return DISPATCHED;
1356         }
1357         resetPos(bv);
1358         return DISPATCHED_NOUPDATE;
1359 }
1360
1361
1362 UpdatableInset::RESULT InsetTabular::moveUp(BufferView * bv, bool lock)
1363 {
1364         int const ocell = actcell;
1365         actcell = tabular->GetCellAbove(actcell);
1366         if (actcell == ocell) // we moved out of the inset
1367                 return FINISHED;
1368         resetPos(bv);
1369         if (lock) {
1370                 int x = 0;
1371                 int y = 0;
1372                 if (old_locking_inset) {
1373                         old_locking_inset->GetCursorPos(bv, x, y);
1374                         x -= cursor.x() + tabular->GetBeginningOfTextInCell(actcell);
1375                 }
1376                 if (ActivateCellInset(bv, x, 0))
1377                         return DISPATCHED;
1378         }
1379         return DISPATCHED_NOUPDATE;
1380 }
1381
1382
1383 UpdatableInset::RESULT InsetTabular::moveDown(BufferView * bv, bool lock)
1384 {
1385         int const ocell = actcell;
1386         actcell = tabular->GetCellBelow(actcell);
1387         if (actcell == ocell) // we moved out of the inset
1388                 return FINISHED;
1389         resetPos(bv);
1390         if (lock) {
1391                 int x = 0;
1392                 int y = 0;
1393                 if (old_locking_inset) {
1394                         old_locking_inset->GetCursorPos(bv, x, y);
1395                         x -= cursor.x() + tabular->GetBeginningOfTextInCell(actcell);
1396                 }
1397                 if (ActivateCellInset(bv, x, 0))
1398                         return DISPATCHED;
1399         }
1400         return DISPATCHED_NOUPDATE;
1401 }
1402
1403
1404 bool InsetTabular::moveNextCell(BufferView * bv, bool lock)
1405 {
1406         if (isRightToLeft(bv)) {
1407                 if (tabular->IsFirstCellInRow(actcell)) {
1408                         int row = tabular->row_of_cell(actcell);
1409                         if (row == tabular->rows() - 1)
1410                                 return false;
1411                         actcell = tabular->GetLastCellInRow(row);
1412                         actcell = tabular->GetCellBelow(actcell);
1413                 } else {
1414                         if (!actcell)
1415                                 return false;
1416                         --actcell;
1417                 }
1418         } else {
1419                 if (tabular->IsLastCell(actcell))
1420                         return false;
1421                 ++actcell;
1422         }
1423         if (lock) {
1424                 bool rtl = tabular->GetCellInset(actcell)->par->
1425                         isRightToLeftPar(bv->buffer()->params);
1426                 ActivateCellInset(bv, 0, 0, 0, !rtl);
1427         }
1428         resetPos(bv);
1429         return true;
1430 }
1431
1432
1433 bool InsetTabular::movePrevCell(BufferView * bv, bool lock)
1434 {
1435         if (isRightToLeft(bv)) {
1436                 if (tabular->IsLastCellInRow(actcell)) {
1437                         int row = tabular->row_of_cell(actcell);
1438                         if (row == 0)
1439                                 return false;
1440                         actcell = tabular->GetFirstCellInRow(row);
1441                         actcell = tabular->GetCellAbove(actcell);
1442                 } else {
1443                         if (tabular->IsLastCell(actcell))
1444                                 return false;
1445                         ++actcell;
1446                 }
1447         } else {
1448                 if (!actcell) // first cell
1449                         return false;
1450                 --actcell;
1451         }
1452         if (lock) {
1453                 bool rtl = tabular->GetCellInset(actcell)->par->
1454                         isRightToLeftPar(bv->buffer()->params);
1455                 ActivateCellInset(bv, 0, 0, 0, !rtl);
1456         }
1457         resetPos(bv);
1458         return true;
1459 }
1460
1461
1462 bool InsetTabular::Delete()
1463 {
1464         return true;
1465 }
1466
1467
1468 void InsetTabular::SetFont(BufferView * bv, LyXFont const & font, bool tall,
1469                            bool selectall)
1470 {
1471         if (selectall) {
1472                 sel_cell_start = 0;
1473                 sel_cell_end = tabular->GetNumberOfCells() - 1;
1474         }
1475         if (hasSelection()) {
1476                 bool frozen;
1477                 bv->text->SetUndo(bv->buffer(), Undo::EDIT,
1478                                   bv->text->cursor.par()->previous(),
1479                                   bv->text->cursor.par()->next());
1480                 frozen = bv->text->undo_frozen;
1481                 if (!frozen)
1482                         bv->text->FreezeUndo();
1483                 // apply the fontchange on the whole selection
1484                 int sel_row_start;
1485                 int sel_row_end;
1486                 int sel_col_start;
1487                 int sel_col_end;
1488                 getSelection(sel_row_start, sel_row_end, sel_col_start, sel_col_end);
1489                 for(int i=sel_row_start; i <= sel_row_end; ++i) {
1490                         for(int j=sel_col_start; j <= sel_col_end; ++j) {
1491                                 tabular->GetCellInset(i, j)->SetFont(bv, font, tall, true);
1492                         }
1493                 }
1494                 if (!frozen)
1495                         bv->text->UnFreezeUndo();
1496                 UpdateLocal(bv, INIT, true);
1497         }
1498         if (the_locking_inset)
1499                 the_locking_inset->SetFont(bv, font, tall);
1500 }
1501
1502
1503 bool InsetTabular::TabularFeatures(BufferView * bv, string const & what)
1504 {
1505         LyXTabular::Feature action = LyXTabular::LAST_ACTION;
1506         
1507         int i = 0;
1508         for (; tabularFeatures[i].action != LyXTabular::LAST_ACTION; ++i) {
1509                 string const tmp = tabularFeatures[i].feature;
1510                 
1511                 if (tmp == what.substr(0, tmp.length())) {
1512                         //if (!compare(tabularFeatures[i].feature.c_str(), what.c_str(),
1513                         //tabularFeatures[i].feature.length())) {
1514                         action = tabularFeatures[i].action;
1515                         break;
1516                 }
1517         }
1518         if (action == LyXTabular::LAST_ACTION)
1519                 return false;
1520
1521         string const val =
1522                 frontStrip(what.substr(tabularFeatures[i].feature.length()));
1523         TabularFeatures(bv, action, val);
1524         return true;
1525 }
1526
1527
1528 void InsetTabular::TabularFeatures(BufferView * bv,
1529                                    LyXTabular::Feature feature,
1530                                    string const & value)
1531 {
1532         //int i;
1533         //int j;
1534         int sel_col_start;
1535         int sel_col_end;
1536         int sel_row_start;
1537         int sel_row_end;
1538         bool setLines = false;
1539         LyXAlignment setAlign = LYX_ALIGN_LEFT;
1540         LyXTabular::VAlignment setVAlign = LyXTabular::LYX_VALIGN_TOP;
1541         //int lineSet;
1542         //bool what;
1543
1544         switch (feature) {
1545         case LyXTabular::M_ALIGN_LEFT:
1546         case LyXTabular::ALIGN_LEFT:
1547                 setAlign=LYX_ALIGN_LEFT;
1548                 break;
1549         case LyXTabular::M_ALIGN_RIGHT:
1550         case LyXTabular::ALIGN_RIGHT:
1551                 setAlign=LYX_ALIGN_RIGHT;
1552                 break;
1553         case LyXTabular::M_ALIGN_CENTER:
1554         case LyXTabular::ALIGN_CENTER:
1555                 setAlign=LYX_ALIGN_CENTER;
1556                 break;
1557         case LyXTabular::M_VALIGN_TOP:
1558         case LyXTabular::VALIGN_TOP:
1559                 setVAlign=LyXTabular::LYX_VALIGN_TOP;
1560                 break;
1561         case LyXTabular::M_VALIGN_BOTTOM:
1562         case LyXTabular::VALIGN_BOTTOM:
1563                 setVAlign=LyXTabular::LYX_VALIGN_BOTTOM;
1564                 break;
1565         case LyXTabular::M_VALIGN_CENTER:
1566         case LyXTabular::VALIGN_CENTER:
1567                 setVAlign=LyXTabular::LYX_VALIGN_CENTER;
1568                 break;
1569         default:
1570                 break;
1571         }
1572         if (hasSelection()) {
1573                 getSelection(sel_row_start, sel_row_end, sel_col_start, sel_col_end);
1574         } else {
1575                 sel_col_start = sel_col_end = tabular->column_of_cell(actcell);
1576                 sel_row_start = sel_row_end = tabular->row_of_cell(actcell);
1577         }
1578         bv->text->SetUndo(bv->buffer(), Undo::FINISH,
1579                           bv->text->cursor.par()->previous(),
1580                           bv->text->cursor.par()->next());
1581
1582         int row = tabular->row_of_cell(actcell);
1583         int column = tabular->column_of_cell(actcell);
1584         bool flag = true;
1585         
1586         switch (feature) {
1587         case LyXTabular::SET_PWIDTH:
1588         {
1589                 bool const update = (tabular->GetColumnPWidth(actcell) != value);
1590                 tabular->SetColumnPWidth(actcell,value);
1591                 if (update) {
1592                         for (int i = 0; i < tabular->rows(); ++i) {
1593                                 tabular->GetCellInset(tabular->GetCellNumber(i, column))->
1594                                         resizeLyXText(bv);
1595                         }
1596                         UpdateLocal(bv, INIT, true);
1597                 }
1598         }
1599         break;
1600         case LyXTabular::SET_MPWIDTH:
1601         {
1602                 bool const update = (tabular->GetPWidth(actcell) != value);
1603                 tabular->SetMColumnPWidth(actcell,value);
1604                 if (update) {
1605                         for (int i = 0; i < tabular->rows(); ++i) {
1606                                 tabular->GetCellInset(tabular->GetCellNumber(i, column))->
1607                                         resizeLyXText(bv);
1608                         }
1609                         UpdateLocal(bv, INIT, true);
1610                 }
1611         }
1612         break;
1613         case LyXTabular::SET_SPECIAL_COLUMN:
1614         case LyXTabular::SET_SPECIAL_MULTI:
1615                 tabular->SetAlignSpecial(actcell,value,feature);
1616                 break;
1617         case LyXTabular::APPEND_ROW:
1618                 // append the row into the tabular
1619                 UnlockInsetInInset(bv, the_locking_inset);
1620                 tabular->AppendRow(actcell);
1621                 UpdateLocal(bv, INIT, true);
1622                 break;
1623         case LyXTabular::APPEND_COLUMN:
1624                 // append the column into the tabular
1625                 UnlockInsetInInset(bv, the_locking_inset);
1626                 tabular->AppendColumn(actcell);
1627                 actcell = tabular->GetCellNumber(row, column);
1628                 UpdateLocal(bv, INIT, true);
1629                 break;
1630         case LyXTabular::DELETE_ROW:
1631                 UnlockInsetInInset(bv, the_locking_inset);
1632                 tabular->DeleteRow(tabular->row_of_cell(actcell));
1633                 if ((row+1) > tabular->rows())
1634                         --row;
1635                 actcell = tabular->GetCellNumber(row, column);
1636                 clearSelection();
1637                 UpdateLocal(bv, INIT, true);
1638                 break;
1639         case LyXTabular::DELETE_COLUMN:
1640                 UnlockInsetInInset(bv, the_locking_inset);
1641                 tabular->DeleteColumn(tabular->column_of_cell(actcell));
1642                 if ((column+1) > tabular->columns())
1643                         --column;
1644                 actcell = tabular->GetCellNumber(row, column);
1645                 clearSelection();
1646                 UpdateLocal(bv, INIT, true);
1647                 break;
1648         case LyXTabular::M_TOGGLE_LINE_TOP:
1649                 flag = false;
1650         case LyXTabular::TOGGLE_LINE_TOP:
1651         {
1652                 bool lineSet = !tabular->TopLine(actcell, flag);
1653                 for (int i = sel_row_start; i <= sel_row_end; ++i)
1654                         for (int j = sel_col_start; j <= sel_col_end; ++j)
1655                                 tabular->SetTopLine(
1656                                         tabular->GetCellNumber(i, j),
1657                                         lineSet, flag);
1658                 UpdateLocal(bv, INIT, true);
1659                 break;
1660         }
1661         
1662         case LyXTabular::M_TOGGLE_LINE_BOTTOM:
1663                 flag = false;
1664         case LyXTabular::TOGGLE_LINE_BOTTOM:
1665         {
1666                 bool lineSet = !tabular->BottomLine(actcell, flag); 
1667                 for (int i = sel_row_start; i <= sel_row_end; ++i)
1668                         for (int j = sel_col_start; j <= sel_col_end; ++j)
1669                                 tabular->SetBottomLine(
1670                                         tabular->GetCellNumber(i, j),
1671                                         lineSet,
1672                                         flag);
1673                 UpdateLocal(bv, INIT, true);
1674                 break;
1675         }
1676         
1677         case LyXTabular::M_TOGGLE_LINE_LEFT:
1678                 flag = false;
1679         case LyXTabular::TOGGLE_LINE_LEFT:
1680         {
1681                 bool lineSet = !tabular->LeftLine(actcell, flag);
1682                 for (int i = sel_row_start; i <= sel_row_end; ++i)
1683                         for (int j = sel_col_start; j <= sel_col_end; ++j)
1684                                 tabular->SetLeftLine(
1685                                         tabular->GetCellNumber(i,j),
1686                                         lineSet,
1687                                         flag);
1688                 UpdateLocal(bv, INIT, true);
1689                 break;
1690         }
1691         
1692         case LyXTabular::M_TOGGLE_LINE_RIGHT:
1693                 flag = false;
1694         case LyXTabular::TOGGLE_LINE_RIGHT:
1695         {
1696                 bool lineSet = !tabular->RightLine(actcell, flag);
1697                 for (int i = sel_row_start; i <= sel_row_end; ++i)
1698                         for (int j = sel_col_start; j <= sel_col_end; ++j)
1699                                 tabular->SetRightLine(
1700                                         tabular->GetCellNumber(i,j),
1701                                         lineSet,
1702                                         flag);
1703                 UpdateLocal(bv, INIT, true);
1704                 break;
1705         }
1706         
1707         case LyXTabular::M_ALIGN_LEFT:
1708         case LyXTabular::M_ALIGN_RIGHT:
1709         case LyXTabular::M_ALIGN_CENTER:
1710                 flag = false;
1711         case LyXTabular::ALIGN_LEFT:
1712         case LyXTabular::ALIGN_RIGHT:
1713         case LyXTabular::ALIGN_CENTER:
1714                 for (int i = sel_row_start; i <= sel_row_end; ++i)
1715                         for (int j = sel_col_start; j <= sel_col_end; ++j)
1716                                 tabular->SetAlignment(
1717                                         tabular->GetCellNumber(i, j),
1718                                         setAlign,
1719                                         flag);
1720                 UpdateLocal(bv, INIT, true);
1721                 break;
1722         case LyXTabular::M_VALIGN_TOP:
1723         case LyXTabular::M_VALIGN_BOTTOM:
1724         case LyXTabular::M_VALIGN_CENTER:
1725                 flag = false;
1726         case LyXTabular::VALIGN_TOP:
1727         case LyXTabular::VALIGN_BOTTOM:
1728         case LyXTabular::VALIGN_CENTER:
1729                 for (int i = sel_row_start; i <= sel_row_end; ++i)
1730                         for (int j = sel_col_start; j <= sel_col_end; ++j)
1731                                 tabular->SetVAlignment(
1732                                         tabular->GetCellNumber(i, j),
1733                                         setVAlign, flag);
1734                 UpdateLocal(bv, INIT, true);
1735                 break;
1736         case LyXTabular::MULTICOLUMN:
1737         {
1738                 if (sel_row_start != sel_row_end) {
1739                         WriteAlert(_("Impossible Operation!"), 
1740                                    _("Multicolumns can only be horizontally."), 
1741                                    _("Sorry."));
1742                         return;
1743                 }
1744                 // just multicol for one Single Cell
1745                 if (!hasSelection()) {
1746                         // check wether we are completly in a multicol
1747                         if (tabular->IsMultiColumn(actcell)) {
1748                                 tabular->UnsetMultiColumn(actcell);
1749                                 UpdateLocal(bv, INIT, true);
1750                         } else {
1751                                 tabular->SetMultiColumn(actcell, 1);
1752                                 UpdateLocal(bv, CELL, true);
1753                         }
1754                         return;
1755                 }
1756                 // we have a selection so this means we just add all this
1757                 // cells to form a multicolumn cell
1758                 int s_start;
1759                 int s_end;
1760
1761                 if (sel_cell_start > sel_cell_end) {
1762                         s_start = sel_cell_end;
1763                         s_end = sel_cell_start;
1764                 } else {
1765                         s_start = sel_cell_start;
1766                         s_end = sel_cell_end;
1767                 }
1768                 tabular->SetMultiColumn(s_start, s_end - s_start + 1);
1769                 actcell = s_start;
1770                 sel_cell_end = sel_cell_start;
1771                 UpdateLocal(bv, INIT, true);
1772                 break;
1773         }
1774         case LyXTabular::SET_ALL_LINES:
1775                 setLines = true;
1776         case LyXTabular::UNSET_ALL_LINES:
1777                 for (int i = sel_row_start; i <= sel_row_end; ++i)
1778                         for (int j = sel_col_start; j <= sel_col_end; ++j)
1779                                 tabular->SetAllLines(
1780                                         tabular->GetCellNumber(i,j), setLines);
1781                 UpdateLocal(bv, INIT, true);
1782                 break;
1783         case LyXTabular::SET_LONGTABULAR:
1784                 tabular->SetLongTabular(true);
1785                 UpdateLocal(bv, INIT, true); // because this toggles displayed
1786                 break;
1787         case LyXTabular::UNSET_LONGTABULAR:
1788                 tabular->SetLongTabular(false);
1789                 UpdateLocal(bv, INIT, true); // because this toggles displayed
1790                 break;
1791         case LyXTabular::SET_ROTATE_TABULAR:
1792                 tabular->SetRotateTabular(true);
1793                 break;
1794         case LyXTabular::UNSET_ROTATE_TABULAR:
1795                 tabular->SetRotateTabular(false);
1796                 break;
1797         case LyXTabular::SET_ROTATE_CELL:
1798                 for (int i = sel_row_start; i <= sel_row_end; ++i)
1799                         for (int j = sel_col_start; j<=sel_col_end; ++j)
1800                                 tabular->SetRotateCell(
1801                                         tabular->GetCellNumber(i, j),
1802                                         true);
1803                 break;
1804         case LyXTabular::UNSET_ROTATE_CELL:
1805                 for (int i = sel_row_start; i <= sel_row_end; ++i)
1806                         for (int j = sel_col_start; j <= sel_col_end; ++j)
1807                                 tabular->SetRotateCell(
1808                                         tabular->GetCellNumber(i, j), false);
1809                 break;
1810         case LyXTabular::SET_USEBOX:
1811         {
1812                 LyXTabular::BoxType val = LyXTabular::BoxType(strToInt(value));
1813                 if (val == tabular->GetUsebox(actcell))
1814                         val = LyXTabular::BOX_NONE;
1815                 for (int i = sel_row_start; i <= sel_row_end; ++i)
1816                         for (int j = sel_col_start; j <= sel_col_end; ++j)
1817                                 tabular->SetUsebox(
1818                                         tabular->GetCellNumber(i, j), val);
1819                 break;
1820         }
1821         case LyXTabular::SET_LTFIRSTHEAD:
1822                 tabular->SetLTHead(actcell, true);
1823                 break;
1824         case LyXTabular::SET_LTHEAD:
1825                 tabular->SetLTHead(actcell, false);
1826                 break;
1827         case LyXTabular::SET_LTFOOT:
1828                 tabular->SetLTFoot(actcell, false);
1829                 break;
1830         case LyXTabular::SET_LTLASTFOOT:
1831                 tabular->SetLTFoot(actcell, true);
1832                 break;
1833         case LyXTabular::SET_LTNEWPAGE:
1834         {
1835                 bool what = !tabular->GetLTNewPage(actcell);
1836                 tabular->SetLTNewPage(actcell, what);
1837                 break;
1838         }
1839         // dummy stuff just to avoid warnings
1840         case LyXTabular::LAST_ACTION:
1841                 break;
1842         }
1843 }
1844
1845
1846 bool InsetTabular::ActivateCellInset(BufferView * bv, int x, int y, int button,
1847                                      bool behind)
1848 {
1849         UpdatableInset * inset =
1850                 static_cast<UpdatableInset*>(tabular->GetCellInset(actcell));
1851         LyXFont font(LyXFont::ALL_SANE);
1852         if (behind) {
1853                 x = inset->x() + inset->width(bv, font);
1854                 y = inset->descent(bv, font);
1855         }
1856         //inset_x = cursor.x() - top_x + tabular->GetBeginningOfTextInCell(actcell);
1857         //inset_y = cursor.y();
1858         inset->Edit(bv, x,  y, button);
1859         if (!the_locking_inset)
1860                 return false;
1861         UpdateLocal(bv, CELL, false);
1862         return (the_locking_inset != 0);
1863 }
1864
1865
1866 bool InsetTabular::ActivateCellInsetAbs(BufferView * bv, int x, int y,
1867                                         int button)
1868 {
1869         inset_x = cursor.x()
1870                 - top_x + tabular->GetBeginningOfTextInCell(actcell);
1871         inset_y = cursor.y();
1872         return ActivateCellInset(bv, x - inset_x, y - inset_y, button);
1873 }
1874
1875
1876 bool InsetTabular::InsetHit(BufferView *, int x, int) const
1877 {
1878         return (x + top_x)
1879                 > (cursor.x() + tabular->GetBeginningOfTextInCell(actcell));
1880 }
1881
1882
1883 // This returns paperWidth() if the cell-width is unlimited or the width
1884 // in pixels if we have a pwidth for this cell.
1885 int InsetTabular::GetMaxWidthOfCell(BufferView * bv, int cell) const
1886 {
1887         string const s = tabular->GetPWidth(cell);
1888         
1889         if (s.empty())
1890                 return -1;
1891         return VSpace(s).inPixels(bv);
1892 }
1893
1894
1895 int InsetTabular::getMaxWidth(BufferView * bv,
1896                               UpdatableInset const * inset) const
1897 {
1898         int const n = tabular->GetNumberOfCells();
1899         int cell = 0;
1900         for (; cell < n; ++cell) {
1901                 if (tabular->GetCellInset(cell) == inset)
1902                         break;
1903         }
1904         if (cell >= n)
1905                 return -1;
1906         int w = GetMaxWidthOfCell(bv, cell);
1907         if (w > 0)
1908                 // because the inset then subtracts it's top_x and owner->x()
1909                 w += (inset->x() - top_x);
1910         return w;
1911 }
1912
1913
1914 void InsetTabular::resizeLyXText(BufferView *) const
1915 {
1916         need_update = FULL;
1917 }
1918
1919
1920 LyXText * InsetTabular::getLyXText(BufferView const * bv,
1921                                    bool const recursive) const
1922 {
1923         if (the_locking_inset)
1924                 return the_locking_inset->getLyXText(bv, recursive);
1925         return Inset::getLyXText(bv, recursive);
1926 }
1927
1928
1929 bool InsetTabular::ShowInsetDialog(BufferView * bv) const
1930 {
1931         if (!the_locking_inset || !the_locking_inset->ShowInsetDialog(bv))
1932                 bv->owner()->getDialogs()
1933                         ->showTabular(const_cast<InsetTabular *>(this));
1934         return true;
1935 }
1936
1937
1938 void InsetTabular::OpenLayoutDialog(BufferView * bv) const
1939 {
1940         if (the_locking_inset) {
1941                 InsetTabular * i = static_cast<InsetTabular *>
1942                         (the_locking_inset->GetFirstLockingInsetOfType(TABULAR_CODE));
1943                 if (i) {
1944                         i->OpenLayoutDialog(bv);
1945                         return;
1946                 }
1947         }
1948         bv->owner()->getDialogs()->showTabular(
1949                 const_cast<InsetTabular *>(this));
1950 }
1951
1952 //
1953 // functions returns:
1954 // 0 ... disabled
1955 // 1 ... enabled
1956 // 2 ... toggled on
1957 // 3 ... toggled off
1958 //
1959 LyXFunc::func_status InsetTabular::getStatus(string const & what) const
1960 {
1961         int action = LyXTabular::LAST_ACTION;
1962         LyXFunc::func_status status = LyXFunc::OK;
1963         
1964         int i = 0;
1965         for (; tabularFeatures[i].action != LyXTabular::LAST_ACTION; ++i) {
1966                 string const tmp = tabularFeatures[i].feature;
1967                 if (tmp == what.substr(0, tmp.length())) {                  
1968                         //if (!compare(tabularFeatures[i].feature.c_str(), what.c_str(),
1969                         //   tabularFeatures[i].feature.length())) {
1970                         action = tabularFeatures[i].action;
1971                         break;
1972                 }
1973         }
1974         if (action == LyXTabular::LAST_ACTION)
1975                 return LyXFunc::Unknown;
1976
1977         string const argument = frontStrip(what.substr(tabularFeatures[i].feature.length()));
1978
1979         int sel_row_start;
1980         int sel_row_end;
1981         int dummy;
1982         bool flag = true;
1983
1984         if (hasSelection()) {
1985                 getSelection(sel_row_start, sel_row_end, dummy, dummy);
1986         } else {
1987                 sel_row_start = sel_row_end = tabular->row_of_cell(actcell);
1988         }
1989
1990         switch (action) {
1991         case LyXTabular::SET_PWIDTH:
1992         case LyXTabular::SET_MPWIDTH:
1993         case LyXTabular::SET_SPECIAL_COLUMN:
1994         case LyXTabular::SET_SPECIAL_MULTI:
1995                 status |= LyXFunc::Disabled;
1996                 return status;
1997
1998         case LyXTabular::APPEND_ROW:
1999         case LyXTabular::APPEND_COLUMN:
2000         case LyXTabular::DELETE_ROW:
2001         case LyXTabular::DELETE_COLUMN:
2002         case LyXTabular::SET_ALL_LINES:
2003         case LyXTabular::UNSET_ALL_LINES:
2004                 status |= LyXFunc::OK;
2005                 return status;
2006
2007         case LyXTabular::MULTICOLUMN:
2008                 if (tabular->IsMultiColumn(actcell))
2009                         status |= LyXFunc::ToggleOn;
2010                 else
2011                         status |= LyXFunc::ToggleOff;
2012                 break;
2013         case LyXTabular::M_TOGGLE_LINE_TOP:
2014                 flag = false;
2015         case LyXTabular::TOGGLE_LINE_TOP:
2016                 if (tabular->TopLine(actcell, flag))
2017                         status |= LyXFunc::ToggleOn;
2018                 else
2019                         status |= LyXFunc::ToggleOff;
2020                 break;
2021         case LyXTabular::M_TOGGLE_LINE_BOTTOM:
2022                 flag = false;
2023         case LyXTabular::TOGGLE_LINE_BOTTOM:
2024                 if (tabular->BottomLine(actcell, flag))
2025                         status |= LyXFunc::ToggleOn;
2026                 else
2027                         status |= LyXFunc::ToggleOff;
2028                 break;
2029         case LyXTabular::M_TOGGLE_LINE_LEFT:
2030                 flag = false;
2031         case LyXTabular::TOGGLE_LINE_LEFT:
2032                 if (tabular->LeftLine(actcell, flag))
2033                         status |= LyXFunc::ToggleOn;
2034                 else
2035                         status |= LyXFunc::ToggleOff;
2036                 break;
2037         case LyXTabular::M_TOGGLE_LINE_RIGHT:
2038                 flag = false;
2039         case LyXTabular::TOGGLE_LINE_RIGHT:
2040                 if (tabular->RightLine(actcell, flag))
2041                         status |= LyXFunc::ToggleOn;
2042                 else
2043                         status |= LyXFunc::ToggleOff;
2044                 break;
2045         case LyXTabular::M_ALIGN_LEFT:
2046                 flag = false;
2047         case LyXTabular::ALIGN_LEFT:
2048                 if (tabular->GetAlignment(actcell, flag) == LYX_ALIGN_LEFT)
2049                         status |= LyXFunc::ToggleOn;
2050                 else
2051                         status |= LyXFunc::ToggleOff;
2052                 break;
2053         case LyXTabular::M_ALIGN_RIGHT:
2054                 flag = false;
2055         case LyXTabular::ALIGN_RIGHT:
2056                 if (tabular->GetAlignment(actcell, flag) == LYX_ALIGN_RIGHT)
2057                         status |= LyXFunc::ToggleOn;
2058                 else
2059                         status |= LyXFunc::ToggleOff;
2060                 break;
2061         case LyXTabular::M_ALIGN_CENTER:
2062                 flag = false;
2063         case LyXTabular::ALIGN_CENTER:
2064                 if (tabular->GetAlignment(actcell, flag) == LYX_ALIGN_CENTER)
2065                         status |= LyXFunc::ToggleOn;
2066                 else
2067                         status |= LyXFunc::ToggleOff;
2068                 break;
2069         case LyXTabular::M_VALIGN_TOP:
2070                 flag = false;
2071         case LyXTabular::VALIGN_TOP:
2072                 if (tabular->GetVAlignment(actcell, flag) == LyXTabular::LYX_VALIGN_TOP)
2073                         status |= LyXFunc::ToggleOn;
2074                 else
2075                         status |= LyXFunc::ToggleOff;
2076                 break;
2077         case LyXTabular::M_VALIGN_BOTTOM:
2078                 flag = false;
2079         case LyXTabular::VALIGN_BOTTOM:
2080                 if (tabular->GetVAlignment(actcell, flag) == LyXTabular::LYX_VALIGN_BOTTOM)
2081                         status |= LyXFunc::ToggleOn;
2082                 else
2083                         status |= LyXFunc::ToggleOff;
2084                 break;
2085         case LyXTabular::M_VALIGN_CENTER:
2086                 flag = false;
2087         case LyXTabular::VALIGN_CENTER:
2088                 if (tabular->GetVAlignment(actcell, flag) == LyXTabular::LYX_VALIGN_CENTER)
2089                         status |= LyXFunc::ToggleOn;
2090                 else
2091                         status |= LyXFunc::ToggleOff;
2092                 break;
2093         case LyXTabular::SET_LONGTABULAR:
2094                 if (tabular->IsLongTabular())
2095                         status |= LyXFunc::ToggleOn;
2096                 else
2097                         status |= LyXFunc::ToggleOff;
2098                 break;
2099         case LyXTabular::UNSET_LONGTABULAR:
2100                 if (!tabular->IsLongTabular())
2101                         status |= LyXFunc::ToggleOn;
2102                 else
2103                         status |= LyXFunc::ToggleOff;
2104                 break;
2105         case LyXTabular::SET_ROTATE_TABULAR:
2106                 if (tabular->GetRotateTabular())
2107                         status |= LyXFunc::ToggleOn;
2108                 else
2109                         status |= LyXFunc::ToggleOff;
2110                 break;
2111         case LyXTabular::UNSET_ROTATE_TABULAR:
2112                 if (!tabular->GetRotateTabular())
2113                         status |= LyXFunc::ToggleOn;
2114                 else
2115                         status |= LyXFunc::ToggleOff;
2116                 break;
2117         case LyXTabular::SET_ROTATE_CELL:
2118                 if (tabular->GetRotateCell(actcell))
2119                         status |= LyXFunc::ToggleOn;
2120                 else
2121                         status |= LyXFunc::ToggleOff;
2122                 break;
2123         case LyXTabular::UNSET_ROTATE_CELL:
2124                 if (!tabular->GetRotateCell(actcell))
2125                         status |= LyXFunc::ToggleOn;
2126                 else
2127                         status |= LyXFunc::ToggleOff;
2128                 break;
2129         case LyXTabular::SET_USEBOX:
2130                 if (strToInt(argument) == tabular->GetUsebox(actcell))
2131                         status |= LyXFunc::ToggleOn;
2132                 else
2133                         status |= LyXFunc::ToggleOff;
2134                 break;
2135         case LyXTabular::SET_LTFIRSTHEAD:
2136                 if (tabular->GetRowOfLTHead(actcell, dummy))
2137                         status |= LyXFunc::ToggleOn;
2138                 else
2139                         status |= LyXFunc::ToggleOff;
2140                 break;
2141         case LyXTabular::SET_LTHEAD:
2142                 if (tabular->GetRowOfLTHead(actcell, dummy))
2143                         status |= LyXFunc::ToggleOn;
2144                 else
2145                         status |= LyXFunc::ToggleOff;
2146                 break;
2147         case LyXTabular::SET_LTFOOT:
2148                 if (tabular->GetRowOfLTFoot(actcell, dummy))
2149                         status |= LyXFunc::ToggleOn;
2150                 else
2151                         status |= LyXFunc::ToggleOff;
2152                 break;
2153         case LyXTabular::SET_LTLASTFOOT:
2154                 if (tabular->GetRowOfLTFoot(actcell, dummy))
2155                         status |= LyXFunc::ToggleOn;
2156                 else
2157                         status |= LyXFunc::ToggleOff;
2158                 break;
2159         case LyXTabular::SET_LTNEWPAGE:
2160                 if (tabular->GetLTNewPage(actcell))
2161                         status |= LyXFunc::ToggleOn;
2162                 else
2163                         status |= LyXFunc::ToggleOff;
2164                 break;
2165         default:
2166                 status = LyXFunc::Disabled;
2167                 break;
2168         }
2169         return status;
2170 }
2171
2172
2173 std::vector<string> const InsetTabular::getLabelList() const
2174 {
2175         return tabular->getLabelList();
2176 }
2177
2178
2179 bool InsetTabular::copySelection(BufferView * bv)
2180 {
2181         if (!hasSelection())
2182                 return false;
2183         //delete paste_tabular;
2184
2185         //int sel_col_start;
2186         //int sel_col_end;
2187         //int sel_row_start;
2188         //int sel_row_end;
2189
2190         int sel_col_start = tabular->column_of_cell(sel_cell_start);
2191         int sel_col_end = tabular->column_of_cell(sel_cell_end);
2192         if (sel_col_start > sel_col_end) {
2193                 sel_col_start = sel_col_end;
2194                 sel_col_end = tabular->right_column_of_cell(sel_cell_start);
2195         } else {
2196                 sel_col_end = tabular->right_column_of_cell(sel_cell_end);
2197         }
2198         int const columns = sel_col_end - sel_col_start + 1;
2199
2200         int sel_row_start = tabular->row_of_cell(sel_cell_start);
2201         int sel_row_end = tabular->row_of_cell(sel_cell_end);
2202         if (sel_row_start > sel_row_end) {
2203                 //int tmp tmp = sel_row_start;
2204                 //sel_row_start = sel_row_end;
2205                 //sel_row_end = tmp;
2206                 swap(sel_row_start, sel_row_end);
2207         }
2208         int const rows = sel_row_end - sel_row_start + 1;
2209
2210         delete paste_tabular;
2211         paste_tabular = new LyXTabular(this, *tabular); // rows, columns);
2212         //int i;
2213         for (int i = 0; i < sel_row_start; ++i)
2214                 paste_tabular->DeleteRow(0);
2215         while(paste_tabular->rows() > rows)
2216                 paste_tabular->DeleteRow(rows);
2217         paste_tabular->SetTopLine(0, true, true);
2218         paste_tabular->SetBottomLine(paste_tabular->GetFirstCellInRow(rows-1),
2219                                      true, true);
2220         for (int i = 0; i < sel_col_start; ++i)
2221                 paste_tabular->DeleteColumn(0);
2222         while (paste_tabular->columns() > columns)
2223                 paste_tabular->DeleteColumn(columns);
2224         paste_tabular->SetLeftLine(0, true, true);
2225         paste_tabular->SetRightLine(paste_tabular->GetLastCellInRow(0),
2226                                     true, true);
2227
2228         ostringstream sstr;
2229         paste_tabular->Ascii(bv->buffer(), sstr);
2230         bv->stuffClipboard(sstr.str().c_str());
2231         return true;
2232 }
2233
2234
2235 bool InsetTabular::pasteSelection(BufferView * bv)
2236 {
2237         if (!paste_tabular)
2238                 return false;
2239
2240         for (int r1 = 0, r2 = actrow;
2241              (r1 < paste_tabular->rows()) && (r2 < tabular->rows());
2242              ++r1, ++r2) {
2243                 for(int c1 = 0, c2 = actcol;
2244                     (c1 < paste_tabular->columns()) && (c2 < tabular->columns());
2245                     ++c1, ++c2) {
2246                         if (paste_tabular->IsPartOfMultiColumn(r1,c1) &&
2247                             tabular->IsPartOfMultiColumn(r2,c2))
2248                                 continue;
2249                         if (paste_tabular->IsPartOfMultiColumn(r1,c1)) {
2250                                 --c2;
2251                                 continue;
2252                         }
2253                         if (tabular->IsPartOfMultiColumn(r2,c2)) {
2254                                 --c1;
2255                                 continue;
2256                         }
2257                         int const n1 = paste_tabular->GetCellNumber(r1, c1);
2258                         int const n2 = tabular->GetCellNumber(r2, c2);
2259                         *(tabular->GetCellInset(n2)) = *(paste_tabular->GetCellInset(n1));
2260                         tabular->GetCellInset(n2)->setOwner(this);
2261                         tabular->GetCellInset(n2)->deleteLyXText(bv);
2262                 }
2263         }
2264         return true;
2265 }
2266
2267
2268 bool InsetTabular::cutSelection()
2269 {
2270         if (!hasSelection())
2271                 return false;
2272
2273         //int sel_col_start;
2274         //int sel_col_end;
2275         //int sel_row_start;
2276         //int sel_row_end;
2277
2278         int sel_col_start = tabular->column_of_cell(sel_cell_start);
2279         int sel_col_end = tabular->column_of_cell(sel_cell_end);
2280         if (sel_col_start > sel_col_end) {
2281                 sel_col_start = sel_col_end;
2282                 sel_col_end = tabular->right_column_of_cell(sel_cell_start);
2283         } else {
2284                 sel_col_end = tabular->right_column_of_cell(sel_cell_end);
2285         }
2286         int sel_row_start = tabular->row_of_cell(sel_cell_start);
2287         int sel_row_end = tabular->row_of_cell(sel_cell_end);
2288         if (sel_row_start > sel_row_end) {
2289                 //int tmp = sel_row_start;
2290                 //sel_row_start = sel_row_end;
2291                 //sel_row_end = tmp;
2292                 swap(sel_row_start, sel_row_end);
2293         }
2294         if (sel_cell_start > sel_cell_end) {
2295                 //int tmp = sel_cell_start;
2296                 //sel_cell_start = sel_cell_end;
2297                 //sel_cell_end = tmp;
2298                 swap(sel_cell_start, sel_cell_end);
2299         }
2300         for (int i = sel_row_start; i <= sel_row_end; ++i) {
2301                 for (int j = sel_col_start; j <= sel_col_end; ++j) {
2302                         tabular->GetCellInset(tabular->GetCellNumber(i, j))->clear();
2303                 }
2304         }
2305         return true;
2306 }
2307
2308
2309 bool InsetTabular::isRightToLeft(BufferView *bv )
2310 {
2311         return bv->getParentLanguage(this)->RightToLeft();
2312 }
2313
2314 bool InsetTabular::nodraw() const
2315 {
2316         if (the_locking_inset)
2317                 return the_locking_inset->nodraw();
2318         return UpdatableInset::nodraw();
2319 }
2320
2321 int InsetTabular::scroll(bool recursive) const
2322 {
2323         int sx = UpdatableInset::scroll(false);
2324
2325         if (recursive && the_locking_inset)
2326                 sx += the_locking_inset->scroll(recursive);
2327
2328         return sx;
2329 }
2330
2331 bool InsetTabular::doClearArea() const
2332 {
2333         return !locked || (need_update & (FULL|INIT));
2334 }
2335
2336 void InsetTabular::getSelection(int & srow, int & erow, int & scol, int & ecol) const
2337 {
2338                 srow = tabular->row_of_cell(sel_cell_start);
2339                 erow = tabular->row_of_cell(sel_cell_end);
2340                 if (srow > erow)
2341                         swap(srow, erow);
2342
2343                 scol = tabular->column_of_cell(sel_cell_start);
2344                 ecol = tabular->column_of_cell(sel_cell_end);
2345                 if (scol > ecol)
2346                         swap(scol, ecol);
2347                 else
2348                         ecol = tabular->right_column_of_cell(sel_cell_end);
2349 }
2350
2351 /* Emacs:
2352  * Local variables:
2353  * tab-width: 4
2354  * End:
2355  * vi:set tabstop=4:
2356  */