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