private void UpdateTableCells(DomTable table, bool fixTableCellSize) { // Number of table column var columns = 0; // Flag of cell merge var merge = false; // Right position of all cells var rights = new ArrayList(); // Right position of table var tableLeft = 0; for (var count = table.Elements.Count - 1; count >= 0; count--) { var tableRow = (DomTableRow) table.Elements[count]; if (tableRow.Elements.Count == 0) table.Elements.RemoveAt(count); } if (table.Elements.Count == 0) Debug.WriteLine(""); foreach (DomTableRow tableRow in table.Elements) { var lastCellX = 0; columns = Math.Max(columns, tableRow.Elements.Count); if (tableRow.HasAttribute(Consts.Irow)) { tableRow.RowIndex = tableRow.Attributes[Consts.Irow]; } tableRow.IsLastRow = tableRow.HasAttribute(Consts.Lastrow); tableRow.Header = tableRow.HasAttribute(Consts.Trhdr); // Read row height if (tableRow.HasAttribute(Consts.Trrh)) { tableRow.Height = tableRow.Attributes[Consts.Trrh]; if (tableRow.Height == 0) tableRow.Height = DefaultRowHeight; else if (tableRow.Height < 0) tableRow.Height = -tableRow.Height; } else tableRow.Height = DefaultRowHeight; // Read default padding of cell tableRow.PaddingLeft = tableRow.HasAttribute(Consts.Trpaddl) ? tableRow.Attributes[Consts.Trpaddl] : int.MinValue; tableRow.PaddingTop = tableRow.HasAttribute(Consts.Trpaddt) ? tableRow.Attributes[Consts.Trpaddt] : int.MinValue; tableRow.PaddingRight = tableRow.HasAttribute(Consts.Trpaddr) ? tableRow.Attributes[Consts.Trpaddr] : int.MinValue; tableRow.PaddingBottom = tableRow.HasAttribute(Consts.Trpaddb) ? tableRow.Attributes[Consts.Trpaddb] : int.MinValue; if (tableRow.HasAttribute(Consts.Trleft)) tableLeft = tableRow.Attributes[Consts.Trleft]; if (tableRow.HasAttribute(Consts.Trcbpat)) tableRow.Format.BackColor = ColorTable.GetColor( tableRow.Attributes[Consts.Trcbpat], Color.Transparent); var widthCount = 0; foreach (DomTableCell cell in tableRow.Elements) { // Set cell's dispaly format if (cell.HasAttribute(Consts.Clvmgf)) merge = true; if (cell.HasAttribute(Consts.Clvmrg)) merge = true; cell.PaddingLeft = cell.HasAttribute(Consts.Clpadl) ? cell.Attributes[Consts.Clpadl] : int.MinValue; cell.PaddingRight = cell.HasAttribute(Consts.Clpadr) ? cell.Attributes[Consts.Clpadr] : int.MinValue; cell.PaddingTop = cell.HasAttribute(Consts.Clpadt) ? cell.Attributes[Consts.Clpadt] : int.MinValue; cell.PaddingBottom = cell.HasAttribute(Consts.Clpadb) ? cell.Attributes[Consts.Clpadb] : int.MinValue; // Whether display border line cell.Format.LeftBorder = cell.HasAttribute(Consts.Clbrdrl); cell.Format.TopBorder = cell.HasAttribute(Consts.Clbrdrt); cell.Format.RightBorder = cell.HasAttribute(Consts.Clbrdrr); cell.Format.BottomBorder = cell.HasAttribute(Consts.Clbrdrb); if (cell.HasAttribute(Consts.Brdrcf)) { cell.Format.BorderColor = ColorTable.GetColor( cell.GetAttributeValue(Consts.Brdrcf, 1), Color.Black); } for (var count = cell.Attributes.Count - 1; count >= 0; count--) { var name3 = cell.Attributes.GetItem(count).Name; if (name3 == Consts.Brdrtbl || name3 == Consts.Brdrnone || name3 == Consts.Brdrnil) { for (var count2 = count - 1; count2 >= 0; count2--) { var name2 = cell.Attributes.GetItem(count2).Name; if (name2 == Consts.Clbrdrl) { cell.Format.LeftBorder = false; break; } if (name2 == Consts.Clbrdrt) { cell.Format.TopBorder = false; break; } if (name2 == Consts.Clbrdrr) { cell.Format.RightBorder = false; break; } if (name2 == Consts.Clbrdrb) { cell.Format.BottomBorder = false; break; } } } } // Vertial alignment if (cell.HasAttribute(Consts.Clvertalt)) cell.VerticalAlignment = RtfVerticalAlignment.Top; else if (cell.HasAttribute(Consts.Clvertalc)) cell.VerticalAlignment = RtfVerticalAlignment.Middle; else if (cell.HasAttribute(Consts.Clvertalb)) cell.VerticalAlignment = RtfVerticalAlignment.Bottom; // Background color cell.Format.BackColor = cell.HasAttribute(Consts.Clcbpat) ? ColorTable.GetColor(cell.Attributes[Consts.Clcbpat], Color.Transparent) : Color.Transparent; if (cell.HasAttribute(Consts.Clcfpat)) cell.Format.BorderColor = ColorTable.GetColor(cell.Attributes[Consts.Clcfpat], Color.Black); // Cell's width var cellWidth = 2763; // cell's default with is 2763 Twips(570 Document) if (cell.HasAttribute(Consts.Cellx)) { cellWidth = cell.Attributes[Consts.Cellx] - lastCellX; if (cellWidth < 100) cellWidth = 100; } var right = lastCellX + cellWidth; // fix cell's right position , if this position is very near with another cell's // right position( less then 45 twips or 3 pixel), then consider these two position // is the same , this can decrease number of table columns foreach (var t in rights) { if (Math.Abs(right - (int) t) < 45) { right = (int) t; cellWidth = right - lastCellX; break; } } cell.Left = lastCellX; cell.Width = cellWidth; widthCount += cellWidth; if (rights.Contains(right) == false) { // becase of convert twips to unit of document may cause truncation error. // This may cause rights.Contains mistake . so scale cell's with with // native twips unit , after all computing , convert to unit of document. rights.Add(right); } lastCellX = lastCellX + cellWidth; } //foreach tableRow.Width = widthCount; } //foreach if (rights.Count == 0) { // can not detect cell's width , so consider set cell's width // automatic, then set cell's default width. var cols = 1; foreach (DomTableRow row in table.Elements) cols = Math.Max(cols, row.Elements.Count); var w = ClientWidth/cols; for (var count = 0; count < cols; count++) rights.Add(count*w + w); } // Computing cell's rowspan and colspan , number of rights array is the number of table columns. rights.Add(0); rights.Sort(); // Add table column instance for (var count = 1; count < rights.Count; count++) { var col = new DomTableColumn {Width = (int) rights[count] - (int) rights[count - 1]}; table.Columns.Add(col); } for (var rowIndex = 1; rowIndex < table.Elements.Count; rowIndex++) { var row = (DomTableRow) table.Elements[rowIndex]; for (var colIndex = 0; colIndex < row.Elements.Count; colIndex++) { var cell = (DomTableCell) row.Elements[colIndex]; if (cell.Width == 0) { // If current cell not special width , then use the width of cell which // in the same colum and in the last row var preRow = (DomTableRow) table.Elements[rowIndex - 1]; if (preRow.Elements.Count > colIndex) { var preCell = (DomTableCell) preRow.Elements[colIndex]; cell.Left = preCell.Left; cell.Width = preCell.Width; CopyStyleAttribute(cell, preCell.Attributes); } } } } if (merge == false) { // If not detect cell merge , maby exist cell merge in the same row foreach (DomTableRow row in table.Elements) { if (row.Elements.Count < table.Columns.Count) { // If number of row's cells not equals the number of table's columns // then exist cell merge. merge = true; break; } } } if (merge) { // Detect cell merge , begin merge operation // Because of in rtf format,cell which merged by another cell in the same row , // does no written in rtf text , so delay create those cell instance . foreach (DomTableRow row in table.Elements) { if (row.Elements.Count != table.Columns.Count) { // If number of row's cells not equals number of table's columns , // then consider there are hanppend horizontal merge. var cells = row.Elements.ToArray(); foreach (var domElement in cells) { var cell = (DomTableCell) domElement; var index = rights.IndexOf(cell.Left); var index2 = rights.IndexOf(cell.Left + cell.Width); var intColSpan = index2 - index; // detect vertical merge var verticalMerge = cell.HasAttribute(Consts.Clvmrg); if (verticalMerge == false) { // If this cell does not merged by another cell abover , // then set colspan cell.ColSpan = intColSpan; } if (row.Elements.LastElement == cell) { cell.ColSpan = table.Columns.Count - row.Elements.Count + 1; intColSpan = cell.ColSpan; } for (var count = 0; count < intColSpan - 1; count++) { var newCell = new DomTableCell {Attributes = cell.Attributes.Clone()}; row.Elements.Insert(row.Elements.IndexOf(cell) + 1, newCell); if (verticalMerge) { // This cell has been merged. newCell.Attributes[Consts.Clvmrg] = 1; newCell.OverrideCell = cell; } } } if (row.Elements.Count != table.Columns.Count) { // If the last cell has been merged. then supply new cells. var lastCell = (DomTableCell) row.Elements.LastElement; if (lastCell == null) Console.WriteLine(""); for (var count = row.Elements.Count; count < rights.Count; count++) { var newCell = new DomTableCell(); if (lastCell != null) CopyStyleAttribute(newCell, lastCell.Attributes); row.Elements.Add(newCell); } } } } // Set cell's vertial merge. foreach (DomTableRow tableRow in table.Elements) { foreach (DomTableCell tableCell in tableRow.Elements) { if (tableCell.HasAttribute(Consts.Clvmgf) == false) { //if this cell does not mark vertial merge , then next cell continue; } // if this cell mark vertial merge. var colIndex = tableRow.Elements.IndexOf(tableCell); for (var rowIndex = table.Elements.IndexOf(tableRow) + 1; rowIndex < table.Elements.Count; rowIndex++) { var row2 = (DomTableRow) table.Elements[rowIndex]; if (colIndex >= row2.Elements.Count) { Console.Write(""); } var cell2 = (DomTableCell) row2.Elements[colIndex]; if (cell2.HasAttribute(Consts.Clvmrg)) { if (cell2.OverrideCell != null) // If this cell has been merge by another cell( must in the same row ) // then break the circle break; // Increase vertial merge. tableCell.RowSpan++; cell2.OverrideCell = tableCell; } else // if this cell not mark merged by another cell , then break the circel break; } } } // Set cell's OverridedCell information foreach (DomTableRow tableRow in table.Elements) { foreach (DomTableCell tableCell in tableRow.Elements) { if (tableCell.RowSpan > 1 || tableCell.ColSpan > 1) { for (var rowIndex = 1; rowIndex <= tableCell.RowSpan; rowIndex++) { for (var colIndex = 1; colIndex <= tableCell.ColSpan; colIndex++) { var r = table.Elements.IndexOf(tableRow) + rowIndex - 1; var c = tableRow.Elements.IndexOf(tableCell) + colIndex - 1; var cell2 = (DomTableCell) table.Elements[r].Elements[c]; if (tableCell != cell2) { cell2.OverrideCell = tableCell; } } } } } } } if (fixTableCellSize) { // Fix table's left position use the first table column if (table.Columns.Count > 0) ((DomTableColumn) table.Columns[0]).Width -= tableLeft; } }
/// <summary> /// Create table /// </summary> /// <param name="rows">table rows</param> /// <returns>new table</returns> private DomTable CreateTable(ArrayList rows) { if (rows.Count > 0) { var table = new DomTable(); var index = 0; foreach (DomTableRow row in rows) { row.RowIndex = index; index++; table.AppendChild(row); } rows.Clear(); foreach (DomTableRow tableRow in table.Elements) { foreach (DomTableCell cell in tableRow.Elements) CombineTable(cell); } return table; } throw new ArgumentException("rows"); }