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