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