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