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