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