+
+inline
+bool string2type(string const str, LyXTabular::BoxType & num)
+{
+ if (str == "none")
+ num = LyXTabular::BOX_NONE;
+ else if (str == "parbox")
+ num = LyXTabular::BOX_PARBOX;
+ else if (str == "minipage")
+ num = LyXTabular::BOX_MINIPAGE;
+ else
+ return false;
+ return true;
+}
+
+
+inline
+bool string2type(string const str, bool & num)
+{
+ if (str == "true")
+ num = true;
+ else if (str == "false")
+ num = false;
+ else
+ return false;
+ return true;
+}
+
+
+bool getTokenValue(string const & str, const char * token, string & ret)
+{
+ size_t token_length = strlen(token);
+ string::size_type pos = str.find(token);
+
+ if (pos == string::npos || pos+token_length+1 >= str.length()
+ || str[pos+token_length] != '=')
+ return false;
+ ret.erase();
+ pos += token_length + 1;
+ char ch = str[pos];
+ if ((ch != '"') && (ch != '\'')) { // only read till next space
+ ret += ch;
+ ch = ' ';
+ }
+ while((pos < str.length() - 1) && (str[++pos] != ch))
+ ret += str[pos];
+
+ return true;
+}
+
+
+bool getTokenValue(string const & str, const char * token, int & num)
+{
+ string tmp;
+ if (!getTokenValue(str, token, tmp))
+ return false;
+ num = strToInt(tmp);
+ return true;
+}
+
+
+bool getTokenValue(string const & str, const char * token, LyXAlignment & num)
+{
+ string tmp;
+ if (!getTokenValue(str, token, tmp))
+ return false;
+ return string2type(tmp, num);
+}
+
+
+bool getTokenValue(string const & str, const char * token,
+ LyXTabular::VAlignment & num)
+{
+ string tmp;
+ if (!getTokenValue(str, token, tmp))
+ return false;
+ return string2type(tmp, num);
+}
+
+
+bool getTokenValue(string const & str, const char * token,
+ LyXTabular::BoxType & num)
+{
+ string tmp;
+ if (!getTokenValue(str, token, tmp))
+ return false;
+ return string2type(tmp, num);
+}
+
+
+bool getTokenValue(string const & str, const char * token, bool & flag)
+{
+ string tmp;
+ if (!getTokenValue(str, token, tmp))
+ return false;
+ return string2type(tmp, flag);
+}
+
+
+inline
+void l_getline(istream & is, string & str)
+{
+ str.erase();
+ while (str.empty()) {
+ getline(is, str);
+ if (!str.empty() && str[str.length() - 1] == '\r')
+ str.erase(str.length() - 1);
+ }
+}
+
+} // namespace anon
+
+
+void LyXTabular::Read(Buffer const * buf, LyXLex & lex)
+{
+ string line;
+ istream & is = lex.getStream();
+
+ l_getline(is, line);
+ if (!prefixIs(line, "<lyxtabular ")
+ && !prefixIs(line, "<LyXTabular ")) {
+ OldFormatRead(lex, line);
+ return;
+ }
+
+ int version;
+ if (!getTokenValue(line, "version", version))
+ return;
+ if (version == 1)
+ ReadOld(buf, is, lex, line);
+ else if (version == 2)
+ ReadNew(buf, is, lex, line);
+}
+
+
+void LyXTabular::ReadNew(Buffer const * buf, istream & is,
+ LyXLex & lex, string const & l)
+{
+ string line(l);
+ int rows_arg;
+ if (!getTokenValue(line, "rows", rows_arg))
+ return;
+ int columns_arg;
+ if (!getTokenValue(line, "columns", columns_arg))
+ return;
+ Init(rows_arg, columns_arg);
+ l_getline(is, line);
+ if (!prefixIs(line, "<features")) {
+ lyxerr << "Wrong tabular format (expected <features ...> got" <<
+ line << ")" << endl;
+ return;
+ }
+ getTokenValue(line, "rotate", rotate);
+ getTokenValue(line, "islongtable", is_long_tabular);
+ getTokenValue(line, "endhead", endhead);
+ getTokenValue(line, "endfirsthead", endfirsthead);
+ getTokenValue(line, "endfoot", endfoot);
+ getTokenValue(line, "endlastfoot", endlastfoot);
+
+ for (int j = 0; j < columns_; ++j) {
+ l_getline(is,line);
+ if (!prefixIs(line,"<column")) {
+ lyxerr << "Wrong tabular format (expected <column ...> got" <<
+ line << ")" << endl;
+ return;
+ }
+ getTokenValue(line, "alignment", column_info[j].alignment);
+ getTokenValue(line, "valignment", column_info[j].valignment);
+ getTokenValue(line, "leftline", column_info[j].left_line);
+ getTokenValue(line, "rightline", column_info[j].right_line);
+ getTokenValue(line, "width", column_info[j].p_width);
+ getTokenValue(line, "special", column_info[j].align_special);
+ }
+
+ for (int i = 0; i < rows_; ++i) {
+ l_getline(is, line);
+ if (!prefixIs(line, "<row")) {
+ lyxerr << "Wrong tabular format (expected <row ...> got" <<
+ line << ")" << endl;
+ return;
+ }
+ getTokenValue(line, "topline", row_info[i].top_line);
+ getTokenValue(line, "bottomline", row_info[i].bottom_line);
+ getTokenValue(line, "newpage", row_info[i].newpage);
+ for (int j = 0; j < columns_; ++j) {
+ l_getline(is, line);
+ if (!prefixIs(line, "<cell")) {
+ lyxerr << "Wrong tabular format (expected <cell ...> got" <<
+ line << ")" << endl;
+ return;
+ }
+ getTokenValue(line, "multicolumn", cell_info[i][j].multicolumn);
+ getTokenValue(line, "alignment", cell_info[i][j].alignment);
+ getTokenValue(line, "valignment", cell_info[i][j].valignment);
+ getTokenValue(line, "topline", cell_info[i][j].top_line);
+ getTokenValue(line, "bottomline", cell_info[i][j].bottom_line);
+ getTokenValue(line, "leftline", cell_info[i][j].left_line);
+ getTokenValue(line, "rightline", cell_info[i][j].right_line);
+ getTokenValue(line, "rotate", cell_info[i][j].rotate);
+ getTokenValue(line, "usebox", cell_info[i][j].usebox);
+ getTokenValue(line, "width", cell_info[i][j].p_width);
+ getTokenValue(line, "special", cell_info[i][j].align_special);
+ l_getline(is, line);
+ if (prefixIs(line, "\\begin_inset")) {
+ cell_info[i][j].inset.Read(buf, lex);
+ l_getline(is, line);
+ }
+ if (!prefixIs(line, "</cell>")) {
+ lyxerr << "Wrong tabular format (expected </cell> got" <<
+ line << ")" << endl;
+ return;
+ }
+ }
+ l_getline(is, line);
+ if (!prefixIs(line, "</row>")) {
+ lyxerr << "Wrong tabular format (expected </row> got" <<
+ line << ")" << endl;
+ return;
+ }
+ }
+ while (!prefixIs(line, "</lyxtabular>")) {
+ l_getline(is, line);
+ }
+ set_row_column_number_info();
+}
+
+
+void LyXTabular::OldFormatRead(LyXLex & lex, string const & fl)
+{
+ int version;
+ int i;
+ int j;
+ int rows_arg = 0;
+ int columns_arg = 0;
+ int is_long_tabular_arg = false;
+ int rotate_arg = false;
+ int a = -1;
+ int b = -1;
+ int c = -1;
+ int d = -1;
+ int e = 0;
+ int f = 0;
+ int g = 0;
+
+ istream & is = lex.getStream();
+ string s(fl);
+ if (s.length() > 8)
+ version = lyx::atoi(s.substr(8, string::npos));
+ else
+ version = 1;
+
+ vector<int> cont_row_info;
+
+ if (version < 5) {
+ lyxerr << "Tabular format < 5 is not supported anymore\n"
+ "Get an older version of LyX (< 1.1.x) for conversion!"
+ << endl;
+ WriteAlert(_("Warning:"),
+ _("Tabular format < 5 is not supported anymore\n"),
+ _("Get an older version of LyX (< 1.1.x) for conversion!"));
+ if (version > 2) {
+ is >> rows_arg >> columns_arg >> is_long_tabular_arg
+ >> rotate_arg >> a >> b >> c >> d;
+ } else
+ is >> rows_arg >> columns_arg;
+ Init(rows_arg, columns_arg);
+ cont_row_info = vector<int>(rows_arg);
+ SetLongTabular(is_long_tabular_arg);
+ SetRotateTabular(rotate_arg);
+ string tmp;
+ for (i = 0; i < rows_; ++i) {
+ getline(is, tmp);
+ cont_row_info[i] = false;
+ }
+ for (i = 0; i < columns_; ++i) {
+ getline(is, tmp);
+ }
+ for (i = 0; i < rows_; ++i) {
+ for (j = 0; j < columns_; ++j) {
+ getline(is, tmp);
+ }
+ }
+ } else {
+ is >> rows_arg >> columns_arg >> is_long_tabular_arg
+ >> rotate_arg >> a >> b >> c >> d;
+ Init(rows_arg, columns_arg);
+ cont_row_info = vector<int>(rows_arg);
+ SetLongTabular(is_long_tabular_arg);
+ SetRotateTabular(rotate_arg);
+ endhead = a + 1;
+ endfirsthead = b + 1;
+ endfoot = c + 1;
+ endlastfoot = d + 1;
+ for (i = 0; i < rows_; ++i) {
+ a = b = c = d = e = f = g = 0;
+ is >> a >> b >> c >> d;
+ row_info[i].top_line = a;
+ row_info[i].bottom_line = b;
+ cont_row_info[i] = c;
+ row_info[i].newpage = d;
+ }
+ for (i = 0; i < columns_; ++i) {
+ string s1;
+ string s2;
+ is >> a >> b >> c;
+#if 1
+ char ch; // skip '"'
+ is >> ch;
+#else
+ // ignore is buggy but we will use it later (Lgb)
+ is.ignore(); // skip '"'
+#endif
+ getline(is, s1, '"');
+#if 1
+ is >> ch; // skip '"'
+#else
+ // ignore is buggy but we will use it later (Lgb)
+ is.ignore(); // skip '"'
+#endif
+ getline(is, s2, '"');
+ column_info[i].alignment = static_cast<LyXAlignment>(a);
+ column_info[i].left_line = b;
+ column_info[i].right_line = c;
+ column_info[i].p_width = s1;
+ column_info[i].align_special = s2;
+ }
+ for (i = 0; i < rows_; ++i) {
+ for (j = 0; j < columns_; ++j) {
+ string s1;
+ string s2;
+ is >> a >> b >> c >> d >> e >> f >> g;
+#if 1
+ char ch;
+ is >> ch; // skip '"'
+#else
+ // ignore is buggy but we will use it later (Lgb)
+ is.ignore(); // skip '"'
+#endif
+ getline(is, s1, '"');
+#if 1
+ is >> ch; // skip '"'
+#else
+ // ignore is buggy but we will use it later (Lgb)
+ is.ignore(); // skip '"'
+#endif
+ getline(is, s2, '"');
+ cell_info[i][j].multicolumn = static_cast<char>(a);
+ cell_info[i][j].alignment = static_cast<LyXAlignment>(b);
+ cell_info[i][j].top_line = static_cast<char>(c);
+ cell_info[i][j].bottom_line = static_cast<char>(d);
+ cell_info[i][j].left_line = column_info[j].left_line;
+ cell_info[i][j].right_line = column_info[j].right_line;
+ cell_info[i][j].rotate = static_cast<bool>(f);
+ cell_info[i][j].usebox = static_cast<BoxType>(g);
+ cell_info[i][j].align_special = s1;
+ cell_info[i][j].p_width = s2;
+ }
+ }
+ }
+ set_row_column_number_info(true);
+
+ LyXParagraph * par = new LyXParagraph;
+ LyXParagraph * return_par = 0;
+#ifndef NEW_INSETS
+ LyXParagraph::footnote_flag footnoteflag = LyXParagraph::NO_FOOTNOTE;
+ LyXParagraph::footnote_kind footnotekind = LyXParagraph::FOOTNOTE;
+#endif
+ string tmptok;
+ int pos = 0;
+ char depth = 0;
+ LyXFont font(LyXFont::ALL_INHERIT);
+ font.setLanguage(owner_->BufferOwner()->GetLanguage());
+
+ while (lex.IsOK()) {
+ lex.nextToken();
+ string const token = lex.GetString();
+ if (token.empty())
+ continue;
+ if (token == "\\layout"
+ || token == "\\end_float"
+ || token == "\\end_deeper") {
+ lex.pushToken(token);
+ break;
+ }
+ if (owner_->BufferOwner()->parseSingleLyXformat2Token(lex, par,
+ return_par,
+ token, pos,
+ depth, font
+#ifndef NEW_INSETS
+ ,
+ footnoteflag,
+ footnotekind
+#endif
+ ))
+ {
+ // the_end read
+ lex.pushToken(token);
+ break;
+ }
+ if (return_par) {
+ lex.printError("New Paragraph allocated! This should not happen!");
+ lex.pushToken(token);
+ delete par;
+ par = return_par;
+ break;
+ }
+ }
+ // now we have the par we should fill the insets with this!
+ int cell = 0;
+ InsetText * inset = GetCellInset(cell);
+ int row;
+
+#ifndef NEW_INSETS
+ for (int i = 0; i < par->Last(); ++i)
+#else
+ for (int i = 0; i < par->size(); ++i)
+#endif
+ {
+ if (par->IsNewline(i)) {
+ ++cell;
+ if (cell > GetNumberOfCells()) {
+ lyxerr << "Some error in reading old table format occured!" <<
+ endl << "Terminating when reading cell[" << cell << "]!" <<
+ endl;
+ delete par;
+ return;
+ }
+ row = row_of_cell(cell);
+ if (cont_row_info[row]) {
+ DeleteRow(row);
+ cont_row_info.erase(cont_row_info.begin() + row); //&cont_row_info[row]);
+ while(!IsFirstCellInRow(--cell));
+ } else {
+ inset = GetCellInset(cell);
+ continue;
+ }
+ inset = GetCellInset(cell);
+ row = row_of_cell(cell);
+ if (!cell_info[row_of_cell(cell)][column_of_cell(cell)].usebox)
+ {
+ // insert a space instead
+ par->Erase(i);
+ par->InsertChar(i, ' ');
+ }
+ }
+ par->CopyIntoMinibuffer(*owner_->BufferOwner(), i);
+#ifndef NEW_INSETS
+ inset->par->InsertFromMinibuffer(inset->par->Last());
+#else
+ inset->par->InsertFromMinibuffer(inset->par->size());
+#endif
+ }
+ delete par;
+ Reinit();
+}
+
+
+bool LyXTabular::IsMultiColumn(int cell, bool real) const
+{
+ return ((!real || (column_of_cell(cell) != right_column_of_cell(cell))) &&
+ (cellinfo_of_cell(cell)->multicolumn != LyXTabular::CELL_NORMAL));
+}
+
+
+LyXTabular::cellstruct * LyXTabular::cellinfo_of_cell(int cell) const
+{
+ int const row = row_of_cell(cell);
+ int const column = column_of_cell(cell);
+ return &cell_info[row][column];
+}
+
+
+void LyXTabular::SetMultiColumn(int cell, int number)
+{
+ cellinfo_of_cell(cell)->multicolumn = CELL_BEGIN_OF_MULTICOLUMN;
+ cellinfo_of_cell(cell)->alignment = column_info[column_of_cell(cell)].alignment;
+ cellinfo_of_cell(cell)->top_line = row_info[row_of_cell(cell)].top_line;
+ cellinfo_of_cell(cell)->bottom_line = row_info[row_of_cell(cell)].bottom_line;
+ for (number--; number > 0; --number) {
+ cellinfo_of_cell(cell+number)->multicolumn = CELL_PART_OF_MULTICOLUMN;
+ }
+ set_row_column_number_info();
+}
+
+
+int LyXTabular::cells_in_multicolumn(int cell) const
+{
+ int const row = row_of_cell(cell);
+ int column = column_of_cell(cell);
+ int result = 1;
+ ++column;
+ while ((column < columns_) &&
+ cell_info[row][column].multicolumn == CELL_PART_OF_MULTICOLUMN)
+ {
+ ++result;
+ ++column;
+ }
+ return result;
+}
+
+
+int LyXTabular::UnsetMultiColumn(int cell)
+{
+ int const row = row_of_cell(cell);
+ int column = column_of_cell(cell);
+
+ int result = 0;
+
+ if (cell_info[row][column].multicolumn == CELL_BEGIN_OF_MULTICOLUMN) {
+ cell_info[row][column].multicolumn = CELL_NORMAL;
+ ++column;
+ while ((column < columns_) &&
+ (cell_info[row][column].multicolumn ==CELL_PART_OF_MULTICOLUMN))
+ {
+ cell_info[row][column].multicolumn = CELL_NORMAL;
+ ++column;
+ ++result;
+ }
+ }
+ set_row_column_number_info();
+ return result;
+}
+
+
+void LyXTabular::SetLongTabular(bool what)
+{
+ is_long_tabular = what;
+}
+
+
+bool LyXTabular::IsLongTabular() const
+{
+ return is_long_tabular;
+}
+
+
+void LyXTabular::SetRotateTabular(bool flag)
+{
+ rotate = flag;
+}
+
+
+bool LyXTabular::GetRotateTabular() const
+{
+ return rotate;
+}
+
+
+void LyXTabular::SetRotateCell(int cell, bool flag)
+{
+ cellinfo_of_cell(cell)->rotate = flag;
+}
+
+
+bool LyXTabular::GetRotateCell(int cell) const
+{
+ return cellinfo_of_cell(cell)->rotate;
+}
+
+
+bool LyXTabular::NeedRotating() const
+{
+ if (rotate)
+ return true;
+ for (int i = 0; i < rows_; ++i) {
+ for (int j = 0; j < columns_; ++j) {
+ if (cell_info[i][j].rotate)
+ return true;
+ }
+ }
+ return false;
+}
+
+
+bool LyXTabular::IsLastCell(int cell) const
+{
+ if ((cell + 1) < GetNumberOfCells())
+ return false;
+ return true;
+}
+
+
+int LyXTabular::GetCellAbove(int cell) const
+{
+ if (row_of_cell(cell) > 0)
+ return cell_info[row_of_cell(cell)-1][column_of_cell(cell)].cellno;
+ return cell;
+}
+
+
+int LyXTabular::GetCellBelow(int cell) const
+{
+ if (row_of_cell(cell) + 1 < rows_)
+ return cell_info[row_of_cell(cell)+1][column_of_cell(cell)].cellno;
+ return cell;
+}
+
+
+int LyXTabular::GetLastCellAbove(int cell) const
+{
+ if (row_of_cell(cell) <= 0)
+ return cell;
+ if (!IsMultiColumn(cell))
+ return GetCellAbove(cell);
+ return cell_info[row_of_cell(cell) - 1][right_column_of_cell(cell)].cellno;
+}
+
+
+int LyXTabular::GetLastCellBelow(int cell) const
+{
+ if (row_of_cell(cell) + 1 >= rows_)
+ return cell;
+ if (!IsMultiColumn(cell))
+ return GetCellBelow(cell);
+ return cell_info[row_of_cell(cell) + 1][right_column_of_cell(cell)].cellno;
+}
+
+
+int LyXTabular::GetCellNumber(int row, int column) const
+{
+ if (column >= columns_)
+ column = columns_ - 1;
+ else if (column < 0)
+ column = 0;
+ if (row >= rows_)
+ row = rows_ - 1;
+ else if (row < 0)
+ row = 0;
+
+ return cell_info[row][column].cellno;
+}
+
+
+void LyXTabular::SetUsebox(int cell, BoxType type)
+{
+ cellinfo_of_cell(cell)->usebox = type;
+}
+
+
+LyXTabular::BoxType LyXTabular::GetUsebox(int cell) const
+{
+ if (column_info[column_of_cell(cell)].p_width.empty() &&
+ !(IsMultiColumn(cell) && !cellinfo_of_cell(cell)->p_width.empty()))
+ return BOX_NONE;
+ if (cellinfo_of_cell(cell)->usebox > 1)
+ return cellinfo_of_cell(cell)->usebox;
+ return UseParbox(cell);
+}
+
+
+void LyXTabular::SetLTHead(int cell, bool first)
+{
+ int const row = row_of_cell(cell);
+ int const val = (row + 1) * (column_of_cell(cell) ? 1 : -1);
+
+ if (first) {
+ if (endfirsthead == val)
+ endfirsthead = 0;
+ else
+ endfirsthead = val;
+ } else {
+ if (endhead == val)
+ endhead = 0;
+ else
+ endhead = val;
+ }
+}
+
+
+bool LyXTabular::GetRowOfLTHead(int cell, int & row) const
+{
+ row = endhead;
+ if (abs(endhead) > rows_)
+ return false;
+ return (row_of_cell(cell) == abs(endhead) - 1);
+}
+
+
+bool LyXTabular::GetRowOfLTFirstHead(int cell, int & row) const
+{
+ row = endfirsthead;
+ if (abs(endfirsthead) > rows_)
+ return false;
+ return (row_of_cell(cell) == abs(endfirsthead) - 1);
+}
+
+
+void LyXTabular::SetLTFoot(int cell, bool last)
+{
+ int const row = row_of_cell(cell);
+ int const val = (row + 1) * (column_of_cell(cell) ? 1 : -1);
+
+ if (last) {
+ if (endlastfoot == val)
+ endlastfoot = 0;
+ else
+ endlastfoot = val;
+ } else {
+ if (endfoot == val)
+ endfoot = 0;
+ else
+ endfoot = val;
+ }
+}
+
+
+bool LyXTabular::GetRowOfLTFoot(int cell, int & row) const
+{
+ row = endfoot;
+ if ((endfoot + 1) > rows_)
+ return false;
+ return (row_of_cell(cell) == abs(endfoot) - 1);
+}
+
+
+bool LyXTabular::GetRowOfLTLastFoot(int cell, int & row) const