]> git.lyx.org Git - features.git/blob - src/insets/insettabular.C
Implemented Search/Replace functionality for Insets. Cleaned up a bit.
[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
44 using std::ostream;
45 using std::ifstream;
46 using std::max;
47 using std::endl;
48 using std::swap;
49 using std::max;
50
51 namespace {
52
53 const int ADD_TO_HEIGHT = 2;
54 const int ADD_TO_TABULAR_WIDTH = 2;
55 ///
56 LyXTabular * paste_tabular = 0;
57
58
59 struct TabularFeature {
60         LyXTabular::Feature action;
61         string feature;
62 };
63
64 //tabular_features * tabularFeatures = 0;
65
66 TabularFeature tabularFeature[] =
67 {
68         { LyXTabular::APPEND_ROW, "append-row" },
69         { LyXTabular::APPEND_COLUMN, "append-column" },
70         { LyXTabular::DELETE_ROW, "delete-row" },
71         { LyXTabular::DELETE_COLUMN, "delete-column" },
72         { LyXTabular::TOGGLE_LINE_TOP, "toggle-line-top" },
73         { LyXTabular::TOGGLE_LINE_BOTTOM, "toggle-line-bottom" },
74         { LyXTabular::TOGGLE_LINE_LEFT, "toggle-line-left" },
75         { LyXTabular::TOGGLE_LINE_RIGHT, "toggle-line-right" },
76         { LyXTabular::ALIGN_LEFT, "align-left" },
77         { LyXTabular::ALIGN_RIGHT, "align-right" },
78         { LyXTabular::ALIGN_CENTER, "align-center" },
79         { LyXTabular::VALIGN_TOP, "valign-top" },
80         { LyXTabular::VALIGN_BOTTOM, "valign-bottom" },
81         { LyXTabular::VALIGN_CENTER, "valign-center" },
82         { LyXTabular::M_TOGGLE_LINE_TOP, "m-toggle-line-top" },
83         { LyXTabular::M_TOGGLE_LINE_BOTTOM, "m-toggle-line-bottom" },
84         { LyXTabular::M_TOGGLE_LINE_LEFT, "m-toggle-line-left" },
85         { LyXTabular::M_TOGGLE_LINE_RIGHT, "m-toggle-line-right" },
86         { LyXTabular::M_ALIGN_LEFT, "m-align-left" },
87         { LyXTabular::M_ALIGN_RIGHT, "m-align-right" },
88         { LyXTabular::M_ALIGN_CENTER, "m-align-center" },
89         { LyXTabular::M_VALIGN_TOP, "m-valign-top" },
90         { LyXTabular::M_VALIGN_BOTTOM, "m-valign-bottom" },
91         { LyXTabular::M_VALIGN_CENTER, "m-valign-center" },
92         { LyXTabular::MULTICOLUMN, "multicolumn" },
93         { LyXTabular::SET_ALL_LINES, "set-all-lines" },
94         { LyXTabular::UNSET_ALL_LINES, "unset-all-lines" },
95         { LyXTabular::SET_LONGTABULAR, "set-longtabular" },
96         { LyXTabular::UNSET_LONGTABULAR, "unset-longtabular" },
97         { LyXTabular::SET_PWIDTH, "set-pwidth" },
98         { LyXTabular::SET_MPWIDTH, "set-mpwidth" },
99         { LyXTabular::SET_ROTATE_TABULAR, "set-rotate-tabular" },
100         { LyXTabular::UNSET_ROTATE_TABULAR, "unset-rotate-tabular" },
101         { LyXTabular::SET_ROTATE_CELL, "set-rotate-cell" },
102         { LyXTabular::UNSET_ROTATE_CELL, "unset-rotate-cell" },
103         { LyXTabular::SET_USEBOX, "set-usebox" },
104         { LyXTabular::SET_LTHEAD, "set-lthead" },
105         { LyXTabular::SET_LTFIRSTHEAD, "set-ltfirsthead" },
106         { LyXTabular::SET_LTFOOT, "set-ltfoot" },
107         { LyXTabular::SET_LTLASTFOOT, "set-ltlastfoot" },
108         { LyXTabular::SET_LTNEWPAGE, "set-ltnewpage" },
109         { LyXTabular::SET_SPECIAL_COLUMN, "set-special-column" },
110         { LyXTabular::SET_SPECIAL_MULTI, "set-special-multi" },
111         { LyXTabular::LAST_ACTION, "" }
112 };
113
114 } // namespace anon
115
116
117 bool InsetTabular::hasPasteBuffer() const
118 {
119         return (paste_tabular != 0);
120 }
121
122
123 InsetTabular::InsetTabular(Buffer const & buf, int rows, int columns)
124         : buffer(&buf)
125 {
126         if (rows <= 0)
127                 rows = 1;
128         if (columns <= 0)
129                 columns = 1;
130         tabular.reset(new LyXTabular(this, rows, columns));
131         // for now make it always display as display() inset
132         // just for test!!!
133         the_locking_inset = 0;
134         locked = no_selection = false;
135         oldcell = -1;
136         actrow = actcell = 0;
137         clearSelection();
138         need_update = INIT;
139 }
140
141
142 InsetTabular::InsetTabular(InsetTabular const & tab, Buffer const & buf,
143                                                    bool same_id)
144         : buffer(&buf)
145 {
146         tabular.reset(new LyXTabular(this, *(tab.tabular)));
147         the_locking_inset = 0;
148         locked = no_selection = false;
149         oldcell = -1;
150         actrow = actcell = 0;
151         sel_cell_start = sel_cell_end = 0;
152         need_update = INIT;
153         if (same_id)
154                 id_ = tab.id_;
155 }
156
157
158 InsetTabular::~InsetTabular()
159 {
160         hideDialog();
161 }
162
163
164 Inset * InsetTabular::clone(Buffer const & buf, bool same_id) const
165 {
166         return new InsetTabular(*this, buf, same_id);
167 }
168
169
170 void InsetTabular::write(Buffer const * buf, ostream & os) const
171 {
172         os << " Tabular" << endl;
173         tabular->Write(buf, os);
174 }
175
176
177 void InsetTabular::read(Buffer const * buf, LyXLex & lex)
178 {
179         bool const old_format = (lex.GetString() == "\\LyXTable");
180
181         //if (tabular)
182         //delete tabular;
183         //tabular = new LyXTabular(buf, this, lex);
184         tabular.reset(new LyXTabular(buf, this, lex));
185
186         need_update = INIT;
187
188         if (old_format)
189                 return;
190
191         lex.nextToken();
192         string token = lex.GetString();
193         while (lex.IsOK() && (token != "\\end_inset")) {
194                 lex.nextToken();
195                 token = lex.GetString();
196         }
197         if (token != "\\end_inset") {
198                 lex.printError("Missing \\end_inset at this point. "
199                                "Read: `$$Token'");
200         }
201 }
202
203
204 int InsetTabular::ascent(BufferView *, LyXFont const &) const
205 {
206         return tabular->GetAscentOfRow(0);
207 }
208
209
210 int InsetTabular::descent(BufferView *, LyXFont const &) const
211 {
212         return tabular->GetHeightOfTabular() - tabular->GetAscentOfRow(0) + 1;
213 }
214
215
216 int InsetTabular::width(BufferView *, LyXFont const &) const
217 {
218         return tabular->GetWidthOfTabular() + (2 * ADD_TO_TABULAR_WIDTH);
219 }
220
221
222 void InsetTabular::draw(BufferView * bv, LyXFont const & font, int baseline,
223                         float & x, bool cleared) const
224 {
225         if (nodraw()) {
226                 if (cleared)
227                         need_update = FULL;
228                 return;
229         }
230 #if 0
231         if (need_update == INIT) {
232                 if (calculate_dimensions_of_cells(bv, font, true))
233                         bv->text->status = LyXText::CHANGED_IN_DRAW;
234                 need_update = FULL;
235         }
236 #endif
237
238         Painter & pain = bv->painter();
239         int i;
240         int j;
241         int nx;
242
243 #if 0
244         UpdatableInset::draw(bv, font, baseline, x, cleared);
245 #else
246         if (!owner())
247                 x += static_cast<float>(scroll());
248 #endif
249         if (!cleared && ((need_update == INIT) || (need_update == FULL) ||
250                          (top_x != int(x)) || (top_baseline != baseline))) {
251                 int h = ascent(bv, font) + descent(bv, font);
252                 int const tx = display() || !owner() ? 0 : top_x;
253                 int w =  tx ? width(bv, font) : pain.paperWidth();
254                 int ty = baseline - ascent(bv, font);
255         
256                 if (ty < 0)
257                         ty = 0;
258                 if ((ty + h) > pain.paperHeight())
259                         h = pain.paperHeight();
260                 if ((top_x + w) > pain.paperWidth())
261                         w = pain.paperWidth();
262                 pain.fillRectangle(tx, ty, w, h);
263                 need_update = FULL;
264                 cleared = true;
265         }
266         top_x = int(x);
267         top_baseline = baseline;
268         x += ADD_TO_TABULAR_WIDTH;
269         if (cleared) {
270                 int cell = 0;
271                 float cx;
272                 first_visible_cell = -1;
273                 for (i = 0; i < tabular->rows(); ++i) {
274                         nx = int(x);
275                         cell = tabular->GetCellNumber(i, 0);
276                         if (!((baseline + tabular->GetDescentOfRow(i)) > 0) &&
277                                 (baseline - tabular->GetAscentOfRow(i))<pain.paperHeight())
278                         {
279                                 baseline += tabular->GetDescentOfRow(i) +
280                                         tabular->GetAscentOfRow(i + 1) +
281                                         tabular->GetAdditionalHeight(i + 1);
282                                 continue;
283                         }
284                         for (j = 0; j < tabular->columns(); ++j) {
285                                 if (nx > bv->workWidth())
286                                         break;
287                                 if (tabular->IsPartOfMultiColumn(i, j))
288                                         continue;
289                                 cx = nx + tabular->GetBeginningOfTextInCell(cell);
290                                 if (first_visible_cell < 0)
291                                         first_visible_cell = cell;
292                                 if (hasSelection())
293                                         drawCellSelection(pain, nx, baseline, i, j, cell);
294                                 
295                                 tabular->GetCellInset(cell)->draw(bv, font, baseline, cx,
296                                                                                                   cleared);
297                                 drawCellLines(pain, nx, baseline, i, cell);
298                                 nx += tabular->GetWidthOfColumn(cell);
299                                 ++cell;
300                         }
301                         baseline += tabular->GetDescentOfRow(i) +
302                                 tabular->GetAscentOfRow(i + 1) +
303                                 tabular->GetAdditionalHeight(i + 1);
304                 }
305         } else if (need_update == CELL) {
306                 int cell = 0;
307                 nx = int(x);
308                 if (the_locking_inset &&
309                         tabular->GetCellInset(actcell) != the_locking_inset)
310                 {
311                         Inset * inset = tabular->GetCellInset(cell);
312                         for (i = 0;
313                              inset != the_locking_inset && i < tabular->rows();
314                              ++i) {
315                                 for (j = 0;
316                                      inset != the_locking_inset
317                                              && j < tabular->columns();
318                                      ++j) {
319                                         if (tabular->IsPartOfMultiColumn(i, j))
320                                                 continue;
321                                         nx += tabular->GetWidthOfColumn(cell);
322                                         ++cell;
323                                         inset = tabular->GetCellInset(cell);
324                                 }
325                                 if (tabular->row_of_cell(cell) > i) {
326                                         nx = int(x);
327                                         baseline += tabular->GetDescentOfRow(i) +
328                                                 tabular->GetAscentOfRow(i + 1) +
329                                                 tabular->GetAdditionalHeight(i + 1);
330                                 }
331                         }
332                 } else {
333                         // compute baseline for actual row
334                         for (i = 0; i < actrow; ++i) {
335                                 baseline += tabular->GetDescentOfRow(i) +
336                                         tabular->GetAscentOfRow(i + 1) +
337                                         tabular->GetAdditionalHeight(i + 1);
338                         }
339                         // now compute the right x position
340                         cell = tabular->GetCellNumber(actrow, 0);
341                         for (j = 0; (cell < actcell) && (j < tabular->columns()); ++j) {
342                                         if (tabular->IsPartOfMultiColumn(actrow, j))
343                                                 continue;
344                                         nx += tabular->GetWidthOfColumn(cell);
345                                         ++cell;
346                         }
347                 }
348                 i = tabular->row_of_cell(cell);
349                 if (the_locking_inset != tabular->GetCellInset(cell)) {
350                         lyxerr[Debug::INSETS] << "ERROR this shouldn't happen\n";
351                         return;
352                 }
353                 float dx = nx + tabular->GetBeginningOfTextInCell(cell);
354                 float cx = dx;
355                 //cx = dx = nx + tabular->GetBeginningOfTextInCell(cell);
356                 tabular->GetCellInset(cell)->draw(bv, font, baseline, dx, false);
357 #if 0
358                 if (bv->text->status == LyXText::CHANGED_IN_DRAW)
359                         return;
360 #endif
361                 // clear only if we didn't have a change
362                 if (need_update == CELL) {
363                         // clear before the inset
364                         pain.fillRectangle(
365                                 nx + 1,
366                                 baseline - tabular->GetAscentOfRow(i) + 1,
367                                 int(cx - nx - 1),
368                                 tabular->GetAscentOfRow(i) +
369                                 tabular->GetDescentOfRow(i) - 1);
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                 }
381         }
382         x -= ADD_TO_TABULAR_WIDTH;
383         x += width(bv, font);
384         if (bv->text->status() == LyXText::CHANGED_IN_DRAW) {
385                 int i = 0;
386                 for(Inset * inset=owner(); inset; ++i)
387                         inset = inset->owner();
388                 if (calculate_dimensions_of_cells(bv, font, false))
389                         need_update = INIT;
390         } else {
391                 need_update = NONE;
392         }
393 }
394
395
396 void InsetTabular::drawCellLines(Painter & pain, int x, int baseline,
397                                  int row, int cell) const
398 {
399         int x2 = x + tabular->GetWidthOfColumn(cell);
400         bool on_off;
401         
402         if (!tabular->TopAlreadyDrawed(cell)) {
403                 on_off = !tabular->TopLine(cell);
404                 pain.line(x, baseline - tabular->GetAscentOfRow(row),
405                           x2, baseline -  tabular->GetAscentOfRow(row),
406                           on_off ? LColor::tabularonoffline : LColor::tabularline,
407                           on_off ? Painter::line_onoffdash : Painter::line_solid);
408         }
409         on_off = !tabular->BottomLine(cell);
410         pain.line(x,baseline +  tabular->GetDescentOfRow(row),
411                   x2, baseline +  tabular->GetDescentOfRow(row),
412                   on_off ? LColor::tabularonoffline : LColor::tabularline,
413                   on_off ? Painter::line_onoffdash : Painter::line_solid);
414         if (!tabular->LeftAlreadyDrawed(cell)) {
415                 on_off = !tabular->LeftLine(cell);
416                 pain.line(x, baseline -  tabular->GetAscentOfRow(row),
417                           x, baseline +  tabular->GetDescentOfRow(row),
418                           on_off ? LColor::tabularonoffline : LColor::tabularline,
419                           on_off ? Painter::line_onoffdash : Painter::line_solid);
420         }
421         on_off = !tabular->RightLine(cell);
422         pain.line(x2 - tabular->GetAdditionalWidth(cell),
423                   baseline -  tabular->GetAscentOfRow(row),
424                   x2 - tabular->GetAdditionalWidth(cell),
425                   baseline +  tabular->GetDescentOfRow(row),
426                   on_off ? LColor::tabularonoffline : LColor::tabularline,
427                   on_off ? Painter::line_onoffdash : Painter::line_solid);
428 }
429
430
431 void InsetTabular::drawCellSelection(Painter & pain, int x, int baseline,
432                                      int row, int column, int cell) const
433 {
434         int cs = tabular->column_of_cell(sel_cell_start);
435         int ce = tabular->column_of_cell(sel_cell_end);
436         if (cs > ce) {
437                 ce = cs;
438                 cs = tabular->column_of_cell(sel_cell_end);
439         } else {
440                 ce = tabular->right_column_of_cell(sel_cell_end);
441         }
442         
443         int rs = tabular->row_of_cell(sel_cell_start);
444         int re = tabular->row_of_cell(sel_cell_end);
445         if (rs > re) swap(rs, re);
446         
447         if ((column >= cs) && (column <= ce) && (row >= rs) && (row <= re)) {
448                 int w = tabular->GetWidthOfColumn(cell);
449                 int h = tabular->GetAscentOfRow(row) + tabular->GetDescentOfRow(row);
450                 pain.fillRectangle(x, baseline - tabular->GetAscentOfRow(row),
451                                    w, h, LColor::selection);
452         }
453 }
454
455
456 void InsetTabular::update(BufferView * bv, LyXFont const & font, bool reinit)
457 {
458         if (reinit) {
459                 need_update = INIT;
460                 calculate_dimensions_of_cells(bv, font, true);
461                 if (owner())
462                         owner()->update(bv, font, true);
463                 return;
464         }
465         if (the_locking_inset)
466                 the_locking_inset->update(bv, font, reinit);
467         if (need_update < FULL &&
468                 bv->text->status() == LyXText::NEED_MORE_REFRESH)
469         {
470                 need_update = FULL;
471         }
472
473         switch (need_update) {
474         case INIT:
475         case FULL:
476         case CELL:
477                 if (calculate_dimensions_of_cells(bv, font, false))
478                         need_update = INIT;
479                 break;
480         case SELECTION:
481                 need_update = INIT;
482                 break;
483         default:
484                 break;
485         }
486 }
487
488
489 string const InsetTabular::editMessage() const
490 {
491         return _("Opened Tabular Inset");
492 }
493
494
495 void InsetTabular::edit(BufferView * bv, int x, int y, unsigned int button)
496 {
497         UpdatableInset::edit(bv, x, y, button);
498         
499         if (!bv->lockInset(this)) {
500                 lyxerr[Debug::INSETS] << "InsetTabular::Cannot lock inset" << endl;
501                 return;
502         }
503         locked = true;
504         the_locking_inset = 0;
505         inset_x = 0;
506         inset_y = 0;
507         setPos(bv, x, y);
508         sel_cell_start = sel_cell_end = actcell;
509         finishUndo();
510         if (insetHit(bv, x, y) && (button != 3)) {
511                 activateCellInsetAbs(bv, x, y, button);
512         }
513 }
514
515
516 void InsetTabular::edit(BufferView * bv, bool front)
517 {
518         UpdatableInset::edit(bv, front);
519         
520         if (!bv->lockInset(this)) {
521                 lyxerr[Debug::INSETS] << "InsetTabular::Cannot lock inset" << endl;
522                 return;
523         }
524         locked = true;
525         the_locking_inset = 0;
526         inset_x = 0;
527         inset_y = 0;
528         if (front)
529                 actcell = 0;
530         else
531                 actcell = tabular->GetNumberOfCells() - 1;
532         sel_cell_start = sel_cell_end = actcell;
533         resetPos(bv);
534         finishUndo();
535 }
536
537
538 void InsetTabular::insetUnlock(BufferView * bv)
539 {
540         if (the_locking_inset) {
541                 the_locking_inset->insetUnlock(bv);
542                 the_locking_inset = 0;
543         }
544         hideInsetCursor(bv);
545         no_selection = false;
546         oldcell = -1;
547         locked = false;
548         if (scroll(false) || hasSelection()) {
549                 sel_cell_start = sel_cell_end = 0;
550                 if (scroll(false)) {
551                         scroll(bv, 0.0F);
552                 }
553                 updateLocal(bv, FULL, false);
554         }
555 }
556
557
558 void InsetTabular::updateLocal(BufferView * bv, UpdateCodes what,
559                                bool mark_dirty) const
560 {
561         if (need_update < what) // only set this if it has greater update
562                 need_update = what;
563         if ((what == INIT) && hasSelection())
564                 clearSelection();
565         // Dirty Cast! (Lgb)
566         if (need_update != NONE) {
567                 bv->updateInset(const_cast<InsetTabular *>(this), mark_dirty);
568                 if (locked) // && (what != NONE))
569                         resetPos(bv);
570         }
571 }
572
573
574 bool InsetTabular::lockInsetInInset(BufferView * bv, UpdatableInset * inset)
575 {
576         lyxerr[Debug::INSETS] << "InsetTabular::LockInsetInInset("
577                               << inset << "): ";
578         if (!inset)
579                 return false;
580         oldcell = -1;
581         if (inset == tabular->GetCellInset(actcell)) {
582                 lyxerr[Debug::INSETS] << "OK" << endl;
583                 the_locking_inset = tabular->GetCellInset(actcell);
584                 resetPos(bv);
585                 inset_x = cursor_.x() - top_x + tabular->GetBeginningOfTextInCell(actcell);
586                 inset_y = cursor_.y();
587                 return true;
588         } else if (the_locking_inset && (the_locking_inset == inset)) {
589                 lyxerr[Debug::INSETS] << "OK" << endl;
590                 resetPos(bv);
591                 inset_x = cursor_.x() - top_x + tabular->GetBeginningOfTextInCell(actcell);
592                 inset_y = cursor_.y();
593         } else if (the_locking_inset) {
594                 lyxerr[Debug::INSETS] << "MAYBE" << endl;
595                 return the_locking_inset->lockInsetInInset(bv, inset);
596         }
597         lyxerr[Debug::INSETS] << "NOT OK" << endl;
598         return false;
599 }
600
601
602 bool InsetTabular::unlockInsetInInset(BufferView * bv, UpdatableInset * inset,
603                                       bool lr)
604 {
605         if (!the_locking_inset)
606                 return false;
607         if (the_locking_inset == inset) {
608                 the_locking_inset->insetUnlock(bv);
609                 the_locking_inset = 0;
610 #ifdef WITH_WARNINGS
611 #warning fix scrolling when cellinset has requested a scroll (Jug)!!!
612 #endif
613 #if 0
614                 if (scroll(false))
615                         scroll(bv, 0.0F);
616 #endif
617                 updateLocal(bv, CELL, false);
618                 showInsetCursor(bv, false);
619                 return true;
620         }
621         if (the_locking_inset->unlockInsetInInset(bv, inset, lr)) {
622                 if (inset->lyxCode() == TABULAR_CODE &&
623                     !the_locking_inset->getFirstLockingInsetOfType(TABULAR_CODE)) {
624                         bv->owner()->getDialogs()->updateTabular(this);
625                         oldcell = actcell;
626                 }
627                 return true;
628         }
629         return false;
630 }
631
632
633 bool InsetTabular::updateInsetInInset(BufferView * bv, Inset * inset)
634 {
635         if (!the_locking_inset)
636                 return false;
637         if (the_locking_inset != inset) {
638                 if (!the_locking_inset->updateInsetInInset(bv, inset))
639                         return false;
640         }
641         updateLocal(bv, CELL, false);
642         return true;
643 }
644
645
646 unsigned int InsetTabular::insetInInsetY()
647 {
648         if (!the_locking_inset)
649                 return 0;
650         
651         return inset_y + the_locking_inset->insetInInsetY();
652 }
653
654
655 UpdatableInset * InsetTabular::getLockingInset() const
656 {
657         return the_locking_inset ? the_locking_inset->getLockingInset() :
658                 const_cast<InsetTabular *>(this);
659 }
660
661
662 UpdatableInset * InsetTabular::getFirstLockingInsetOfType(Inset::Code c)
663 {
664         if (c == lyxCode())
665                 return this;
666         if (the_locking_inset)
667                 return the_locking_inset->getFirstLockingInsetOfType(c);
668         return 0;
669 }
670
671
672 bool InsetTabular::insertInset(BufferView * bv, Inset * inset)
673 {
674         if (the_locking_inset)
675                 return the_locking_inset->insertInset(bv, inset);
676         return false;
677 }
678
679
680 void InsetTabular::insetButtonPress(BufferView * bv, int x, int y, int button)
681 {
682         if (hasSelection() && (button == 3))
683                 return;
684
685         if (hasSelection()) {
686                 clearSelection();
687                 updateLocal(bv, SELECTION, false);
688         }
689
690         no_selection = false;
691
692         int const ocell = actcell;
693         int const orow = actrow;
694
695         hideInsetCursor(bv);
696         setPos(bv, x, y);
697         if (actrow != orow)
698                 updateLocal(bv, NONE, false);
699         sel_cell_start = sel_cell_end = actcell;
700         if (button == 3) {
701                 if ((ocell != actcell) && the_locking_inset) {
702                         the_locking_inset->insetUnlock(bv);
703                         the_locking_inset = 0;
704                 }
705                 showInsetCursor(bv);
706                 return;
707         }
708
709         bool const inset_hit = insetHit(bv, x, y);
710
711         if ((ocell == actcell) && the_locking_inset && inset_hit) {
712                 resetPos(bv);
713                 the_locking_inset->insetButtonPress(bv,
714                                                     x - inset_x, y - inset_y,
715                                                     button);
716                 return;
717         } else if (the_locking_inset) {
718                 the_locking_inset->insetUnlock(bv);
719         }
720         the_locking_inset = 0;
721         if (button == 2) {
722                 localDispatch(bv, LFUN_PASTESELECTION, "paragraph");
723                 return;
724         }
725         if (inset_hit && bv->theLockingInset()) {
726                 if (activateCellInsetAbs(bv, x, y, button))
727                         the_locking_inset->insetButtonPress(bv,
728                                                             x - inset_x,
729                                                             y - inset_y,
730                                                             button);
731                 return;
732         }
733         showInsetCursor(bv);
734 }
735
736
737 void InsetTabular::insetButtonRelease(BufferView * bv,
738                                       int x, int y, int button)
739 {
740         if (button == 3) {
741                 if (the_locking_inset) {
742                         UpdatableInset * i;
743                         if ((i = the_locking_inset->getFirstLockingInsetOfType(TABULAR_CODE))) {
744                                 i->insetButtonRelease(bv, x, y, button);
745                                 return;
746                         }
747                 }
748                 bv->owner()->getDialogs()->showTabular(this);
749                 return;
750         }
751         if (the_locking_inset) {
752                 the_locking_inset->insetButtonRelease(bv,
753                                                       x - inset_x, y - inset_y,
754                                                       button);
755                 return;
756         }
757         no_selection = false;
758 }
759
760
761 void InsetTabular::insetMotionNotify(BufferView * bv, int x, int y, int button)
762 {
763         if (the_locking_inset) {
764                 the_locking_inset->insetMotionNotify(bv,
765                                                      x - inset_x,
766                                                      y - inset_y,
767                                                      button);
768                 return;
769         }
770         if (!no_selection) {
771                 hideInsetCursor(bv);
772                 int const old_cell = actcell;
773                 
774                 setPos(bv, x, y);
775                 sel_cell_end = actcell;
776                 if (sel_cell_end != old_cell)
777                         updateLocal(bv, SELECTION, false);
778                 showInsetCursor(bv);
779         }
780         no_selection = false;
781 }
782
783
784 void InsetTabular::insetKeyPress(XKeyEvent * xke)
785 {
786         if (the_locking_inset) {
787                 the_locking_inset->insetKeyPress(xke);
788                 return;
789         }
790 }
791
792
793 UpdatableInset::RESULT
794 InsetTabular::localDispatch(BufferView * bv,
795                             kb_action action,
796                             string const & arg)
797 {
798         // We need to save the value of the_locking_inset as the call to 
799         // the_locking_inset->LocalDispatch might unlock it.
800         old_locking_inset = the_locking_inset;
801         no_selection = false;
802         UpdatableInset::RESULT result =
803                 UpdatableInset::localDispatch(bv, action, arg);
804         if (result == DISPATCHED || result == DISPATCHED_NOUPDATE) {
805                 resetPos(bv);
806                 return result;
807         }
808
809         if ((action < 0) && arg.empty())
810                 return FINISHED;
811
812         bool hs = hasSelection();
813
814         result = DISPATCHED;
815         // this one have priority over the locked InsetText!
816         switch (action) {
817         case LFUN_SHIFT_TAB:
818         case LFUN_TAB:
819         {
820                 if (getFirstLockingInsetOfType(Inset::TABULAR_CODE) != this)
821                         break;
822                 hideInsetCursor(bv);
823                 if (the_locking_inset) {
824                         unlockInsetInInset(bv, the_locking_inset);
825                         the_locking_inset = 0;
826                 }
827                 if (action == LFUN_TAB)
828                         moveNextCell(bv, old_locking_inset != 0);
829                 else
830                         movePrevCell(bv, old_locking_inset != 0);
831                 sel_cell_start = sel_cell_end = actcell;
832                 if (hs)
833                         updateLocal(bv, SELECTION, false);
834                 if (!the_locking_inset) {
835                         showInsetCursor(bv);
836                         return DISPATCHED_NOUPDATE;
837                 }
838                 return result;
839         }
840         // this to avoid compiler warnings.
841         default:
842                 break;
843         }
844
845         if (the_locking_inset) {
846                 result = the_locking_inset->localDispatch(bv, action, arg);
847                 if (result == DISPATCHED_NOUPDATE) {
848                         int sc = scroll();
849                         resetPos(bv);
850                         if (sc != scroll()) { // inset has been scrolled
851                                 the_locking_inset->toggleInsetCursor(bv);
852                                 updateLocal(bv, FULL, false);
853                                 the_locking_inset->toggleInsetCursor(bv);
854                         }
855                         return result;
856                 } else if (result == DISPATCHED) {
857                         the_locking_inset->toggleInsetCursor(bv);
858                         updateLocal(bv, CELL, false);
859                         the_locking_inset->toggleInsetCursor(bv);
860                         return result;
861                 } else if (result == FINISHED) {
862                 }
863         }
864
865         hideInsetCursor(bv);
866         result=DISPATCHED;
867         switch (action) {
868                 // --- Cursor Movements ----------------------------------
869         case LFUN_RIGHTSEL:
870                 if (tabular->IsLastCellInRow(actcell))
871                         break;
872                 moveRight(bv, false);
873                 sel_cell_end = actcell;
874                 updateLocal(bv, SELECTION, false);
875                 break;
876         case LFUN_RIGHT:
877                 result = moveRight(bv);
878                 sel_cell_start = sel_cell_end = actcell;
879                 if (hs)
880                         updateLocal(bv, SELECTION, false);
881                 break;
882         case LFUN_LEFTSEL:
883                 if (tabular->IsFirstCellInRow(actcell))
884                         break;
885                 moveLeft(bv, false);
886                 sel_cell_end = actcell;
887                 updateLocal(bv, SELECTION, false);
888                 break;
889         case LFUN_LEFT:
890                 result = moveLeft(bv);
891                 sel_cell_start = sel_cell_end = actcell;
892                 if (hs)
893                         updateLocal(bv, SELECTION, false);
894                 break;
895         case LFUN_DOWNSEL:
896         {
897                 int const ocell = actcell;
898                 moveDown(bv, false);
899                 if ((ocell == sel_cell_end) ||
900                     (tabular->column_of_cell(ocell)>tabular->column_of_cell(actcell)))
901                         sel_cell_end = tabular->GetCellBelow(sel_cell_end);
902                 else
903                         sel_cell_end = tabular->GetLastCellBelow(sel_cell_end);
904                 updateLocal(bv, SELECTION, false);
905         }
906         break;
907         case LFUN_DOWN:
908                 result = moveDown(bv, old_locking_inset != 0);
909                 sel_cell_start = sel_cell_end = actcell;
910                 if (hs)
911                         updateLocal(bv, SELECTION, false);
912                 break;
913         case LFUN_UPSEL:
914         {
915                 int const ocell = actcell;
916                 moveUp(bv, false);
917                 if ((ocell == sel_cell_end) ||
918                     (tabular->column_of_cell(ocell)>tabular->column_of_cell(actcell)))
919                         sel_cell_end = tabular->GetCellAbove(sel_cell_end);
920                 else
921                         sel_cell_end = tabular->GetLastCellAbove(sel_cell_end);
922                 updateLocal(bv, SELECTION, false);
923         }
924         break;
925         case LFUN_UP:
926                 result = moveUp(bv, old_locking_inset != 0);
927                 sel_cell_start = sel_cell_end = actcell;
928                 if (hs)
929                         updateLocal(bv, SELECTION, false);
930                 break;
931         case LFUN_NEXT: {
932                 int column = actcol;
933                 if (the_locking_inset) {
934                         unlockInsetInInset(bv, the_locking_inset);
935                         the_locking_inset = 0;
936                 }
937                 if (bv->text->first + bv->painter().paperHeight() <
938                     (top_baseline + tabular->GetHeightOfTabular()))
939                         {
940                                 bv->scrollCB(bv->text->first + bv->painter().paperHeight());
941                                 updateLocal(bv, FULL, false);
942                                 actcell = tabular->GetCellBelow(first_visible_cell) + column;
943                         } else {
944                                 actcell = tabular->GetFirstCellInRow(tabular->rows() - 1) + column;
945                         }
946                 resetPos(bv);
947                 updateLocal(bv, CURSOR, false);
948                 break;
949         }
950         case LFUN_PRIOR: {
951                 int column = actcol;
952                 if (the_locking_inset) {
953                         unlockInsetInInset(bv, the_locking_inset);
954                         the_locking_inset = 0;
955                 }
956                 if (top_baseline < 0) {
957                         bv->scrollCB(bv->text->first - bv->painter().paperHeight());
958                         updateLocal(bv, FULL, false);
959                         if (top_baseline > 0)
960                                 actcell = column;
961                         else
962                                 actcell = tabular->GetCellBelow(first_visible_cell) + column;
963                 } else {
964                         actcell = column;
965                 }
966                 resetPos(bv);
967                 updateLocal(bv, CURSOR, false);
968                 break;
969         }
970         case LFUN_BACKSPACE:
971                 break;
972         case LFUN_DELETE:
973                 break;
974         case LFUN_HOME:
975                 break;
976         case LFUN_END:
977                 break;
978         case LFUN_LAYOUT_TABULAR:
979         {
980                 bv->owner()->getDialogs()->showTabular(this);
981         }
982         break;
983         case LFUN_TABULAR_FEATURE:
984                 if (!tabularFeatures(bv, arg))
985                         result = UNDISPATCHED;
986                 break;
987         case LFUN_CUT:
988                 if (!copySelection(bv))
989                         break;
990                 setUndo(bv, Undo::DELETE,
991                         bv->text->cursor.par(),
992                         bv->text->cursor.par()->next());
993                 cutSelection();
994                 updateLocal(bv, INIT, true);
995                 break;
996         case LFUN_COPY:
997                 if (!hasSelection())
998                         break;
999                 finishUndo();
1000                 copySelection(bv);
1001                 break;
1002         case LFUN_PASTESELECTION:
1003         {
1004                 string const clip(bv->getClipboard());
1005         
1006                 if (clip.empty())
1007                         break;
1008                 if (clip.find('\t') != string::npos) {
1009                         int cols = 1;
1010                         int rows = 1;
1011                         int maxCols = 1;
1012                         unsigned int len = clip.length();
1013                         string::size_type p = 0;
1014
1015                         while(p < len &&
1016                               ((p = clip.find_first_of("\t\n", p)) != string::npos)) {
1017                                 switch(clip[p]) {
1018                                 case '\t':
1019                                         ++cols;
1020                                         break;
1021                                 case '\n':
1022                                         if ((p+1) < len)
1023                                                 ++rows;
1024                                         maxCols = max(cols, maxCols);
1025                                         cols = 1;
1026                                         break;
1027                                 }
1028                                 ++p;
1029                         }
1030                         maxCols = max(cols, maxCols);
1031                         delete paste_tabular;
1032                         paste_tabular = new LyXTabular(this, rows, maxCols);
1033                         string::size_type op = 0;
1034                         int cell = 0;
1035                         int cells = paste_tabular->GetNumberOfCells();
1036                         p = cols = 0;
1037                         while((cell < cells) && (p < len) &&
1038                               (p = clip.find_first_of("\t\n", p)) != string::npos) {
1039                                 if (p >= len)
1040                                         break;
1041                                 switch(clip[p]) {
1042                                 case '\t':
1043                                         paste_tabular->GetCellInset(cell)->setText(clip.substr(op, p-op));
1044                                         ++cols;
1045                                         ++cell;
1046                                         break;
1047                                 case '\n':
1048                                         paste_tabular->GetCellInset(cell)->setText(clip.substr(op, p-op));
1049                                         while(cols++ < maxCols)
1050                                                 ++cell;
1051                                         cols = 0;
1052                                         break;
1053                                 }
1054                                 ++p;
1055                                 op = p;
1056                         }
1057                         // check for the last cell if there is no trailing '\n'
1058                         if ((cell < cells) && (op < len))
1059                                 paste_tabular->GetCellInset(cell)->setText(clip.substr(op, len-op));
1060                 } else {
1061                         // so that the clipboard is used and it goes on
1062                         // to default
1063                         // and executes LFUN_PASTESELECTION in insettext!
1064                         delete paste_tabular;
1065                         paste_tabular = 0;
1066                 }
1067         }
1068         case LFUN_PASTE:
1069                 if (hasPasteBuffer()) {
1070                         setUndo(bv, Undo::INSERT,
1071                                 bv->text->cursor.par(),
1072                                 bv->text->cursor.par()->next());
1073                         pasteSelection(bv);
1074                         updateLocal(bv, INIT, true);
1075                         break;
1076                 }
1077                 // ATTENTION: the function above has to be PASTE and PASTESELECTION!!!
1078         default:
1079                 // we try to activate the actual inset and put this event down to
1080                 // the insets dispatch function.
1081                 result = UNDISPATCHED;
1082                 if (the_locking_inset)
1083                         break;
1084                 nodraw(true);
1085                 if (activateCellInset(bv)) {
1086                         // reset need_update setted in above function!
1087                         need_update = NONE;
1088                         result = the_locking_inset->localDispatch(bv, action, arg);
1089                         if ((result == UNDISPATCHED) || (result == FINISHED)) {
1090                                 unlockInsetInInset(bv, the_locking_inset);
1091                                 nodraw(false);
1092                                 the_locking_inset = 0;
1093                                 // we need to update if this was requested before
1094                                 updateLocal(bv, NONE, false);
1095                                 return UNDISPATCHED;
1096                         }
1097                         nodraw(false);
1098 //                      the_locking_inset->ToggleInsetCursor(bv);
1099                         updateLocal(bv, CELL, false);
1100 //                      the_locking_inset->ToggleInsetCursor(bv);
1101                         return result;
1102                 }
1103                 break;
1104         }
1105         if (result!=FINISHED) {
1106                 if (!the_locking_inset) {
1107                         showInsetCursor(bv);
1108                 }
1109         } else
1110                 bv->unlockInset(this);
1111         return result;
1112 }
1113
1114
1115 int InsetTabular::latex(Buffer const * buf, ostream & os,
1116                         bool fragile, bool fp) const
1117 {
1118         return tabular->Latex(buf, os, fragile, fp);
1119 }
1120
1121
1122 int InsetTabular::ascii(Buffer const * buf, ostream & os, int) const
1123 {
1124         // This should be changed to a real ascii export
1125         return tabular->Ascii(buf, os);
1126 }
1127
1128
1129 int InsetTabular::linuxdoc(Buffer const *, ostream &) const
1130 {
1131         return 0;
1132 }
1133
1134
1135 int InsetTabular::docBook(Buffer const * buf, ostream & os) const
1136 {
1137         return tabular->DocBook(buf,os);
1138 }
1139
1140
1141 void InsetTabular::validate(LaTeXFeatures & features) const
1142 {
1143         tabular->Validate(features);
1144 }
1145
1146
1147 bool InsetTabular::calculate_dimensions_of_cells(BufferView * bv,
1148                                                  LyXFont const & font,
1149                                                  bool reinit) const
1150 {
1151         int cell = -1;
1152         int maxAsc = 0;
1153         int maxDesc = 0;
1154         InsetText * inset;
1155         bool changed = false;
1156         
1157         // if we have a locking_inset we should have to check only this cell for
1158         // change so I'll try this to have a boost, but who knows ;)
1159         if ((need_update != INIT) &&
1160             (the_locking_inset == tabular->GetCellInset(actcell))) {
1161                 for(int i = 0; i < tabular->columns(); ++i) {
1162                         maxAsc = max(tabular->GetCellInset(actrow, i)->ascent(bv, font),
1163                                      maxAsc);
1164                         maxDesc = max(tabular->GetCellInset(actrow, i)->descent(bv, font),
1165                                       maxDesc);
1166                 }
1167                 changed = tabular->SetWidthOfCell(actcell, the_locking_inset->width(bv, font));
1168                 changed = tabular->SetAscentOfRow(actrow, maxAsc + ADD_TO_HEIGHT) || changed;
1169                 changed = tabular->SetDescentOfRow(actrow, maxDesc + ADD_TO_HEIGHT) || changed;
1170                 return changed;
1171         }
1172 #if 0
1173         cur_cell = -1;
1174 #endif
1175         for (int i = 0; i < tabular->rows(); ++i) {
1176                 maxAsc = 0;
1177                 maxDesc = 0;
1178                 for (int j = 0; j < tabular->columns(); ++j) {
1179                         if (tabular->IsPartOfMultiColumn(i,j))
1180                                 continue;
1181                         ++cell;
1182                         inset = tabular->GetCellInset(cell);
1183                         if (!reinit)
1184                                 inset->update(bv, font, false);
1185                         maxAsc = max(maxAsc, inset->ascent(bv, font));
1186                         maxDesc = max(maxDesc, inset->descent(bv, font));
1187                         changed = tabular->SetWidthOfCell(cell, inset->width(bv, font)) || changed;
1188                 }
1189                 changed = tabular->SetAscentOfRow(i, maxAsc + ADD_TO_HEIGHT) || changed;
1190                 changed = tabular->SetDescentOfRow(i, maxDesc + ADD_TO_HEIGHT) || changed;
1191         }
1192         return changed;
1193 }
1194
1195
1196 void InsetTabular::getCursorPos(BufferView * bv, int & x, int & y) const
1197 {
1198         if (the_locking_inset) {
1199                 the_locking_inset->getCursorPos(bv, x, y);
1200                 return;
1201         }
1202         x = cursor_.x() - top_x;
1203         y = cursor_.y();
1204 }
1205
1206
1207 void InsetTabular::toggleInsetCursor(BufferView * bv)
1208 {
1209         if (the_locking_inset) {
1210                 the_locking_inset->toggleInsetCursor(bv);
1211                 return;
1212         }
1213         
1214         LyXFont font; // = the_locking_inset->GetFont(par, cursor.pos);
1215         
1216         int const asc = lyxfont::maxAscent(font);
1217         int const desc = lyxfont::maxDescent(font);
1218         
1219         if (isCursorVisible())
1220                 bv->hideLockedInsetCursor();
1221         else
1222                 bv->showLockedInsetCursor(cursor_.x(), cursor_.y(), asc, desc);
1223         toggleCursorVisible();
1224 }
1225
1226
1227 void InsetTabular::showInsetCursor(BufferView * bv, bool show)
1228 {
1229         if (!isCursorVisible()) {
1230                 LyXFont font; // = GetFont(par, cursor.pos);
1231         
1232                 int const asc = lyxfont::maxAscent(font);
1233                 int const desc = lyxfont::maxDescent(font);
1234                 bv->fitLockedInsetCursor(cursor_.x(), cursor_.y(), asc, desc);
1235                 if (show)
1236                         bv->showLockedInsetCursor(cursor_.x(), cursor_.y(), asc, desc);
1237                 setCursorVisible(true);
1238         }
1239 }
1240
1241
1242 void InsetTabular::hideInsetCursor(BufferView * bv)
1243 {
1244         if (isCursorVisible()) {
1245                 bv->hideLockedInsetCursor();
1246                 setCursorVisible(false);
1247         }
1248 //    if (cursor_visible)
1249 //        ToggleInsetCursor(bv);
1250 }
1251
1252
1253 void InsetTabular::setPos(BufferView * bv, int x, int y) const
1254 {
1255         cursor_.y(0);
1256         
1257         actcell = actrow = actcol = 0;
1258         int ly = tabular->GetDescentOfRow(actrow);
1259
1260         // first search the right row
1261         while((ly < y) && (actrow < tabular->rows())) {
1262                 cursor_.y(cursor_.y() + tabular->GetDescentOfRow(actrow) +
1263                                  tabular->GetAscentOfRow(actrow + 1) +
1264                                  tabular->GetAdditionalHeight(actrow + 1));
1265                 ++actrow;
1266                 ly = cursor_.y() + tabular->GetDescentOfRow(actrow);
1267         }
1268         actcell = tabular->GetCellNumber(actrow, actcol);
1269
1270         // now search the right column
1271         int lx = tabular->GetWidthOfColumn(actcell) -
1272                 tabular->GetAdditionalWidth(actcell);
1273 #if 0
1274 #ifdef WITH_WARNINGS
1275 #warning Jürgen, can you rewrite this to _not_ use the sequencing operator. (Lgb)
1276 #endif
1277         for (; !tabular->IsLastCellInRow(actcell) && (lx < x);
1278              ++actcell,lx += tabular->GetWidthOfColumn(actcell) +
1279                      tabular->GetAdditionalWidth(actcell - 1));
1280 #else
1281         // Jürgen, you should check that this is correct. (Lgb)
1282         for (; !tabular->IsLastCellInRow(actcell) && lx < x; ++actcell) {
1283                 lx += tabular->GetWidthOfColumn(actcell + 1)
1284                         + tabular->GetAdditionalWidth(actcell);
1285         }
1286         
1287 #endif
1288         cursor_.x(lx - tabular->GetWidthOfColumn(actcell) + top_x + 2);
1289         resetPos(bv);
1290 }
1291
1292
1293 int InsetTabular::getCellXPos(int cell) const
1294 {
1295         int c = cell;
1296         
1297         for (; !tabular->IsFirstCellInRow(c); --c)
1298                 ;
1299         int lx = tabular->GetWidthOfColumn(cell);
1300         for (; c < cell; ++c) {
1301                 lx += tabular->GetWidthOfColumn(c);
1302         }
1303         return (lx - tabular->GetWidthOfColumn(cell) + top_x);
1304 }
1305
1306
1307 void InsetTabular::resetPos(BufferView * bv) const
1308 {
1309         if (!locked)
1310                 return;
1311         actcol = tabular->column_of_cell(actcell);
1312
1313         int cell = 0;
1314         actrow = 0;
1315         cursor_.y(0);
1316         for (; (cell < actcell) && !tabular->IsLastRow(cell); ++cell) {
1317                 if (tabular->IsLastCellInRow(cell)) {
1318                         cursor_.y(cursor_.y() + tabular->GetDescentOfRow(actrow) +
1319                                          tabular->GetAscentOfRow(actrow + 1) +
1320                                          tabular->GetAdditionalHeight(actrow + 1));
1321                         ++actrow;
1322                 }
1323         }
1324         static int const offset = ADD_TO_TABULAR_WIDTH + 2;
1325         int new_x = getCellXPos(actcell);
1326         int old_x = cursor_.x();
1327         new_x += offset;
1328         cursor_.x(new_x);
1329 //    cursor.x(getCellXPos(actcell) + offset);
1330         if ((actcol < tabular->columns()-1) && scroll(false) &&
1331                 (tabular->GetWidthOfTabular() < bv->workWidth()-20))
1332         {
1333                 scroll(bv, 0.0F);
1334                 updateLocal(bv, FULL, false);
1335         } else if (the_locking_inset &&
1336                  (tabular->GetWidthOfColumn(actcell) > bv->workWidth()-20))
1337         {
1338                 int xx = cursor_.x() - offset + bv->text->getRealCursorX(bv);
1339                 if (xx > (bv->workWidth()-20)) {
1340                         scroll(bv, -(xx - bv->workWidth() + 60));
1341                         updateLocal(bv, FULL, false);
1342                 } else if (xx < 20) {
1343                         if (xx < 0)
1344                                 xx = -xx + 60;
1345                         else
1346                                 xx = 60;
1347                         scroll(bv, xx);
1348                         updateLocal(bv, FULL, false);
1349                 }
1350         } else if ((cursor_.x() - offset) > 20 &&
1351                    (cursor_.x() - offset + tabular->GetWidthOfColumn(actcell))
1352                    > (bv->workWidth() - 20)) {
1353                 scroll(bv, -tabular->GetWidthOfColumn(actcell) - 20);
1354                 updateLocal(bv, FULL, false);
1355         } else if ((cursor_.x() - offset) < 20) {
1356                 scroll(bv, 20 - cursor_.x() + offset);
1357                 updateLocal(bv, FULL, false);
1358         } else if (scroll(false) && top_x > 20 &&
1359                    (top_x + tabular->GetWidthOfTabular()) > (bv->workWidth() - 20)) {
1360                 scroll(bv, old_x - cursor_.x());
1361                 updateLocal(bv, FULL, false);
1362         }
1363         if ((!the_locking_inset ||
1364              !the_locking_inset->getFirstLockingInsetOfType(TABULAR_CODE)) &&
1365             actcell != oldcell) {
1366                 InsetTabular * inset = const_cast<InsetTabular *>(this);
1367                 bv->owner()->getDialogs()->updateTabular(inset);
1368                 oldcell = actcell;
1369         }
1370 }
1371
1372
1373 UpdatableInset::RESULT InsetTabular::moveRight(BufferView * bv, bool lock)
1374 {
1375         if (lock && !old_locking_inset) {
1376                 if (activateCellInset(bv))
1377                         return DISPATCHED;
1378         } else {
1379                 bool moved = isRightToLeft(bv)
1380                         ? movePrevCell(bv) : moveNextCell(bv);
1381                 if (!moved)
1382                         return FINISHED;
1383                 if (lock && activateCellInset(bv))
1384                         return DISPATCHED;
1385         }
1386         resetPos(bv);
1387         return DISPATCHED_NOUPDATE;
1388 }
1389
1390
1391 UpdatableInset::RESULT InsetTabular::moveLeft(BufferView * bv, bool lock)
1392 {
1393         bool moved = isRightToLeft(bv) ? moveNextCell(bv) : movePrevCell(bv);
1394         if (!moved)
1395                 return FINISHED;
1396         if (lock) {       // behind the inset
1397                 if (activateCellInset(bv, 0, 0, 0, true))
1398                         return DISPATCHED;
1399         }
1400         resetPos(bv);
1401         return DISPATCHED_NOUPDATE;
1402 }
1403
1404
1405 UpdatableInset::RESULT InsetTabular::moveUp(BufferView * bv, bool lock)
1406 {
1407         int const ocell = actcell;
1408         actcell = tabular->GetCellAbove(actcell);
1409         if (actcell == ocell) // we moved out of the inset
1410                 return FINISHED;
1411         resetPos(bv);
1412         if (lock) {
1413                 int x = 0;
1414                 int y = 0;
1415                 if (old_locking_inset) {
1416                         old_locking_inset->getCursorPos(bv, x, y);
1417                         x -= cursor_.x() + tabular->GetBeginningOfTextInCell(actcell);
1418                 }
1419                 if (activateCellInset(bv, x, 0))
1420                         return DISPATCHED;
1421         }
1422         return DISPATCHED_NOUPDATE;
1423 }
1424
1425
1426 UpdatableInset::RESULT InsetTabular::moveDown(BufferView * bv, bool lock)
1427 {
1428         int const ocell = actcell;
1429         actcell = tabular->GetCellBelow(actcell);
1430         if (actcell == ocell) // we moved out of the inset
1431                 return FINISHED;
1432         resetPos(bv);
1433         if (lock) {
1434                 int x = 0;
1435                 int y = 0;
1436                 if (old_locking_inset) {
1437                         old_locking_inset->getCursorPos(bv, x, y);
1438                         x -= cursor_.x() + tabular->GetBeginningOfTextInCell(actcell);
1439                 }
1440                 if (activateCellInset(bv, x, 0))
1441                         return DISPATCHED;
1442         }
1443         return DISPATCHED_NOUPDATE;
1444 }
1445
1446
1447 bool InsetTabular::moveNextCell(BufferView * bv, bool lock)
1448 {
1449         if (isRightToLeft(bv)) {
1450                 if (tabular->IsFirstCellInRow(actcell)) {
1451                         int row = tabular->row_of_cell(actcell);
1452                         if (row == tabular->rows() - 1)
1453                                 return false;
1454                         actcell = tabular->GetLastCellInRow(row);
1455                         actcell = tabular->GetCellBelow(actcell);
1456                 } else {
1457                         if (!actcell)
1458                                 return false;
1459                         --actcell;
1460                 }
1461         } else {
1462                 if (tabular->IsLastCell(actcell))
1463                         return false;
1464                 ++actcell;
1465         }
1466         if (lock) {
1467                 bool rtl = tabular->GetCellInset(actcell)->paragraph()->
1468                         isRightToLeftPar(bv->buffer()->params);
1469                 activateCellInset(bv, 0, 0, 0, !rtl);
1470         }
1471         resetPos(bv);
1472         return true;
1473 }
1474
1475
1476 bool InsetTabular::movePrevCell(BufferView * bv, bool lock)
1477 {
1478         if (isRightToLeft(bv)) {
1479                 if (tabular->IsLastCellInRow(actcell)) {
1480                         int row = tabular->row_of_cell(actcell);
1481                         if (row == 0)
1482                                 return false;
1483                         actcell = tabular->GetFirstCellInRow(row);
1484                         actcell = tabular->GetCellAbove(actcell);
1485                 } else {
1486                         if (tabular->IsLastCell(actcell))
1487                                 return false;
1488                         ++actcell;
1489                 }
1490         } else {
1491                 if (!actcell) // first cell
1492                         return false;
1493                 --actcell;
1494         }
1495         if (lock) {
1496                 bool rtl = tabular->GetCellInset(actcell)->paragraph()->
1497                         isRightToLeftPar(bv->buffer()->params);
1498                 activateCellInset(bv, 0, 0, 0, !rtl);
1499         }
1500         resetPos(bv);
1501         return true;
1502 }
1503
1504
1505 bool InsetTabular::Delete()
1506 {
1507 #warning Is this func correctly named? Or should it be "deletable"? (Lgb?)
1508 #warning I guess this could be 'deletable'! (Jug)
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 // functions returns:
2034 // 0 ... disabled
2035 // 1 ... enabled
2036 // 2 ... toggled on
2037 // 3 ... toggled off
2038 //
2039 func_status::value_type InsetTabular::getStatus(string const & what) const
2040 {
2041         int action = LyXTabular::LAST_ACTION;
2042         func_status::value_type status = func_status::OK;
2043         
2044         int i = 0;
2045         for (; tabularFeature[i].action != LyXTabular::LAST_ACTION; ++i) {
2046                 string const tmp = tabularFeature[i].feature;
2047                 if (tmp == what.substr(0, tmp.length())) {                  
2048                         //if (!compare(tabularFeatures[i].feature.c_str(), what.c_str(),
2049                         //   tabularFeatures[i].feature.length())) {
2050                         action = tabularFeature[i].action;
2051                         break;
2052                 }
2053         }
2054         if (action == LyXTabular::LAST_ACTION)
2055                 return func_status::Unknown;
2056
2057         string const argument = frontStrip(what.substr(tabularFeature[i].feature.length()));
2058
2059         int sel_row_start;
2060         int sel_row_end;
2061         int dummy;
2062         bool flag = true;
2063
2064         if (hasSelection()) {
2065                 getSelection(sel_row_start, sel_row_end, dummy, dummy);
2066         } else {
2067                 sel_row_start = sel_row_end = tabular->row_of_cell(actcell);
2068         }
2069
2070         switch (action) {
2071         case LyXTabular::SET_PWIDTH:
2072         case LyXTabular::SET_MPWIDTH:
2073         case LyXTabular::SET_SPECIAL_COLUMN:
2074         case LyXTabular::SET_SPECIAL_MULTI:
2075                 status |= func_status::Disabled;
2076                 return status;
2077
2078         case LyXTabular::APPEND_ROW:
2079         case LyXTabular::APPEND_COLUMN:
2080         case LyXTabular::DELETE_ROW:
2081         case LyXTabular::DELETE_COLUMN:
2082         case LyXTabular::SET_ALL_LINES:
2083         case LyXTabular::UNSET_ALL_LINES:
2084                 status |= func_status::OK;
2085                 return status;
2086
2087         case LyXTabular::MULTICOLUMN:
2088                 if (tabular->IsMultiColumn(actcell))
2089                         status |= func_status::ToggleOn;
2090                 else
2091                         status |= func_status::ToggleOff;
2092                 break;
2093         case LyXTabular::M_TOGGLE_LINE_TOP:
2094                 flag = false;
2095         case LyXTabular::TOGGLE_LINE_TOP:
2096                 if (tabular->TopLine(actcell, flag))
2097                         status |= func_status::ToggleOn;
2098                 else
2099                         status |= func_status::ToggleOff;
2100                 break;
2101         case LyXTabular::M_TOGGLE_LINE_BOTTOM:
2102                 flag = false;
2103         case LyXTabular::TOGGLE_LINE_BOTTOM:
2104                 if (tabular->BottomLine(actcell, flag))
2105                         status |= func_status::ToggleOn;
2106                 else
2107                         status |= func_status::ToggleOff;
2108                 break;
2109         case LyXTabular::M_TOGGLE_LINE_LEFT:
2110                 flag = false;
2111         case LyXTabular::TOGGLE_LINE_LEFT:
2112                 if (tabular->LeftLine(actcell, flag))
2113                         status |= func_status::ToggleOn;
2114                 else
2115                         status |= func_status::ToggleOff;
2116                 break;
2117         case LyXTabular::M_TOGGLE_LINE_RIGHT:
2118                 flag = false;
2119         case LyXTabular::TOGGLE_LINE_RIGHT:
2120                 if (tabular->RightLine(actcell, flag))
2121                         status |= func_status::ToggleOn;
2122                 else
2123                         status |= func_status::ToggleOff;
2124                 break;
2125         case LyXTabular::M_ALIGN_LEFT:
2126                 flag = false;
2127         case LyXTabular::ALIGN_LEFT:
2128                 if (tabular->GetAlignment(actcell, flag) == LYX_ALIGN_LEFT)
2129                         status |= func_status::ToggleOn;
2130                 else
2131                         status |= func_status::ToggleOff;
2132                 break;
2133         case LyXTabular::M_ALIGN_RIGHT:
2134                 flag = false;
2135         case LyXTabular::ALIGN_RIGHT:
2136                 if (tabular->GetAlignment(actcell, flag) == LYX_ALIGN_RIGHT)
2137                         status |= func_status::ToggleOn;
2138                 else
2139                         status |= func_status::ToggleOff;
2140                 break;
2141         case LyXTabular::M_ALIGN_CENTER:
2142                 flag = false;
2143         case LyXTabular::ALIGN_CENTER:
2144                 if (tabular->GetAlignment(actcell, flag) == LYX_ALIGN_CENTER)
2145                         status |= func_status::ToggleOn;
2146                 else
2147                         status |= func_status::ToggleOff;
2148                 break;
2149         case LyXTabular::M_VALIGN_TOP:
2150                 flag = false;
2151         case LyXTabular::VALIGN_TOP:
2152                 if (tabular->GetVAlignment(actcell, flag) == LyXTabular::LYX_VALIGN_TOP)
2153                         status |= func_status::ToggleOn;
2154                 else
2155                         status |= func_status::ToggleOff;
2156                 break;
2157         case LyXTabular::M_VALIGN_BOTTOM:
2158                 flag = false;
2159         case LyXTabular::VALIGN_BOTTOM:
2160                 if (tabular->GetVAlignment(actcell, flag) == LyXTabular::LYX_VALIGN_BOTTOM)
2161                         status |= func_status::ToggleOn;
2162                 else
2163                         status |= func_status::ToggleOff;
2164                 break;
2165         case LyXTabular::M_VALIGN_CENTER:
2166                 flag = false;
2167         case LyXTabular::VALIGN_CENTER:
2168                 if (tabular->GetVAlignment(actcell, flag) == LyXTabular::LYX_VALIGN_CENTER)
2169                         status |= func_status::ToggleOn;
2170                 else
2171                         status |= func_status::ToggleOff;
2172                 break;
2173         case LyXTabular::SET_LONGTABULAR:
2174                 if (tabular->IsLongTabular())
2175                         status |= func_status::ToggleOn;
2176                 else
2177                         status |= func_status::ToggleOff;
2178                 break;
2179         case LyXTabular::UNSET_LONGTABULAR:
2180                 if (!tabular->IsLongTabular())
2181                         status |= func_status::ToggleOn;
2182                 else
2183                         status |= func_status::ToggleOff;
2184                 break;
2185         case LyXTabular::SET_ROTATE_TABULAR:
2186                 if (tabular->GetRotateTabular())
2187                         status |= func_status::ToggleOn;
2188                 else
2189                         status |= func_status::ToggleOff;
2190                 break;
2191         case LyXTabular::UNSET_ROTATE_TABULAR:
2192                 if (!tabular->GetRotateTabular())
2193                         status |= func_status::ToggleOn;
2194                 else
2195                         status |= func_status::ToggleOff;
2196                 break;
2197         case LyXTabular::SET_ROTATE_CELL:
2198                 if (tabular->GetRotateCell(actcell))
2199                         status |= func_status::ToggleOn;
2200                 else
2201                         status |= func_status::ToggleOff;
2202                 break;
2203         case LyXTabular::UNSET_ROTATE_CELL:
2204                 if (!tabular->GetRotateCell(actcell))
2205                         status |= func_status::ToggleOn;
2206                 else
2207                         status |= func_status::ToggleOff;
2208                 break;
2209         case LyXTabular::SET_USEBOX:
2210                 if (strToInt(argument) == tabular->GetUsebox(actcell))
2211                         status |= func_status::ToggleOn;
2212                 else
2213                         status |= func_status::ToggleOff;
2214                 break;
2215         case LyXTabular::SET_LTFIRSTHEAD:
2216                 if (tabular->GetRowOfLTHead(actcell, dummy))
2217                         status |= func_status::ToggleOn;
2218                 else
2219                         status |= func_status::ToggleOff;
2220                 break;
2221         case LyXTabular::SET_LTHEAD:
2222                 if (tabular->GetRowOfLTHead(actcell, dummy))
2223                         status |= func_status::ToggleOn;
2224                 else
2225                         status |= func_status::ToggleOff;
2226                 break;
2227         case LyXTabular::SET_LTFOOT:
2228                 if (tabular->GetRowOfLTFoot(actcell, dummy))
2229                         status |= func_status::ToggleOn;
2230                 else
2231                         status |= func_status::ToggleOff;
2232                 break;
2233         case LyXTabular::SET_LTLASTFOOT:
2234                 if (tabular->GetRowOfLTFoot(actcell, dummy))
2235                         status |= func_status::ToggleOn;
2236                 else
2237                         status |= func_status::ToggleOff;
2238                 break;
2239         case LyXTabular::SET_LTNEWPAGE:
2240                 if (tabular->GetLTNewPage(actcell))
2241                         status |= func_status::ToggleOn;
2242                 else
2243                         status |= func_status::ToggleOff;
2244                 break;
2245         default:
2246                 status = func_status::Disabled;
2247                 break;
2248         }
2249         return status;
2250 }
2251
2252
2253 std::vector<string> const InsetTabular::getLabelList() const
2254 {
2255         return tabular->getLabelList();
2256 }
2257
2258
2259 bool InsetTabular::copySelection(BufferView * bv)
2260 {
2261         if (!hasSelection())
2262                 return false;
2263
2264         int sel_col_start = tabular->column_of_cell(sel_cell_start);
2265         int sel_col_end = tabular->column_of_cell(sel_cell_end);
2266         if (sel_col_start > sel_col_end) {
2267                 sel_col_start = sel_col_end;
2268                 sel_col_end = tabular->right_column_of_cell(sel_cell_start);
2269         } else {
2270                 sel_col_end = tabular->right_column_of_cell(sel_cell_end);
2271         }
2272         int const columns = sel_col_end - sel_col_start + 1;
2273
2274         int sel_row_start = tabular->row_of_cell(sel_cell_start);
2275         int sel_row_end = tabular->row_of_cell(sel_cell_end);
2276         if (sel_row_start > sel_row_end) {
2277                 swap(sel_row_start, sel_row_end);
2278         }
2279         int const rows = sel_row_end - sel_row_start + 1;
2280
2281         delete paste_tabular;
2282         paste_tabular = new LyXTabular(this, *tabular); // rows, columns);
2283         for (int i = 0; i < sel_row_start; ++i)
2284                 paste_tabular->DeleteRow(0);
2285         while(paste_tabular->rows() > rows)
2286                 paste_tabular->DeleteRow(rows);
2287         paste_tabular->SetTopLine(0, true, true);
2288         paste_tabular->SetBottomLine(paste_tabular->GetFirstCellInRow(rows-1),
2289                                      true, true);
2290         for (int i = 0; i < sel_col_start; ++i)
2291                 paste_tabular->DeleteColumn(0);
2292         while (paste_tabular->columns() > columns)
2293                 paste_tabular->DeleteColumn(columns);
2294         paste_tabular->SetLeftLine(0, true, true);
2295         paste_tabular->SetRightLine(paste_tabular->GetLastCellInRow(0),
2296                                     true, true);
2297
2298         ostringstream sstr;
2299         paste_tabular->Ascii(bv->buffer(), sstr);
2300         bv->stuffClipboard(sstr.str().c_str());
2301         return true;
2302 }
2303
2304
2305 bool InsetTabular::pasteSelection(BufferView * bv)
2306 {
2307         if (!paste_tabular)
2308                 return false;
2309
2310         for (int r1 = 0, r2 = actrow;
2311              (r1 < paste_tabular->rows()) && (r2 < tabular->rows());
2312              ++r1, ++r2) {
2313                 for(int c1 = 0, c2 = actcol;
2314                     (c1 < paste_tabular->columns()) && (c2 < tabular->columns());
2315                     ++c1, ++c2) {
2316                         if (paste_tabular->IsPartOfMultiColumn(r1,c1) &&
2317                             tabular->IsPartOfMultiColumn(r2,c2))
2318                                 continue;
2319                         if (paste_tabular->IsPartOfMultiColumn(r1,c1)) {
2320                                 --c2;
2321                                 continue;
2322                         }
2323                         if (tabular->IsPartOfMultiColumn(r2,c2)) {
2324                                 --c1;
2325                                 continue;
2326                         }
2327                         int const n1 = paste_tabular->GetCellNumber(r1, c1);
2328                         int const n2 = tabular->GetCellNumber(r2, c2);
2329                         *(tabular->GetCellInset(n2)) = *(paste_tabular->GetCellInset(n1));
2330                         tabular->GetCellInset(n2)->setOwner(this);
2331                         tabular->GetCellInset(n2)->deleteLyXText(bv);
2332                 }
2333         }
2334         return true;
2335 }
2336
2337
2338 bool InsetTabular::cutSelection()
2339 {
2340         if (!hasSelection())
2341                 return false;
2342
2343         //int sel_col_start;
2344         //int sel_col_end;
2345         //int sel_row_start;
2346         //int sel_row_end;
2347
2348         int sel_col_start = tabular->column_of_cell(sel_cell_start);
2349         int sel_col_end = tabular->column_of_cell(sel_cell_end);
2350         if (sel_col_start > sel_col_end) {
2351                 sel_col_start = sel_col_end;
2352                 sel_col_end = tabular->right_column_of_cell(sel_cell_start);
2353         } else {
2354                 sel_col_end = tabular->right_column_of_cell(sel_cell_end);
2355         }
2356         int sel_row_start = tabular->row_of_cell(sel_cell_start);
2357         int sel_row_end = tabular->row_of_cell(sel_cell_end);
2358         if (sel_row_start > sel_row_end) {
2359                 //int tmp = sel_row_start;
2360                 //sel_row_start = sel_row_end;
2361                 //sel_row_end = tmp;
2362                 swap(sel_row_start, sel_row_end);
2363         }
2364         if (sel_cell_start > sel_cell_end) {
2365                 //int tmp = sel_cell_start;
2366                 //sel_cell_start = sel_cell_end;
2367                 //sel_cell_end = tmp;
2368                 swap(sel_cell_start, sel_cell_end);
2369         }
2370         for (int i = sel_row_start; i <= sel_row_end; ++i) {
2371                 for (int j = sel_col_start; j <= sel_col_end; ++j) {
2372                         tabular->GetCellInset(tabular->GetCellNumber(i, j))->clear();
2373                 }
2374         }
2375         return true;
2376 }
2377
2378
2379 bool InsetTabular::isRightToLeft(BufferView *bv )
2380 {
2381         return bv->getParentLanguage(this)->RightToLeft();
2382 }
2383
2384
2385 bool InsetTabular::nodraw() const
2386 {
2387         if (!UpdatableInset::nodraw() && the_locking_inset)
2388                 return the_locking_inset->nodraw();
2389         return UpdatableInset::nodraw();
2390 }
2391
2392
2393 int InsetTabular::scroll(bool recursive) const
2394 {
2395         int sx = UpdatableInset::scroll(false);
2396
2397         if (recursive && the_locking_inset)
2398                 sx += the_locking_inset->scroll(recursive);
2399
2400         return sx;
2401 }
2402
2403
2404 bool InsetTabular::doClearArea() const
2405 {
2406         return !locked || (need_update & (FULL|INIT));
2407 }
2408
2409
2410 void InsetTabular::getSelection(int & srow, int & erow, int & scol, int & ecol) const
2411 {
2412                 srow = tabular->row_of_cell(sel_cell_start);
2413                 erow = tabular->row_of_cell(sel_cell_end);
2414                 if (srow > erow)
2415                         swap(srow, erow);
2416
2417                 scol = tabular->column_of_cell(sel_cell_start);
2418                 ecol = tabular->column_of_cell(sel_cell_end);
2419                 if (scol > ecol)
2420                         swap(scol, ecol);
2421                 else
2422                         ecol = tabular->right_column_of_cell(sel_cell_end);
2423 }
2424
2425 Paragraph * InsetTabular::getParFromID(int id) const
2426 {
2427         Paragraph * result;
2428         for(int i = 0; i < tabular->rows(); ++i) {
2429                 for(int j = 0; j < tabular->columns(); ++j) {
2430                         if ((result = tabular->GetCellInset(i, j)->getParFromID(id)))
2431                                 return result;
2432                 }
2433         }
2434         return 0;
2435 }
2436
2437 Paragraph * InsetTabular::firstParagraph() const
2438 {
2439         if (the_locking_inset)
2440                 return the_locking_inset->firstParagraph();
2441         return 0;
2442 }
2443
2444 LyXCursor const & InsetTabular::cursor(BufferView * bv) const
2445 {
2446         if (the_locking_inset)
2447                 return the_locking_inset->cursor(bv);
2448         return Inset::cursor(bv);
2449 }
2450
2451
2452 Inset * InsetTabular::getInsetFromID(int id_arg) const
2453 {
2454         if (id_arg == id())
2455                 return const_cast<InsetTabular *>(this);
2456
2457         Inset * result;
2458         for(int i=0; i < tabular->rows(); ++i) {
2459                 for(int j=0; j < tabular->columns(); ++j) {
2460                         if ((result = tabular->GetCellInset(i, j)->getInsetFromID(id_arg)))
2461                                 return result;
2462                 }
2463         }
2464         return 0;
2465 }
2466
2467
2468 string InsetTabular::selectNextWord(BufferView * bv, float & value) const
2469 {
2470         if (the_locking_inset) {
2471                 string str;
2472                 str = the_locking_inset->selectNextWord(bv, value);
2473                 if (!str.empty())
2474                         return str;
2475                 if (tabular->IsLastCell(actcell)) {
2476                         bv->unlockInset(const_cast<InsetTabular *>(this));
2477                         return string();
2478                 }
2479                 ++actcell;
2480         }
2481         
2482         // otherwise we have to lock the next inset and ask for it's selecttion
2483         UpdatableInset * inset =
2484                 static_cast<UpdatableInset*>(tabular->GetCellInset(actcell));
2485         inset->edit(bv, 0,  0, 0);
2486         string str = selectNextWordInt(bv, value);
2487         if (!str.empty())
2488                 resetPos(bv);
2489         return str;
2490 }
2491
2492 string InsetTabular::selectNextWordInt(BufferView * bv, float & value) const
2493 {
2494         // when entering this function the inset should be ALWAYS locked!
2495         lyx::Assert(the_locking_inset);
2496
2497         string str;
2498         str = the_locking_inset->selectNextWord(bv, value);
2499         if (!str.empty())
2500                 return str;
2501
2502         if (tabular->IsLastCell(actcell)) {
2503                 bv->unlockInset(const_cast<InsetTabular *>(this));
2504                 return string();
2505         }
2506         
2507         // otherwise we have to lock the next inset and ask for it's selecttion
2508         UpdatableInset * inset =
2509                 static_cast<UpdatableInset*>(tabular->GetCellInset(++actcell));
2510         inset->edit(bv, 0,  0, 0);
2511         return selectNextWordInt(bv, value);
2512 }
2513
2514
2515 void InsetTabular::selectSelectedWord(BufferView * bv)
2516 {
2517         if (the_locking_inset) {
2518                 the_locking_inset->selectSelectedWord(bv);
2519                 return;
2520         }
2521         return;
2522 }
2523
2524 void InsetTabular::toggleSelection(BufferView * bv, bool kill_selection)
2525 {
2526         if (the_locking_inset) {
2527                 the_locking_inset->toggleSelection(bv, kill_selection);
2528         }
2529 }
2530
2531
2532 bool InsetTabular::searchForward(BufferView * bv, string const & str,
2533                               bool const & cs, bool const & mw)
2534 {
2535         if (the_locking_inset) {
2536                 if (the_locking_inset->searchForward(bv, str, cs, mw))
2537                         return true;
2538                 if (tabular->IsLastCell(actcell)) {
2539                         bv->unlockInset(const_cast<InsetTabular *>(this));
2540                         return false;
2541                 }
2542                 ++actcell;
2543         }
2544         nodraw(true);
2545         // otherwise we have to lock the next inset and search there
2546         UpdatableInset * inset =
2547                 static_cast<UpdatableInset*>(tabular->GetCellInset(actcell));
2548         inset->edit(bv);
2549         bool res = searchForward(bv, str, cs, mw);
2550         updateLocal(bv, NONE, false);
2551         nodraw(false);
2552         bv->updateInset(const_cast<InsetTabular *>(this), false);
2553         return res;
2554 }
2555
2556 bool InsetTabular::searchBackward(BufferView * bv, string const & str,
2557                                bool const & cs, bool const & mw)
2558 {
2559         if (the_locking_inset) {
2560                 if (the_locking_inset->searchBackward(bv, str, cs, mw))
2561                         return true;
2562                 if (!actcell) { // we are already in the first cell
2563                         bv->unlockInset(const_cast<InsetTabular *>(this));
2564                         return false;
2565                 }
2566                 --actcell;
2567         }
2568         nodraw(true);
2569         // otherwise we have to lock the next inset and search there
2570         UpdatableInset * inset =
2571                 static_cast<UpdatableInset*>(tabular->GetCellInset(actcell));
2572         inset->edit(bv, false);
2573         bool res = searchBackward(bv, str, cs, mw);
2574         nodraw(false);
2575         bv->updateInset(const_cast<InsetTabular *>(this), false);
2576         return res;
2577 }