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