1 /* This file is part of
2 * ======================================================
4 * LyX, The Document Processor
6 * Copyright 2000-2002 The LyX Team.
8 * @author: Jürgen Vigna
10 * ======================================================
15 // temporary until verified (08/08/2001 Jug)
16 #define SPECIAL_COLUM_HANDLING 1
23 #include "BufferView.h"
24 #include "frontends/Painter.h"
25 #include "LaTeXFeatures.h"
26 #include "insets/insettabular.h"
27 #include "insets/insettext.h"
28 #include "support/lstrings.h"
29 #include "support/lyxmanip.h"
30 #include "support/LAssert.h"
31 #include "frontends/Alert.h"
34 #include "tabular_funcs.h"
40 using namespace lyx::support;
50 #ifndef CXX_GLOBAL_CSTD
56 int const WIDTH_OF_LINE = 5;
60 /// Define a few methods for the inner structs
62 LyXTabular::cellstruct::cellstruct(BufferParams const & bg)
67 multicolumn = LyXTabular::CELL_NORMAL;
68 alignment = LYX_ALIGN_CENTER;
69 valignment = LYX_VALIGN_TOP;
79 LyXTabular::rowstruct::rowstruct()
93 LyXTabular::columnstruct::columnstruct()
97 alignment = LYX_ALIGN_CENTER;
98 valignment = LYX_VALIGN_TOP;
103 LyXTabular::ltType::ltType()
111 LyXTabular::LyXTabular(BufferParams const & bp,
112 InsetTabular * inset, int rows_arg, int columns_arg)
116 init(bp, rows_arg, columns_arg);
120 LyXTabular::LyXTabular(BufferParams const & bp,
121 InsetTabular * inset, LyXTabular const & lt)
125 init(bp, lt.rows_, lt.columns_, <);
128 #warning Jürgen, can you make it the other way round. So that copy assignment depends on the copy constructor and not the other way. (Lgb)
135 LyXTabular::LyXTabular(Buffer const * buf, InsetTabular * inset, LyXLex & lex)
143 LyXTabular & LyXTabular::operator=(LyXTabular const & lt)
146 #warning This whole method should look like this: (Lgb)
151 // If this and lt is not of the same size we have a serious bug
152 // So then it is ok to throw an exception, or for now
154 Assert(rows_ == lt.rows_ && columns_ == lt.columns_);
156 cell_info = lt.cell_info;
157 row_info = lt.row_info;
158 column_info = lt.column_info;
159 setLongTabular(lt.is_long_tabular);
168 LyXTabular * LyXTabular::clone(BufferParams const & bp,
169 InsetTabular * inset)
171 LyXTabular * result = new LyXTabular(bp, inset, *this);
173 // don't know if this is good but I need to Clone also
174 // the text-insets here, this is for the Undo-facility!
175 for (int i = 0; i < rows_; ++i) {
176 for (int j = 0; j < columns_; ++j) {
177 result->cell_info[i][j].inset = cell_info[i][j].inset;
178 result->cell_info[i][j].inset.setOwner(inset);
186 // activates all lines and sets all widths to 0
187 void LyXTabular::init(BufferParams const & bp,
188 int rows_arg, int columns_arg, LyXTabular const * lt)
191 columns_ = columns_arg;
192 row_info = row_vector(rows_, rowstruct());
193 column_info = column_vector(columns_, columnstruct());
194 cell_info = cell_vvector(rows_, cell_vector(columns_, cellstruct(bp)));
202 for (int i = 0; i < rows_; ++i) {
203 for (int j = 0; j < columns_; ++j) {
204 cell_info[i][j].inset.setOwner(owner_);
205 cell_info[i][j].inset.setDrawFrame(0, InsetText::LOCKED);
206 cell_info[i][j].cellno = cellno++;
208 cell_info[i].back().right_line = true;
210 row_info.back().bottom_line = true;
211 row_info.front().bottom_line = true;
213 for (int i = 0; i < columns_; ++i) {
214 calculate_width_of_column(i);
216 column_info.back().right_line = true;
218 calculate_width_of_tabular();
220 rowofcell = vector<int>();
221 columnofcell = vector<int>();
222 set_row_column_number_info();
223 is_long_tabular = false;
228 void LyXTabular::appendRow(BufferParams const & bp, int cell)
232 int row = row_of_cell(cell);
234 row_vector::iterator rit = row_info.begin() + row;
235 row_info.insert(rit, rowstruct());
236 // now set the values of the row before
237 row_info[row] = row_info[row + 1];
240 cell_vvector::iterator cit = cell_info.begin() + row;
241 cell_info.insert(cit, vector<cellstruct>(columns_, cellstruct(bp)));
243 cell_vvector c_info = cell_vvector(rows_, cell_vector(columns_,
246 for (int i = 0; i <= row; ++i) {
247 for (int j = 0; j < columns_; ++j) {
248 c_info[i][j] = cell_info[i][j];
251 for (int i = row + 1; i < rows_; ++i) {
252 for (int j = 0; j < columns_; ++j) {
253 c_info[i][j] = cell_info[i-1][j];
258 for (int j = 0; j < columns_; ++j) {
259 cell_info[row][j].inset.clear(false);
260 if (bp.tracking_changes)
261 cell_info[row][j].inset.markNew(true);
268 void LyXTabular::deleteRow(int row)
270 if (rows_ == 1) return; // Not allowed to delete last row
272 row_info.erase(row_info.begin() + row); //&row_info[row]);
273 cell_info.erase(cell_info.begin() + row); //&cell_info[row]);
279 void LyXTabular::appendColumn(BufferParams const & bp, int cell)
283 cell_vvector c_info = cell_vvector(rows_, cell_vector(columns_,
285 int const column = column_of_cell(cell);
286 column_vector::iterator cit = column_info.begin() + column + 1;
287 column_info.insert(cit, columnstruct());
288 // set the column values of the column before
289 column_info[column + 1] = column_info[column];
291 for (int i = 0; i < rows_; ++i) {
292 for (int j = 0; j <= column; ++j) {
293 c_info[i][j] = cell_info[i][j];
295 for (int j = column + 1; j < columns_; ++j) {
296 c_info[i][j] = cell_info[i][j - 1];
298 // care about multicolumns
299 if (c_info[i][column + 1].multicolumn==CELL_BEGIN_OF_MULTICOLUMN)
301 c_info[i][column + 1].multicolumn = CELL_PART_OF_MULTICOLUMN;
303 if ((column + 2) >= columns_ ||
304 c_info[i][column + 2].multicolumn != CELL_PART_OF_MULTICOLUMN)
306 c_info[i][column + 1].multicolumn = LyXTabular::CELL_NORMAL;
311 for (int i = 0; i < rows_; ++i) {
312 cell_info[i][column + 1].inset.clear(false);
313 if (bp.tracking_changes)
314 cell_info[i][column + 1].inset.markNew(true);
320 void LyXTabular::deleteColumn(int column)
322 // Similar to deleteRow
323 //if (!(columns_ - 1))
325 if (columns_ == 1) return; // Not allowed to delete last column
327 column_info.erase(column_info.begin() + column);
328 for (int i = 0; i < rows_; ++i) {
329 cell_info[i].erase(cell_info[i].begin() + column);
336 void LyXTabular::reinit()
342 void LyXTabular::Reinit(bool reset_widths)
345 for (int i = 0; i < rows_; ++i) {
346 for (int j = 0; j < columns_; ++j) {
347 cell_info[i][j].width_of_cell = 0;
348 cell_info[i][j].inset.setOwner(owner_);
353 for (int i = 0; i < columns_; ++i) {
354 calculate_width_of_column(i);
356 calculate_width_of_tabular();
358 set_row_column_number_info();
362 void LyXTabular::set_row_column_number_info(bool oldformat)
365 for (int row = 0; row < rows_; ++row) {
366 for (int column = 0; column<columns_; ++column) {
367 if (cell_info[row][column].multicolumn
368 != LyXTabular::CELL_PART_OF_MULTICOLUMN)
370 cell_info[row][column].cellno = numberofcells;
373 ++numberofcells; // because this is one more than as we start from 0
375 rowofcell.resize(numberofcells);
376 columnofcell.resize(numberofcells);
378 for (int row = 0, column = 0, c = 0;
379 c < numberofcells && row < rows_ && column < columns_;) {
381 columnofcell[c] = column;
385 } while (column < columns_ &&
386 cell_info[row][column].multicolumn
387 == LyXTabular::CELL_PART_OF_MULTICOLUMN);
388 if (column == columns_) {
394 for (int row = 0; row < rows_; ++row) {
395 for (int column = 0; column < columns_; ++column) {
396 if (isPartOfMultiColumn(row,column))
398 // now set the right line of multicolumns right for oldformat read
400 cell_info[row][column].multicolumn==CELL_BEGIN_OF_MULTICOLUMN)
402 int cn=cells_in_multicolumn(cell_info[row][column].cellno);
403 cell_info[row][column].right_line =
404 cell_info[row][column+cn-1].right_line;
406 cell_info[row][column].inset.setAutoBreakRows(
407 !getPWidth(getCellNumber(row, column)).zero());
413 int LyXTabular::getNumberOfCells() const
415 return numberofcells;
419 int LyXTabular::numberOfCellsInRow(int cell) const
421 int const row = row_of_cell(cell);
423 for (int i = 0; i < columns_; ++i) {
424 if (cell_info[row][i].multicolumn != LyXTabular::CELL_PART_OF_MULTICOLUMN)
431 // returns 1 if there is a topline, returns 0 if not
432 bool LyXTabular::topLine(int cell, bool onlycolumn) const
434 int const row = row_of_cell(cell);
436 if (!onlycolumn && isMultiColumn(cell))
437 return cellinfo_of_cell(cell)->top_line;
438 return row_info[row].top_line;
442 bool LyXTabular::bottomLine(int cell, bool onlycolumn) const
444 // no bottom line underneath non-existent cells if you please
445 // Isn't that a programming error? Is so this should
446 // be an Assert instead. (Lgb)
447 if (cell >= numberofcells)
450 if (!onlycolumn && isMultiColumn(cell))
451 return cellinfo_of_cell(cell)->bottom_line;
452 return row_info[row_of_cell(cell)].bottom_line;
456 bool LyXTabular::leftLine(int cell, bool onlycolumn) const
458 if (!onlycolumn && isMultiColumn(cell) &&
459 (isFirstCellInRow(cell) || isMultiColumn(cell-1)))
461 #ifdef SPECIAL_COLUM_HANDLING
462 if (cellinfo_of_cell(cell)->align_special.empty())
463 return cellinfo_of_cell(cell)->left_line;
464 return prefixIs(ltrim(cellinfo_of_cell(cell)->align_special), "|");
466 return cellinfo_of_cell(cell)->left_line;
469 #ifdef SPECIAL_COLUM_HANDLING
470 if (column_info[column_of_cell(cell)].align_special.empty())
471 return column_info[column_of_cell(cell)].left_line;
472 return prefixIs(ltrim(column_info[column_of_cell(cell)].align_special), "|");
474 return column_info[column_of_cell(cell)].left_line;
479 bool LyXTabular::rightLine(int cell, bool onlycolumn) const
481 if (!onlycolumn && isMultiColumn(cell) &&
482 (isLastCellInRow(cell) || isMultiColumn(cell+1)))
484 #ifdef SPECIAL_COLUM_HANDLING
485 if (cellinfo_of_cell(cell)->align_special.empty())
486 return cellinfo_of_cell(cell)->right_line;
487 return suffixIs(rtrim(cellinfo_of_cell(cell)->align_special), "|");
489 return cellinfo_of_cell(cell)->right_line;
492 #ifdef SPECIAL_COLUM_HANDLING
493 if (column_info[column_of_cell(cell)].align_special.empty())
494 return column_info[right_column_of_cell(cell)].right_line;
495 return suffixIs(rtrim(column_info[column_of_cell(cell)].align_special), "|");
497 return column_info[right_column_of_cell(cell)].right_line;
502 bool LyXTabular::topAlreadyDrawn(int cell) const
504 int row = row_of_cell(cell);
505 if ((row > 0) && !getAdditionalHeight(row)) {
506 int column = column_of_cell(cell);
509 && cell_info[row][column].multicolumn
510 == LyXTabular::CELL_PART_OF_MULTICOLUMN)
512 if (cell_info[row][column].multicolumn == LyXTabular::CELL_NORMAL)
513 return row_info[row].bottom_line;
515 return cell_info[row][column].bottom_line;
521 bool LyXTabular::leftAlreadyDrawn(int cell) const
523 int column = column_of_cell(cell);
525 int row = row_of_cell(cell);
527 (cell_info[row][column].multicolumn ==
528 LyXTabular::CELL_PART_OF_MULTICOLUMN));
529 if (getAdditionalWidth(cell_info[row][column].cellno))
531 #ifdef SPECIAL_COLUM_HANDLING
532 return rightLine(cell_info[row][column].cellno);
534 return rightLine(cell_info[row][column].cellno, true);
541 bool LyXTabular::isLastRow(int cell) const
543 return (row_of_cell(cell) == rows_ - 1);
547 int LyXTabular::getAdditionalHeight(int row) const
549 if (!row || row >= rows_)
555 for (int column = 0; column < columns_ && bottom; ++column) {
556 switch (cell_info[row - 1][column].multicolumn) {
557 case LyXTabular::CELL_BEGIN_OF_MULTICOLUMN:
558 bottom = cell_info[row - 1][column].bottom_line;
560 case LyXTabular::CELL_NORMAL:
561 bottom = row_info[row - 1].bottom_line;
564 for (int column = 0; column < columns_ && top; ++column) {
565 switch (cell_info[row][column].multicolumn) {
566 case LyXTabular::CELL_BEGIN_OF_MULTICOLUMN:
567 top = cell_info[row][column].top_line;
569 case LyXTabular::CELL_NORMAL:
570 top = row_info[row].top_line;
574 return WIDTH_OF_LINE;
579 int LyXTabular::getAdditionalWidth(int cell) const
581 // internally already set in setWidthOfCell
582 // used to get it back in text.C
583 int const col = right_column_of_cell(cell);
584 int const row = row_of_cell(cell);
585 if (col < columns_ - 1 && rightLine(cell) &&
586 leftLine(cell_info[row][col+1].cellno)) // column_info[col+1].left_line)
588 return WIDTH_OF_LINE;
595 // returns the maximum over all rows
596 int LyXTabular::getWidthOfColumn(int cell) const
598 int const column1 = column_of_cell(cell);
599 int const column2 = right_column_of_cell(cell);
601 for (int i = column1; i <= column2; ++i) {
602 result += column_info[i].width_of_column;
608 int LyXTabular::getWidthOfTabular() const
610 return width_of_tabular;
614 // returns true if a complete update is necessary, otherwise false
615 bool LyXTabular::setWidthOfMulticolCell(int cell, int new_width)
617 if (!isMultiColumn(cell))
620 int const row = row_of_cell(cell);
621 int const column1 = column_of_cell(cell);
622 int const column2 = right_column_of_cell(cell);
623 int const old_val = cell_info[row][column2].width_of_cell;
625 // first set columns to 0 so we can calculate the right width
626 for (int i = column1; i <= column2; ++i) {
627 cell_info[row][i].width_of_cell = 0;
629 // set the width to MAX_WIDTH until width > 0
630 int width = (new_width + 2 * WIDTH_OF_LINE);
632 for (; i < column2 && width > column_info[i].width_of_column; ++i) {
633 cell_info[row][i].width_of_cell = column_info[i].width_of_column;
634 width -= column_info[i].width_of_column;
637 cell_info[row][i].width_of_cell = width;
639 if (old_val != cell_info[row][column2].width_of_cell) {
640 // in this case we have to recalculate all multicolumn cells which
641 // have this column as one of theirs but not as last one
642 calculate_width_of_column_NMC(i);
643 recalculateMulticolumnsOfColumn(i);
644 calculate_width_of_column(i);
650 void LyXTabular::recalculateMulticolumnsOfColumn(int column)
652 // the last column does not have to be recalculated because all
653 // multicolumns will have here there last multicolumn cell which
654 // always will have the whole rest of the width of the cell.
655 if (column > (columns_ - 2))
657 for(int row = 0; row < rows_; ++row) {
658 int mc = cell_info[row][column].multicolumn;
659 int nmc = cell_info[row][column+1].multicolumn;
660 // we only have to update multicolumns which do not have this
661 // column as their last column!
662 if (mc == CELL_BEGIN_OF_MULTICOLUMN ||
663 ((mc == CELL_PART_OF_MULTICOLUMN) &&
664 (nmc == CELL_PART_OF_MULTICOLUMN)))
666 int const cellno = cell_info[row][column].cellno;
667 setWidthOfMulticolCell(cellno,
668 getWidthOfCell(cellno)-(2 * WIDTH_OF_LINE));
674 // returns 1 if a complete update is necessary, otherwise 0
675 bool LyXTabular::setWidthOfCell(int cell, int new_width)
677 int const row = row_of_cell(cell);
678 int const column1 = column_of_cell(cell);
683 #ifdef SPECIAL_COLUM_HANDLING
684 if (rightLine(cell_info[row][column1].cellno, true) &&
685 (column1 < columns_-1) &&
686 leftLine(cell_info[row][column1+1].cellno, true))
688 if (column_info[column1].right_line && (column1 < columns_-1) &&
689 column_info[column1+1].left_line) // additional width
693 add_width = WIDTH_OF_LINE;
695 if (getWidthOfCell(cell) == (new_width+2*WIDTH_OF_LINE+add_width)) {
698 if (isMultiColumn(cell, true)) {
699 tmp = setWidthOfMulticolCell(cell, new_width);
701 width = new_width + 2 * WIDTH_OF_LINE + add_width;
702 cell_info[row][column1].width_of_cell = width;
703 tmp = calculate_width_of_column_NMC(column1);
705 recalculateMulticolumnsOfColumn(column1);
708 for (int i = 0; i < columns_; ++i)
709 calculate_width_of_column(i);
710 calculate_width_of_tabular();
717 bool LyXTabular::setAlignment(int cell, LyXAlignment align, bool onlycolumn)
719 if (!isMultiColumn(cell) || onlycolumn)
720 column_info[column_of_cell(cell)].alignment = align;
722 cellinfo_of_cell(cell)->alignment = align;
727 bool LyXTabular::setVAlignment(int cell, VAlignment align, bool onlycolumn)
729 if (!isMultiColumn(cell) || onlycolumn)
730 column_info[column_of_cell(cell)].valignment = align;
732 cellinfo_of_cell(cell)->valignment = align;
737 bool LyXTabular::setColumnPWidth(int cell, LyXLength const & width)
739 bool flag = !width.zero();
740 int const j = column_of_cell(cell);
742 column_info[j].p_width = width;
743 // This should not ne necessary anymore
744 // if (flag) // do this only if there is a width
745 // setAlignment(cell, LYX_ALIGN_LEFT);
746 for (int i = 0; i < rows_; ++i) {
747 int c = getCellNumber(i, j);
748 flag = !getPWidth(c).zero(); // because of multicolumns!
749 getCellInset(c)->setAutoBreakRows(flag);
755 bool LyXTabular::setMColumnPWidth(int cell, LyXLength const & width)
757 bool const flag = !width.zero();
759 cellinfo_of_cell(cell)->p_width = width;
760 if (isMultiColumn(cell)) {
761 getCellInset(cell)->setAutoBreakRows(flag);
768 bool LyXTabular::setAlignSpecial(int cell, string const & special,
769 LyXTabular::Feature what)
771 if (what == SET_SPECIAL_MULTI)
772 cellinfo_of_cell(cell)->align_special = special;
774 column_info[column_of_cell(cell)].align_special = special;
779 bool LyXTabular::setAllLines(int cell, bool line)
781 setTopLine(cell, line);
782 setBottomLine(cell, line);
783 setRightLine(cell, line);
784 setLeftLine(cell, line);
789 bool LyXTabular::setTopLine(int cell, bool line, bool onlycolumn)
791 int const row = row_of_cell(cell);
793 if (onlycolumn || !isMultiColumn(cell))
794 row_info[row].top_line = line;
796 cellinfo_of_cell(cell)->top_line = line;
801 bool LyXTabular::setBottomLine(int cell, bool line, bool onlycolumn)
803 if (onlycolumn || !isMultiColumn(cell))
804 row_info[row_of_cell(cell)].bottom_line = line;
806 cellinfo_of_cell(cell)->bottom_line = line;
811 bool LyXTabular::setLeftLine(int cell, bool line, bool onlycolumn)
813 if (onlycolumn || !isMultiColumn(cell))
814 column_info[column_of_cell(cell)].left_line = line;
816 cellinfo_of_cell(cell)->left_line = line;
821 bool LyXTabular::setRightLine(int cell, bool line, bool onlycolumn)
823 if (onlycolumn || !isMultiColumn(cell))
824 column_info[right_column_of_cell(cell)].right_line = line;
826 cellinfo_of_cell(cell)->right_line = line;
831 LyXAlignment LyXTabular::getAlignment(int cell, bool onlycolumn) const
833 if (!onlycolumn && isMultiColumn(cell))
834 return cellinfo_of_cell(cell)->alignment;
836 return column_info[column_of_cell(cell)].alignment;
840 LyXTabular::VAlignment
841 LyXTabular::getVAlignment(int cell, bool onlycolumn) const
843 if (!onlycolumn && isMultiColumn(cell))
844 return cellinfo_of_cell(cell)->valignment;
846 return column_info[column_of_cell(cell)].valignment;
850 LyXLength const LyXTabular::getPWidth(int cell) const
852 if (isMultiColumn(cell))
853 return cellinfo_of_cell(cell)->p_width;
854 return column_info[column_of_cell(cell)].p_width;
858 LyXLength const LyXTabular::getColumnPWidth(int cell) const
860 return column_info[column_of_cell(cell)].p_width;
864 LyXLength const LyXTabular::getMColumnPWidth(int cell) const
866 if (isMultiColumn(cell))
867 return cellinfo_of_cell(cell)->p_width;
872 string const LyXTabular::getAlignSpecial(int cell, int what) const
874 if (what == SET_SPECIAL_MULTI)
875 return cellinfo_of_cell(cell)->align_special;
876 return column_info[column_of_cell(cell)].align_special;
880 int LyXTabular::getWidthOfCell(int cell) const
882 int const row = row_of_cell(cell);
883 int const column1 = column_of_cell(cell);
884 int const column2 = right_column_of_cell(cell);
886 for (int i = column1; i <= column2; ++i) {
887 result += cell_info[row][i].width_of_cell;
893 int LyXTabular::getBeginningOfTextInCell(int cell) const
897 switch (getAlignment(cell)) {
898 case LYX_ALIGN_CENTER:
899 x += (getWidthOfColumn(cell) - getWidthOfCell(cell)) / 2;
901 case LYX_ALIGN_RIGHT:
902 x += getWidthOfColumn(cell) - getWidthOfCell(cell);
903 // + getAdditionalWidth(cell);
906 // LYX_ALIGN_LEFT: nothing :-)
916 bool LyXTabular::isFirstCellInRow(int cell) const
918 return column_of_cell(cell) == 0;
922 int LyXTabular::getFirstCellInRow(int row) const
926 return cell_info[row][0].cellno;
929 bool LyXTabular::isLastCellInRow(int cell) const
931 return (right_column_of_cell(cell) == (columns_ - 1));
935 int LyXTabular::getLastCellInRow(int row) const
939 return cell_info[row][columns_-1].cellno;
943 bool LyXTabular::calculate_width_of_column(int column)
945 int const old_column_width = column_info[column].width_of_column;
948 for (int i = 0; i < rows_; ++i) {
949 maximum = max(cell_info[i][column].width_of_cell, maximum);
951 column_info[column].width_of_column = maximum;
952 return (column_info[column].width_of_column != old_column_width);
957 // Calculate the columns regarding ONLY the normal cells and if this
958 // column is inside a multicolumn cell then use it only if its the last
959 // column of this multicolumn cell as this gives an added with to the
960 // column, all the rest should be adapted!
962 bool LyXTabular::calculate_width_of_column_NMC(int column)
964 int const old_column_width = column_info[column].width_of_column;
966 for (int i = 0; i < rows_; ++i) {
967 int cell = getCellNumber(i, column);
968 bool ismulti = isMultiColumn(cell, true);
969 if ((!ismulti || (column == right_column_of_cell(cell))) &&
970 (cell_info[i][column].width_of_cell > max))
972 max = cell_info[i][column].width_of_cell;
975 column_info[column].width_of_column = max;
976 return (column_info[column].width_of_column != old_column_width);
980 void LyXTabular::calculate_width_of_tabular()
982 width_of_tabular = 0;
983 for (int i = 0; i < columns_; ++i) {
984 width_of_tabular += column_info[i].width_of_column;
989 int LyXTabular::row_of_cell(int cell) const
991 if (cell >= numberofcells)
995 return rowofcell[cell];
999 int LyXTabular::column_of_cell(int cell) const
1001 if (cell >= numberofcells)
1002 return columns_ - 1;
1005 return columnofcell[cell];
1009 int LyXTabular::right_column_of_cell(int cell) const
1011 int const row = row_of_cell(cell);
1012 int column = column_of_cell(cell);
1013 while (column < (columns_ - 1) &&
1014 cell_info[row][column + 1].multicolumn == LyXTabular::CELL_PART_OF_MULTICOLUMN)
1020 void LyXTabular::write(Buffer const * buf, ostream & os) const
1024 << write_attribute("version", 3)
1025 << write_attribute("rows", rows_)
1026 << write_attribute("columns", columns_)
1028 // global longtable options
1030 << write_attribute("rotate", rotate)
1031 << write_attribute("islongtable", is_long_tabular)
1032 << write_attribute("firstHeadTopDL", endfirsthead.topDL)
1033 << write_attribute("firstHeadBottomDL", endfirsthead.bottomDL)
1034 << write_attribute("firstHeadEmpty", endfirsthead.empty)
1035 << write_attribute("headTopDL", endhead.topDL)
1036 << write_attribute("headBottomDL", endhead.bottomDL)
1037 << write_attribute("footTopDL", endfoot.topDL)
1038 << write_attribute("footBottomDL", endfoot.bottomDL)
1039 << write_attribute("lastFootTopDL", endlastfoot.topDL)
1040 << write_attribute("lastFootBottomDL", endlastfoot.bottomDL)
1041 << write_attribute("lastFootEmpty", endlastfoot.empty)
1043 for (int j = 0; j < columns_; ++j) {
1045 << write_attribute("alignment", column_info[j].alignment)
1046 << write_attribute("valignment", column_info[j].valignment)
1047 << write_attribute("leftline", column_info[j].left_line)
1048 << write_attribute("rightline", column_info[j].right_line)
1049 << write_attribute("width", column_info[j].p_width.asString())
1050 << write_attribute("special", column_info[j].align_special)
1053 for (int i = 0; i < rows_; ++i) {
1055 << write_attribute("topline", row_info[i].top_line)
1056 << write_attribute("bottomline", row_info[i].bottom_line)
1057 << write_attribute("endhead", row_info[i].endhead)
1058 << write_attribute("endfirsthead", row_info[i].endfirsthead)
1059 << write_attribute("endfoot", row_info[i].endfoot)
1060 << write_attribute("endlastfoot", row_info[i].endlastfoot)
1061 << write_attribute("newpage", row_info[i].newpage)
1063 for (int j = 0; j < columns_; ++j) {
1065 << write_attribute("multicolumn", cell_info[i][j].multicolumn)
1066 << write_attribute("alignment", cell_info[i][j].alignment)
1067 << write_attribute("valignment", cell_info[i][j].valignment)
1068 << write_attribute("topline", cell_info[i][j].top_line)
1069 << write_attribute("bottomline", cell_info[i][j].bottom_line)
1070 << write_attribute("leftline", cell_info[i][j].left_line)
1071 << write_attribute("rightline", cell_info[i][j].right_line)
1072 << write_attribute("rotate", cell_info[i][j].rotate)
1073 << write_attribute("usebox", cell_info[i][j].usebox)
1074 << write_attribute("width", cell_info[i][j].p_width)
1075 << write_attribute("special", cell_info[i][j].align_special)
1077 os << "\\begin_inset ";
1078 cell_info[i][j].inset.write(buf, os);
1079 os << "\n\\end_inset \n"
1084 os << "</lyxtabular>\n";
1088 void LyXTabular::setHeaderFooterRows(int hr, int fhr, int fr, int lfr)
1092 row_info[--hr].endhead = true;
1094 // set firstheader info
1095 if (fhr && (fhr < rows_)) {
1096 if (row_info[fhr].endhead) {
1098 row_info[--fhr].endfirsthead = true;
1099 row_info[fhr].endhead = false;
1101 } else if (row_info[fhr - 1].endhead) {
1102 endfirsthead.empty = true;
1104 while((fhr > 0) && !row_info[--fhr].endhead) {
1105 row_info[fhr].endfirsthead = true;
1110 if (fr && (fr < rows_)) {
1111 if (row_info[fr].endhead && row_info[fr-1].endhead) {
1112 while((fr > 0) && !row_info[--fr].endhead) {
1113 row_info[fr].endfoot = true;
1114 row_info[fr].endhead = false;
1116 } else if (row_info[fr].endfirsthead && row_info[fr-1].endfirsthead) {
1117 while((fr > 0) && !row_info[--fr].endfirsthead) {
1118 row_info[fr].endfoot = true;
1119 row_info[fr].endfirsthead = false;
1121 } else if (!row_info[fr - 1].endhead && !row_info[fr - 1].endfirsthead) {
1122 while((fr > 0) && !row_info[--fr].endhead &&
1123 !row_info[fr].endfirsthead)
1125 row_info[fr].endfoot = true;
1129 // set lastfooter info
1130 if (lfr && (lfr < rows_)) {
1131 if (row_info[lfr].endhead && row_info[lfr - 1].endhead) {
1132 while((lfr > 0) && !row_info[--lfr].endhead) {
1133 row_info[lfr].endlastfoot = true;
1134 row_info[lfr].endhead = false;
1136 } else if (row_info[lfr].endfirsthead &&
1137 row_info[lfr - 1].endfirsthead)
1139 while((lfr > 0) && !row_info[--lfr].endfirsthead) {
1140 row_info[lfr].endlastfoot = true;
1141 row_info[lfr].endfirsthead = false;
1143 } else if (row_info[lfr].endfoot
1144 && row_info[lfr - 1].endfoot) {
1145 while((lfr > 0) && !row_info[--lfr].endfoot) {
1146 row_info[lfr].endlastfoot = true;
1147 row_info[lfr].endfoot = false;
1149 } else if (!row_info[fr - 1].endhead
1150 && !row_info[fr - 1].endfirsthead &&
1151 !row_info[fr - 1].endfoot)
1154 !row_info[--lfr].endhead && !row_info[lfr].endfirsthead &&
1155 !row_info[lfr].endfoot)
1157 row_info[lfr].endlastfoot = true;
1159 } else if (haveLTFoot()) {
1160 endlastfoot.empty = true;
1166 void LyXTabular::read(Buffer const * buf, LyXLex & lex)
1169 istream & is = lex.getStream();
1171 l_getline(is, line);
1172 if (!prefixIs(line, "<lyxtabular ")
1173 && !prefixIs(line, "<LyXTabular ")) {
1179 if (!getTokenValue(line, "version", version))
1181 Assert(version >= 2);
1184 if (!getTokenValue(line, "rows", rows_arg))
1187 if (!getTokenValue(line, "columns", columns_arg))
1189 init(buf->params, rows_arg, columns_arg);
1190 l_getline(is, line);
1191 if (!prefixIs(line, "<features")) {
1192 lyxerr << "Wrong tabular format (expected <features ...> got"
1193 << line << ')' << endl;
1196 getTokenValue(line, "rotate", rotate);
1197 getTokenValue(line, "islongtable", is_long_tabular);
1198 // compatibility read for old longtable options. Now we can make any
1199 // row part of the header/footer type we want before it was strict
1200 // sequential from the first row down (as LaTeX does it!). So now when
1201 // we find a header/footer line we have to go up the rows and set it
1202 // on all preceding rows till the first or one with already a h/f option
1203 // set. If we find a firstheader on the same line as a header or a
1204 // lastfooter on the same line as a footer then this should be set empty.
1212 getTokenValue(line, "endhead", hrow);
1213 getTokenValue(line, "endfirsthead", fhrow);
1214 getTokenValue(line, "endfoot", frow);
1215 getTokenValue(line, "endlastfoot", lfrow);
1216 setHeaderFooterRows(abs(hrow), abs(fhrow), abs(frow), abs(lfrow));
1218 getTokenValue(line, "firstHeadTopDL", endfirsthead.topDL);
1219 getTokenValue(line, "firstHeadBottomDL", endfirsthead.bottomDL);
1220 getTokenValue(line, "firstHeadEmpty", endfirsthead.empty);
1221 getTokenValue(line, "headTopDL", endhead.topDL);
1222 getTokenValue(line, "headBottomDL", endhead.bottomDL);
1223 getTokenValue(line, "footTopDL", endfoot.topDL);
1224 getTokenValue(line, "footBottomDL", endfoot.bottomDL);
1225 getTokenValue(line, "lastFootTopDL", endlastfoot.topDL);
1226 getTokenValue(line, "lastFootBottomDL", endlastfoot.bottomDL);
1227 getTokenValue(line, "lastFootEmpty", endlastfoot.empty);
1229 for (int j = 0; j < columns_; ++j) {
1231 if (!prefixIs(line,"<column")) {
1232 lyxerr << "Wrong tabular format (expected <column ...> got"
1233 << line << ')' << endl;
1236 getTokenValue(line, "alignment", column_info[j].alignment);
1237 getTokenValue(line, "valignment", column_info[j].valignment);
1238 getTokenValue(line, "leftline", column_info[j].left_line);
1239 getTokenValue(line, "rightline", column_info[j].right_line);
1240 getTokenValue(line, "width", column_info[j].p_width);
1241 getTokenValue(line, "special", column_info[j].align_special);
1244 for (int i = 0; i < rows_; ++i) {
1245 l_getline(is, line);
1246 if (!prefixIs(line, "<row")) {
1247 lyxerr << "Wrong tabular format (expected <row ...> got"
1248 << line << ')' << endl;
1251 getTokenValue(line, "topline", row_info[i].top_line);
1252 getTokenValue(line, "bottomline", row_info[i].bottom_line);
1253 getTokenValue(line, "endfirsthead", row_info[i].endfirsthead);
1254 getTokenValue(line, "endhead", row_info[i].endhead);
1255 getTokenValue(line, "endfoot", row_info[i].endfoot);
1256 getTokenValue(line, "endlastfoot", row_info[i].endlastfoot);
1257 getTokenValue(line, "newpage", row_info[i].newpage);
1258 for (int j = 0; j < columns_; ++j) {
1259 l_getline(is, line);
1260 if (!prefixIs(line, "<cell")) {
1261 lyxerr << "Wrong tabular format (expected <cell ...> got"
1262 << line << ')' << endl;
1265 getTokenValue(line, "multicolumn", cell_info[i][j].multicolumn);
1266 getTokenValue(line, "alignment", cell_info[i][j].alignment);
1267 getTokenValue(line, "valignment", cell_info[i][j].valignment);
1268 getTokenValue(line, "topline", cell_info[i][j].top_line);
1269 getTokenValue(line, "bottomline", cell_info[i][j].bottom_line);
1270 getTokenValue(line, "leftline", cell_info[i][j].left_line);
1271 getTokenValue(line, "rightline", cell_info[i][j].right_line);
1272 getTokenValue(line, "rotate", cell_info[i][j].rotate);
1273 getTokenValue(line, "usebox", cell_info[i][j].usebox);
1274 getTokenValue(line, "width", cell_info[i][j].p_width);
1275 getTokenValue(line, "special", cell_info[i][j].align_special);
1276 l_getline(is, line);
1277 if (prefixIs(line, "\\begin_inset")) {
1278 cell_info[i][j].inset.read(buf, lex);
1279 l_getline(is, line);
1281 if (!prefixIs(line, "</cell>")) {
1282 lyxerr << "Wrong tabular format (expected </cell> got"
1283 << line << ')' << endl;
1287 l_getline(is, line);
1288 if (!prefixIs(line, "</row>")) {
1289 lyxerr << "Wrong tabular format (expected </row> got"
1290 << line << ')' << endl;
1294 while (!prefixIs(line, "</lyxtabular>")) {
1295 l_getline(is, line);
1297 set_row_column_number_info();
1301 bool LyXTabular::isMultiColumn(int cell, bool real) const
1303 return (!real || column_of_cell(cell) != right_column_of_cell(cell)) &&
1304 (cellinfo_of_cell(cell)->multicolumn != LyXTabular::CELL_NORMAL);
1308 LyXTabular::cellstruct * LyXTabular::cellinfo_of_cell(int cell) const
1310 int const row = row_of_cell(cell);
1311 int const column = column_of_cell(cell);
1312 return &cell_info[row][column];
1316 void LyXTabular::setMultiColumn(Buffer * buffer, int cell, int number)
1318 cellinfo_of_cell(cell)->multicolumn = CELL_BEGIN_OF_MULTICOLUMN;
1319 cellinfo_of_cell(cell)->alignment = column_info[column_of_cell(cell)].alignment;
1320 cellinfo_of_cell(cell)->top_line = row_info[row_of_cell(cell)].top_line;
1321 cellinfo_of_cell(cell)->bottom_line = row_info[row_of_cell(cell)].bottom_line;
1322 cellinfo_of_cell(cell)->right_line = column_info[column_of_cell(cell+number-1)].right_line;
1324 for (int i = 1; i < number; ++i) {
1325 cellinfo_of_cell(cell + i)->multicolumn = CELL_PART_OF_MULTICOLUMN;
1326 cellinfo_of_cell(cell)->inset.appendParagraphs(buffer,
1327 cellinfo_of_cell(cell+i)->inset.paragraphs);
1328 cellinfo_of_cell(cell + i)->inset.clear(false);
1331 for (number--; number > 0; --number) {
1332 cellinfo_of_cell(cell + number)->multicolumn = CELL_PART_OF_MULTICOLUMN;
1335 set_row_column_number_info();
1339 int LyXTabular::cells_in_multicolumn(int cell) const
1341 int const row = row_of_cell(cell);
1342 int column = column_of_cell(cell);
1345 while ((column < columns_) &&
1346 cell_info[row][column].multicolumn == CELL_PART_OF_MULTICOLUMN)
1355 int LyXTabular::unsetMultiColumn(int cell)
1357 int const row = row_of_cell(cell);
1358 int column = column_of_cell(cell);
1362 if (cell_info[row][column].multicolumn == CELL_BEGIN_OF_MULTICOLUMN) {
1363 cell_info[row][column].multicolumn = CELL_NORMAL;
1365 while ((column < columns_) &&
1366 (cell_info[row][column].multicolumn ==CELL_PART_OF_MULTICOLUMN))
1368 cell_info[row][column].multicolumn = CELL_NORMAL;
1373 set_row_column_number_info();
1378 void LyXTabular::setLongTabular(bool what)
1380 is_long_tabular = what;
1384 bool LyXTabular::isLongTabular() const
1386 return is_long_tabular;
1390 void LyXTabular::setRotateTabular(bool flag)
1396 bool LyXTabular::getRotateTabular() const
1402 void LyXTabular::setRotateCell(int cell, bool flag)
1404 cellinfo_of_cell(cell)->rotate = flag;
1408 bool LyXTabular::getRotateCell(int cell) const
1410 return cellinfo_of_cell(cell)->rotate;
1414 bool LyXTabular::needRotating() const
1418 for (int i = 0; i < rows_; ++i) {
1419 for (int j = 0; j < columns_; ++j) {
1420 if (cell_info[i][j].rotate)
1428 bool LyXTabular::isLastCell(int cell) const
1430 if (cell + 1 < numberofcells)
1436 int LyXTabular::getCellAbove(int cell) const
1438 if (row_of_cell(cell) > 0)
1439 return cell_info[row_of_cell(cell)-1][column_of_cell(cell)].cellno;
1444 int LyXTabular::getCellBelow(int cell) const
1446 if (row_of_cell(cell) + 1 < rows_)
1447 return cell_info[row_of_cell(cell)+1][column_of_cell(cell)].cellno;
1452 int LyXTabular::getLastCellAbove(int cell) const
1454 if (row_of_cell(cell) <= 0)
1456 if (!isMultiColumn(cell))
1457 return getCellAbove(cell);
1458 return cell_info[row_of_cell(cell) - 1][right_column_of_cell(cell)].cellno;
1462 int LyXTabular::getLastCellBelow(int cell) const
1464 if (row_of_cell(cell) + 1 >= rows_)
1466 if (!isMultiColumn(cell))
1467 return getCellBelow(cell);
1468 return cell_info[row_of_cell(cell) + 1][right_column_of_cell(cell)].cellno;
1472 int LyXTabular::getCellNumber(int row, int column) const
1475 if (column >= columns_)
1476 column = columns_ - 1;
1477 else if (column < 0)
1484 Assert(column >= 0 || column < columns_ || row >= 0 || row < rows_);
1486 return cell_info[row][column].cellno;
1490 void LyXTabular::setUsebox(int cell, BoxType type)
1492 cellinfo_of_cell(cell)->usebox = type;
1496 LyXTabular::BoxType LyXTabular::getUsebox(int cell) const
1498 if (column_info[column_of_cell(cell)].p_width.zero() &&
1499 !(isMultiColumn(cell) && !cellinfo_of_cell(cell)->p_width.zero()))
1501 if (cellinfo_of_cell(cell)->usebox > 1)
1502 return cellinfo_of_cell(cell)->usebox;
1503 return useParbox(cell);
1508 // This are functions used for the longtable support
1510 void LyXTabular::setLTHead(int row, bool flag, ltType const & hd, bool first)
1515 row_info[row].endfirsthead = flag;
1519 row_info[row].endhead = flag;
1524 bool LyXTabular::getRowOfLTHead(int row, ltType & hd) const
1527 hd.set = haveLTHead();
1528 return row_info[row].endhead;
1532 bool LyXTabular::getRowOfLTFirstHead(int row, ltType & hd) const
1535 hd.set = haveLTFirstHead();
1536 return row_info[row].endfirsthead;
1540 void LyXTabular::setLTFoot(int row, bool flag, ltType const & fd, bool last)
1545 row_info[row].endlastfoot = flag;
1549 row_info[row].endfoot = flag;
1554 bool LyXTabular::getRowOfLTFoot(int row, ltType & fd) const
1557 fd.set = haveLTFoot();
1558 return row_info[row].endfoot;
1562 bool LyXTabular::getRowOfLTLastFoot(int row, ltType & fd) const
1565 fd.set = haveLTLastFoot();
1566 return row_info[row].endlastfoot;
1570 void LyXTabular::setLTNewPage(int row, bool what)
1572 row_info[row].newpage = what;
1576 bool LyXTabular::getLTNewPage(int row) const
1578 return row_info[row].newpage;
1582 bool LyXTabular::haveLTHead() const
1584 for (int i = 0; i < rows_; ++i) {
1585 if (row_info[i].endhead)
1592 bool LyXTabular::haveLTFirstHead() const
1594 if (endfirsthead.empty)
1596 for (int i = 0; i < rows_; ++i) {
1597 if (row_info[i].endfirsthead)
1604 bool LyXTabular::haveLTFoot() const
1606 for (int i = 0; i < rows_; ++i) {
1607 if (row_info[i].endfoot)
1614 bool LyXTabular::haveLTLastFoot() const
1616 if (endlastfoot.empty)
1618 for (int i = 0; i < rows_; ++i) {
1619 if (row_info[i].endlastfoot)
1626 // end longtable support functions
1628 bool LyXTabular::setAscentOfRow(int row, int height)
1630 if (row >= rows_ || row_info[row].ascent_of_row == height)
1632 row_info[row].ascent_of_row = height;
1637 bool LyXTabular::setDescentOfRow(int row, int height)
1639 if (row >= rows_ || row_info[row].descent_of_row == height)
1641 row_info[row].descent_of_row = height;
1646 int LyXTabular::getAscentOfRow(int row) const
1650 return row_info[row].ascent_of_row;
1654 int LyXTabular::getDescentOfRow(int row) const
1658 return row_info[row].descent_of_row;
1662 int LyXTabular::getHeightOfTabular() const
1666 for (int row = 0; row < rows_; ++row)
1667 height += getAscentOfRow(row) + getDescentOfRow(row) +
1668 getAdditionalHeight(row);
1673 bool LyXTabular::isPartOfMultiColumn(int row, int column) const
1675 if ((row >= rows_) || (column >= columns_))
1677 return (cell_info[row][column].multicolumn == CELL_PART_OF_MULTICOLUMN);
1681 int LyXTabular::TeXTopHLine(ostream & os, int row) const
1683 if ((row < 0) || (row >= rows_))
1686 int const fcell = getFirstCellInRow(row);
1687 int const n = numberOfCellsInRow(fcell) + fcell;
1690 for (int i = fcell; i < n; ++i) {
1694 if (tmp == (n - fcell)) {
1697 for (int i = fcell; i < n; ++i) {
1700 << column_of_cell(i) + 1
1702 << right_column_of_cell(i) + 1
1714 int LyXTabular::TeXBottomHLine(ostream & os, int row) const
1716 if ((row < 0) || (row >= rows_))
1719 int const fcell = getFirstCellInRow(row);
1720 int const n = numberOfCellsInRow(fcell) + fcell;
1723 for (int i = fcell; i < n; ++i) {
1727 if (tmp == (n - fcell)) {
1730 for (int i = fcell; i < n; ++i) {
1731 if (bottomLine(i)) {
1733 << column_of_cell(i) + 1
1735 << right_column_of_cell(i) + 1
1747 int LyXTabular::TeXCellPreamble(ostream & os, int cell) const
1751 if (getRotateCell(cell)) {
1752 os << "\\begin{sideways}\n";
1755 if (isMultiColumn(cell)) {
1756 os << "\\multicolumn{" << cells_in_multicolumn(cell) << "}{";
1757 if (!cellinfo_of_cell(cell)->align_special.empty()) {
1758 os << cellinfo_of_cell(cell)->align_special << "}{";
1760 if (leftLine(cell) &&
1761 (isFirstCellInRow(cell) ||
1762 (!isMultiColumn(cell-1) && !leftLine(cell, true) &&
1763 !rightLine(cell-1, true))))
1767 if (!getPWidth(cell).zero()) {
1768 switch (getVAlignment(cell)) {
1769 case LYX_VALIGN_TOP:
1772 case LYX_VALIGN_CENTER:
1775 case LYX_VALIGN_BOTTOM:
1780 << getPWidth(cell).asLatexString()
1783 switch (getAlignment(cell)) {
1784 case LYX_ALIGN_LEFT:
1787 case LYX_ALIGN_RIGHT:
1795 if (rightLine(cell))
1797 if (((cell + 1) < numberofcells) && !isFirstCellInRow(cell+1) &&
1803 if (getUsebox(cell) == BOX_PARBOX) {
1805 switch (getVAlignment(cell)) {
1806 case LYX_VALIGN_TOP:
1809 case LYX_VALIGN_CENTER:
1812 case LYX_VALIGN_BOTTOM:
1816 os << "]{" << getPWidth(cell).asLatexString() << "}{";
1817 } else if (getUsebox(cell) == BOX_MINIPAGE) {
1818 os << "\\begin{minipage}[";
1819 switch (getVAlignment(cell)) {
1820 case LYX_VALIGN_TOP:
1823 case LYX_VALIGN_CENTER:
1826 case LYX_VALIGN_BOTTOM:
1830 os << "]{" << getPWidth(cell).asLatexString() << "}\n";
1837 int LyXTabular::TeXCellPostamble(ostream & os, int cell) const
1842 if (getUsebox(cell) == BOX_PARBOX)
1844 else if (getUsebox(cell) == BOX_MINIPAGE) {
1845 os << "%\n\\end{minipage}";
1848 if (isMultiColumn(cell)) {
1851 if (getRotateCell(cell)) {
1852 os << "%\n\\end{sideways}";
1859 int LyXTabular::TeXLongtableHeaderFooter(ostream & os, Buffer const * buf,
1860 LatexRunParams const & runparams) const
1862 if (!is_long_tabular)
1866 // output header info
1868 if (endhead.topDL) {
1872 for (int i = 0; i < rows_; ++i) {
1873 if (row_info[i].endhead) {
1874 ret += TeXRow(os, i, buf, runparams);
1877 if (endhead.bottomDL) {
1881 os << "\\endhead\n";
1883 if (endfirsthead.empty) {
1884 os << "\\endfirsthead\n";
1888 // output firstheader info
1889 if (haveLTFirstHead()) {
1890 if (endfirsthead.topDL) {
1894 for (int i = 0; i < rows_; ++i) {
1895 if (row_info[i].endfirsthead) {
1896 ret += TeXRow(os, i, buf, runparams);
1899 if (endfirsthead.bottomDL) {
1903 os << "\\endfirsthead\n";
1906 // output footer info
1908 if (endfoot.topDL) {
1912 for (int i = 0; i < rows_; ++i) {
1913 if (row_info[i].endfoot) {
1914 ret += TeXRow(os, i, buf, runparams);
1917 if (endfoot.bottomDL) {
1921 os << "\\endfoot\n";
1923 if (endlastfoot.empty) {
1924 os << "\\endlastfoot\n";
1928 // output lastfooter info
1929 if (haveLTLastFoot()) {
1930 if (endlastfoot.topDL) {
1934 for (int i = 0; i < rows_; ++i) {
1935 if (row_info[i].endlastfoot) {
1936 ret += TeXRow(os, i, buf, runparams);
1939 if (endlastfoot.bottomDL) {
1943 os << "\\endlastfoot\n";
1950 bool LyXTabular::isValidRow(int const row) const
1952 if (!is_long_tabular)
1954 return (!row_info[row].endhead && !row_info[row].endfirsthead &&
1955 !row_info[row].endfoot && !row_info[row].endlastfoot);
1959 int LyXTabular::TeXRow(ostream & os, int const i, Buffer const * buf,
1960 LatexRunParams const & runparams) const
1963 int cell = getCellNumber(i, 0);
1965 ret += TeXTopHLine(os, i);
1966 for (int j = 0; j < columns_; ++j) {
1967 if (isPartOfMultiColumn(i,j))
1969 ret += TeXCellPreamble(os, cell);
1970 InsetText * inset = getCellInset(cell);
1972 bool rtl = inset->paragraphs.begin()->isRightToLeftPar(buf->params) &&
1973 !inset->paragraphs.begin()->empty() && getPWidth(cell).zero();
1977 ret += inset->latex(buf, os, runparams);
1981 ret += TeXCellPostamble(os, cell);
1982 if (!isLastCellInRow(cell)) { // not last cell in row
1988 os << "\\tabularnewline\n";
1990 ret += TeXBottomHLine(os, i);
1995 int LyXTabular::latex(Buffer const * buf, ostream & os,
1996 LatexRunParams const & runparams) const
2000 //+---------------------------------------------------------------------
2001 //+ first the opening preamble +
2002 //+---------------------------------------------------------------------
2005 os << "\\begin{sideways}\n";
2008 if (is_long_tabular)
2009 os << "\\begin{longtable}{";
2011 os << "\\begin{tabular}{";
2012 for (int i = 0; i < columns_; ++i) {
2013 if (!column_info[i].align_special.empty()) {
2014 os << column_info[i].align_special;
2016 if (column_info[i].left_line)
2018 if (!column_info[i].p_width.zero()) {
2019 switch (column_info[i].alignment) {
2020 case LYX_ALIGN_LEFT:
2021 os << ">{\\raggedright}";
2023 case LYX_ALIGN_RIGHT:
2024 os << ">{\\raggedleft}";
2026 case LYX_ALIGN_CENTER:
2027 os << ">{\\centering}";
2029 case LYX_ALIGN_NONE:
2030 case LYX_ALIGN_BLOCK:
2031 case LYX_ALIGN_LAYOUT:
2032 case LYX_ALIGN_SPECIAL:
2036 switch (column_info[i].valignment) {
2037 case LYX_VALIGN_TOP:
2040 case LYX_VALIGN_CENTER:
2043 case LYX_VALIGN_BOTTOM:
2048 << column_info[i].p_width.asLatexString()
2051 switch (column_info[i].alignment) {
2052 case LYX_ALIGN_LEFT:
2055 case LYX_ALIGN_RIGHT:
2063 if (column_info[i].right_line)
2070 ret += TeXLongtableHeaderFooter(os, buf, runparams);
2072 //+---------------------------------------------------------------------
2073 //+ the single row and columns (cells) +
2074 //+---------------------------------------------------------------------
2076 for (int i = 0; i < rows_; ++i) {
2077 if (isValidRow(i)) {
2078 ret += TeXRow(os, i, buf, runparams);
2079 if (is_long_tabular && row_info[i].newpage) {
2080 os << "\\newpage\n";
2086 //+---------------------------------------------------------------------
2087 //+ the closing of the tabular +
2088 //+---------------------------------------------------------------------
2090 if (is_long_tabular)
2091 os << "\\end{longtable}";
2093 os << "\\end{tabular}";
2095 os << "\n\\end{sideways}";
2103 int LyXTabular::docbookRow(Buffer const * buf, ostream & os, int row) const
2106 int cell = getFirstCellInRow(row);
2109 for (int j = 0; j < columns_; ++j) {
2110 if (isPartOfMultiColumn(row, j))
2113 os << "<entry align=\"";
2114 switch (getAlignment(cell)) {
2115 case LYX_ALIGN_LEFT:
2118 case LYX_ALIGN_RIGHT:
2126 os << "\" valign=\"";
2127 switch (getVAlignment(cell)) {
2128 case LYX_VALIGN_TOP:
2131 case LYX_VALIGN_BOTTOM:
2134 case LYX_VALIGN_CENTER:
2139 if (isMultiColumn(cell)) {
2140 os << " namest=\"col" << j << "\" ";
2141 os << "nameend=\"col" << j + cells_in_multicolumn(cell) - 1<< '"';
2145 ret += getCellInset(cell)->docbook(buf, os, true);
2154 int LyXTabular::docbook(Buffer const * buf, ostream & os,
2155 bool /*mixcont*/) const
2159 //+---------------------------------------------------------------------
2160 //+ first the opening preamble +
2161 //+---------------------------------------------------------------------
2163 os << "<tgroup cols=\"" << columns_
2164 << "\" colsep=\"1\" rowsep=\"1\">\n";
2166 for (int i = 0; i < columns_; ++i) {
2167 os << "<colspec colname=\"col" << i << "\" align=\"";
2168 switch (column_info[i].alignment) {
2169 case LYX_ALIGN_LEFT:
2172 case LYX_ALIGN_RIGHT:
2183 //+---------------------------------------------------------------------
2184 //+ Long Tabular case +
2185 //+---------------------------------------------------------------------
2187 // output header info
2188 if (haveLTHead() || haveLTFirstHead()) {
2191 for (int i = 0; i < rows_; ++i) {
2192 if (row_info[i].endhead || row_info[i].endfirsthead) {
2193 ret += docbookRow(buf, os, i);
2199 // output footer info
2200 if (haveLTFoot() || haveLTLastFoot()) {
2203 for (int i = 0; i < rows_; ++i) {
2204 if (row_info[i].endfoot || row_info[i].endlastfoot) {
2205 ret += docbookRow(buf, os, i);
2212 //+---------------------------------------------------------------------
2213 //+ the single row and columns (cells) +
2214 //+---------------------------------------------------------------------
2218 for (int i = 0; i < rows_; ++i) {
2219 if (isValidRow(i)) {
2220 ret += docbookRow(buf, os, i);
2225 //+---------------------------------------------------------------------
2226 //+ the closing of the tabular +
2227 //+---------------------------------------------------------------------
2236 int LyXTabular::asciiTopHLine(ostream & os, int row,
2237 vector<unsigned int> const & clen) const
2239 int const fcell = getFirstCellInRow(row);
2240 int const n = numberOfCellsInRow(fcell) + fcell;
2243 for (int i = fcell; i < n; ++i) {
2253 for (int i = fcell; i < n; ++i) {
2264 int column = column_of_cell(i);
2265 int len = clen[column];
2266 while (isPartOfMultiColumn(row, ++column))
2267 len += clen[column] + 4;
2268 os << string(len, ch);
2283 int LyXTabular::asciiBottomHLine(ostream & os, int row,
2284 vector<unsigned int> const & clen) const
2286 int const fcell = getFirstCellInRow(row);
2287 int const n = numberOfCellsInRow(fcell) + fcell;
2290 for (int i = fcell; i < n; ++i) {
2291 if (bottomLine(i)) {
2300 for (int i = fcell; i < n; ++i) {
2301 if (bottomLine(i)) {
2311 int column = column_of_cell(i);
2312 int len = clen[column];
2313 while (isPartOfMultiColumn(row, ++column))
2314 len += clen[column] + 4;
2315 os << string(len, ch);
2316 if (bottomLine(i)) {
2330 int LyXTabular::asciiPrintCell(Buffer const * buf, ostream & os,
2331 int cell, int row, int column,
2332 vector<unsigned int> const & clen,
2333 bool onlydata) const
2336 int ret = getCellInset(cell)->ascii(buf, sstr, 0);
2348 unsigned int len1 = sstr.str().length();
2349 unsigned int len2 = clen[column];
2350 while (isPartOfMultiColumn(row, ++column))
2351 len2 += clen[column] + 4;
2354 switch (getAlignment(cell)) {
2356 case LYX_ALIGN_LEFT:
2359 case LYX_ALIGN_RIGHT:
2363 case LYX_ALIGN_CENTER:
2369 os << string(len1, ' ') << sstr.str() << string(len2, ' ');
2371 if (rightLine(cell))
2380 int LyXTabular::ascii(Buffer const * buf, ostream & os, int const depth,
2381 bool onlydata, unsigned char delim) const
2385 // first calculate the width of the single columns
2386 vector<unsigned int> clen(columns_);
2389 // first all non (real) multicolumn cells!
2390 for (int j = 0; j < columns_; ++j) {
2392 for (int i = 0; i < rows_; ++i) {
2393 int cell = getCellNumber(i, j);
2394 if (isMultiColumn(cell, true))
2397 getCellInset(cell)->ascii(buf, sstr, 0);
2398 if (clen[j] < sstr.str().length())
2399 clen[j] = sstr.str().length();
2402 // then all (real) multicolumn cells!
2403 for (int j = 0; j < columns_; ++j) {
2404 for (int i = 0; i < rows_; ++i) {
2405 int cell = getCellNumber(i, j);
2406 if (!isMultiColumn(cell, true) || isPartOfMultiColumn(i, j))
2409 getCellInset(cell)->ascii(buf, sstr, 0);
2410 int len = int(sstr.str().length());
2411 int const n = cells_in_multicolumn(cell);
2412 for (int k = j; (len > 0) && (k < (j + n - 1)); ++k)
2414 if (len > int(clen[j + n - 1]))
2415 clen[j + n - 1] = len;
2420 for (int i = 0; i < rows_; ++i) {
2422 if (asciiTopHLine(os, i, clen)) {
2423 for (int j = 0; j < depth; ++j)
2427 for (int j = 0; j < columns_; ++j) {
2428 if (isPartOfMultiColumn(i,j))
2430 if (onlydata && j > 0)
2432 ret += asciiPrintCell(buf, os, cell, i, j, clen, onlydata);
2437 for (int j = 0; j < depth; ++j)
2439 if (asciiBottomHLine(os, i, clen)) {
2440 for (int j = 0; j < depth; ++j)
2449 InsetText * LyXTabular::getCellInset(int cell) const
2452 return & cell_info[row_of_cell(cell)][column_of_cell(cell)].inset;
2456 InsetText * LyXTabular::getCellInset(int row, int column) const
2458 cur_cell = getCellNumber(row, column);
2459 return & cell_info[row][column].inset;
2463 int LyXTabular::getCellFromInset(Inset const * inset, int maybe_cell) const
2465 // is this inset part of the tabular?
2466 if (!inset || inset->owner() != owner_) {
2467 lyxerr[Debug::INSETTEXT]
2468 << "this is not a cell of the tabular!" << endl;
2472 const int save_cur_cell = cur_cell;
2473 int cell = cur_cell;
2474 if (getCellInset(cell) != inset) {
2476 if (cell == -1 || getCellInset(cell) != inset) {
2482 for (cell = getNumberOfCells(); cell >= 0; --cell) {
2483 if (getCellInset(cell) == inset)
2486 lyxerr[Debug::INSETTEXT]
2487 << "LyXTabular::getCellFromInset: "
2489 << ", cur_cell=" << save_cur_cell
2490 << ", maybe_cell=" << maybe_cell
2492 // We should have found a cell at this point
2494 lyxerr << "LyXTabular::getCellFromInset: "
2495 << "Cell not found!" << endl;
2503 void LyXTabular::validate(LaTeXFeatures & features) const
2505 features.require("NeedTabularnewline");
2506 if (isLongTabular())
2507 features.require("longtable");
2509 features.require("rotating");
2510 for (int cell = 0; cell < numberofcells; ++cell) {
2511 if (getVAlignment(cell) != LYX_VALIGN_TOP ||
2512 (!getPWidth(cell).zero() && !isMultiColumn(cell)))
2513 features.require("array");
2514 getCellInset(cell)->validate(features);
2519 void LyXTabular::getLabelList(std::vector<string> & list) const
2521 for (int i = 0; i < rows_; ++i)
2522 for (int j = 0; j < columns_; ++j)
2523 getCellInset(i, j)->getLabelList(list);
2527 LyXTabular::BoxType LyXTabular::useParbox(int cell) const
2529 ParagraphList const & parlist = getCellInset(cell)->paragraphs;
2530 ParagraphList::const_iterator cit = parlist.begin();
2531 ParagraphList::const_iterator end = parlist.end();
2533 for (; cit != end; ++cit) {
2534 for (int i = 0; i < cit->size(); ++i) {
2535 if (cit->isNewline(i))