using System; using System.Collections.Generic; using System.Text; using System.IO; using System.Xml; using System.Xml.Serialization; using System.Xml.Schema; using System.Drawing; namespace Volian.Controls.Library { [Serializable] [XmlRoot("VlnBorders")] public class VlnBorders { #region Properties private int _Rows; [XmlAttribute("Rows")] public int Rows { get { return _Rows; } set { _Rows = value; } } private int _Columns; [XmlAttribute("Columns")] public int Columns { get { return _Columns; } set { _Columns = value; } } private LinePatternArray _VerticalLines; public LinePatternArray VerticalLines { get { return _VerticalLines; } set { _VerticalLines = value; } } private LinePatternArray _HorizontalLines; public LinePatternArray HorizontalLines { get { return _HorizontalLines; } set { _HorizontalLines = value; } } #endregion #region ctor public VlnBorders() { ;} public VlnBorders(GridLinePattern defaultLinePattern, int rows, int columns) { Rows = rows; Columns = columns; HorizontalLines = new LinePatternArray(defaultLinePattern, Rows + 1, Columns); VerticalLines = new LinePatternArray(defaultLinePattern, Rows, Columns + 1); } #endregion #region SetRange - Set the border styles over a range of cells public void SetRange(int r1, int c1, int r2, int c2, GridLinePattern top, GridLinePattern middle, GridLinePattern bottom, GridLinePattern left, GridLinePattern center, GridLinePattern right) { for (int c = c1; c <= c2; c++) { if (top != GridLinePattern.Mixed) HorizontalLines[r1, c] = top; for (int r = r1 + 1; r <= r2; r++) if (middle != GridLinePattern.Mixed) HorizontalLines[r, c] = middle; if (bottom != GridLinePattern.Mixed) HorizontalLines[r2 + 1, c] = bottom; } for (int r = r1; r <= r2; r++) { if (left != GridLinePattern.Mixed) VerticalLines[r, c1] = left; for (int c = c1 + 1; c <= c2; c++) if (center != GridLinePattern.Mixed) VerticalLines[r, c] = center; if (right != GridLinePattern.Mixed) VerticalLines[r, c2 + 1] = right; } } #endregion #region Get Borders over a Range - Return Mixed if multiple values are found. public GridLinePattern RangeTopBorder(int r1, int c1, int r2, int c2) { GridLinePattern linePattern = HorizontalLines[r1, c1]; for (int c = c1; c <= c2; c++) if (linePattern != HorizontalLines[r1, c]) return GridLinePattern.Mixed; return linePattern; } public GridLinePattern RangeHorizontalBorder(int r1, int c1, int r2, int c2) { if (r1 == r2) return GridLinePattern.None; GridLinePattern linePattern = HorizontalLines[r1 + 1, c1]; for (int r = r1 + 1; r <= r2; r++) for (int c = c1; c <= c2; c++) if (linePattern != HorizontalLines[r, c]) return GridLinePattern.Mixed; return linePattern; } public GridLinePattern RangeBottomBorder(int r1, int c1, int r2, int c2) { GridLinePattern linePattern = HorizontalLines[r2 + 1, c1]; for (int c = c1; c <= c2; c++) if (linePattern != HorizontalLines[r2 + 1, c]) return GridLinePattern.Mixed; return linePattern; } public GridLinePattern RangeLeftBorder(int r1, int c1, int r2, int c2) { GridLinePattern linePattern = VerticalLines[r1, c1]; for (int r = r1; r <= r2; r++) if (linePattern != VerticalLines[r, c1]) return GridLinePattern.Mixed; return linePattern; } public GridLinePattern RangeVerticalBorder(int r1, int c1, int r2, int c2) { if (c1 == c2) return GridLinePattern.None; GridLinePattern linePattern = VerticalLines[r1, c1 + 1]; for (int c = c1 + 1; c <= c2; c++) for (int r = r1 + 1; r <= r2; r++) if (linePattern != VerticalLines[r, c]) return GridLinePattern.Mixed; return linePattern; } public GridLinePattern RangeRightBorder(int r1, int c1, int r2, int c2) { GridLinePattern linePattern = VerticalLines[r1, c2 + 1]; for (int r = r1; r <= r2; r++) if (linePattern != VerticalLines[r, c2 + 1]) return GridLinePattern.Mixed; return linePattern; } #endregion #region Insert and Remove Rows and Columns public void InsertRow(int row) { HorizontalLines.InsertRow(row); VerticalLines.InsertRow(row); } public void InsertRows(int row, int count) { HorizontalLines.InsertRows(row, count); VerticalLines.InsertRows(row, count); } public void DeleteRow(int row) { HorizontalLines.DeleteRow(row); VerticalLines.DeleteRow(row); } public void DeleteRows(int row, int count) { HorizontalLines.DeleteRows(row, count); VerticalLines.DeleteRows(row, count); } public void InsertColumn(int column) { HorizontalLines.InsertColumn(column); VerticalLines.InsertColumn(column); } public void InsertColumns(int column, int count) { HorizontalLines.InsertColumns(column, count); VerticalLines.InsertColumns(column, count); } public void DeleteColumn(int column) { HorizontalLines.DeleteColumn(column); VerticalLines.DeleteColumn(column); } public void DeleteColumns(int column, int count) { HorizontalLines.DeleteColumns(column, count); VerticalLines.DeleteColumns(column, count); } #endregion #region Serialize public string ConvertToString() { return GenericSerializer.StringSerialize(this); } public override string ToString() { return "Volian Custom Borders"; } public static VlnBorders Get(string xml) { return GenericSerializer.StringDeserialize(xml); } #endregion #region Line Pattern Static Methods public static int LineWidth(GridLinePattern linePattern) { switch (linePattern) { case GridLinePattern.Double: case GridLinePattern.Thick: return 3; case GridLinePattern.None: case GridLinePattern.Single: case GridLinePattern.Dotted: case GridLinePattern.Dashed: case GridLinePattern.Mixed: default: return 1; } } public static int LineWidth0(GridLinePattern linePattern) { switch (linePattern) { case GridLinePattern.None: return 0; case GridLinePattern.Double: case GridLinePattern.Thick: return 3; case GridLinePattern.Single: case GridLinePattern.Dotted: case GridLinePattern.Dashed: case GridLinePattern.Mixed: default: return 1; } } public static Pen LinePen(GridLinePattern linePattern, Color foreColor) { Pen pn = new Pen(foreColor, 1); switch (linePattern) { case GridLinePattern.None: pn.Width = 0; break; case GridLinePattern.Thick: pn.Width = 3; break; case GridLinePattern.Dotted: pn.DashStyle = System.Drawing.Drawing2D.DashStyle.Custom; float[] patternDot = { 1, 2 }; pn.DashPattern = patternDot; break; case GridLinePattern.Dashed: pn.DashStyle = System.Drawing.Drawing2D.DashStyle.Custom; float[] patternDash = { 6, 6 }; pn.DashPattern = patternDash; break; case GridLinePattern.Mixed: pn.Color = Color.LightGray; break; case GridLinePattern.Double: case GridLinePattern.Single: default: break; } return pn; } #endregion } [Serializable] public class LinePatternArray { #region Properties protected static readonly log4net.ILog _MyLog = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); private int _Rows; [XmlAttribute("Rows")] public int Rows { get { return _Rows; } set { _Rows = value; } } private int _Columns; [XmlAttribute("Columns")] public int Columns { get { return _Columns; } set { _Columns = value; } } private GridLinePattern[] _Lines; public GridLinePattern[] Lines { get { return _Lines; } set { _Lines = value; } } #endregion #region ctor public LinePatternArray() { ;} public LinePatternArray(GridLinePattern defaultLinePattern, int rows, int columns) { Rows = rows; Columns = columns; Lines = new GridLinePattern[rows * columns]; for (int r = 0; r < Rows; r++) for (int c = 0; c < Columns; c++) Lines[r * Columns + c] = defaultLinePattern; } #endregion #region Array Access public GridLinePattern this[int r, int c] { get { int indx = r * Columns + c; if (indx < Lines.Length) return Lines[r * Columns + c]; _MyLog.WarnFormat("GridLinePattern: Lines Array Access out-of-bounds ({0}, {1}) within ({2}, {3})", r, c, Rows, Columns); return GridLinePattern.Single; } set { Lines[r * Columns + c] = value; } } #endregion #region Insert and Delete Rows and Columns public void InsertRow(int row) { InsertRows(row, 1); } public void InsertRows(int row, int count) { // Create a new Array of the correct size GridLinePattern[] newLines = new GridLinePattern[(Rows + count) * Columns]; int newRows = Rows + count; for (int r = 0; r < newRows; r++) { int rSrc = r < row ? r : r > row + count ? r - count : row; if (rSrc > Rows - 1) rSrc = Rows - 1; for (int c = 0; c < Columns; c++) { newLines[r * Columns + c] = Lines[rSrc * Columns + c]; } } Lines = newLines; Rows = newRows; } public void DeleteRow(int row) { DeleteRows(row, 1); } public void DeleteRows(int row, int count) { GridLinePattern[] newLines = new GridLinePattern[(Rows - count) * Columns]; int newRows = Rows - count; for (int r = 0; r < newRows; r++) { int rSrc = r < row ? r : r + count; for (int c = 0; c < Columns; c++) { newLines[r * Columns + c] = Lines[rSrc * Columns + c]; } } Lines = newLines; Rows = newRows; } public void InsertColumn(int column) { InsertColumns(column, 1); } public void InsertColumns(int column, int count) { // Create a new Array of the correct size GridLinePattern[] newLines = new GridLinePattern[Rows * (Columns + count)]; int newColumns = Columns + count; for (int r = 0; r < Rows; r++) { for (int c = 0; c < newColumns; c++) { int cSrc = c < column ? c : c > column + count ? c - count : column; newLines[r * newColumns + c] = Lines[r * Columns + cSrc]; } } Lines = newLines; Columns = newColumns; } public void DeleteColumn(int column) { DeleteColumns(column, 1); } public void DeleteColumns(int column, int count) { GridLinePattern[] newLines = new GridLinePattern[Rows * (Columns - count)]; int newColumns = Columns - count; for (int r = 0; r < Rows; r++) { for (int c = 0; c < newColumns; c++) { int cSrc = c < column ? c : c + count; newLines[r * newColumns + c] = Lines[r * Columns + cSrc]; } } Lines = newLines; Columns = newColumns; } #endregion } public static class GenericSerializer where T : class { public static string StringSerialize(T t) { string strOutput = string.Empty; XmlSerializer xs = new XmlSerializer(typeof(T)); using (MemoryStream ms = new MemoryStream()) { xs.Serialize(new NonXsiTextWriter(ms, Encoding.UTF8), t); //xs.Serialize(ms, t); ms.Position = 0; StreamReader sr = new StreamReader(ms); strOutput = sr.ReadToEnd(); ms.Close(); } return strOutput; } public static T StringDeserialize(string s) { T t; XmlSerializer xs = new XmlSerializer(typeof(T)); UTF8Encoding enc = new UTF8Encoding(); Byte[] arrBytData = enc.GetBytes(s); using (MemoryStream ms = new MemoryStream(arrBytData)) { t = (T)xs.Deserialize(ms); } return t; } //public static void WriteFile(T t, string fileName) //{ // string strOutput = string.Empty; // XmlSerializer xs = new XmlSerializer(typeof(T)); // using (FileStream fs = new FileStream(fileName, FileMode.Create)) // { // xs.Serialize(new NonXsiTextWriter(fs, Encoding.UTF8), t); // fs.Close(); // } //} //public static T ReadFile(string fileName) //{ // T t; // XmlSerializer xs = new XmlSerializer(typeof(T)); // using (FileStream fs = new FileStream(fileName, FileMode.Open)) // { // t = (T)xs.Deserialize(fs); // } // return t; //} } public class NonXsiTextWriter : XmlTextWriter { public NonXsiTextWriter(TextWriter w) : base(w) { } public NonXsiTextWriter(Stream w, Encoding encoding) : base(w, encoding) { this.Formatting = Formatting.Indented; } public NonXsiTextWriter(string filename, Encoding encoding) : base(filename, encoding) { } bool _skip = false; public override void WriteStartAttribute(string prefix, string localName, string ns) { if ((prefix == "xmlns" && (localName == "xsd" || localName == "xsi")) || // Omits XSD and XSI declarations. ns == XmlSchema.InstanceNamespace) // Omits all XSI attributes. { _skip = true; return; } if (localName == "xlink_href") base.WriteStartAttribute(prefix, "xlink:href", ns); else base.WriteStartAttribute(prefix, localName, ns); } public override void WriteString(string text) { if (_skip) return; base.WriteString(text); } public override void WriteEndAttribute() { if (_skip) { // Reset the flag, so we keep writing. _skip = false; return; } base.WriteEndAttribute(); } } public enum GridLinePattern : int { Unknown = -1, None = 0, Single = 1, Double = 2, Thick = 3, Dotted = 4, Dashed = 5, Mixed = 6 } }