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