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