3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
8 * Full author contact details are available in file CREDITS
14 #include "insettabular.h"
15 #include "insettext.h"
18 #include "BufferView.h"
19 #include "commandtags.h"
21 #include "funcrequest.h"
24 #include "LaTeXFeatures.h"
27 #include "lyxlength.h"
30 #include "ParagraphParameters.h"
31 #include "undo_funcs.h"
32 #include "WordLangTuple.h"
34 #include "frontends/Alert.h"
35 #include "frontends/Dialogs.h"
36 #include "frontends/font_metrics.h"
37 #include "frontends/LyXView.h"
38 #include "frontends/Painter.h"
40 #include "support/LAssert.h"
41 #include "support/lstrings.h"
60 int const ADD_TO_HEIGHT = 2;
61 int const ADD_TO_TABULAR_WIDTH = 2;
64 LyXTabular * paste_tabular = 0;
67 struct TabularFeature {
68 LyXTabular::Feature action;
73 TabularFeature tabularFeature[] =
75 { LyXTabular::APPEND_ROW, "append-row" },
76 { LyXTabular::APPEND_COLUMN, "append-column" },
77 { LyXTabular::DELETE_ROW, "delete-row" },
78 { LyXTabular::DELETE_COLUMN, "delete-column" },
79 { LyXTabular::TOGGLE_LINE_TOP, "toggle-line-top" },
80 { LyXTabular::TOGGLE_LINE_BOTTOM, "toggle-line-bottom" },
81 { LyXTabular::TOGGLE_LINE_LEFT, "toggle-line-left" },
82 { LyXTabular::TOGGLE_LINE_RIGHT, "toggle-line-right" },
83 { LyXTabular::ALIGN_LEFT, "align-left" },
84 { LyXTabular::ALIGN_RIGHT, "align-right" },
85 { LyXTabular::ALIGN_CENTER, "align-center" },
86 { LyXTabular::ALIGN_BLOCK, "align-block" },
87 { LyXTabular::VALIGN_TOP, "valign-top" },
88 { LyXTabular::VALIGN_BOTTOM, "valign-bottom" },
89 { LyXTabular::VALIGN_CENTER, "valign-center" },
90 { LyXTabular::M_TOGGLE_LINE_TOP, "m-toggle-line-top" },
91 { LyXTabular::M_TOGGLE_LINE_BOTTOM, "m-toggle-line-bottom" },
92 { LyXTabular::M_TOGGLE_LINE_LEFT, "m-toggle-line-left" },
93 { LyXTabular::M_TOGGLE_LINE_RIGHT, "m-toggle-line-right" },
94 { LyXTabular::M_ALIGN_LEFT, "m-align-left" },
95 { LyXTabular::M_ALIGN_RIGHT, "m-align-right" },
96 { LyXTabular::M_ALIGN_CENTER, "m-align-center" },
97 { LyXTabular::M_VALIGN_TOP, "m-valign-top" },
98 { LyXTabular::M_VALIGN_BOTTOM, "m-valign-bottom" },
99 { LyXTabular::M_VALIGN_CENTER, "m-valign-center" },
100 { LyXTabular::MULTICOLUMN, "multicolumn" },
101 { LyXTabular::SET_ALL_LINES, "set-all-lines" },
102 { LyXTabular::UNSET_ALL_LINES, "unset-all-lines" },
103 { LyXTabular::SET_LONGTABULAR, "set-longtabular" },
104 { LyXTabular::UNSET_LONGTABULAR, "unset-longtabular" },
105 { LyXTabular::SET_PWIDTH, "set-pwidth" },
106 { LyXTabular::SET_MPWIDTH, "set-mpwidth" },
107 { LyXTabular::SET_ROTATE_TABULAR, "set-rotate-tabular" },
108 { LyXTabular::UNSET_ROTATE_TABULAR, "unset-rotate-tabular" },
109 { LyXTabular::SET_ROTATE_CELL, "set-rotate-cell" },
110 { LyXTabular::UNSET_ROTATE_CELL, "unset-rotate-cell" },
111 { LyXTabular::SET_USEBOX, "set-usebox" },
112 { LyXTabular::SET_LTHEAD, "set-lthead" },
113 { LyXTabular::SET_LTFIRSTHEAD, "set-ltfirsthead" },
114 { LyXTabular::SET_LTFOOT, "set-ltfoot" },
115 { LyXTabular::SET_LTLASTFOOT, "set-ltlastfoot" },
116 { LyXTabular::SET_LTNEWPAGE, "set-ltnewpage" },
117 { LyXTabular::SET_SPECIAL_COLUMN, "set-special-column" },
118 { LyXTabular::SET_SPECIAL_MULTI, "set-special-multi" },
119 { LyXTabular::LAST_ACTION, "" }
123 FindFeature(LyXTabular::Feature feature) : feature_(feature) {}
124 bool operator()(TabularFeature & tf)
126 return tf.action == feature_;
129 LyXTabular::Feature feature_;
135 string const featureAsString(LyXTabular::Feature feature)
137 TabularFeature * it = tabularFeature;
138 TabularFeature * end = it +
139 sizeof(tabularFeature) / sizeof(TabularFeature);
140 it = std::find_if(it, end, FindFeature(feature));
141 return (it == end) ? string() : it->feature;
145 bool InsetTabular::hasPasteBuffer() const
147 return (paste_tabular != 0);
151 InsetTabular::InsetTabular(Buffer const & buf, int rows, int columns)
158 tabular.reset(new LyXTabular(buf.params, this, rows, columns));
159 // for now make it always display as display() inset
161 the_locking_inset = 0;
162 old_locking_inset = 0;
165 actrow = actcell = 0;
175 InsetTabular::InsetTabular(InsetTabular const & tab, Buffer const & buf,
177 : UpdatableInset(tab, same_id), buffer(&buf)
179 tabular.reset(new LyXTabular(buf.params,
180 this, *(tab.tabular), same_id));
181 the_locking_inset = 0;
182 old_locking_inset = 0;
185 actrow = actcell = 0;
195 InsetTabular::~InsetTabular()
197 InsetTabularMailer mailer(*this);
202 Inset * InsetTabular::clone(Buffer const & buf, bool same_id) const
204 return new InsetTabular(*this, buf, same_id);
208 BufferView * InsetTabular::view() const
210 return buffer->getUser();
214 void InsetTabular::write(Buffer const * buf, ostream & os) const
216 os << " Tabular" << endl;
217 tabular->Write(buf, os);
221 void InsetTabular::read(Buffer const * buf, LyXLex & lex)
223 bool const old_format = (lex.getString() == "\\LyXTable");
225 tabular.reset(new LyXTabular(buf, this, lex));
233 string token = lex.getString();
234 while (lex.isOK() && (token != "\\end_inset")) {
236 token = lex.getString();
238 if (token != "\\end_inset") {
239 lex.printError("Missing \\end_inset at this point. "
245 int InsetTabular::ascent(BufferView *, LyXFont const &) const
247 return tabular->GetAscentOfRow(0);
251 int InsetTabular::descent(BufferView *, LyXFont const &) const
253 return tabular->GetHeightOfTabular() - tabular->GetAscentOfRow(0) + 1;
257 int InsetTabular::width(BufferView *, LyXFont const &) const
259 return tabular->GetWidthOfTabular() + (2 * ADD_TO_TABULAR_WIDTH);
263 void InsetTabular::draw(BufferView * bv, LyXFont const & font, int baseline,
264 float & x, bool cleared) const
272 if (need_update == INIT) {
273 if (calculate_dimensions_of_cells(bv, font, true))
274 bv->text->status = LyXText::CHANGED_IN_DRAW;
279 Painter & pain = bv->painter();
285 UpdatableInset::draw(bv, font, baseline, x, cleared);
288 x += static_cast<float>(scroll());
290 if (!cleared && ((need_update == INIT) || (need_update == FULL) ||
291 (top_x != int(x)) || (top_baseline != baseline)))
293 int h = ascent(bv, font) + descent(bv, font);
294 int const tx = display() || !owner() ? 0 : top_x;
295 int w = tx ? width(bv, font) : pain.paperWidth();
296 int ty = baseline - ascent(bv, font);
300 if ((ty + h) > pain.paperHeight())
301 h = pain.paperHeight();
302 if ((top_x + w) > pain.paperWidth())
303 w = pain.paperWidth();
304 pain.fillRectangle(tx, ty, w, h, backgroundColor());
310 top_baseline = baseline;
311 x += ADD_TO_TABULAR_WIDTH;
315 first_visible_cell = -1;
316 for (i = 0; i < tabular->rows(); ++i) {
318 cell = tabular->GetCellNumber(i, 0);
319 if (!((baseline + tabular->GetDescentOfRow(i)) > 0) &&
320 (baseline - tabular->GetAscentOfRow(i))<pain.paperHeight())
322 baseline += tabular->GetDescentOfRow(i) +
323 tabular->GetAscentOfRow(i + 1) +
324 tabular->GetAdditionalHeight(i + 1);
327 for (j = 0; j < tabular->columns(); ++j) {
328 if (nx > bv->workWidth())
330 if (tabular->IsPartOfMultiColumn(i, j))
332 cx = nx + tabular->GetBeginningOfTextInCell(cell);
333 if (first_visible_cell < 0)
334 first_visible_cell = cell;
335 if (hasSelection()) {
336 drawCellSelection(pain, nx, baseline, i, j, cell);
339 tabular->GetCellInset(cell)->draw(bv, font, baseline, cx, cleared);
340 drawCellLines(pain, nx, baseline, i, cell);
341 nx += tabular->GetWidthOfColumn(cell);
344 baseline += tabular->GetDescentOfRow(i) +
345 tabular->GetAscentOfRow(i + 1) +
346 tabular->GetAdditionalHeight(i + 1);
348 } else if (need_update == CELL) {
351 if (the_locking_inset &&
352 tabular->GetCellInset(actcell) != the_locking_inset)
354 Inset * inset = tabular->GetCellInset(cell);
356 inset != the_locking_inset && i < tabular->rows();
360 inset != the_locking_inset && j < tabular->columns();
363 if (tabular->IsPartOfMultiColumn(i, j))
365 nx += tabular->GetWidthOfColumn(cell);
367 inset = tabular->GetCellInset(cell);
369 if (tabular->row_of_cell(cell) > i) {
371 baseline += tabular->GetDescentOfRow(i) +
372 tabular->GetAscentOfRow(i + 1) +
373 tabular->GetAdditionalHeight(i + 1);
377 // compute baseline for actual row
378 for (i = 0; i < actrow; ++i) {
379 baseline += tabular->GetDescentOfRow(i) +
380 tabular->GetAscentOfRow(i + 1) +
381 tabular->GetAdditionalHeight(i + 1);
383 // now compute the right x position
384 cell = tabular->GetCellNumber(actrow, 0);
385 for (j = 0; (cell < actcell) && (j < tabular->columns()); ++j) {
386 if (tabular->IsPartOfMultiColumn(actrow, j))
388 nx += tabular->GetWidthOfColumn(cell);
392 i = tabular->row_of_cell(cell);
393 if (the_locking_inset != tabular->GetCellInset(cell)) {
394 lyxerr[Debug::INSETTEXT] << "ERROR this shouldn't happen\n";
397 float dx = nx + tabular->GetBeginningOfTextInCell(cell);
399 tabular->GetCellInset(cell)->draw(bv, font, baseline, dx, false);
401 // Here we use rectangular backgroundColor patches to clean up
402 // within a cell around the cell's red inset box. As follows:
404 // +--------------------+
405 // | C | The rectangles are A, B and C
406 // | A |------------| B | below, origin top left (tx, ty),
407 // | | inset box | | dimensions w(idth), h(eight).
408 // +---+------------+---+ x grows rightward, y downward
410 // +--------------------+
413 // clear only if we didn't have a change
414 if (bv->text->status() != LyXText::CHANGED_IN_DRAW) {
416 // clear before the inset
419 ty = baseline - tabular->GetAscentOfRow(i) + 1;
420 w = int(cx - nx - 1);
421 h = tabular->GetAscentOfRow(i) +
422 tabular->GetDescentOfRow(i) - 1;
423 pain.fillRectangle(tx, ty, w, h, backgroundColor());
424 // clear behind the inset
425 tx = int(cx + the_locking_inset->width(bv,font) + 1);
426 ty = baseline - tabular->GetAscentOfRow(i) + 1;
427 w = tabular->GetWidthOfColumn(cell) -
428 tabular->GetBeginningOfTextInCell(cell) -
429 the_locking_inset->width(bv,font) -
430 tabular->GetAdditionalWidth(cell) - 1;
431 h = tabular->GetAscentOfRow(i) + tabular->GetDescentOfRow(i) - 1;
432 pain.fillRectangle(tx, ty, w, h, backgroundColor());
433 // clear below the inset
435 ty = baseline + the_locking_inset->descent(bv, font) + 1;
436 w = tabular->GetWidthOfColumn(cell) -
437 tabular->GetAdditionalWidth(cell) - 1;
438 h = tabular->GetDescentOfRow(i) -
439 the_locking_inset->descent(bv, font) - 1;
440 pain.fillRectangle(tx, ty, w, h, backgroundColor());
441 // clear above the inset
443 ty = baseline - tabular->GetAscentOfRow(i) + 1;
444 w = tabular->GetWidthOfColumn(cell) -
445 tabular->GetAdditionalWidth(cell) - 1;
446 h = tabular->GetAscentOfRow(i) - the_locking_inset->ascent(bv, font);
447 pain.fillRectangle(tx, ty, w, h, backgroundColor());
452 x -= ADD_TO_TABULAR_WIDTH;
453 x += width(bv, font);
454 if (bv->text->status() == LyXText::CHANGED_IN_DRAW) {
456 for(Inset * inset = owner(); inset; ++i)
457 inset = inset->owner();
458 if (calculate_dimensions_of_cells(bv, font, false))
466 void InsetTabular::drawCellLines(Painter & pain, int x, int baseline,
467 int row, int cell) const
469 int x2 = x + tabular->GetWidthOfColumn(cell);
472 if (!tabular->topAlreadyDrawn(cell)) {
473 on_off = !tabular->TopLine(cell);
474 pain.line(x, baseline - tabular->GetAscentOfRow(row),
475 x2, baseline - tabular->GetAscentOfRow(row),
476 on_off ? LColor::tabularonoffline : LColor::tabularline,
477 on_off ? Painter::line_onoffdash : Painter::line_solid);
479 on_off = !tabular->BottomLine(cell);
480 pain.line(x, baseline + tabular->GetDescentOfRow(row),
481 x2, baseline + tabular->GetDescentOfRow(row),
482 on_off ? LColor::tabularonoffline : LColor::tabularline,
483 on_off ? Painter::line_onoffdash : Painter::line_solid);
484 if (!tabular->leftAlreadyDrawn(cell)) {
485 on_off = !tabular->LeftLine(cell);
486 pain.line(x, baseline - tabular->GetAscentOfRow(row),
487 x, baseline + tabular->GetDescentOfRow(row),
488 on_off ? LColor::tabularonoffline : LColor::tabularline,
489 on_off ? Painter::line_onoffdash : Painter::line_solid);
491 on_off = !tabular->RightLine(cell);
492 pain.line(x2 - tabular->GetAdditionalWidth(cell),
493 baseline - tabular->GetAscentOfRow(row),
494 x2 - tabular->GetAdditionalWidth(cell),
495 baseline + tabular->GetDescentOfRow(row),
496 on_off ? LColor::tabularonoffline : LColor::tabularline,
497 on_off ? Painter::line_onoffdash : Painter::line_solid);
501 void InsetTabular::drawCellSelection(Painter & pain, int x, int baseline,
502 int row, int column, int cell) const
504 lyx::Assert(hasSelection());
505 int cs = tabular->column_of_cell(sel_cell_start);
506 int ce = tabular->column_of_cell(sel_cell_end);
509 cs = tabular->column_of_cell(sel_cell_end);
511 ce = tabular->right_column_of_cell(sel_cell_end);
514 int rs = tabular->row_of_cell(sel_cell_start);
515 int re = tabular->row_of_cell(sel_cell_end);
519 if ((column >= cs) && (column <= ce) && (row >= rs) && (row <= re)) {
520 int w = tabular->GetWidthOfColumn(cell);
521 int h = tabular->GetAscentOfRow(row) + tabular->GetDescentOfRow(row)-1;
522 pain.fillRectangle(x, baseline - tabular->GetAscentOfRow(row) + 1,
523 w, h, LColor::selection);
528 void InsetTabular::update(BufferView * bv, LyXFont const & font, bool reinit)
534 owner()->update(bv, font, true);
541 if (calculate_dimensions_of_cells(bv, font, true))
544 owner()->update(bv, font, true);
548 if (the_locking_inset)
549 the_locking_inset->update(bv, font, reinit);
550 if (need_update < FULL &&
551 bv->text->status() == LyXText::NEED_MORE_REFRESH)
556 switch (need_update) {
560 if (calculate_dimensions_of_cells(bv, font, false)) {
575 string const InsetTabular::editMessage() const
577 return _("Opened Tabular Inset");
581 void InsetTabular::edit(BufferView * bv, int x, int y, mouse_button::state button)
583 UpdatableInset::edit(bv, x, y, button);
585 if (!bv->lockInset(this)) {
586 lyxerr[Debug::INSETTEXT] << "InsetTabular::Cannot lock inset" << endl;
590 the_locking_inset = 0;
596 if (insetHit(bv, x, y) && (button != mouse_button::button3)) {
597 activateCellInsetAbs(bv, x, y, button);
602 void InsetTabular::edit(BufferView * bv, bool front)
604 UpdatableInset::edit(bv, front);
606 if (!bv->lockInset(this)) {
607 lyxerr[Debug::INSETTEXT] << "InsetTabular::Cannot lock inset" << endl;
612 the_locking_inset = 0;
616 if (isRightToLeft(bv))
617 actcell = tabular->GetLastCellInRow(0);
621 if (isRightToLeft(bv))
622 actcell = tabular->GetFirstCellInRow(tabular->rows()-1);
624 actcell = tabular->GetNumberOfCells() - 1;
632 void InsetTabular::insetUnlock(BufferView * bv)
634 if (the_locking_inset) {
635 the_locking_inset->insetUnlock(bv);
636 updateLocal(bv, CELL, false);
637 the_locking_inset = 0;
643 if (scroll(false) || hasSelection()) {
648 updateLocal(bv, FULL, false);
653 void InsetTabular::updateLocal(BufferView * bv, UpdateCodes what,
654 bool mark_dirty) const
658 calculate_dimensions_of_cells(bv, font, true);
660 if (!locked && what == CELL)
662 if (need_update < what) // only set this if it has greater update
665 if (need_update != NONE) {
666 bv->updateInset(const_cast<InsetTabular *>(this), mark_dirty);
673 bool InsetTabular::lockInsetInInset(BufferView * bv, UpdatableInset * inset)
675 lyxerr[Debug::INSETTEXT] << "InsetTabular::LockInsetInInset("
680 if (inset == tabular->GetCellInset(actcell)) {
681 lyxerr[Debug::INSETTEXT] << "OK" << endl;
682 the_locking_inset = tabular->GetCellInset(actcell);
685 } else if (!the_locking_inset) {
686 int const n = tabular->GetNumberOfCells();
687 int const id = inset->id();
688 for (int i = 0; i < n; ++i) {
689 InsetText * in = tabular->GetCellInset(i);
692 the_locking_inset = in;
697 if (in->getInsetFromID(id)) {
700 return the_locking_inset->lockInsetInInset(bv, inset);
703 } else if (the_locking_inset && (the_locking_inset == inset)) {
704 lyxerr[Debug::INSETTEXT] << "OK" << endl;
706 } else if (the_locking_inset) {
707 lyxerr[Debug::INSETTEXT] << "MAYBE" << endl;
708 return the_locking_inset->lockInsetInInset(bv, inset);
710 lyxerr[Debug::INSETTEXT] << "NOT OK" << endl;
715 bool InsetTabular::unlockInsetInInset(BufferView * bv, UpdatableInset * inset,
718 if (!the_locking_inset)
720 if (the_locking_inset == inset) {
721 the_locking_inset->insetUnlock(bv);
723 #warning fix scrolling when cellinset has requested a scroll (Jug)!!!
729 updateLocal(bv, CELL, false);
730 // this has to be here otherwise we don't redraw the cell!
731 the_locking_inset = 0;
732 // showInsetCursor(bv, false);
735 if (the_locking_inset->unlockInsetInInset(bv, inset, lr)) {
736 if (inset->lyxCode() == TABULAR_CODE &&
737 !the_locking_inset->getFirstLockingInsetOfType(TABULAR_CODE)) {
738 InsetTabularMailer mailer(*this);
739 mailer.updateDialog(bv);
748 bool InsetTabular::updateInsetInInset(BufferView * bv, Inset * inset)
750 Inset * tl_inset = inset;
751 // look if this inset is really inside myself!
752 while(tl_inset->owner() && tl_inset->owner() != this)
753 tl_inset = tl_inset->owner();
754 // if we enter here it's not ower inset
755 if (!tl_inset->owner())
757 // we only have to do this if this is a subinset of our cells
758 if (tl_inset != inset) {
759 if (!static_cast<InsetText *>(tl_inset)->updateInsetInInset(bv, inset))
762 updateLocal(bv, CELL, false);
767 int InsetTabular::insetInInsetY() const
769 if (!the_locking_inset)
771 return inset_y + the_locking_inset->insetInInsetY();
775 UpdatableInset * InsetTabular::getLockingInset() const
777 return the_locking_inset ? the_locking_inset->getLockingInset() :
778 const_cast<InsetTabular *>(this);
782 UpdatableInset * InsetTabular::getFirstLockingInsetOfType(Inset::Code c)
786 if (the_locking_inset)
787 return the_locking_inset->getFirstLockingInsetOfType(c);
792 bool InsetTabular::insertInset(BufferView * bv, Inset * inset)
794 if (the_locking_inset)
795 return the_locking_inset->insertInset(bv, inset);
800 void InsetTabular::lfunMousePress(FuncRequest const & cmd)
802 if (hasSelection() && cmd.button() == mouse_button::button3)
805 if (hasSelection()) {
807 updateLocal(cmd.view(), SELECTION, false);
810 int const ocell = actcell;
811 int const orow = actrow;
812 BufferView * bv = cmd.view();
817 the_locking_inset = 0;
821 setPos(bv, cmd.x, cmd.y);
823 updateLocal(bv, NONE, false);
826 if (cmd.button() == mouse_button::button3) {
827 if ((ocell != actcell) && the_locking_inset) {
828 the_locking_inset->insetUnlock(bv);
829 updateLocal(bv, CELL, false);
830 the_locking_inset = 0;
837 bool const inset_hit = insetHit(bv, cmd.x, cmd.y);
839 if ((ocell == actcell) && the_locking_inset && inset_hit) {
841 FuncRequest cmd1 = cmd;
844 the_locking_inset->localDispatch(cmd1);
848 if (the_locking_inset) {
849 the_locking_inset->insetUnlock(bv);
850 updateLocal(bv, CELL, false);
851 the_locking_inset = 0;
854 if (cmd.button() == mouse_button::button2) {
855 localDispatch(FuncRequest(bv, LFUN_PASTESELECTION, "paragraph"));
859 if (inset_hit && bv->theLockingInset()) {
860 if (!bv->lockInset(static_cast<UpdatableInset*>
861 (tabular->GetCellInset(actcell))))
863 lyxerr[Debug::INSETS] << "Cannot lock inset" << endl;
866 FuncRequest cmd1 = cmd;
869 the_locking_inset->localDispatch(cmd1);
876 bool InsetTabular::lfunMouseRelease(FuncRequest const & cmd)
879 if (the_locking_inset) {
880 FuncRequest cmd1 = cmd;
883 ret = the_locking_inset->localDispatch(cmd1);
885 if (cmd.button() == mouse_button::button3 && !ret) {
886 InsetTabularMailer mailer(*this);
887 mailer.showDialog(cmd.view());
894 void InsetTabular::lfunMouseMotion(FuncRequest const & cmd)
896 if (the_locking_inset) {
897 FuncRequest cmd1 = cmd;
900 the_locking_inset->localDispatch(cmd1);
904 BufferView * bv = cmd.view();
906 int const old_cell = actcell;
908 setPos(bv, cmd.x, cmd.y);
909 if (!hasSelection()) {
910 setSelection(actcell, actcell);
911 updateLocal(bv, SELECTION, false);
912 } else if (old_cell != actcell) {
913 setSelection(sel_cell_start, actcell);
914 updateLocal(bv, SELECTION, false);
920 Inset::RESULT InsetTabular::localDispatch(FuncRequest const & cmd)
922 // We need to save the value of the_locking_inset as the call to
923 // the_locking_inset->localDispatch might unlock it.
924 old_locking_inset = the_locking_inset;
925 RESULT result = UpdatableInset::localDispatch(cmd);
927 BufferView * bv = cmd.view();
928 if (result == DISPATCHED || result == DISPATCHED_NOUPDATE) {
933 if (cmd.action < 0 && cmd.argument.empty())
936 bool hs = hasSelection();
939 // this one have priority over the locked InsetText, if we're not already
940 // inside another tabular then that one get's priority!
941 if (getFirstLockingInsetOfType(Inset::TABULAR_CODE) == this) {
942 switch (cmd.action) {
943 case LFUN_MOUSE_PRESS:
947 case LFUN_MOUSE_MOTION:
948 lfunMouseMotion(cmd);
951 case LFUN_MOUSE_RELEASE:
952 return lfunMouseRelease(cmd) ? DISPATCHED : UNDISPATCHED;
957 unlockInsetInInset(bv, the_locking_inset);
958 if (cmd.action == LFUN_TAB)
959 moveNextCell(bv, old_locking_inset != 0);
961 movePrevCell(bv, old_locking_inset != 0);
964 updateLocal(bv, SELECTION, false);
965 if (!the_locking_inset) {
967 return DISPATCHED_NOUPDATE;
970 // this to avoid compiler warnings.
976 kb_action action = cmd.action;
977 string arg = cmd.argument;
978 if (the_locking_inset) {
979 result = the_locking_inset->localDispatch(cmd);
980 if (result == DISPATCHED_NOUPDATE) {
983 if (sc != scroll()) { // inset has been scrolled
984 the_locking_inset->toggleInsetCursor(bv);
985 updateLocal(bv, FULL, false);
986 the_locking_inset->toggleInsetCursor(bv);
989 } else if (result == DISPATCHED) {
990 the_locking_inset->toggleInsetCursor(bv);
991 updateLocal(bv, CELL, false);
992 the_locking_inset->toggleInsetCursor(bv);
994 } else if (result == FINISHED_UP) {
996 } else if (result == FINISHED_DOWN) {
998 } else if (result == FINISHED_RIGHT) {
1003 hideInsetCursor(bv);
1004 result = DISPATCHED;
1006 // --- Cursor Movements ----------------------------------
1007 case LFUN_RIGHTSEL: {
1008 int const start = hasSelection() ? sel_cell_start : actcell;
1009 if (tabular->IsLastCellInRow(actcell)) {
1010 setSelection(start, actcell);
1015 // if we are starting a selection, only select
1016 // the current cell at the beginning
1017 if (hasSelection()) {
1018 moveRight(bv, false);
1021 setSelection(start, end);
1022 updateLocal(bv, SELECTION, false);
1026 result = moveRight(bv);
1029 updateLocal(bv, SELECTION, false);
1031 case LFUN_LEFTSEL: {
1032 int const start = hasSelection() ? sel_cell_start : actcell;
1033 if (tabular->IsFirstCellInRow(actcell)) {
1034 setSelection(start, actcell);
1039 // if we are starting a selection, only select
1040 // the current cell at the beginning
1041 if (hasSelection()) {
1042 moveLeft(bv, false);
1045 setSelection(start, end);
1046 updateLocal(bv, SELECTION, false);
1050 result = moveLeft(bv);
1053 updateLocal(bv, SELECTION, false);
1055 case LFUN_DOWNSEL: {
1056 int const start = hasSelection() ? sel_cell_start : actcell;
1057 int const ocell = actcell;
1058 // if we are starting a selection, only select
1059 // the current cell at the beginning
1060 if (hasSelection()) {
1061 moveDown(bv, false);
1062 if ((ocell == sel_cell_end) ||
1063 (tabular->column_of_cell(ocell)>tabular->column_of_cell(actcell)))
1064 setSelection(start, tabular->GetCellBelow(sel_cell_end));
1066 setSelection(start, tabular->GetLastCellBelow(sel_cell_end));
1068 setSelection(start, start);
1070 updateLocal(bv, SELECTION, false);
1074 result = moveDown(bv, old_locking_inset != 0);
1077 updateLocal(bv, SELECTION, false);
1081 int const start = hasSelection() ? sel_cell_start : actcell;
1082 int const ocell = actcell;
1083 // if we are starting a selection, only select
1084 // the current cell at the beginning
1085 if (hasSelection()) {
1087 if ((ocell == sel_cell_end) ||
1088 (tabular->column_of_cell(ocell)>tabular->column_of_cell(actcell)))
1089 setSelection(start, tabular->GetCellAbove(sel_cell_end));
1091 setSelection(start, tabular->GetLastCellAbove(sel_cell_end));
1093 setSelection(start, start);
1095 updateLocal(bv, SELECTION, false);
1099 result = moveUp(bv, old_locking_inset != 0);
1102 updateLocal(bv, SELECTION, false);
1105 UpdateCodes code = CURSOR;
1110 int column = actcol;
1111 unlockInsetInInset(bv, the_locking_inset);
1112 if (bv->text->top_y() + bv->painter().paperHeight() <
1113 (top_baseline + tabular->GetHeightOfTabular()))
1115 bv->scrollDocView(bv->text->top_y() + bv->painter().paperHeight());
1117 actcell = tabular->GetCellBelow(first_visible_cell) + column;
1119 actcell = tabular->GetFirstCellInRow(tabular->rows() - 1) + column;
1122 updateLocal(bv, code, false);
1126 UpdateCodes code = CURSOR;
1131 int column = actcol;
1132 unlockInsetInInset(bv, the_locking_inset);
1133 if (top_baseline < 0) {
1134 bv->scrollDocView(bv->text->top_y() - bv->painter().paperHeight());
1136 if (top_baseline > 0)
1139 actcell = tabular->GetCellBelow(first_visible_cell) + column;
1144 updateLocal(bv, code, false);
1147 // none of these make sense for insettabular,
1148 // but we must catch them to prevent any
1149 // selection from being confused
1153 case LFUN_WORDLEFTSEL:
1154 case LFUN_WORDRIGHT:
1155 case LFUN_WORDRIGHTSEL:
1157 case LFUN_DOWN_PARAGRAPH:
1158 case LFUN_DOWN_PARAGRAPHSEL:
1159 case LFUN_UP_PARAGRAPH:
1160 case LFUN_UP_PARAGRAPHSEL:
1161 case LFUN_BACKSPACE:
1166 case LFUN_BEGINNINGBUF:
1167 case LFUN_BEGINNINGBUFSEL:
1169 case LFUN_ENDBUFSEL:
1171 case LFUN_LAYOUT_TABULAR: {
1172 InsetTabularMailer mailer(*this);
1173 mailer.showDialog(bv);
1176 case LFUN_INSET_DIALOG_UPDATE: {
1177 InsetTabularMailer mailer(*this);
1178 mailer.updateDialog(bv);
1181 case LFUN_TABULAR_FEATURE:
1182 if (!tabularFeatures(bv, arg))
1183 result = UNDISPATCHED;
1185 // insert file functions
1186 case LFUN_FILE_INSERT_ASCII_PARA:
1187 case LFUN_FILE_INSERT_ASCII:
1189 string tmpstr = getContentsOfAsciiFile(bv, arg, false);
1192 if (insertAsciiString(bv, tmpstr, false))
1193 updateLocal(bv, INIT, true);
1195 result = UNDISPATCHED;
1198 // cut and paste functions
1200 if (!copySelection(bv))
1204 setUndo(bv, Undo::DELETE,
1205 bv->text->cursor.par(),
1206 bv->text->cursor.par()->next());
1207 cutSelection(bv->buffer()->params);
1208 updateLocal(bv, INIT, true);
1211 if (!hasSelection())
1216 case LFUN_PASTESELECTION:
1218 string const clip(bv->getClipboard());
1222 if (clip.find('\t') != string::npos) {
1226 string::size_type len = clip.length();
1227 string::size_type p = 0;
1230 ((p = clip.find_first_of("\t\n", p)) != string::npos)) {
1238 maxCols = max(cols, maxCols);
1244 maxCols = max(cols, maxCols);
1245 delete paste_tabular;
1246 paste_tabular = new LyXTabular(bv->buffer()->params,
1247 this, rows, maxCols);
1248 string::size_type op = 0;
1250 int cells = paste_tabular->GetNumberOfCells();
1252 while ((cell < cells) && (p < len) &&
1253 (p = clip.find_first_of("\t\n", p)) != string::npos) {
1258 paste_tabular->GetCellInset(cell)->setText(clip.substr(op, p-op));
1263 paste_tabular->GetCellInset(cell)->setText(clip.substr(op, p-op));
1264 while (cols++ < maxCols)
1272 // check for the last cell if there is no trailing '\n'
1273 if ((cell < cells) && (op < len))
1274 paste_tabular->GetCellInset(cell)->setText(clip.substr(op, len-op));
1277 if (!insertAsciiString(bv, clip, true))
1280 // so that the clipboard is used and it goes on
1282 // and executes LFUN_PASTESELECTION in insettext!
1283 delete paste_tabular;
1288 if (hasPasteBuffer()) {
1289 setUndo(bv, Undo::INSERT,
1290 bv->text->cursor.par(),
1291 bv->text->cursor.par()->next());
1293 updateLocal(bv, INIT, true);
1296 // ATTENTION: the function above has to be PASTE and PASTESELECTION!!!
1298 // handle font changing stuff on selection before we lock the inset
1299 // in the default part!
1300 result = UNDISPATCHED;
1311 case LFUN_UNDERLINE:
1312 case LFUN_FONT_SIZE:
1313 if (bv->dispatch(FuncRequest(bv, action, arg)))
1314 result = DISPATCHED;
1320 // we try to activate the actual inset and put this event down to
1321 // the insets dispatch function.
1322 if ((result == DISPATCHED) || the_locking_inset)
1325 if (activateCellInset(bv)) {
1326 // reset need_update setted in above function!
1328 result = the_locking_inset->localDispatch(FuncRequest(bv, action, arg));
1329 if ((result == UNDISPATCHED) || (result >= FINISHED)) {
1330 unlockInsetInInset(bv, the_locking_inset);
1332 // we need to update if this was requested before
1333 updateLocal(bv, NONE, false);
1334 return UNDISPATCHED;
1337 // so the below CELL is not set because this is higher
1338 // priority and we get a full redraw
1339 need_update = SELECTION;
1342 updateLocal(bv, CELL, false);
1347 if (result < FINISHED) {
1348 if (!the_locking_inset) {
1349 if (bv->fitCursor())
1350 updateLocal(bv, FULL, false);
1352 showInsetCursor(bv);
1355 bv->unlockInset(this);
1360 int InsetTabular::latex(Buffer const * buf, ostream & os,
1361 bool fragile, bool fp) const
1363 return tabular->latex(buf, os, fragile, fp);
1367 int InsetTabular::ascii(Buffer const * buf, ostream & os, int ll) const
1370 return tabular->ascii(buf, os, (int)parOwner()->params().depth(),
1372 return tabular->ascii(buf, os, 0, false,0);
1376 int InsetTabular::linuxdoc(Buffer const * buf, ostream & os) const
1379 int const ret = tabular->ascii(buf,os,
1380 (int)parOwner()->params().depth(),
1387 int InsetTabular::docbook(Buffer const * buf, ostream & os, bool mixcont) const
1392 // if the table is inside a float it doesn't need the informaltable
1393 // wrapper. Search for it.
1394 for(master = owner();
1395 master && master->lyxCode() != Inset::FLOAT_CODE;
1396 master = master->owner());
1399 os << "<informaltable>";
1404 ret+= tabular->docbook(buf, os, mixcont);
1406 os << "</informaltable>";
1415 void InsetTabular::validate(LaTeXFeatures & features) const
1417 tabular->Validate(features);
1421 bool InsetTabular::calculate_dimensions_of_cells(BufferView * bv,
1422 LyXFont const & font,
1429 bool changed = false;
1431 // if we have a locking_inset we should have to check only this cell for
1432 // change so I'll try this to have a boost, but who knows ;)
1433 if ((need_update != INIT) &&
1434 (the_locking_inset == tabular->GetCellInset(actcell))) {
1435 for(int i = 0; i < tabular->columns(); ++i) {
1436 maxAsc = max(tabular->GetCellInset(actrow, i)->ascent(bv, font),
1438 maxDesc = max(tabular->GetCellInset(actrow, i)->descent(bv, font),
1441 changed = tabular->SetWidthOfCell(actcell, the_locking_inset->width(bv, font));
1442 changed = tabular->SetAscentOfRow(actrow, maxAsc + ADD_TO_HEIGHT) || changed;
1443 changed = tabular->SetDescentOfRow(actrow, maxDesc + ADD_TO_HEIGHT) || changed;
1446 for (int i = 0; i < tabular->rows(); ++i) {
1449 for (int j = 0; j < tabular->columns(); ++j) {
1450 if (tabular->IsPartOfMultiColumn(i,j))
1453 inset = tabular->GetCellInset(cell);
1454 if (!reinit && !tabular->GetPWidth(cell).zero())
1455 inset->update(bv, font, false);
1456 maxAsc = max(maxAsc, inset->ascent(bv, font));
1457 maxDesc = max(maxDesc, inset->descent(bv, font));
1458 changed = tabular->SetWidthOfCell(cell, inset->width(bv, font)) || changed;
1460 changed = tabular->SetAscentOfRow(i, maxAsc + ADD_TO_HEIGHT) || changed;
1461 changed = tabular->SetDescentOfRow(i, maxDesc + ADD_TO_HEIGHT) || changed;
1469 void InsetTabular::getCursorPos(BufferView * bv, int & x, int & y) const
1471 if (the_locking_inset) {
1472 the_locking_inset->getCursorPos(bv, x, y);
1475 x = cursor_.x() - top_x;
1480 void InsetTabular::toggleInsetCursor(BufferView * bv)
1483 if (isCursorVisible())
1484 bv->hideLockedInsetCursor();
1487 if (the_locking_inset) {
1488 the_locking_inset->toggleInsetCursor(bv);
1492 LyXFont font; // = the_locking_inset->GetFont(par, cursor.pos);
1494 int const asc = font_metrics::maxAscent(font);
1495 int const desc = font_metrics::maxDescent(font);
1497 if (isCursorVisible())
1498 bv->hideLockedInsetCursor();
1500 bv->showLockedInsetCursor(cursor_.x(), cursor_.y(), asc, desc);
1501 toggleCursorVisible();
1505 void InsetTabular::showInsetCursor(BufferView * bv, bool show)
1509 if (!isCursorVisible()) {
1510 LyXFont font; // = GetFont(par, cursor.pos);
1512 int const asc = font_metrics::maxAscent(font);
1513 int const desc = font_metrics::maxDescent(font);
1514 bv->fitLockedInsetCursor(cursor_.x(), cursor_.y(), asc, desc);
1516 bv->showLockedInsetCursor(cursor_.x(), cursor_.y(), asc, desc);
1517 setCursorVisible(true);
1522 void InsetTabular::hideInsetCursor(BufferView * bv)
1524 if (isCursorVisible()) {
1525 bv->hideLockedInsetCursor();
1526 setCursorVisible(false);
1531 void InsetTabular::fitInsetCursor(BufferView * bv) const
1533 if (the_locking_inset) {
1534 int old_top_y = bv->text->top_y();
1535 the_locking_inset->fitInsetCursor(bv);
1536 if (old_top_y != bv->text->top_y())
1542 int const asc = font_metrics::maxAscent(font);
1543 int const desc = font_metrics::maxDescent(font);
1546 if (bv->fitLockedInsetCursor(cursor_.x(), cursor_.y(), asc, desc))
1551 void InsetTabular::setPos(BufferView * bv, int x, int y) const
1555 actcell = actrow = actcol = 0;
1556 int ly = tabular->GetDescentOfRow(actrow);
1558 // first search the right row
1559 while ((ly < y) && ((actrow+1) < tabular->rows())) {
1560 cursor_.y(cursor_.y() + tabular->GetDescentOfRow(actrow) +
1561 tabular->GetAscentOfRow(actrow + 1) +
1562 tabular->GetAdditionalHeight(actrow + 1));
1564 ly = cursor_.y() + tabular->GetDescentOfRow(actrow);
1566 actcell = tabular->GetCellNumber(actrow, actcol);
1568 // now search the right column
1569 int lx = tabular->GetWidthOfColumn(actcell) -
1570 tabular->GetAdditionalWidth(actcell);
1571 for (; !tabular->IsLastCellInRow(actcell) && lx < x; ++actcell) {
1572 lx += tabular->GetWidthOfColumn(actcell + 1)
1573 + tabular->GetAdditionalWidth(actcell);
1575 cursor_.x(lx - tabular->GetWidthOfColumn(actcell) + top_x + 2);
1580 int InsetTabular::getCellXPos(int cell) const
1584 for (; !tabular->IsFirstCellInRow(c); --c)
1586 int lx = tabular->GetWidthOfColumn(cell);
1587 for (; c < cell; ++c) {
1588 lx += tabular->GetWidthOfColumn(c);
1590 return (lx - tabular->GetWidthOfColumn(cell) + top_x);
1594 void InsetTabular::resetPos(BufferView * bv) const
1596 #ifdef WITH_WARNINGS
1597 #warning This should be fixed in the right manner (20011128 Jug)
1599 // fast hack to fix infinite repaintings!
1600 if (in_reset_pos > 0)
1604 actcol = tabular->column_of_cell(actcell);
1607 for (; (cell < actcell) && !tabular->IsLastRow(cell); ++cell) {
1608 if (tabular->IsLastCellInRow(cell)) {
1609 cursor_.y(cursor_.y() + tabular->GetDescentOfRow(actrow) +
1610 tabular->GetAscentOfRow(actrow + 1) +
1611 tabular->GetAdditionalHeight(actrow + 1));
1615 if (!locked || nodraw()) {
1616 if (the_locking_inset)
1617 inset_y = cursor_.y();
1620 // we need this only from here on!!!
1622 static int const offset = ADD_TO_TABULAR_WIDTH + 2;
1623 int new_x = getCellXPos(actcell);
1624 int old_x = cursor_.x();
1627 // cursor.x(getCellXPos(actcell) + offset);
1628 if ((actcol < tabular->columns() - 1) && scroll(false) &&
1629 (tabular->GetWidthOfTabular() < bv->workWidth()-20))
1632 updateLocal(bv, FULL, false);
1633 } else if (the_locking_inset &&
1634 (tabular->GetWidthOfColumn(actcell) > bv->workWidth()-20))
1636 int xx = cursor_.x() - offset + bv->text->getRealCursorX(bv);
1637 if (xx > (bv->workWidth()-20)) {
1638 scroll(bv, -(xx - bv->workWidth() + 60));
1639 updateLocal(bv, FULL, false);
1640 } else if (xx < 20) {
1646 updateLocal(bv, FULL, false);
1648 } else if ((cursor_.x() - offset) > 20 &&
1649 (cursor_.x() - offset + tabular->GetWidthOfColumn(actcell))
1650 > (bv->workWidth() - 20)) {
1651 scroll(bv, -tabular->GetWidthOfColumn(actcell) - 20);
1652 updateLocal(bv, FULL, false);
1653 } else if ((cursor_.x() - offset) < 20) {
1654 scroll(bv, 20 - cursor_.x() + offset);
1655 updateLocal(bv, FULL, false);
1656 } else if (scroll() && top_x > 20 &&
1657 (top_x + tabular->GetWidthOfTabular()) > (bv->workWidth() - 20)) {
1658 scroll(bv, old_x - cursor_.x());
1659 updateLocal(bv, FULL, false);
1661 if (the_locking_inset) {
1662 inset_x = cursor_.x() - top_x + tabular->GetBeginningOfTextInCell(actcell);
1663 inset_y = cursor_.y();
1665 if ((!the_locking_inset ||
1666 !the_locking_inset->getFirstLockingInsetOfType(TABULAR_CODE)) &&
1667 actcell != oldcell) {
1668 InsetTabular * inset = const_cast<InsetTabular *>(this);
1669 InsetTabularMailer mailer(*inset);
1670 mailer.updateDialog(bv);
1677 Inset::RESULT InsetTabular::moveRight(BufferView * bv, bool lock)
1679 if (lock && !old_locking_inset) {
1680 if (activateCellInset(bv))
1683 bool moved = isRightToLeft(bv)
1684 ? movePrevCell(bv) : moveNextCell(bv);
1686 return FINISHED_RIGHT;
1687 if (lock && activateCellInset(bv))
1691 return DISPATCHED_NOUPDATE;
1695 Inset::RESULT InsetTabular::moveLeft(BufferView * bv, bool lock)
1697 bool moved = isRightToLeft(bv) ? moveNextCell(bv) : movePrevCell(bv);
1700 if (lock) { // behind the inset
1701 if (activateCellInset(bv, 0, 0, mouse_button::none, true))
1705 return DISPATCHED_NOUPDATE;
1709 Inset::RESULT InsetTabular::moveUp(BufferView * bv, bool lock)
1711 int const ocell = actcell;
1712 actcell = tabular->GetCellAbove(actcell);
1713 if (actcell == ocell) // we moved out of the inset
1719 if (old_locking_inset) {
1720 old_locking_inset->getCursorPos(bv, x, y);
1721 x -= cursor_.x() + tabular->GetBeginningOfTextInCell(actcell);
1723 if (activateCellInset(bv, x, 0))
1726 return DISPATCHED_NOUPDATE;
1730 Inset::RESULT InsetTabular::moveDown(BufferView * bv, bool lock)
1732 int const ocell = actcell;
1733 actcell = tabular->GetCellBelow(actcell);
1734 if (actcell == ocell) // we moved out of the inset
1735 return FINISHED_DOWN;
1740 if (old_locking_inset) {
1741 old_locking_inset->getCursorPos(bv, x, y);
1742 x -= cursor_.x() + tabular->GetBeginningOfTextInCell(actcell);
1744 if (activateCellInset(bv, x, 0))
1747 return DISPATCHED_NOUPDATE;
1751 bool InsetTabular::moveNextCell(BufferView * bv, bool lock)
1753 if (isRightToLeft(bv)) {
1754 if (tabular->IsFirstCellInRow(actcell)) {
1755 int row = tabular->row_of_cell(actcell);
1756 if (row == tabular->rows() - 1)
1758 actcell = tabular->GetLastCellInRow(row);
1759 actcell = tabular->GetCellBelow(actcell);
1766 if (tabular->IsLastCell(actcell))
1771 bool rtl = tabular->GetCellInset(actcell)->paragraph()->
1772 isRightToLeftPar(bv->buffer()->params);
1773 activateCellInset(bv, 0, 0, mouse_button::none, !rtl);
1780 bool InsetTabular::movePrevCell(BufferView * bv, bool lock)
1782 if (isRightToLeft(bv)) {
1783 if (tabular->IsLastCellInRow(actcell)) {
1784 int row = tabular->row_of_cell(actcell);
1787 actcell = tabular->GetFirstCellInRow(row);
1788 actcell = tabular->GetCellAbove(actcell);
1790 if (tabular->IsLastCell(actcell))
1795 if (!actcell) // first cell
1800 bool rtl = tabular->GetCellInset(actcell)->paragraph()->
1801 isRightToLeftPar(bv->buffer()->params);
1802 activateCellInset(bv, 0, 0, mouse_button::none, !rtl);
1809 void InsetTabular::setFont(BufferView * bv, LyXFont const & font, bool tall,
1813 setSelection(0, tabular->GetNumberOfCells() - 1);
1815 if (hasSelection()) {
1816 setUndo(bv, Undo::EDIT,
1817 bv->text->cursor.par(),
1818 bv->text->cursor.par()->next());
1819 bool const frozen = undo_frozen;
1822 // apply the fontchange on the whole selection
1827 getSelection(sel_row_start, sel_row_end, sel_col_start, sel_col_end);
1828 for(int i = sel_row_start; i <= sel_row_end; ++i) {
1829 for(int j = sel_col_start; j <= sel_col_end; ++j) {
1830 tabular->GetCellInset(i, j)->setFont(bv, font, tall, true);
1837 updateLocal(bv, INIT, true);
1839 if (the_locking_inset)
1840 the_locking_inset->setFont(bv, font, tall);
1844 bool InsetTabular::tabularFeatures(BufferView * bv, string const & what)
1846 LyXTabular::Feature action = LyXTabular::LAST_ACTION;
1849 for (; tabularFeature[i].action != LyXTabular::LAST_ACTION; ++i) {
1850 string const tmp = tabularFeature[i].feature;
1852 if (tmp == what.substr(0, tmp.length())) {
1853 //if (!compare(tabularFeatures[i].feature.c_str(), what.c_str(),
1854 //tabularFeatures[i].feature.length())) {
1855 action = tabularFeature[i].action;
1859 if (action == LyXTabular::LAST_ACTION)
1863 ltrim(what.substr(tabularFeature[i].feature.length()));
1864 tabularFeatures(bv, action, val);
1870 void checkLongtableSpecial(LyXTabular::ltType & ltt,
1871 string const & special, bool & flag)
1873 if (special == "dl_above") {
1876 } else if (special == "dl_below") {
1877 ltt.bottomDL = flag;
1879 } else if (special == "empty") {
1891 void InsetTabular::tabularFeatures(BufferView * bv,
1892 LyXTabular::Feature feature,
1893 string const & value)
1899 bool setLines = false;
1900 LyXAlignment setAlign = LYX_ALIGN_LEFT;
1901 LyXTabular::VAlignment setVAlign = LyXTabular::LYX_VALIGN_TOP;
1904 case LyXTabular::M_ALIGN_LEFT:
1905 case LyXTabular::ALIGN_LEFT:
1906 setAlign = LYX_ALIGN_LEFT;
1908 case LyXTabular::M_ALIGN_RIGHT:
1909 case LyXTabular::ALIGN_RIGHT:
1910 setAlign = LYX_ALIGN_RIGHT;
1912 case LyXTabular::M_ALIGN_CENTER:
1913 case LyXTabular::ALIGN_CENTER:
1914 setAlign = LYX_ALIGN_CENTER;
1916 case LyXTabular::ALIGN_BLOCK:
1917 setAlign = LYX_ALIGN_BLOCK;
1919 case LyXTabular::M_VALIGN_TOP:
1920 case LyXTabular::VALIGN_TOP:
1921 setVAlign = LyXTabular::LYX_VALIGN_TOP;
1923 case LyXTabular::M_VALIGN_BOTTOM:
1924 case LyXTabular::VALIGN_BOTTOM:
1925 setVAlign = LyXTabular::LYX_VALIGN_BOTTOM;
1927 case LyXTabular::M_VALIGN_CENTER:
1928 case LyXTabular::VALIGN_CENTER:
1929 setVAlign = LyXTabular::LYX_VALIGN_CENTER;
1934 if (hasSelection()) {
1935 getSelection(sel_row_start, sel_row_end, sel_col_start, sel_col_end);
1937 sel_col_start = sel_col_end = tabular->column_of_cell(actcell);
1938 sel_row_start = sel_row_end = tabular->row_of_cell(actcell);
1940 setUndo(bv, Undo::FINISH,
1941 bv->text->cursor.par(),
1942 bv->text->cursor.par()->next());
1944 int row = tabular->row_of_cell(actcell);
1945 int column = tabular->column_of_cell(actcell);
1947 LyXTabular::ltType ltt;
1950 case LyXTabular::SET_PWIDTH:
1952 LyXLength const vallen(value);
1953 LyXLength const & tmplen = tabular->GetColumnPWidth(actcell);
1955 bool const update = (tmplen != vallen);
1956 tabular->SetColumnPWidth(actcell, vallen);
1959 for (int i = 0; i < tabular->rows(); ++i) {
1960 cell = tabular->GetCellNumber(i,column);
1961 tabular->GetCellInset(cell)->resizeLyXText(bv);
1963 updateLocal(bv, INIT, true);
1967 && tabular->GetAlignment(actcell, true) == LYX_ALIGN_BLOCK)
1968 tabularFeatures(bv, LyXTabular::ALIGN_CENTER, string());
1969 else if (!vallen.zero()
1970 && tabular->GetAlignment(actcell, true) != LYX_ALIGN_BLOCK)
1971 tabularFeatures(bv, LyXTabular::ALIGN_BLOCK, string());
1974 case LyXTabular::SET_MPWIDTH:
1976 LyXLength const vallen(value);
1977 LyXLength const & tmplen = tabular->GetPWidth(actcell);
1979 bool const update = (tmplen != vallen);
1980 tabular->SetMColumnPWidth(actcell, vallen);
1982 for (int i = 0; i < tabular->rows(); ++i) {
1983 tabular->GetCellInset(tabular->GetCellNumber(i, column))->
1986 updateLocal(bv, INIT, true);
1990 case LyXTabular::SET_SPECIAL_COLUMN:
1991 case LyXTabular::SET_SPECIAL_MULTI:
1992 tabular->SetAlignSpecial(actcell,value,feature);
1993 updateLocal(bv, FULL, true);
1995 case LyXTabular::APPEND_ROW:
1996 // append the row into the tabular
1997 unlockInsetInInset(bv, the_locking_inset);
1998 tabular->AppendRow(bv->buffer()->params, actcell);
1999 updateLocal(bv, INIT, true);
2001 case LyXTabular::APPEND_COLUMN:
2002 // append the column into the tabular
2003 unlockInsetInInset(bv, the_locking_inset);
2004 tabular->AppendColumn(bv->buffer()->params, actcell);
2005 actcell = tabular->GetCellNumber(row, column);
2006 updateLocal(bv, INIT, true);
2008 case LyXTabular::DELETE_ROW:
2009 unlockInsetInInset(bv, the_locking_inset);
2010 for(int i = sel_row_start; i <= sel_row_end; ++i) {
2011 tabular->DeleteRow(sel_row_start);
2013 if (sel_row_start >= tabular->rows())
2015 actcell = tabular->GetCellNumber(sel_row_start, column);
2017 updateLocal(bv, INIT, true);
2019 case LyXTabular::DELETE_COLUMN:
2020 unlockInsetInInset(bv, the_locking_inset);
2021 for(int i = sel_col_start; i <= sel_col_end; ++i) {
2022 tabular->DeleteColumn(sel_col_start);
2024 if (sel_col_start >= tabular->columns())
2026 actcell = tabular->GetCellNumber(row, sel_col_start);
2028 updateLocal(bv, INIT, true);
2030 case LyXTabular::M_TOGGLE_LINE_TOP:
2032 case LyXTabular::TOGGLE_LINE_TOP:
2034 bool lineSet = !tabular->TopLine(actcell, flag);
2035 for (int i = sel_row_start; i <= sel_row_end; ++i)
2036 for (int j = sel_col_start; j <= sel_col_end; ++j)
2037 tabular->SetTopLine(
2038 tabular->GetCellNumber(i, j),
2040 updateLocal(bv, INIT, true);
2044 case LyXTabular::M_TOGGLE_LINE_BOTTOM:
2046 case LyXTabular::TOGGLE_LINE_BOTTOM:
2048 bool lineSet = !tabular->BottomLine(actcell, flag);
2049 for (int i = sel_row_start; i <= sel_row_end; ++i)
2050 for (int j = sel_col_start; j <= sel_col_end; ++j)
2051 tabular->SetBottomLine(
2052 tabular->GetCellNumber(i, j),
2055 updateLocal(bv, INIT, true);
2059 case LyXTabular::M_TOGGLE_LINE_LEFT:
2061 case LyXTabular::TOGGLE_LINE_LEFT:
2063 bool lineSet = !tabular->LeftLine(actcell, flag);
2064 for (int i = sel_row_start; i <= sel_row_end; ++i)
2065 for (int j = sel_col_start; j <= sel_col_end; ++j)
2066 tabular->SetLeftLine(
2067 tabular->GetCellNumber(i,j),
2070 updateLocal(bv, INIT, true);
2074 case LyXTabular::M_TOGGLE_LINE_RIGHT:
2076 case LyXTabular::TOGGLE_LINE_RIGHT:
2078 bool lineSet = !tabular->RightLine(actcell, flag);
2079 for (int i = sel_row_start; i <= sel_row_end; ++i)
2080 for (int j = sel_col_start; j <= sel_col_end; ++j)
2081 tabular->SetRightLine(
2082 tabular->GetCellNumber(i,j),
2085 updateLocal(bv, INIT, true);
2089 case LyXTabular::M_ALIGN_LEFT:
2090 case LyXTabular::M_ALIGN_RIGHT:
2091 case LyXTabular::M_ALIGN_CENTER:
2093 case LyXTabular::ALIGN_LEFT:
2094 case LyXTabular::ALIGN_RIGHT:
2095 case LyXTabular::ALIGN_CENTER:
2096 case LyXTabular::ALIGN_BLOCK:
2097 for (int i = sel_row_start; i <= sel_row_end; ++i)
2098 for (int j = sel_col_start; j <= sel_col_end; ++j)
2099 tabular->SetAlignment(
2100 tabular->GetCellNumber(i, j),
2103 updateLocal(bv, INIT, true);
2105 case LyXTabular::M_VALIGN_TOP:
2106 case LyXTabular::M_VALIGN_BOTTOM:
2107 case LyXTabular::M_VALIGN_CENTER:
2109 case LyXTabular::VALIGN_TOP:
2110 case LyXTabular::VALIGN_BOTTOM:
2111 case LyXTabular::VALIGN_CENTER:
2112 for (int i = sel_row_start; i <= sel_row_end; ++i)
2113 for (int j = sel_col_start; j <= sel_col_end; ++j)
2114 tabular->SetVAlignment(
2115 tabular->GetCellNumber(i, j),
2117 updateLocal(bv, INIT, true);
2119 case LyXTabular::MULTICOLUMN:
2121 if (sel_row_start != sel_row_end) {
2122 Alert::alert(_("Impossible operation!"),
2123 _("Multicolumns can only be horizontally."),
2127 // just multicol for one Single Cell
2128 if (!hasSelection()) {
2129 // check wether we are completly in a multicol
2130 if (tabular->IsMultiColumn(actcell)) {
2131 tabular->UnsetMultiColumn(actcell);
2132 updateLocal(bv, INIT, true);
2134 tabular->SetMultiColumn(bv->buffer(), actcell, 1);
2135 updateLocal(bv, CELL, true);
2139 // we have a selection so this means we just add all this
2140 // cells to form a multicolumn cell
2144 if (sel_cell_start > sel_cell_end) {
2145 s_start = sel_cell_end;
2146 s_end = sel_cell_start;
2148 s_start = sel_cell_start;
2149 s_end = sel_cell_end;
2151 tabular->SetMultiColumn(bv->buffer(), s_start, s_end - s_start + 1);
2154 updateLocal(bv, INIT, true);
2157 case LyXTabular::SET_ALL_LINES:
2159 case LyXTabular::UNSET_ALL_LINES:
2160 for (int i = sel_row_start; i <= sel_row_end; ++i)
2161 for (int j = sel_col_start; j <= sel_col_end; ++j)
2162 tabular->SetAllLines(
2163 tabular->GetCellNumber(i,j), setLines);
2164 updateLocal(bv, INIT, true);
2166 case LyXTabular::SET_LONGTABULAR:
2167 tabular->SetLongTabular(true);
2168 updateLocal(bv, INIT, true); // because this toggles displayed
2170 case LyXTabular::UNSET_LONGTABULAR:
2171 tabular->SetLongTabular(false);
2172 updateLocal(bv, INIT, true); // because this toggles displayed
2174 case LyXTabular::SET_ROTATE_TABULAR:
2175 tabular->SetRotateTabular(true);
2177 case LyXTabular::UNSET_ROTATE_TABULAR:
2178 tabular->SetRotateTabular(false);
2180 case LyXTabular::SET_ROTATE_CELL:
2181 for (int i = sel_row_start; i <= sel_row_end; ++i)
2182 for (int j = sel_col_start; j<=sel_col_end; ++j)
2183 tabular->SetRotateCell(
2184 tabular->GetCellNumber(i, j),
2187 case LyXTabular::UNSET_ROTATE_CELL:
2188 for (int i = sel_row_start; i <= sel_row_end; ++i)
2189 for (int j = sel_col_start; j <= sel_col_end; ++j)
2190 tabular->SetRotateCell(
2191 tabular->GetCellNumber(i, j), false);
2193 case LyXTabular::SET_USEBOX:
2195 LyXTabular::BoxType val = LyXTabular::BoxType(strToInt(value));
2196 if (val == tabular->GetUsebox(actcell))
2197 val = LyXTabular::BOX_NONE;
2198 for (int i = sel_row_start; i <= sel_row_end; ++i)
2199 for (int j = sel_col_start; j <= sel_col_end; ++j)
2201 tabular->GetCellNumber(i, j), val);
2204 case LyXTabular::UNSET_LTFIRSTHEAD:
2206 case LyXTabular::SET_LTFIRSTHEAD:
2207 (void)tabular->GetRowOfLTFirstHead(row, ltt);
2208 checkLongtableSpecial(ltt, value, flag);
2209 tabular->SetLTHead(row, flag, ltt, true);
2211 case LyXTabular::UNSET_LTHEAD:
2213 case LyXTabular::SET_LTHEAD:
2214 (void)tabular->GetRowOfLTHead(row, ltt);
2215 checkLongtableSpecial(ltt, value, flag);
2216 tabular->SetLTHead(row, flag, ltt, false);
2218 case LyXTabular::UNSET_LTFOOT:
2220 case LyXTabular::SET_LTFOOT:
2221 (void)tabular->GetRowOfLTFoot(row, ltt);
2222 checkLongtableSpecial(ltt, value, flag);
2223 tabular->SetLTFoot(row, flag, ltt, false);
2225 case LyXTabular::UNSET_LTLASTFOOT:
2227 case LyXTabular::SET_LTLASTFOOT:
2228 (void)tabular->GetRowOfLTLastFoot(row, ltt);
2229 checkLongtableSpecial(ltt, value, flag);
2230 tabular->SetLTFoot(row, flag, ltt, true);
2232 case LyXTabular::SET_LTNEWPAGE:
2234 bool what = !tabular->GetLTNewPage(row);
2235 tabular->SetLTNewPage(row, what);
2238 // dummy stuff just to avoid warnings
2239 case LyXTabular::LAST_ACTION:
2245 bool InsetTabular::activateCellInset(BufferView * bv, int x, int y, mouse_button::state button,
2248 UpdatableInset * inset =
2249 static_cast<UpdatableInset*>(tabular->GetCellInset(actcell));
2250 LyXFont font(LyXFont::ALL_SANE);
2252 x = inset->x() + inset->width(bv, font);
2253 y = inset->descent(bv, font);
2255 //inset_x = cursor.x() - top_x + tabular->GetBeginningOfTextInCell(actcell);
2256 //inset_y = cursor.y();
2257 inset->edit(bv, x, y, button);
2258 if (!the_locking_inset)
2260 updateLocal(bv, CELL, false);
2261 return (the_locking_inset != 0);
2265 bool InsetTabular::activateCellInsetAbs(BufferView * bv, int x, int y,
2266 mouse_button::state button)
2268 inset_x = cursor_.x()
2269 - top_x + tabular->GetBeginningOfTextInCell(actcell);
2270 inset_y = cursor_.y();
2271 return activateCellInset(bv, x - inset_x, y - inset_y, button);
2275 bool InsetTabular::insetHit(BufferView *, int x, int) const
2278 > (cursor_.x() + tabular->GetBeginningOfTextInCell(actcell));
2282 // This returns paperWidth() if the cell-width is unlimited or the width
2283 // in pixels if we have a pwidth for this cell.
2284 int InsetTabular::getMaxWidthOfCell(BufferView * bv, int cell) const
2286 LyXLength const len = tabular->GetPWidth(cell);
2290 return len.inPixels(latexTextWidth(bv));
2294 int InsetTabular::getMaxWidth(BufferView * bv,
2295 UpdatableInset const * inset) const
2297 int cell = tabular->GetCellFromInset(inset, actcell);
2300 lyxerr << "Own inset not found, shouldn't really happen!"
2305 int w = getMaxWidthOfCell(bv, cell);
2307 // because the inset then subtracts it's top_x and owner->x()
2308 w += (inset->x() - top_x);
2315 void InsetTabular::deleteLyXText(BufferView * bv, bool recursive) const
2317 resizeLyXText(bv, recursive);
2321 void InsetTabular::resizeLyXText(BufferView * bv, bool force) const
2324 for(int i = 0; i < tabular->rows(); ++i) {
2325 for(int j = 0; j < tabular->columns(); ++j) {
2326 tabular->GetCellInset(i, j)->resizeLyXText(bv, true);
2334 LyXText * InsetTabular::getLyXText(BufferView const * bv,
2335 bool const recursive) const
2337 if (the_locking_inset)
2338 return the_locking_inset->getLyXText(bv, recursive);
2340 // if we're locked lock the actual insettext and return it's LyXText!!!
2342 UpdatableInset * inset =
2343 static_cast<UpdatableInset*>(tabular->GetCellInset(actcell));
2344 inset->edit(const_cast<BufferView *>(bv), 0, 0, 0);
2345 return the_locking_inset->getLyXText(bv, recursive);
2348 return Inset::getLyXText(bv, recursive);
2352 bool InsetTabular::showInsetDialog(BufferView * bv) const
2354 if (!the_locking_inset || !the_locking_inset->showInsetDialog(bv)) {
2355 InsetTabular * tmp = const_cast<InsetTabular *>(this);
2356 InsetTabularMailer mailer(*tmp);
2357 mailer.showDialog(bv);
2363 void InsetTabular::openLayoutDialog(BufferView * bv) const
2365 if (the_locking_inset) {
2366 InsetTabular * i = static_cast<InsetTabular *>
2367 (the_locking_inset->getFirstLockingInsetOfType(TABULAR_CODE));
2369 i->openLayoutDialog(bv);
2373 InsetTabular * tmp = const_cast<InsetTabular *>(this);
2374 InsetTabularMailer mailer(*tmp);
2375 mailer.showDialog(bv);
2380 // function returns an object as defined in func_status.h:
2381 // states OK, Unknown, Disabled, On, Off.
2383 FuncStatus InsetTabular::getStatus(string const & what) const
2385 int action = LyXTabular::LAST_ACTION;
2389 for (; tabularFeature[i].action != LyXTabular::LAST_ACTION; ++i) {
2390 string const tmp = tabularFeature[i].feature;
2391 if (tmp == what.substr(0, tmp.length())) {
2392 //if (!compare(tabularFeatures[i].feature.c_str(), what.c_str(),
2393 // tabularFeatures[i].feature.length())) {
2394 action = tabularFeature[i].action;
2398 if (action == LyXTabular::LAST_ACTION) {
2400 return status.unknown(true);
2403 string const argument = ltrim(what.substr(tabularFeature[i].feature.length()));
2408 LyXTabular::ltType dummyltt;
2411 if (hasSelection()) {
2412 getSelection(sel_row_start, sel_row_end, dummy, dummy);
2414 sel_row_start = sel_row_end = tabular->row_of_cell(actcell);
2418 case LyXTabular::SET_PWIDTH:
2419 case LyXTabular::SET_MPWIDTH:
2420 case LyXTabular::SET_SPECIAL_COLUMN:
2421 case LyXTabular::SET_SPECIAL_MULTI:
2422 return status.disabled(true);
2424 case LyXTabular::APPEND_ROW:
2425 case LyXTabular::APPEND_COLUMN:
2426 case LyXTabular::DELETE_ROW:
2427 case LyXTabular::DELETE_COLUMN:
2428 case LyXTabular::SET_ALL_LINES:
2429 case LyXTabular::UNSET_ALL_LINES:
2430 return status.clear();
2432 case LyXTabular::MULTICOLUMN:
2433 status.setOnOff(tabular->IsMultiColumn(actcell));
2435 case LyXTabular::M_TOGGLE_LINE_TOP:
2437 case LyXTabular::TOGGLE_LINE_TOP:
2438 status.setOnOff(tabular->TopLine(actcell, flag));
2440 case LyXTabular::M_TOGGLE_LINE_BOTTOM:
2442 case LyXTabular::TOGGLE_LINE_BOTTOM:
2443 status.setOnOff(tabular->BottomLine(actcell, flag));
2445 case LyXTabular::M_TOGGLE_LINE_LEFT:
2447 case LyXTabular::TOGGLE_LINE_LEFT:
2448 status.setOnOff(tabular->LeftLine(actcell, flag));
2450 case LyXTabular::M_TOGGLE_LINE_RIGHT:
2452 case LyXTabular::TOGGLE_LINE_RIGHT:
2453 status.setOnOff(tabular->RightLine(actcell, flag));
2455 case LyXTabular::M_ALIGN_LEFT:
2457 case LyXTabular::ALIGN_LEFT:
2458 status.setOnOff(tabular->GetAlignment(actcell, flag) == LYX_ALIGN_LEFT);
2460 case LyXTabular::M_ALIGN_RIGHT:
2462 case LyXTabular::ALIGN_RIGHT:
2463 status.setOnOff(tabular->GetAlignment(actcell, flag) == LYX_ALIGN_RIGHT);
2465 case LyXTabular::M_ALIGN_CENTER:
2467 case LyXTabular::ALIGN_CENTER:
2468 status.setOnOff(tabular->GetAlignment(actcell, flag) == LYX_ALIGN_CENTER);
2470 case LyXTabular::ALIGN_BLOCK:
2471 status.disabled(tabular->GetPWidth(actcell).zero());
2472 status.setOnOff(tabular->GetAlignment(actcell, flag) == LYX_ALIGN_BLOCK);
2474 case LyXTabular::M_VALIGN_TOP:
2476 case LyXTabular::VALIGN_TOP:
2477 status.setOnOff(tabular->GetVAlignment(actcell, flag) == LyXTabular::LYX_VALIGN_TOP);
2479 case LyXTabular::M_VALIGN_BOTTOM:
2481 case LyXTabular::VALIGN_BOTTOM:
2482 status.setOnOff(tabular->GetVAlignment(actcell, flag) == LyXTabular::LYX_VALIGN_BOTTOM);
2484 case LyXTabular::M_VALIGN_CENTER:
2486 case LyXTabular::VALIGN_CENTER:
2487 status.setOnOff(tabular->GetVAlignment(actcell, flag) == LyXTabular::LYX_VALIGN_CENTER);
2489 case LyXTabular::SET_LONGTABULAR:
2490 status.setOnOff(tabular->IsLongTabular());
2492 case LyXTabular::UNSET_LONGTABULAR:
2493 status.setOnOff(!tabular->IsLongTabular());
2495 case LyXTabular::SET_ROTATE_TABULAR:
2496 status.setOnOff(tabular->GetRotateTabular());
2498 case LyXTabular::UNSET_ROTATE_TABULAR:
2499 status.setOnOff(!tabular->GetRotateTabular());
2501 case LyXTabular::SET_ROTATE_CELL:
2502 status.setOnOff(tabular->GetRotateCell(actcell));
2504 case LyXTabular::UNSET_ROTATE_CELL:
2505 status.setOnOff(!tabular->GetRotateCell(actcell));
2507 case LyXTabular::SET_USEBOX:
2508 status.setOnOff(strToInt(argument) == tabular->GetUsebox(actcell));
2510 case LyXTabular::SET_LTFIRSTHEAD:
2511 status.setOnOff(tabular->GetRowOfLTHead(sel_row_start, dummyltt));
2513 case LyXTabular::SET_LTHEAD:
2514 status.setOnOff(tabular->GetRowOfLTHead(sel_row_start, dummyltt));
2516 case LyXTabular::SET_LTFOOT:
2517 status.setOnOff(tabular->GetRowOfLTFoot(sel_row_start, dummyltt));
2519 case LyXTabular::SET_LTLASTFOOT:
2520 status.setOnOff(tabular->GetRowOfLTFoot(sel_row_start, dummyltt));
2522 case LyXTabular::SET_LTNEWPAGE:
2523 status.setOnOff(tabular->GetLTNewPage(sel_row_start));
2527 status.disabled(true);
2534 vector<string> const InsetTabular::getLabelList() const
2536 return tabular->getLabelList();
2540 bool InsetTabular::copySelection(BufferView * bv)
2542 if (!hasSelection())
2545 int sel_col_start = tabular->column_of_cell(sel_cell_start);
2546 int sel_col_end = tabular->column_of_cell(sel_cell_end);
2547 if (sel_col_start > sel_col_end) {
2548 sel_col_start = sel_col_end;
2549 sel_col_end = tabular->right_column_of_cell(sel_cell_start);
2551 sel_col_end = tabular->right_column_of_cell(sel_cell_end);
2553 int const columns = sel_col_end - sel_col_start + 1;
2555 int sel_row_start = tabular->row_of_cell(sel_cell_start);
2556 int sel_row_end = tabular->row_of_cell(sel_cell_end);
2557 if (sel_row_start > sel_row_end) {
2558 swap(sel_row_start, sel_row_end);
2560 int const rows = sel_row_end - sel_row_start + 1;
2562 delete paste_tabular;
2563 paste_tabular = new LyXTabular(bv->buffer()->params,
2564 this, *tabular); // rows, columns);
2565 for (int i = 0; i < sel_row_start; ++i)
2566 paste_tabular->DeleteRow(0);
2567 while (paste_tabular->rows() > rows)
2568 paste_tabular->DeleteRow(rows);
2569 paste_tabular->SetTopLine(0, true, true);
2570 paste_tabular->SetBottomLine(paste_tabular->GetFirstCellInRow(rows - 1),
2572 for (int i = 0; i < sel_col_start; ++i)
2573 paste_tabular->DeleteColumn(0);
2574 while (paste_tabular->columns() > columns)
2575 paste_tabular->DeleteColumn(columns);
2576 paste_tabular->SetLeftLine(0, true, true);
2577 paste_tabular->SetRightLine(paste_tabular->GetLastCellInRow(0),
2581 paste_tabular->ascii(bv->buffer(), sstr,
2582 (int)parOwner()->params().depth(), true, '\t');
2583 bv->stuffClipboard(STRCONV(sstr.str()));
2588 bool InsetTabular::pasteSelection(BufferView * bv)
2593 for (int r1 = 0, r2 = actrow;
2594 (r1 < paste_tabular->rows()) && (r2 < tabular->rows());
2596 for(int c1 = 0, c2 = actcol;
2597 (c1 < paste_tabular->columns()) && (c2 < tabular->columns());
2599 if (paste_tabular->IsPartOfMultiColumn(r1,c1) &&
2600 tabular->IsPartOfMultiColumn(r2,c2))
2602 if (paste_tabular->IsPartOfMultiColumn(r1,c1)) {
2606 if (tabular->IsPartOfMultiColumn(r2,c2)) {
2610 int const n1 = paste_tabular->GetCellNumber(r1, c1);
2611 int const n2 = tabular->GetCellNumber(r2, c2);
2612 *(tabular->GetCellInset(n2)) = *(paste_tabular->GetCellInset(n1));
2613 tabular->GetCellInset(n2)->setOwner(this);
2614 tabular->GetCellInset(n2)->deleteLyXText(bv);
2615 tabular->GetCellInset(n2)->markNew();
2622 bool InsetTabular::cutSelection(BufferParams const & bp)
2624 if (!hasSelection())
2627 int sel_col_start = tabular->column_of_cell(sel_cell_start);
2628 int sel_col_end = tabular->column_of_cell(sel_cell_end);
2629 if (sel_col_start > sel_col_end) {
2630 sel_col_start = sel_col_end;
2631 sel_col_end = tabular->right_column_of_cell(sel_cell_start);
2633 sel_col_end = tabular->right_column_of_cell(sel_cell_end);
2635 int sel_row_start = tabular->row_of_cell(sel_cell_start);
2636 int sel_row_end = tabular->row_of_cell(sel_cell_end);
2637 if (sel_row_start > sel_row_end) {
2638 swap(sel_row_start, sel_row_end);
2640 if (sel_cell_start > sel_cell_end) {
2641 swap(sel_cell_start, sel_cell_end);
2643 for (int i = sel_row_start; i <= sel_row_end; ++i) {
2644 for (int j = sel_col_start; j <= sel_col_end; ++j) {
2645 tabular->GetCellInset(tabular->GetCellNumber(i, j))->clear(bp.tracking_changes);
2652 bool InsetTabular::isRightToLeft(BufferView * bv)
2654 return bv->getParentLanguage(this)->RightToLeft();
2658 bool InsetTabular::nodraw() const
2660 if (!UpdatableInset::nodraw() && the_locking_inset)
2661 return the_locking_inset->nodraw();
2662 return UpdatableInset::nodraw();
2666 int InsetTabular::scroll(bool recursive) const
2668 int sx = UpdatableInset::scroll(false);
2670 if (recursive && the_locking_inset)
2671 sx += the_locking_inset->scroll(recursive);
2677 bool InsetTabular::doClearArea() const
2679 return !locked || (need_update & (FULL|INIT));
2683 void InsetTabular::getSelection(int & srow, int & erow,
2684 int & scol, int & ecol) const
2686 int const start = hasSelection() ? sel_cell_start : actcell;
2687 int const end = hasSelection() ? sel_cell_end : actcell;
2689 srow = tabular->row_of_cell(start);
2690 erow = tabular->row_of_cell(end);
2695 scol = tabular->column_of_cell(start);
2696 ecol = tabular->column_of_cell(end);
2700 ecol = tabular->right_column_of_cell(end);
2705 Paragraph * InsetTabular::firstParagraph() const
2707 if (the_locking_inset)
2708 return the_locking_inset->firstParagraph();
2713 Paragraph * InsetTabular::getFirstParagraph(int i) const
2715 return (i < tabular->GetNumberOfCells())
2716 ? tabular->GetCellInset(i)->getFirstParagraph(0)
2721 LyXCursor const & InsetTabular::cursor(BufferView * bv) const
2723 if (the_locking_inset)
2724 return the_locking_inset->cursor(bv);
2725 return Inset::cursor(bv);
2729 Inset * InsetTabular::getInsetFromID(int id_arg) const
2732 return const_cast<InsetTabular *>(this);
2735 for(int i = 0; i < tabular->rows(); ++i) {
2736 for(int j = 0; j < tabular->columns(); ++j) {
2737 if ((result = tabular->GetCellInset(i, j)->getInsetFromID(id_arg)))
2746 InsetTabular::selectNextWordToSpellcheck(BufferView * bv, float & value) const
2749 if (the_locking_inset) {
2750 WordLangTuple word(the_locking_inset->selectNextWordToSpellcheck(bv, value));
2751 if (!word.word().empty()) {
2755 if (tabular->IsLastCell(actcell)) {
2756 bv->unlockInset(const_cast<InsetTabular *>(this));
2758 return WordLangTuple();
2762 // otherwise we have to lock the next inset and ask for it's selecttion
2763 UpdatableInset * inset =
2764 static_cast<UpdatableInset*>(tabular->GetCellInset(actcell));
2765 inset->edit(bv, 0, 0, mouse_button::none);
2766 WordLangTuple word(selectNextWordInt(bv, value));
2768 if (!word.word().empty())
2774 WordLangTuple InsetTabular::selectNextWordInt(BufferView * bv, float & value) const
2776 // when entering this function the inset should be ALWAYS locked!
2777 lyx::Assert(the_locking_inset);
2779 WordLangTuple word(the_locking_inset->selectNextWordToSpellcheck(bv, value));
2780 if (!word.word().empty())
2783 if (tabular->IsLastCell(actcell)) {
2784 bv->unlockInset(const_cast<InsetTabular *>(this));
2785 return WordLangTuple();
2788 // otherwise we have to lock the next inset and ask for it's selecttion
2789 UpdatableInset * inset =
2790 static_cast<UpdatableInset*>(tabular->GetCellInset(++actcell));
2792 return selectNextWordInt(bv, value);
2796 void InsetTabular::selectSelectedWord(BufferView * bv)
2798 if (the_locking_inset) {
2799 the_locking_inset->selectSelectedWord(bv);
2806 void InsetTabular::toggleSelection(BufferView * bv, bool kill_selection)
2808 if (the_locking_inset) {
2809 the_locking_inset->toggleSelection(bv, kill_selection);
2814 void InsetTabular::markErased()
2818 while (!tabular->IsLastCell(cell)) {
2820 InsetText * inset = tabular->GetCellInset(cell);
2821 inset->markErased();
2826 bool InsetTabular::nextChange(BufferView * bv, lyx::pos_type & length)
2828 if (the_locking_inset) {
2829 if (the_locking_inset->nextChange(bv, length)) {
2830 updateLocal(bv, CELL, false);
2833 if (tabular->IsLastCell(actcell))
2837 InsetText * inset = tabular->GetCellInset(actcell);
2838 if (inset->nextChange(bv, length)) {
2839 updateLocal(bv, FULL, false);
2842 while (!tabular->IsLastCell(actcell)) {
2844 inset = tabular->GetCellInset(actcell);
2845 if (inset->nextChange(bv, length)) {
2846 updateLocal(bv, FULL, false);
2854 bool InsetTabular::searchForward(BufferView * bv, string const & str,
2857 if (the_locking_inset) {
2858 if (the_locking_inset->searchForward(bv, str, cs, mw)) {
2859 updateLocal(bv, CELL, false);
2862 if (tabular->IsLastCell(actcell))
2866 InsetText * inset = tabular->GetCellInset(actcell);
2867 if (inset->searchForward(bv, str, cs, mw)) {
2868 updateLocal(bv, FULL, false);
2871 while (!tabular->IsLastCell(actcell)) {
2873 inset = tabular->GetCellInset(actcell);
2874 if (inset->searchForward(bv, str, cs, mw)) {
2875 updateLocal(bv, FULL, false);
2883 bool InsetTabular::searchBackward(BufferView * bv, string const & str,
2886 if (the_locking_inset) {
2887 if (the_locking_inset->searchBackward(bv, str, cs, mw)) {
2888 updateLocal(bv, CELL, false);
2893 actcell = tabular->GetNumberOfCells();
2897 InsetText * inset = tabular->GetCellInset(actcell);
2898 if (inset->searchBackward(bv, str, cs, mw)) {
2899 updateLocal(bv, CELL, false);
2907 bool InsetTabular::insetAllowed(Inset::Code code) const
2909 if (the_locking_inset)
2910 return the_locking_inset->insetAllowed(code);
2911 // we return true here because if the inset is not locked someone
2912 // wants to insert something in one of our insettexts and we generally
2918 bool InsetTabular::forceDefaultParagraphs(Inset const * in) const
2920 const int cell = tabular->GetCellFromInset(in, actcell);
2923 return tabular->GetPWidth(cell).zero();
2925 // well we didn't obviously find it so maybe our owner knows more
2927 return owner()->forceDefaultParagraphs(in);
2928 // if we're here there is really something strange going on!!!
2932 bool InsetTabular::insertAsciiString(BufferView * bv, string const & buf,
2935 if (buf.length() <= 0)
2941 string::size_type len = buf.length();
2942 string::size_type p = 0;
2945 ((p = buf.find_first_of("\t\n", p)) != string::npos))
2954 maxCols = max(cols, maxCols);
2960 maxCols = max(cols, maxCols);
2961 LyXTabular * loctab;
2966 delete paste_tabular;
2967 paste_tabular = new LyXTabular(bv->buffer()->params,
2968 this, rows, maxCols);
2969 loctab = paste_tabular;
2972 loctab = tabular.get();
2978 string::size_type op = 0;
2979 int cells = loctab->GetNumberOfCells();
2982 rows = loctab->rows();
2983 int const columns = loctab->columns();
2985 while ((cell < cells) && (p < len) && (row < rows) &&
2986 (p = buf.find_first_of("\t\n", p)) != string::npos)
2992 // we can only set this if we are not too far right
2993 if (cols < columns) {
2994 InsetText * ti = loctab->GetCellInset(cell);
2995 LyXFont const font = ti->getLyXText(bv)->
2996 getFont(bv->buffer(), ti->paragraph(), 0);
2997 ti->setText(buf.substr(op, p-op), font);
3003 // we can only set this if we are not too far right
3004 if (cols < columns) {
3005 InsetText * ti = loctab->GetCellInset(cell);
3006 LyXFont const font = ti->getLyXText(bv)->
3007 getFont(bv->buffer(), ti->paragraph(), 0);
3008 ti->setText(buf.substr(op, p-op), font);
3013 cell = loctab->GetCellNumber(row, cols);
3019 // check for the last cell if there is no trailing '\n'
3020 if ((cell < cells) && (op < len)) {
3021 InsetText * ti = loctab->GetCellInset(cell);
3022 LyXFont const font = ti->getLyXText(bv)->
3023 getFont(bv->buffer(), ti->paragraph(), 0);
3024 ti->setText(buf.substr(op, len-op), font);
3031 void InsetTabular::addPreview(grfx::PreviewLoader & loader) const
3033 int const rows = tabular->rows();
3034 int const columns = tabular->columns();
3035 for (int i = 0; i < rows; ++i) {
3036 for (int j = 0; j < columns; ++j) {
3037 tabular->GetCellInset(i,j)->addPreview(loader);
3043 string const InsetTabularMailer:: name_("tabular");
3045 InsetTabularMailer::InsetTabularMailer(InsetTabular & inset)
3050 string const InsetTabularMailer::inset2string() const
3052 return params2string(inset_);
3056 int InsetTabularMailer::string2params(string const & in, InsetTabular & inset)
3058 istringstream data(in);
3060 lex.setStream(data);
3064 string const token = lex.getString();
3072 string const token = lex.getString();
3073 if (token != "\\active_cell")
3076 cell = lex.getInteger();
3079 // This is part of the inset proper that is usually swallowed
3080 // by Buffer::readInset
3083 string const token = lex.getString();
3084 if (token != "Tabular")
3091 BufferView * const bv = inset.view();
3092 Buffer const * const buffer = bv ? bv->buffer() : 0;
3094 inset.read(buffer, lex);
3096 // We can't set the active cell, but we can tell the frontend
3103 InsetTabularMailer::params2string(InsetTabular const & inset)
3105 BufferView * const bv = inset.view();
3106 Buffer const * const buffer = bv ? bv->buffer() : 0;
3111 data << name_ << " \\active_cell " << inset.getActCell() << '\n';
3112 inset.write(buffer, data);
3113 data << "\\end_inset\n";