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