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.
13 #include "insettabular.h"
16 #include "bufferparams.h"
17 #include "BufferView.h"
19 #include "dispatchresult.h"
20 #include "funcrequest.h"
21 #include "FuncStatus.h"
24 #include "latexrunparams.h"
28 #include "metricsinfo.h"
29 #include "paragraph.h"
30 #include "paragraph_funcs.h"
31 #include "ParagraphParameters.h"
34 #include "frontends/Alert.h"
35 #include "frontends/font_metrics.h"
36 #include "frontends/LyXView.h"
37 #include "frontends/Painter.h"
39 #include "support/std_sstream.h"
42 using lyx::graphics::PreviewLoader;
44 using lyx::support::ltrim;
45 using lyx::support::strToInt;
52 using std::istringstream;
54 using std::ostringstream;
59 int const ADD_TO_HEIGHT = 2;
60 int const ADD_TO_TABULAR_WIDTH = 2;
63 boost::scoped_ptr<LyXTabular> paste_tabular;
66 struct TabularFeature {
67 LyXTabular::Feature action;
72 TabularFeature tabularFeature[] =
74 { LyXTabular::APPEND_ROW, "append-row" },
75 { LyXTabular::APPEND_COLUMN, "append-column" },
76 { LyXTabular::DELETE_ROW, "delete-row" },
77 { LyXTabular::DELETE_COLUMN, "delete-column" },
78 { LyXTabular::TOGGLE_LINE_TOP, "toggle-line-top" },
79 { LyXTabular::TOGGLE_LINE_BOTTOM, "toggle-line-bottom" },
80 { LyXTabular::TOGGLE_LINE_LEFT, "toggle-line-left" },
81 { LyXTabular::TOGGLE_LINE_RIGHT, "toggle-line-right" },
82 { LyXTabular::ALIGN_LEFT, "align-left" },
83 { LyXTabular::ALIGN_RIGHT, "align-right" },
84 { LyXTabular::ALIGN_CENTER, "align-center" },
85 { LyXTabular::ALIGN_BLOCK, "align-block" },
86 { LyXTabular::VALIGN_TOP, "valign-top" },
87 { LyXTabular::VALIGN_BOTTOM, "valign-bottom" },
88 { LyXTabular::VALIGN_MIDDLE, "valign-middle" },
89 { LyXTabular::M_TOGGLE_LINE_TOP, "m-toggle-line-top" },
90 { LyXTabular::M_TOGGLE_LINE_BOTTOM, "m-toggle-line-bottom" },
91 { LyXTabular::M_TOGGLE_LINE_LEFT, "m-toggle-line-left" },
92 { LyXTabular::M_TOGGLE_LINE_RIGHT, "m-toggle-line-right" },
93 { LyXTabular::M_ALIGN_LEFT, "m-align-left" },
94 { LyXTabular::M_ALIGN_RIGHT, "m-align-right" },
95 { LyXTabular::M_ALIGN_CENTER, "m-align-center" },
96 { LyXTabular::M_VALIGN_TOP, "m-valign-top" },
97 { LyXTabular::M_VALIGN_BOTTOM, "m-valign-bottom" },
98 { LyXTabular::M_VALIGN_MIDDLE, "m-valign-middle" },
99 { LyXTabular::MULTICOLUMN, "multicolumn" },
100 { LyXTabular::SET_ALL_LINES, "set-all-lines" },
101 { LyXTabular::UNSET_ALL_LINES, "unset-all-lines" },
102 { LyXTabular::SET_LONGTABULAR, "set-longtabular" },
103 { LyXTabular::UNSET_LONGTABULAR, "unset-longtabular" },
104 { LyXTabular::SET_PWIDTH, "set-pwidth" },
105 { LyXTabular::SET_MPWIDTH, "set-mpwidth" },
106 { LyXTabular::SET_ROTATE_TABULAR, "set-rotate-tabular" },
107 { LyXTabular::UNSET_ROTATE_TABULAR, "unset-rotate-tabular" },
108 { LyXTabular::SET_ROTATE_CELL, "set-rotate-cell" },
109 { LyXTabular::UNSET_ROTATE_CELL, "unset-rotate-cell" },
110 { LyXTabular::SET_USEBOX, "set-usebox" },
111 { LyXTabular::SET_LTHEAD, "set-lthead" },
112 { LyXTabular::SET_LTFIRSTHEAD, "set-ltfirsthead" },
113 { LyXTabular::SET_LTFOOT, "set-ltfoot" },
114 { LyXTabular::SET_LTLASTFOOT, "set-ltlastfoot" },
115 { LyXTabular::SET_LTNEWPAGE, "set-ltnewpage" },
116 { LyXTabular::SET_SPECIAL_COLUMN, "set-special-column" },
117 { LyXTabular::SET_SPECIAL_MULTI, "set-special-multi" },
118 { LyXTabular::LAST_ACTION, "" }
122 FindFeature(LyXTabular::Feature feature) : feature_(feature) {}
123 bool operator()(TabularFeature & tf)
125 return tf.action == feature_;
128 LyXTabular::Feature feature_;
134 string const featureAsString(LyXTabular::Feature feature)
136 TabularFeature * it = tabularFeature;
137 TabularFeature * end = it +
138 sizeof(tabularFeature) / sizeof(TabularFeature);
139 it = std::find_if(it, end, FindFeature(feature));
140 return (it == end) ? string() : it->feature;
144 bool InsetTabular::hasPasteBuffer() const
146 return (paste_tabular.get() != 0);
150 InsetTabular::InsetTabular(Buffer const & buf, int rows, int columns)
151 : tabular(buf.params(), max(rows, 1), max(columns, 1)),
152 buffer_(&buf), cursorx_(0), cursory_(0)
154 tabular.setOwner(this);
155 // for now make it always display as display() inset
157 the_locking_inset = 0;
158 old_locking_inset = 0;
161 actrow = actcell = 0;
169 InsetTabular::InsetTabular(InsetTabular const & tab)
170 : UpdatableInset(tab), tabular(tab.tabular),
171 buffer_(tab.buffer_), cursorx_(0), cursory_(0)
173 tabular.setOwner(this);
174 the_locking_inset = 0;
175 old_locking_inset = 0;
178 actrow = actcell = 0;
186 InsetTabular::~InsetTabular()
188 InsetTabularMailer(*this).hideDialog();
192 auto_ptr<InsetBase> InsetTabular::clone() const
194 return auto_ptr<InsetBase>(new InsetTabular(*this));
198 Buffer const & InsetTabular::buffer() const
204 BufferView * InsetTabular::view() const
211 void InsetTabular::buffer(Buffer * b)
217 void InsetTabular::write(Buffer const & buf, ostream & os) const
219 os << "Tabular" << endl;
220 tabular.write(buf, os);
224 void InsetTabular::read(Buffer const & buf, LyXLex & lex)
226 bool const old_format = (lex.getString() == "\\LyXTable");
228 tabular.read(buf, lex);
234 string token = lex.getString();
235 while (lex.isOK() && (token != "\\end_inset")) {
237 token = lex.getString();
239 if (token != "\\end_inset") {
240 lex.printError("Missing \\end_inset at this point. "
246 void InsetTabular::metrics(MetricsInfo & mi, Dimension & dim) const
248 //lyxerr << "InsetTabular::metrics: " << mi.base.bv << " width: " <<
249 // mi.base.textwidth << "\n";
251 lyxerr << "InsetTabular::metrics: need bv" << endl;
255 calculate_dimensions_of_cells(mi);
257 dim.asc = tabular.getAscentOfRow(0);
258 dim.des = tabular.getHeightOfTabular() - tabular.getAscentOfRow(0) + 1;
259 dim.wid = tabular.getWidthOfTabular() + 2 * ADD_TO_TABULAR_WIDTH;
264 void InsetTabular::draw(PainterInfo & pi, int x, int y) const
266 //lyxerr << "InsetTabular::draw: " << x << " " << y << endl;
268 BufferView * bv = pi.base.bv;
271 UpdatableInset::draw(pi, x, y);
279 x += ADD_TO_TABULAR_WIDTH;
282 first_visible_cell = -1;
283 for (int i = 0; i < tabular.rows(); ++i) {
285 cell = tabular.getCellNumber(i, 0);
286 if (y + tabular.getDescentOfRow(i) <= 0 &&
287 y - tabular.getAscentOfRow(i) < pi.pain.paperHeight())
289 y += tabular.getDescentOfRow(i) +
290 tabular.getAscentOfRow(i + 1) +
291 tabular.getAdditionalHeight(i + 1);
294 for (int j = 0; j < tabular.columns(); ++j) {
295 if (nx > bv->workWidth())
297 if (tabular.isPartOfMultiColumn(i, j))
299 int cx = nx + tabular.getBeginningOfTextInCell(cell);
300 if (first_visible_cell < 0)
301 first_visible_cell = cell;
302 if (hasSelection()) {
303 drawCellSelection(pi.pain, nx, y, i, j, cell);
306 tabular.getCellInset(cell).draw(pi, cx, y);
307 drawCellLines(pi.pain, nx, y, i, cell);
308 nx += tabular.getWidthOfColumn(cell);
312 // Would be nice, but for some completely unfathomable reason,
313 // on a col resize to a new fixed width, even though the insettexts
314 // are resized, the cell isn't, but drawing all cells in a tall table
315 // has the desired effect somehow. Complete dark magic.
317 // avoiding drawing the rest of a long table is
318 // a pretty big speedup
319 if (y > bv->workHeight())
323 y += tabular.getDescentOfRow(i) +
324 tabular.getAscentOfRow(i + 1) +
325 tabular.getAdditionalHeight(i + 1);
330 void InsetTabular::drawCellLines(Painter & pain, int x, int y,
331 int row, int cell) const
333 int x2 = x + tabular.getWidthOfColumn(cell);
336 if (!tabular.topAlreadyDrawn(cell)) {
337 on_off = !tabular.topLine(cell);
338 pain.line(x, y - tabular.getAscentOfRow(row),
339 x2, y - tabular.getAscentOfRow(row),
340 on_off ? LColor::tabularonoffline : LColor::tabularline,
341 on_off ? Painter::line_onoffdash : Painter::line_solid);
343 on_off = !tabular.bottomLine(cell);
344 pain.line(x, y + tabular.getDescentOfRow(row),
345 x2, y + tabular.getDescentOfRow(row),
346 on_off ? LColor::tabularonoffline : LColor::tabularline,
347 on_off ? Painter::line_onoffdash : Painter::line_solid);
348 if (!tabular.leftAlreadyDrawn(cell)) {
349 on_off = !tabular.leftLine(cell);
350 pain.line(x, y - tabular.getAscentOfRow(row),
351 x, y + tabular.getDescentOfRow(row),
352 on_off ? LColor::tabularonoffline : LColor::tabularline,
353 on_off ? Painter::line_onoffdash : Painter::line_solid);
355 on_off = !tabular.rightLine(cell);
356 pain.line(x2 - tabular.getAdditionalWidth(cell),
357 y - tabular.getAscentOfRow(row),
358 x2 - tabular.getAdditionalWidth(cell),
359 y + tabular.getDescentOfRow(row),
360 on_off ? LColor::tabularonoffline : LColor::tabularline,
361 on_off ? Painter::line_onoffdash : Painter::line_solid);
365 void InsetTabular::drawCellSelection(Painter & pain, int x, int y,
366 int row, int column, int cell) const
368 BOOST_ASSERT(hasSelection());
369 int cs = tabular.column_of_cell(sel_cell_start);
370 int ce = tabular.column_of_cell(sel_cell_end);
373 cs = tabular.column_of_cell(sel_cell_end);
375 ce = tabular.right_column_of_cell(sel_cell_end);
378 int rs = tabular.row_of_cell(sel_cell_start);
379 int re = tabular.row_of_cell(sel_cell_end);
383 if ((column >= cs) && (column <= ce) && (row >= rs) && (row <= re)) {
384 int w = tabular.getWidthOfColumn(cell);
385 int h = tabular.getAscentOfRow(row) + tabular.getDescentOfRow(row)-1;
386 pain.fillRectangle(x, y - tabular.getAscentOfRow(row) + 1,
387 w, h, LColor::selection);
392 string const InsetTabular::editMessage() const
394 return _("Opened table");
398 void InsetTabular::insetUnlock(BufferView * bv)
400 if (the_locking_inset) {
401 the_locking_inset->insetUnlock(bv);
403 the_locking_inset = 0;
408 if (scroll(false) || hasSelection()) {
417 void InsetTabular::updateLocal(BufferView * bv) const
419 bv->updateInset(this);
425 bool InsetTabular::lockInsetInInset(BufferView * bv, UpdatableInset * inset)
427 lyxerr[Debug::INSETTEXT] << "InsetTabular::LockInsetInInset("
434 if (inset == &tabular.getCellInset(actcell)) {
435 lyxerr[Debug::INSETTEXT] << "OK" << endl;
436 the_locking_inset = &tabular.getCellInset(actcell);
441 if (!the_locking_inset) {
442 int const n = tabular.getNumberOfCells();
443 for (int i = 0; i < n; ++i) {
444 InsetText * in = &tabular.getCellInset(i);
447 the_locking_inset = in;
452 if (in->lockInsetInInset(bv, inset)) {
454 the_locking_inset = in;
457 in->dispatch(FuncRequest(bv, LFUN_INSET_EDIT));
464 if (the_locking_inset && (the_locking_inset == inset)) {
465 lyxerr[Debug::INSETTEXT] << "OK" << endl;
470 if (the_locking_inset) {
471 lyxerr[Debug::INSETTEXT] << "MAYBE" << endl;
472 return the_locking_inset->lockInsetInInset(bv, inset);
475 lyxerr[Debug::INSETTEXT] << "NOT OK" << endl;
480 bool InsetTabular::unlockInsetInInset(BufferView * bv, UpdatableInset * inset,
483 if (!the_locking_inset)
485 if (the_locking_inset == inset) {
486 the_locking_inset->insetUnlock(bv);
488 #warning fix scrolling when cellinset has requested a scroll (Jug)!!!
495 // this has to be here otherwise we don't redraw the cell!
496 the_locking_inset = 0;
499 if (the_locking_inset->unlockInsetInInset(bv, inset, lr)) {
500 if (inset->lyxCode() == TABULAR_CODE &&
501 !the_locking_inset->getFirstLockingInsetOfType(TABULAR_CODE)) {
502 InsetTabularMailer(*this).updateDialog(bv);
511 int InsetTabular::insetInInsetY() const
513 if (!the_locking_inset)
515 return inset_y + the_locking_inset->insetInInsetY();
519 UpdatableInset * InsetTabular::getLockingInset() const
521 return the_locking_inset ? the_locking_inset->getLockingInset() :
522 const_cast<InsetTabular *>(this);
526 UpdatableInset * InsetTabular::getFirstLockingInsetOfType(InsetOld::Code c)
530 if (the_locking_inset)
531 return the_locking_inset->getFirstLockingInsetOfType(c);
536 bool InsetTabular::insertInset(BufferView * bv, InsetOld * inset)
538 if (the_locking_inset)
539 return the_locking_inset->insertInset(bv, inset);
544 void InsetTabular::lfunMousePress(FuncRequest const & cmd)
546 if (hasSelection() && cmd.button() == mouse_button::button3)
549 if (hasSelection()) {
551 updateLocal(cmd.view());
554 int const ocell = actcell;
555 BufferView * bv = cmd.view();
559 the_locking_inset = 0;
563 setPos(bv, cmd.x, cmd.y);
566 bool const inset_hit = insetHit(bv, cmd.x, cmd.y);
568 if (ocell == actcell && the_locking_inset && inset_hit) {
570 FuncRequest cmd1 = cmd;
573 the_locking_inset->dispatch(cmd1);
577 if (the_locking_inset) {
578 the_locking_inset->insetUnlock(bv);
580 the_locking_inset = 0;
583 if (cmd.button() == mouse_button::button2) {
584 dispatch(FuncRequest(bv, LFUN_PASTESELECTION, "paragraph"));
588 if (inset_hit && bv->theLockingInset()) {
589 if (!bv->lockInset(&tabular.getCellInset(actcell))) {
590 lyxerr[Debug::INSETS] << "Cannot lock inset" << endl;
593 FuncRequest cmd1 = cmd;
596 the_locking_inset->dispatch(cmd1);
601 bool InsetTabular::lfunMouseRelease(FuncRequest const & cmd)
603 DispatchResult ret(false);
604 if (the_locking_inset) {
605 FuncRequest cmd1 = cmd;
608 ret = the_locking_inset->dispatch(cmd1);
610 if (cmd.button() == mouse_button::button3 && ret == DispatchResult(false)) {
611 InsetTabularMailer(*this).showDialog(cmd.view());
614 return ret.dispatched() || ret.val() > FINISHED;
618 void InsetTabular::lfunMouseMotion(FuncRequest const & cmd)
620 if (the_locking_inset) {
621 FuncRequest cmd1 = cmd;
624 the_locking_inset->dispatch(cmd1);
628 BufferView * bv = cmd.view();
629 int const old_cell = actcell;
631 setPos(bv, cmd.x, cmd.y);
632 if (!hasSelection()) {
633 setSelection(actcell, actcell);
635 } else if (old_cell != actcell) {
636 setSelection(sel_cell_start, actcell);
642 void InsetTabular::edit(BufferView * bv, int index)
644 lyxerr << "InsetTabular::edit" << endl;
645 if (!bv->lockInset(this)) {
646 lyxerr << "InsetTabular::Cannot lock inset (2)" << endl;
651 the_locking_inset = 0;
659 UpdatableInset & inset = tabular.getCellInset(actcell);
660 inset.dispatch(FuncRequest(bv, LFUN_INSET_EDIT, "left"));
661 if (the_locking_inset)
667 InsetTabular::priv_dispatch(FuncRequest const & cmd,
668 idx_type & idx, pos_type & pos)
670 // We need to save the value of the_locking_inset as the call to
671 // the_locking_inset->localDispatch might unlock it.
672 old_locking_inset = the_locking_inset;
673 DispatchResult result = UpdatableInset::priv_dispatch(cmd, idx, pos);
674 BufferView * bv = cmd.view();
676 if (cmd.action == LFUN_INSET_EDIT) {
678 lyxerr << "InsetTabular::edit: " << this << " args: '"
679 << cmd.argument << "' first cell: "
680 << &tabular.cell_info[0][0].inset << endl;
682 if (!bv->lockInset(this)) {
683 lyxerr << "InsetTabular::Cannot lock inset" << endl;
684 return DispatchResult(true, true);
689 the_locking_inset = 0;
693 if (cmd.argument.size()) {
694 if (cmd.argument == "left") {
695 if (isRightToLeft(bv))
696 actcell = tabular.getLastCellInRow(0);
700 if (isRightToLeft(bv))
701 actcell = tabular.getFirstCellInRow(tabular.rows()-1);
703 actcell = tabular.getNumberOfCells() - 1;
711 setPos(bv, cmd.x, cmd.y);
714 if (insetHit(bv, cmd.x, cmd.y) && cmd.button() != mouse_button::button3) {
715 inset_x = cursorx_ - top_x + tabular.getBeginningOfTextInCell(actcell);
717 activateCellInset(bv, cmd.x - inset_x, cmd.y - inset_y, cmd.button());
720 return DispatchResult(true, true);
723 if (result.dispatched()) {
728 if (cmd.action < 0 && cmd.argument.empty())
729 return DispatchResult(false, FINISHED);
731 bool hs = hasSelection();
733 result = DispatchResult(true, true);
734 // this one have priority over the locked InsetText, if we're not already
735 // inside another tabular then that one get's priority!
736 if (getFirstLockingInsetOfType(InsetOld::TABULAR_CODE) == this) {
737 switch (cmd.action) {
738 case LFUN_MOUSE_PRESS:
740 return DispatchResult(true, true);
742 case LFUN_MOUSE_MOTION:
743 lfunMouseMotion(cmd);
744 return DispatchResult(true, true);
746 case LFUN_MOUSE_RELEASE:
747 return DispatchResult(lfunMouseRelease(cmd));
749 case LFUN_CELL_BACKWARD:
750 case LFUN_CELL_FORWARD:
751 unlockInsetInInset(bv, the_locking_inset);
752 if (cmd.action == LFUN_CELL_FORWARD)
753 moveNextCell(bv, old_locking_inset != 0);
755 movePrevCell(bv, old_locking_inset != 0);
759 if (!the_locking_inset)
760 return DispatchResult(true);
762 // this to avoid compiler warnings.
768 kb_action action = cmd.action;
769 string arg = cmd.argument;
770 if (the_locking_inset) {
771 result = the_locking_inset->dispatch(cmd);
772 if (result.dispatched()) {
773 if (result.update()) {
776 int const sc = scroll();
778 if (sc != scroll()) {
779 // inset has been scrolled
784 } else if (result.val() == FINISHED_UP) {
786 // Make sure to reset status message after
787 // exiting, e.g. math inset
788 bv->owner()->clearMessage();
789 } else if (result.val() == FINISHED_DOWN) {
791 bv->owner()->clearMessage();
792 } else if (result.val() == FINISHED_RIGHT) {
794 bv->owner()->clearMessage();
795 } else if (result.val() == FINISHED) {
796 bv->owner()->clearMessage();
800 result = DispatchResult(true, true);
802 // --- Cursor Movements ----------------------------------
803 case LFUN_RIGHTSEL: {
804 int const start = hasSelection() ? sel_cell_start : actcell;
805 if (tabular.isLastCellInRow(actcell)) {
806 setSelection(start, actcell);
811 // if we are starting a selection, only select
812 // the current cell at the beginning
813 if (hasSelection()) {
814 moveRight(bv, false);
817 setSelection(start, end);
822 result = moveRight(bv);
828 int const start = hasSelection() ? sel_cell_start : actcell;
829 if (tabular.isFirstCellInRow(actcell)) {
830 setSelection(start, actcell);
835 // if we are starting a selection, only select
836 // the current cell at the beginning
837 if (hasSelection()) {
841 setSelection(start, end);
846 result = moveLeft(bv);
852 int const start = hasSelection() ? sel_cell_start : actcell;
853 int const ocell = actcell;
854 // if we are starting a selection, only select
855 // the current cell at the beginning
856 if (hasSelection()) {
858 if (ocell == sel_cell_end ||
859 tabular.column_of_cell(ocell) > tabular.column_of_cell(actcell))
860 setSelection(start, tabular.getCellBelow(sel_cell_end));
862 setSelection(start, tabular.getLastCellBelow(sel_cell_end));
864 setSelection(start, start);
870 result = moveDown(bv, old_locking_inset != 0);
876 int const start = hasSelection() ? sel_cell_start : actcell;
877 int const ocell = actcell;
878 // if we are starting a selection, only select
879 // the current cell at the beginning
880 if (hasSelection()) {
882 if ((ocell == sel_cell_end) ||
883 (tabular.column_of_cell(ocell)>tabular.column_of_cell(actcell)))
884 setSelection(start, tabular.getCellAbove(sel_cell_end));
886 setSelection(start, tabular.getLastCellAbove(sel_cell_end));
888 setSelection(start, start);
894 result = moveUp(bv, old_locking_inset != 0);
903 unlockInsetInInset(bv, the_locking_inset);
904 if (bv->top_y() + bv->painter().paperHeight() <
905 top_baseline + tabular.getHeightOfTabular())
907 bv->scrollDocView(bv->top_y() + bv->painter().paperHeight());
908 actcell = tabular.getCellBelow(first_visible_cell) + column;
910 actcell = tabular.getFirstCellInRow(tabular.rows() - 1) + column;
920 unlockInsetInInset(bv, the_locking_inset);
921 if (top_baseline < 0) {
922 bv->scrollDocView(bv->top_y() - bv->painter().paperHeight());
923 if (top_baseline > 0)
926 actcell = tabular.getCellBelow(first_visible_cell) + column;
934 // none of these make sense for insettabular,
935 // but we must catch them to prevent any
936 // selection from being confused
940 case LFUN_WORDLEFTSEL:
942 case LFUN_WORDRIGHTSEL:
944 case LFUN_DOWN_PARAGRAPH:
945 case LFUN_DOWN_PARAGRAPHSEL:
946 case LFUN_UP_PARAGRAPH:
947 case LFUN_UP_PARAGRAPHSEL:
953 case LFUN_BEGINNINGBUF:
954 case LFUN_BEGINNINGBUFSEL:
958 case LFUN_LAYOUT_TABULAR:
959 InsetTabularMailer(*this).showDialog(bv);
961 case LFUN_INSET_DIALOG_UPDATE:
962 InsetTabularMailer(*this).updateDialog(bv);
964 case LFUN_TABULAR_FEATURE:
965 if (!tabularFeatures(bv, arg))
966 result = DispatchResult(false);
968 // insert file functions
969 case LFUN_FILE_INSERT_ASCII_PARA:
970 case LFUN_FILE_INSERT_ASCII:
972 string tmpstr = getContentsOfAsciiFile(bv, arg, false);
975 if (insertAsciiString(bv, tmpstr, false))
978 result = DispatchResult(false);
981 // cut and paste functions
983 if (!copySelection(bv))
987 recordUndo(bv, Undo::DELETE);
988 cutSelection(bv->buffer()->params());
997 case LFUN_PASTESELECTION:
999 string const clip = bv->getClipboard();
1003 if (clip.find('\t') != string::npos) {
1007 string::size_type len = clip.length();
1008 string::size_type p = 0;
1011 ((p = clip.find_first_of("\t\n", p)) != string::npos)) {
1019 maxCols = max(cols, maxCols);
1025 maxCols = max(cols, maxCols);
1027 paste_tabular.reset(
1028 new LyXTabular(bv->buffer()->params(),
1029 this, rows, maxCols)
1032 string::size_type op = 0;
1034 int cells = paste_tabular->getNumberOfCells();
1036 while ((cell < cells) && (p < len) &&
1037 (p = clip.find_first_of("\t\n", p)) != string::npos) {
1042 paste_tabular->getCellInset(cell)->setText(clip.substr(op, p-op));
1047 paste_tabular->getCellInset(cell)->setText(clip.substr(op, p-op));
1048 while (cols++ < maxCols)
1056 // check for the last cell if there is no trailing '\n'
1057 if ((cell < cells) && (op < len))
1058 paste_tabular->getCellInset(cell)->setText(clip.substr(op, len-op));
1061 if (!insertAsciiString(bv, clip, true))
1064 // so that the clipboard is used and it goes on
1066 // and executes LFUN_PASTESELECTION in insettext!
1067 paste_tabular.reset();
1071 if (hasPasteBuffer()) {
1072 recordUndo(bv, Undo::INSERT);
1077 // ATTENTION: the function above has to be PASTE and PASTESELECTION!!!
1079 // handle font changing stuff on selection before we lock the inset
1080 // in the default part!
1081 result = DispatchResult(false);
1092 case LFUN_UNDERLINE:
1093 case LFUN_FONT_SIZE:
1094 if (bv->dispatch(FuncRequest(bv, action, arg)))
1095 result = DispatchResult(true, true);
1101 // we try to activate the actual inset and put this event down to
1102 // the insets dispatch function.
1103 if (result.dispatched() || the_locking_inset)
1105 if (activateCellInset(bv)) {
1106 result = the_locking_inset->dispatch(FuncRequest(bv, action, arg));
1107 if (!result.dispatched()) {
1108 unlockInsetInInset(bv, the_locking_inset);
1109 // we need to update if this was requested before
1111 return DispatchResult(false);
1121 if (result.val() >= FINISHED)
1122 bv->unlockInset(this);
1123 else if (!the_locking_inset && bv->fitCursor())
1130 int InsetTabular::latex(Buffer const & buf, ostream & os,
1131 LatexRunParams const & runparams) const
1133 return tabular.latex(buf, os, runparams);
1137 int InsetTabular::ascii(Buffer const & buf, ostream & os,
1138 LatexRunParams const & runparams) const
1140 if (runparams.linelen > 0)
1141 return tabular.ascii(buf, os, runparams,
1142 ownerPar(buf, this).params().depth(),
1144 return tabular.ascii(buf, os, runparams, 0, false, 0);
1148 int InsetTabular::linuxdoc(Buffer const & buf, ostream & os,
1149 LatexRunParams const & runparams) const
1151 return tabular.linuxdoc(buf,os, runparams);
1155 int InsetTabular::docbook(Buffer const & buf, ostream & os,
1156 LatexRunParams const & runparams) const
1161 // if the table is inside a float it doesn't need the informaltable
1162 // wrapper. Search for it.
1163 for (master = owner();
1164 master && master->lyxCode() != InsetOld::FLOAT_CODE;
1165 master = master->owner());
1168 os << "<informaltable>";
1169 if (runparams.mixed_content)
1173 ret += tabular.docbook(buf, os, runparams);
1175 os << "</informaltable>";
1176 if (runparams.mixed_content)
1184 void InsetTabular::validate(LaTeXFeatures & features) const
1186 tabular.validate(features);
1190 void InsetTabular::calculate_dimensions_of_cells(MetricsInfo & mi) const
1193 // if we have a locking_inset we should have to check only this cell for
1194 // change so I'll try this to have a boost, but who knows ;) (Jug?)
1195 // This is _really_ important (André)
1196 if (the_locking_inset == &tabular.getCellInset(actcell)) {
1199 for (int j = 0; j < tabular.columns(); ++j) {
1203 tabular.column_info[j].p_width.inPixels(mi.base.textwidth);
1204 tabular.getCellInset(actrow, j).metrics(m, dim);
1205 maxAsc = max(dim.asc, maxAsc);
1206 maxDesc = max(dim.des, maxDesc);
1208 tabular.setWidthOfCell(actcell, the_locking_inset->width());
1209 tabular.setAscentOfRow(actrow, maxAsc + ADD_TO_HEIGHT);
1210 tabular.setDescentOfRow(actrow, maxDesc + ADD_TO_HEIGHT);
1216 for (int i = 0; i < tabular.rows(); ++i) {
1219 for (int j = 0; j < tabular.columns(); ++j) {
1220 if (tabular.isPartOfMultiColumn(i, j))
1226 tabular.column_info[j].p_width.inPixels(mi.base.textwidth);
1227 tabular.getCellInset(cell).metrics(m, dim);
1228 maxAsc = max(maxAsc, dim.asc);
1229 maxDesc = max(maxDesc, dim.des);
1230 tabular.setWidthOfCell(cell, dim.wid);
1232 tabular.setAscentOfRow(i, maxAsc + ADD_TO_HEIGHT);
1233 tabular.setDescentOfRow(i, maxDesc + ADD_TO_HEIGHT);
1238 void InsetTabular::getCursor(BufferView & bv, int & x, int & y) const
1240 if (the_locking_inset) {
1241 the_locking_inset->getCursor(bv, x, y);
1246 y = cursory_ + InsetTabular::y();
1249 int desc = tabular.getDescentOfRow(actrow);
1251 int ascdesc = tabular.getAscentOfRow(actrow) + desc;
1253 y += ADD_TO_HEIGHT * 2;
1254 y += TEXT_TO_INSET_OFFSET;
1258 void InsetTabular::getCursorPos(BufferView * bv, int & x, int & y) const
1260 if (the_locking_inset) {
1261 the_locking_inset->getCursorPos(bv, x, y);
1264 x = cursorx_ - top_x;
1269 void InsetTabular::fitInsetCursor(BufferView * bv) const
1271 if (the_locking_inset) {
1272 the_locking_inset->fitInsetCursor(bv);
1277 int const asc = font_metrics::maxAscent(font);
1278 int const desc = font_metrics::maxDescent(font);
1281 bv->fitLockedInsetCursor(cursorx_, cursory_, asc, desc);
1285 void InsetTabular::setPos(BufferView * bv, int x, int y) const
1288 actcell = actrow = actcol = 0;
1289 int ly = tabular.getDescentOfRow(actrow);
1291 // first search the right row
1292 while (ly < y && actrow + 1 < tabular.rows()) {
1293 cursory_ += tabular.getDescentOfRow(actrow) +
1294 tabular.getAscentOfRow(actrow + 1) +
1295 tabular.getAdditionalHeight(actrow + 1);
1297 ly = cursory_ + tabular.getDescentOfRow(actrow);
1299 actcell = tabular.getCellNumber(actrow, actcol);
1301 // now search the right column
1302 int lx = tabular.getWidthOfColumn(actcell) -
1303 tabular.getAdditionalWidth(actcell);
1305 for (; !tabular.isLastCellInRow(actcell) && lx < x; ++actcell)
1306 lx += tabular.getWidthOfColumn(actcell + 1)
1307 + tabular.getAdditionalWidth(actcell);
1309 cursorx_ = lx - tabular.getWidthOfColumn(actcell) + top_x + 2;
1314 int InsetTabular::getCellXPos(int cell) const
1318 for (; !tabular.isFirstCellInRow(c); --c)
1320 int lx = tabular.getWidthOfColumn(cell);
1321 for (; c < cell; ++c)
1322 lx += tabular.getWidthOfColumn(c);
1324 return (lx - tabular.getWidthOfColumn(cell) + top_x);
1328 void InsetTabular::resetPos(BufferView * bv) const
1330 #ifdef WITH_WARNINGS
1331 #warning This should be fixed in the right manner (20011128 Jug)
1333 // fast hack to fix infinite repaintings!
1334 if (in_reset_pos > 0)
1338 actcol = tabular.column_of_cell(actcell);
1341 for (; cell < actcell && !tabular.isLastRow(cell); ++cell) {
1342 if (tabular.isLastCellInRow(cell)) {
1343 cursory_ += tabular.getDescentOfRow(actrow) +
1344 tabular.getAscentOfRow(actrow + 1) +
1345 tabular.getAdditionalHeight(actrow + 1);
1350 if (the_locking_inset)
1354 // we need this only from here on!!!
1356 int const offset = ADD_TO_TABULAR_WIDTH + 2;
1357 int new_x = getCellXPos(actcell);
1358 int old_x = cursorx_;
1361 // cursor.x(getCellXPos(actcell) + offset);
1362 if (actcol < tabular.columns() - 1 && scroll(false) &&
1363 tabular.getWidthOfTabular() < bv->workWidth()-20)
1367 } else if (the_locking_inset &&
1368 tabular.getWidthOfColumn(actcell) > bv->workWidth() - 20)
1370 int xx = cursorx_ - offset + bv->text->getRealCursorX();
1371 if (xx > bv->workWidth()-20) {
1372 scroll(bv, -(xx - bv->workWidth() + 60));
1374 } else if (xx < 20) {
1382 } else if (cursorx_ - offset > 20 &&
1383 cursorx_ - offset + tabular.getWidthOfColumn(actcell)
1384 > bv->workWidth() - 20) {
1385 scroll(bv, -tabular.getWidthOfColumn(actcell) - 20);
1387 } else if (cursorx_ - offset < 20) {
1388 scroll(bv, 20 - cursorx_ + offset);
1390 } else if (scroll() && top_x > 20 &&
1391 (top_x + tabular.getWidthOfTabular()) > bv->workWidth() - 20) {
1392 scroll(bv, old_x - cursorx_);
1395 if (the_locking_inset) {
1396 inset_x = cursorx_ - top_x + tabular.getBeginningOfTextInCell(actcell);
1399 if ((!the_locking_inset ||
1400 !the_locking_inset->getFirstLockingInsetOfType(TABULAR_CODE)) &&
1401 actcell != oldcell) {
1402 InsetTabularMailer(*this).updateDialog(bv);
1409 DispatchResult InsetTabular::moveRight(BufferView * bv, bool lock)
1411 if (lock && !old_locking_inset) {
1412 if (activateCellInset(bv))
1413 return DispatchResult(true, true);
1415 bool moved = isRightToLeft(bv)
1416 ? movePrevCell(bv) : moveNextCell(bv);
1418 return DispatchResult(false, FINISHED_RIGHT);
1419 if (lock && activateCellInset(bv))
1420 return DispatchResult(true, true);
1423 return DispatchResult(true);
1427 DispatchResult InsetTabular::moveLeft(BufferView * bv, bool lock)
1429 bool moved = isRightToLeft(bv) ? moveNextCell(bv) : movePrevCell(bv);
1431 return DispatchResult(false, FINISHED);
1433 if (lock && activateCellInset(bv, 0, 0, mouse_button::none, true))
1434 return DispatchResult(true, true);
1436 return DispatchResult(true);
1440 DispatchResult InsetTabular::moveUp(BufferView * bv, bool lock)
1442 int const ocell = actcell;
1443 actcell = tabular.getCellAbove(actcell);
1444 if (actcell == ocell) // we moved out of the inset
1445 return DispatchResult(false, FINISHED_UP);
1450 if (old_locking_inset) {
1451 old_locking_inset->getCursorPos(bv, x, y);
1452 x -= cursorx_ + tabular.getBeginningOfTextInCell(actcell);
1454 if (activateCellInset(bv, x, 0))
1455 return DispatchResult(true, true);
1457 return DispatchResult(true);
1461 DispatchResult InsetTabular::moveDown(BufferView * bv, bool lock)
1463 int const ocell = actcell;
1464 actcell = tabular.getCellBelow(actcell);
1465 if (actcell == ocell) // we moved out of the inset
1466 return DispatchResult(false, FINISHED_DOWN);
1471 if (old_locking_inset) {
1472 old_locking_inset->getCursorPos(bv, x, y);
1473 x -= cursorx_ + tabular.getBeginningOfTextInCell(actcell);
1475 if (activateCellInset(bv, x, 0))
1476 return DispatchResult(true, true);
1478 return DispatchResult(true);
1482 bool InsetTabular::moveNextCell(BufferView * bv, bool lock)
1484 if (isRightToLeft(bv)) {
1485 if (tabular.isFirstCellInRow(actcell)) {
1486 int row = tabular.row_of_cell(actcell);
1487 if (row == tabular.rows() - 1)
1489 actcell = tabular.getLastCellInRow(row);
1490 actcell = tabular.getCellBelow(actcell);
1497 if (tabular.isLastCell(actcell))
1502 bool rtl = tabular.getCellInset(actcell).paragraphs.begin()->
1503 isRightToLeftPar(bv->buffer()->params());
1504 activateCellInset(bv, 0, 0, mouse_button::none, !rtl);
1511 bool InsetTabular::movePrevCell(BufferView * bv, bool lock)
1513 if (isRightToLeft(bv)) {
1514 if (tabular.isLastCellInRow(actcell)) {
1515 int row = tabular.row_of_cell(actcell);
1518 actcell = tabular.getFirstCellInRow(row);
1519 actcell = tabular.getCellAbove(actcell);
1521 if (tabular.isLastCell(actcell))
1526 if (!actcell) // first cell
1531 bool rtl = tabular.getCellInset(actcell).paragraphs.begin()->
1532 isRightToLeftPar(bv->buffer()->params());
1533 activateCellInset(bv, 0, 0, mouse_button::none, !rtl);
1540 void InsetTabular::setFont(BufferView * bv, LyXFont const & font, bool tall,
1544 setSelection(0, tabular.getNumberOfCells() - 1);
1546 if (hasSelection()) {
1547 recordUndo(bv, Undo::ATOMIC);
1548 bool const frozen = undo_frozen;
1551 // apply the fontchange on the whole selection
1556 getSelection(sel_row_start, sel_row_end, sel_col_start, sel_col_end);
1557 for (int i = sel_row_start; i <= sel_row_end; ++i)
1558 for (int j = sel_col_start; j <= sel_col_end; ++j)
1559 tabular.getCellInset(i, j).setFont(bv, font, tall, true);
1567 if (the_locking_inset)
1568 the_locking_inset->setFont(bv, font, tall);
1572 bool InsetTabular::tabularFeatures(BufferView * bv, string const & what)
1574 LyXTabular::Feature action = LyXTabular::LAST_ACTION;
1577 for (; tabularFeature[i].action != LyXTabular::LAST_ACTION; ++i) {
1578 string const tmp = tabularFeature[i].feature;
1580 if (tmp == what.substr(0, tmp.length())) {
1581 //if (!compare(tabularFeatures[i].feature.c_str(), what.c_str(),
1582 //tabularFeatures[i].feature.length())) {
1583 action = tabularFeature[i].action;
1587 if (action == LyXTabular::LAST_ACTION)
1591 ltrim(what.substr(tabularFeature[i].feature.length()));
1592 tabularFeatures(bv, action, val);
1598 void checkLongtableSpecial(LyXTabular::ltType & ltt,
1599 string const & special, bool & flag)
1601 if (special == "dl_above") {
1604 } else if (special == "dl_below") {
1605 ltt.bottomDL = flag;
1607 } else if (special == "empty") {
1619 void InsetTabular::tabularFeatures(BufferView * bv,
1620 LyXTabular::Feature feature, string const & value)
1626 bool setLines = false;
1627 LyXAlignment setAlign = LYX_ALIGN_LEFT;
1628 LyXTabular::VAlignment setVAlign = LyXTabular::LYX_VALIGN_TOP;
1632 case LyXTabular::M_ALIGN_LEFT:
1633 case LyXTabular::ALIGN_LEFT:
1634 setAlign = LYX_ALIGN_LEFT;
1637 case LyXTabular::M_ALIGN_RIGHT:
1638 case LyXTabular::ALIGN_RIGHT:
1639 setAlign = LYX_ALIGN_RIGHT;
1642 case LyXTabular::M_ALIGN_CENTER:
1643 case LyXTabular::ALIGN_CENTER:
1644 setAlign = LYX_ALIGN_CENTER;
1647 case LyXTabular::ALIGN_BLOCK:
1648 setAlign = LYX_ALIGN_BLOCK;
1651 case LyXTabular::M_VALIGN_TOP:
1652 case LyXTabular::VALIGN_TOP:
1653 setVAlign = LyXTabular::LYX_VALIGN_TOP;
1656 case LyXTabular::M_VALIGN_BOTTOM:
1657 case LyXTabular::VALIGN_BOTTOM:
1658 setVAlign = LyXTabular::LYX_VALIGN_BOTTOM;
1661 case LyXTabular::M_VALIGN_MIDDLE:
1662 case LyXTabular::VALIGN_MIDDLE:
1663 setVAlign = LyXTabular::LYX_VALIGN_MIDDLE;
1670 if (hasSelection()) {
1671 getSelection(sel_row_start, sel_row_end, sel_col_start, sel_col_end);
1673 sel_col_start = sel_col_end = tabular.column_of_cell(actcell);
1674 sel_row_start = sel_row_end = tabular.row_of_cell(actcell);
1676 recordUndo(bv, Undo::ATOMIC);
1678 int row = tabular.row_of_cell(actcell);
1679 int column = tabular.column_of_cell(actcell);
1681 LyXTabular::ltType ltt;
1685 case LyXTabular::SET_PWIDTH: {
1686 LyXLength const len(value);
1687 LyXLength const & oldlen = tabular.getColumnPWidth(actcell);
1689 tabular.setColumnPWidth(actcell, len);
1690 if (oldlen != len) {
1691 // We need this otherwise we won't resize
1692 // the insettext of the active cell (if any)
1693 // until later (see InsetText::do_resize)
1694 unlockInsetInInset(bv, the_locking_inset);
1699 && tabular.getAlignment(actcell, true) == LYX_ALIGN_BLOCK)
1700 tabularFeatures(bv, LyXTabular::ALIGN_CENTER, string());
1701 else if (!len.zero()
1702 && tabular.getAlignment(actcell, true) != LYX_ALIGN_BLOCK)
1703 tabularFeatures(bv, LyXTabular::ALIGN_BLOCK, string());
1707 case LyXTabular::SET_MPWIDTH:
1709 LyXLength const len(value);
1710 LyXLength const & oldlen = tabular.getPWidth(actcell);
1711 tabular.setMColumnPWidth(actcell, len);
1712 if (oldlen != len) {
1713 // We need this otherwise we won't resize
1714 // the insettext of the active cell (if any)
1715 // until later (see InsetText::do_resize)
1716 unlockInsetInInset(bv, the_locking_inset);
1722 case LyXTabular::SET_SPECIAL_COLUMN:
1723 case LyXTabular::SET_SPECIAL_MULTI:
1724 tabular.setAlignSpecial(actcell,value,feature);
1728 case LyXTabular::APPEND_ROW:
1729 // append the row into the tabular
1730 unlockInsetInInset(bv, the_locking_inset);
1731 tabular.appendRow(bv->buffer()->params(), actcell);
1732 tabular.setOwner(this);
1736 case LyXTabular::APPEND_COLUMN:
1737 // append the column into the tabular
1738 unlockInsetInInset(bv, the_locking_inset);
1739 tabular.appendColumn(bv->buffer()->params(), actcell);
1740 tabular.setOwner(this);
1741 actcell = tabular.getCellNumber(row, column);
1745 case LyXTabular::DELETE_ROW:
1746 unlockInsetInInset(bv, the_locking_inset);
1747 for (int i = sel_row_start; i <= sel_row_end; ++i)
1748 tabular.deleteRow(sel_row_start);
1749 if (sel_row_start >= tabular.rows())
1751 actcell = tabular.getCellNumber(sel_row_start, column);
1756 case LyXTabular::DELETE_COLUMN:
1757 unlockInsetInInset(bv, the_locking_inset);
1758 for (int i = sel_col_start; i <= sel_col_end; ++i)
1759 tabular.deleteColumn(sel_col_start);
1760 if (sel_col_start >= tabular.columns())
1762 actcell = tabular.getCellNumber(row, sel_col_start);
1767 case LyXTabular::M_TOGGLE_LINE_TOP:
1769 case LyXTabular::TOGGLE_LINE_TOP: {
1770 bool lineSet = !tabular.topLine(actcell, flag);
1771 for (int i = sel_row_start; i <= sel_row_end; ++i)
1772 for (int j = sel_col_start; j <= sel_col_end; ++j)
1774 tabular.getCellNumber(i, j),
1780 case LyXTabular::M_TOGGLE_LINE_BOTTOM:
1782 case LyXTabular::TOGGLE_LINE_BOTTOM: {
1783 bool lineSet = !tabular.bottomLine(actcell, flag);
1784 for (int i = sel_row_start; i <= sel_row_end; ++i)
1785 for (int j = sel_col_start; j <= sel_col_end; ++j)
1786 tabular.setBottomLine(
1787 tabular.getCellNumber(i, j),
1794 case LyXTabular::M_TOGGLE_LINE_LEFT:
1796 case LyXTabular::TOGGLE_LINE_LEFT: {
1797 bool lineSet = !tabular.leftLine(actcell, flag);
1798 for (int i = sel_row_start; i <= sel_row_end; ++i)
1799 for (int j = sel_col_start; j <= sel_col_end; ++j)
1800 tabular.setLeftLine(
1801 tabular.getCellNumber(i,j),
1808 case LyXTabular::M_TOGGLE_LINE_RIGHT:
1810 case LyXTabular::TOGGLE_LINE_RIGHT: {
1811 bool lineSet = !tabular.rightLine(actcell, flag);
1812 for (int i = sel_row_start; i <= sel_row_end; ++i)
1813 for (int j = sel_col_start; j <= sel_col_end; ++j)
1814 tabular.setRightLine(
1815 tabular.getCellNumber(i,j),
1822 case LyXTabular::M_ALIGN_LEFT:
1823 case LyXTabular::M_ALIGN_RIGHT:
1824 case LyXTabular::M_ALIGN_CENTER:
1826 case LyXTabular::ALIGN_LEFT:
1827 case LyXTabular::ALIGN_RIGHT:
1828 case LyXTabular::ALIGN_CENTER:
1829 case LyXTabular::ALIGN_BLOCK:
1830 for (int i = sel_row_start; i <= sel_row_end; ++i)
1831 for (int j = sel_col_start; j <= sel_col_end; ++j)
1832 tabular.setAlignment(
1833 tabular.getCellNumber(i, j),
1839 case LyXTabular::M_VALIGN_TOP:
1840 case LyXTabular::M_VALIGN_BOTTOM:
1841 case LyXTabular::M_VALIGN_MIDDLE:
1843 case LyXTabular::VALIGN_TOP:
1844 case LyXTabular::VALIGN_BOTTOM:
1845 case LyXTabular::VALIGN_MIDDLE:
1846 for (int i = sel_row_start; i <= sel_row_end; ++i)
1847 for (int j = sel_col_start; j <= sel_col_end; ++j)
1848 tabular.setVAlignment(
1849 tabular.getCellNumber(i, j),
1854 case LyXTabular::MULTICOLUMN: {
1855 if (sel_row_start != sel_row_end) {
1856 #ifdef WITH_WARNINGS
1857 #warning Need I say it ? This is horrible.
1859 Alert::error(_("Error setting multicolumn"),
1860 _("You cannot set multicolumn vertically."));
1863 // just multicol for one Single Cell
1864 if (!hasSelection()) {
1865 // check wether we are completly in a multicol
1866 if (tabular.isMultiColumn(actcell))
1867 tabular.unsetMultiColumn(actcell);
1869 tabular.setMultiColumn(bv->buffer(), actcell, 1);
1873 // we have a selection so this means we just add all this
1874 // cells to form a multicolumn cell
1878 if (sel_cell_start > sel_cell_end) {
1879 s_start = sel_cell_end;
1880 s_end = sel_cell_start;
1882 s_start = sel_cell_start;
1883 s_end = sel_cell_end;
1885 tabular.setMultiColumn(bv->buffer(), s_start, s_end - s_start + 1);
1892 case LyXTabular::SET_ALL_LINES:
1894 case LyXTabular::UNSET_ALL_LINES:
1895 for (int i = sel_row_start; i <= sel_row_end; ++i)
1896 for (int j = sel_col_start; j <= sel_col_end; ++j)
1897 tabular.setAllLines(
1898 tabular.getCellNumber(i,j), setLines);
1902 case LyXTabular::SET_LONGTABULAR:
1903 tabular.setLongTabular(true);
1904 updateLocal(bv); // because this toggles displayed
1907 case LyXTabular::UNSET_LONGTABULAR:
1908 tabular.setLongTabular(false);
1909 updateLocal(bv); // because this toggles displayed
1912 case LyXTabular::SET_ROTATE_TABULAR:
1913 tabular.setRotateTabular(true);
1916 case LyXTabular::UNSET_ROTATE_TABULAR:
1917 tabular.setRotateTabular(false);
1920 case LyXTabular::SET_ROTATE_CELL:
1921 for (int i = sel_row_start; i <= sel_row_end; ++i)
1922 for (int j = sel_col_start; j <= sel_col_end; ++j)
1923 tabular.setRotateCell(
1924 tabular.getCellNumber(i, j), true);
1927 case LyXTabular::UNSET_ROTATE_CELL:
1928 for (int i = sel_row_start; i <= sel_row_end; ++i)
1929 for (int j = sel_col_start; j <= sel_col_end; ++j)
1930 tabular.setRotateCell(
1931 tabular.getCellNumber(i, j), false);
1934 case LyXTabular::SET_USEBOX: {
1935 LyXTabular::BoxType val = LyXTabular::BoxType(strToInt(value));
1936 if (val == tabular.getUsebox(actcell))
1937 val = LyXTabular::BOX_NONE;
1938 for (int i = sel_row_start; i <= sel_row_end; ++i)
1939 for (int j = sel_col_start; j <= sel_col_end; ++j)
1940 tabular.setUsebox(tabular.getCellNumber(i, j), val);
1944 case LyXTabular::UNSET_LTFIRSTHEAD:
1946 case LyXTabular::SET_LTFIRSTHEAD:
1947 tabular.getRowOfLTFirstHead(row, ltt);
1948 checkLongtableSpecial(ltt, value, flag);
1949 tabular.setLTHead(row, flag, ltt, true);
1952 case LyXTabular::UNSET_LTHEAD:
1954 case LyXTabular::SET_LTHEAD:
1955 tabular.getRowOfLTHead(row, ltt);
1956 checkLongtableSpecial(ltt, value, flag);
1957 tabular.setLTHead(row, flag, ltt, false);
1960 case LyXTabular::UNSET_LTFOOT:
1962 case LyXTabular::SET_LTFOOT:
1963 tabular.getRowOfLTFoot(row, ltt);
1964 checkLongtableSpecial(ltt, value, flag);
1965 tabular.setLTFoot(row, flag, ltt, false);
1968 case LyXTabular::UNSET_LTLASTFOOT:
1970 case LyXTabular::SET_LTLASTFOOT:
1971 tabular.getRowOfLTLastFoot(row, ltt);
1972 checkLongtableSpecial(ltt, value, flag);
1973 tabular.setLTFoot(row, flag, ltt, true);
1976 case LyXTabular::SET_LTNEWPAGE:
1977 tabular.setLTNewPage(row, !tabular.getLTNewPage(row));
1980 // dummy stuff just to avoid warnings
1981 case LyXTabular::LAST_ACTION:
1985 InsetTabularMailer(*this).updateDialog(bv);
1989 bool InsetTabular::activateCellInset(BufferView * bv, int x, int y,
1990 mouse_button::state button, bool behind)
1992 UpdatableInset & inset = tabular.getCellInset(actcell);
1995 x = inset.x() + inset.width();
1996 y = inset.descent();
1998 //inset_x = cursorx_ - top_x + tabular.getBeginningOfTextInCell(actcell);
1999 //inset_y = cursory_;
2000 inset.dispatch(FuncRequest(bv, LFUN_INSET_EDIT, x, y, button));
2001 if (!the_locking_inset)
2004 return the_locking_inset;
2008 bool InsetTabular::insetHit(BufferView *, int x, int) const
2010 return x + top_x > cursorx_ + tabular.getBeginningOfTextInCell(actcell);
2014 void InsetTabular::deleteLyXText(BufferView * /*bv*/, bool /*recursive*/) const
2016 //resizeLyXText(bv, recursive);
2020 LyXText * InsetTabular::getLyXText(BufferView const * bv,
2021 bool const recursive) const
2023 if (the_locking_inset)
2024 return the_locking_inset->getLyXText(bv, recursive);
2025 return InsetOld::getLyXText(bv, recursive);
2029 bool InsetTabular::showInsetDialog(BufferView * bv) const
2031 if (!the_locking_inset || !the_locking_inset->showInsetDialog(bv))
2032 InsetTabularMailer(*this).showDialog(bv);
2037 void InsetTabular::openLayoutDialog(BufferView * bv) const
2039 if (the_locking_inset) {
2040 InsetTabular * inset = static_cast<InsetTabular *>
2041 (the_locking_inset->getFirstLockingInsetOfType(TABULAR_CODE));
2043 inset->openLayoutDialog(bv);
2047 InsetTabularMailer(*this).showDialog(bv);
2052 // function returns an object as defined in func_status.h:
2053 // states OK, Unknown, Disabled, On, Off.
2055 FuncStatus InsetTabular::getStatus(string const & what) const
2057 int action = LyXTabular::LAST_ACTION;
2061 for (; tabularFeature[i].action != LyXTabular::LAST_ACTION; ++i) {
2062 string const tmp = tabularFeature[i].feature;
2063 if (tmp == what.substr(0, tmp.length())) {
2064 //if (!compare(tabularFeatures[i].feature.c_str(), what.c_str(),
2065 // tabularFeatures[i].feature.length())) {
2066 action = tabularFeature[i].action;
2070 if (action == LyXTabular::LAST_ACTION) {
2072 status.unknown(true);
2076 string const argument
2077 = ltrim(what.substr(tabularFeature[i].feature.length()));
2082 LyXTabular::ltType dummyltt;
2086 getSelection(sel_row_start, sel_row_end, dummy, dummy);
2088 sel_row_start = sel_row_end = tabular.row_of_cell(actcell);
2091 case LyXTabular::SET_PWIDTH:
2092 case LyXTabular::SET_MPWIDTH:
2093 case LyXTabular::SET_SPECIAL_COLUMN:
2094 case LyXTabular::SET_SPECIAL_MULTI:
2095 case LyXTabular::APPEND_ROW:
2096 case LyXTabular::APPEND_COLUMN:
2097 case LyXTabular::DELETE_ROW:
2098 case LyXTabular::DELETE_COLUMN:
2099 case LyXTabular::SET_ALL_LINES:
2100 case LyXTabular::UNSET_ALL_LINES:
2104 case LyXTabular::MULTICOLUMN:
2105 status.setOnOff(tabular.isMultiColumn(actcell));
2108 case LyXTabular::M_TOGGLE_LINE_TOP:
2110 case LyXTabular::TOGGLE_LINE_TOP:
2111 status.setOnOff(tabular.topLine(actcell, flag));
2114 case LyXTabular::M_TOGGLE_LINE_BOTTOM:
2116 case LyXTabular::TOGGLE_LINE_BOTTOM:
2117 status.setOnOff(tabular.bottomLine(actcell, flag));
2120 case LyXTabular::M_TOGGLE_LINE_LEFT:
2122 case LyXTabular::TOGGLE_LINE_LEFT:
2123 status.setOnOff(tabular.leftLine(actcell, flag));
2126 case LyXTabular::M_TOGGLE_LINE_RIGHT:
2128 case LyXTabular::TOGGLE_LINE_RIGHT:
2129 status.setOnOff(tabular.rightLine(actcell, flag));
2132 case LyXTabular::M_ALIGN_LEFT:
2134 case LyXTabular::ALIGN_LEFT:
2135 status.setOnOff(tabular.getAlignment(actcell, flag) == LYX_ALIGN_LEFT);
2138 case LyXTabular::M_ALIGN_RIGHT:
2140 case LyXTabular::ALIGN_RIGHT:
2141 status.setOnOff(tabular.getAlignment(actcell, flag) == LYX_ALIGN_RIGHT);
2144 case LyXTabular::M_ALIGN_CENTER:
2146 case LyXTabular::ALIGN_CENTER:
2147 status.setOnOff(tabular.getAlignment(actcell, flag) == LYX_ALIGN_CENTER);
2150 case LyXTabular::ALIGN_BLOCK:
2151 status.disabled(tabular.getPWidth(actcell).zero());
2152 status.setOnOff(tabular.getAlignment(actcell, flag) == LYX_ALIGN_BLOCK);
2155 case LyXTabular::M_VALIGN_TOP:
2157 case LyXTabular::VALIGN_TOP:
2158 status.setOnOff(tabular.getVAlignment(actcell, flag) == LyXTabular::LYX_VALIGN_TOP);
2161 case LyXTabular::M_VALIGN_BOTTOM:
2163 case LyXTabular::VALIGN_BOTTOM:
2164 status.setOnOff(tabular.getVAlignment(actcell, flag) == LyXTabular::LYX_VALIGN_BOTTOM);
2167 case LyXTabular::M_VALIGN_MIDDLE:
2169 case LyXTabular::VALIGN_MIDDLE:
2170 status.setOnOff(tabular.getVAlignment(actcell, flag) == LyXTabular::LYX_VALIGN_MIDDLE);
2173 case LyXTabular::SET_LONGTABULAR:
2174 status.setOnOff(tabular.isLongTabular());
2177 case LyXTabular::UNSET_LONGTABULAR:
2178 status.setOnOff(!tabular.isLongTabular());
2181 case LyXTabular::SET_ROTATE_TABULAR:
2182 status.setOnOff(tabular.getRotateTabular());
2185 case LyXTabular::UNSET_ROTATE_TABULAR:
2186 status.setOnOff(!tabular.getRotateTabular());
2189 case LyXTabular::SET_ROTATE_CELL:
2190 status.setOnOff(tabular.getRotateCell(actcell));
2193 case LyXTabular::UNSET_ROTATE_CELL:
2194 status.setOnOff(!tabular.getRotateCell(actcell));
2197 case LyXTabular::SET_USEBOX:
2198 status.setOnOff(strToInt(argument) == tabular.getUsebox(actcell));
2201 case LyXTabular::SET_LTFIRSTHEAD:
2202 status.setOnOff(tabular.getRowOfLTHead(sel_row_start, dummyltt));
2205 case LyXTabular::SET_LTHEAD:
2206 status.setOnOff(tabular.getRowOfLTHead(sel_row_start, dummyltt));
2209 case LyXTabular::SET_LTFOOT:
2210 status.setOnOff(tabular.getRowOfLTFoot(sel_row_start, dummyltt));
2213 case LyXTabular::SET_LTLASTFOOT:
2214 status.setOnOff(tabular.getRowOfLTFoot(sel_row_start, dummyltt));
2217 case LyXTabular::SET_LTNEWPAGE:
2218 status.setOnOff(tabular.getLTNewPage(sel_row_start));
2223 status.disabled(true);
2230 void InsetTabular::getLabelList(Buffer const & buffer,
2231 std::vector<string> & list) const
2233 tabular.getLabelList(buffer, list);
2237 bool InsetTabular::copySelection(BufferView * bv)
2239 if (!hasSelection())
2242 int sel_col_start = tabular.column_of_cell(sel_cell_start);
2243 int sel_col_end = tabular.column_of_cell(sel_cell_end);
2244 if (sel_col_start > sel_col_end) {
2245 sel_col_start = sel_col_end;
2246 sel_col_end = tabular.right_column_of_cell(sel_cell_start);
2248 sel_col_end = tabular.right_column_of_cell(sel_cell_end);
2251 int sel_row_start = tabular.row_of_cell(sel_cell_start);
2252 int sel_row_end = tabular.row_of_cell(sel_cell_end);
2253 if (sel_row_start > sel_row_end)
2254 swap(sel_row_start, sel_row_end);
2256 paste_tabular.reset(new LyXTabular(tabular));
2257 paste_tabular->setOwner(this);
2259 for (int i = 0; i < sel_row_start; ++i)
2260 paste_tabular->deleteRow(0);
2262 int const rows = sel_row_end - sel_row_start + 1;
2263 while (paste_tabular->rows() > rows)
2264 paste_tabular->deleteRow(rows);
2266 paste_tabular->setTopLine(0, true, true);
2267 paste_tabular->setBottomLine(paste_tabular->getFirstCellInRow(rows - 1),
2270 for (int i = 0; i < sel_col_start; ++i)
2271 paste_tabular->deleteColumn(0);
2273 int const columns = sel_col_end - sel_col_start + 1;
2274 while (paste_tabular->columns() > columns)
2275 paste_tabular->deleteColumn(columns);
2277 paste_tabular->setLeftLine(0, true, true);
2278 paste_tabular->setRightLine(paste_tabular->getLastCellInRow(0),
2282 LatexRunParams const runparams;
2283 paste_tabular->ascii(*bv->buffer(), os, runparams,
2284 ownerPar(*bv->buffer(), this).params().depth(), true, '\t');
2285 bv->stuffClipboard(os.str());
2290 bool InsetTabular::pasteSelection(BufferView * bv)
2295 for (int r1 = 0, r2 = actrow;
2296 r1 < paste_tabular->rows() && r2 < tabular.rows();
2298 for (int c1 = 0, c2 = actcol;
2299 c1 < paste_tabular->columns() && c2 < tabular.columns();
2301 if (paste_tabular->isPartOfMultiColumn(r1, c1) &&
2302 tabular.isPartOfMultiColumn(r2, c2))
2304 if (paste_tabular->isPartOfMultiColumn(r1, c1)) {
2308 if (tabular.isPartOfMultiColumn(r2, c2)) {
2312 InsetText & inset = tabular.getCellInset(r2, c2);
2313 inset = paste_tabular->getCellInset(r1, c1);
2314 inset.setOwner(this);
2315 inset.deleteLyXText(bv);
2323 bool InsetTabular::cutSelection(BufferParams const & bp)
2325 if (!hasSelection())
2328 int sel_col_start = tabular.column_of_cell(sel_cell_start);
2329 int sel_col_end = tabular.column_of_cell(sel_cell_end);
2330 if (sel_col_start > sel_col_end) {
2331 sel_col_start = sel_col_end;
2332 sel_col_end = tabular.right_column_of_cell(sel_cell_start);
2334 sel_col_end = tabular.right_column_of_cell(sel_cell_end);
2337 int sel_row_start = tabular.row_of_cell(sel_cell_start);
2338 int sel_row_end = tabular.row_of_cell(sel_cell_end);
2340 if (sel_row_start > sel_row_end)
2341 swap(sel_row_start, sel_row_end);
2343 if (sel_cell_start > sel_cell_end)
2344 swap(sel_cell_start, sel_cell_end);
2346 for (int i = sel_row_start; i <= sel_row_end; ++i)
2347 for (int j = sel_col_start; j <= sel_col_end; ++j)
2348 tabular.getCellInset(tabular.getCellNumber(i, j))
2349 .clear(bp.tracking_changes);
2354 bool InsetTabular::isRightToLeft(BufferView * bv)
2356 return bv->getParentLanguage(this)->RightToLeft();
2360 int InsetTabular::scroll(bool recursive) const
2362 int sx = UpdatableInset::scroll(false);
2364 if (recursive && the_locking_inset)
2365 sx += the_locking_inset->scroll(recursive);
2371 void InsetTabular::getSelection(int & srow, int & erow,
2372 int & scol, int & ecol) const
2374 int const start = hasSelection() ? sel_cell_start : actcell;
2375 int const end = hasSelection() ? sel_cell_end : actcell;
2377 srow = tabular.row_of_cell(start);
2378 erow = tabular.row_of_cell(end);
2382 scol = tabular.column_of_cell(start);
2383 ecol = tabular.column_of_cell(end);
2387 ecol = tabular.right_column_of_cell(end);
2391 ParagraphList * InsetTabular::getParagraphs(int i) const
2393 return i < tabular.getNumberOfCells()
2394 ? tabular.getCellInset(i).getParagraphs(0)
2399 int InsetTabular::numParagraphs() const
2401 return tabular.getNumberOfCells();
2405 LyXText * InsetTabular::getText(int i) const
2407 return i < tabular.getNumberOfCells()
2408 ? tabular.getCellInset(i).getText(0)
2413 LyXCursor const & InsetTabular::cursor(BufferView * bv) const
2415 if (the_locking_inset)
2416 return the_locking_inset->cursor(bv);
2417 return InsetOld::cursor(bv);
2421 void InsetTabular::markErased()
2423 for (int cell = 0; cell < tabular.getNumberOfCells(); ++cell)
2424 tabular.getCellInset(cell).markErased();
2428 bool InsetTabular::nextChange(BufferView * bv, lyx::pos_type & length)
2430 if (the_locking_inset) {
2431 if (the_locking_inset->nextChange(bv, length)) {
2435 if (tabular.isLastCell(actcell))
2439 InsetText & inset = tabular.getCellInset(actcell);
2440 if (inset.nextChange(bv, length)) {
2444 while (!tabular.isLastCell(actcell)) {
2446 InsetText & inset = tabular.getCellInset(actcell);
2447 if (inset.nextChange(bv, length)) {
2456 bool InsetTabular::searchForward(BufferView * bv, string const & str,
2460 if (the_locking_inset) {
2461 if (the_locking_inset->searchForward(bv, str, cs, mw)) {
2465 if (tabular.isLastCell(actcell))
2469 InsetText & inset = tabular.getCellInset(cell);
2470 if (inset.searchForward(bv, str, cs, mw)) {
2474 while (!tabular.isLastCell(cell)) {
2476 InsetText & inset = tabular.getCellInset(cell);
2477 if (inset.searchForward(bv, str, cs, mw)) {
2486 bool InsetTabular::searchBackward(BufferView * bv, string const & str,
2489 int cell = tabular.getNumberOfCells();
2490 if (the_locking_inset) {
2491 if (the_locking_inset->searchBackward(bv, str, cs, mw)) {
2500 InsetText & inset = tabular.getCellInset(cell);
2501 if (inset.searchBackward(bv, str, cs, mw)) {
2510 bool InsetTabular::insetAllowed(InsetOld::Code code) const
2512 if (the_locking_inset)
2513 return the_locking_inset->insetAllowed(code);
2514 // we return true here because if the inset is not locked someone
2515 // wants to insert something in one of our insettexts and we generally
2521 bool InsetTabular::forceDefaultParagraphs(InsetOld const * in) const
2523 const int cell = tabular.getCellFromInset(in);
2526 return tabular.getPWidth(cell).zero();
2528 // this is a workaround for a crash (New, Insert->Tabular,
2529 // Insert->FootNote)
2533 // well we didn't obviously find it so maybe our owner knows more
2534 BOOST_ASSERT(owner());
2535 return owner()->forceDefaultParagraphs(in);
2539 bool InsetTabular::insertAsciiString(BufferView * bv, string const & buf,
2542 if (buf.length() <= 0)
2548 string::size_type len = buf.length();
2549 string::size_type p = 0;
2551 while (p < len && (p = buf.find_first_of("\t\n", p)) != string::npos) {
2559 maxCols = max(cols, maxCols);
2565 maxCols = max(cols, maxCols);
2566 LyXTabular * loctab;
2571 paste_tabular.reset(
2572 new LyXTabular(bv->buffer()->params(), rows, maxCols)
2575 paste_tabular->setOwner(this);
2576 loctab = paste_tabular.get();
2585 string::size_type op = 0;
2586 int cells = loctab->getNumberOfCells();
2589 rows = loctab->rows();
2590 int const columns = loctab->columns();
2592 while (cell < cells && p < len && row < rows &&
2593 (p = buf.find_first_of("\t\n", p)) != string::npos)
2599 // we can only set this if we are not too far right
2600 if (cols < columns) {
2601 InsetText & inset = loctab->getCellInset(cell);
2602 LyXFont const font = inset.getLyXText(bv)->
2603 getFont(inset.paragraphs.begin(), 0);
2604 inset.setText(buf.substr(op, p - op), font);
2610 // we can only set this if we are not too far right
2611 if (cols < columns) {
2612 InsetText & inset = tabular.getCellInset(cell);
2613 LyXFont const font = inset.getLyXText(bv)->
2614 getFont(inset.paragraphs.begin(), 0);
2615 inset.setText(buf.substr(op, p - op), font);
2620 cell = loctab->getCellNumber(row, cols);
2626 // check for the last cell if there is no trailing '\n'
2627 if (cell < cells && op < len) {
2628 InsetText & inset = loctab->getCellInset(cell);
2629 LyXFont const font = inset.getLyXText(bv)->
2630 getFont(inset.paragraphs.begin(), 0);
2631 inset.setText(buf.substr(op, len - op), font);
2638 void InsetTabular::addPreview(PreviewLoader & loader) const
2640 int const rows = tabular.rows();
2641 int const columns = tabular.columns();
2642 for (int i = 0; i < rows; ++i)
2643 for (int j = 0; j < columns; ++j)
2644 tabular.getCellInset(i, j).addPreview(loader);
2648 string const InsetTabularMailer::name_("tabular");
2650 InsetTabularMailer::InsetTabularMailer(InsetTabular const & inset)
2651 : inset_(const_cast<InsetTabular &>(inset))
2655 string const InsetTabularMailer::inset2string(Buffer const &) const
2657 return params2string(inset_);
2661 int InsetTabularMailer::string2params(string const & in, InsetTabular & inset)
2663 istringstream data(in);
2665 lex.setStream(data);
2667 #warning CHECK verify that this is a sane value to return.
2673 string const token = lex.getString();
2681 string const token = lex.getString();
2682 if (token != "\\active_cell")
2685 cell = lex.getInteger();
2688 // This is part of the inset proper that is usually swallowed
2689 // by Buffer::readInset
2692 string const token = lex.getString();
2693 if (token != "Tabular")
2700 Buffer const & buffer = inset.buffer();
2701 inset.read(buffer, lex);
2703 // We can't set the active cell, but we can tell the frontend
2709 string const InsetTabularMailer::params2string(InsetTabular const & inset)
2711 Buffer const & buffer = inset.buffer();
2714 data << name_ << " \\active_cell " << inset.getActCell() << '\n';
2715 inset.write(buffer, data);
2716 data << "\\end_inset\n";