using System; using System.ComponentModel; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Text; using System.Windows.Forms; using System.Drawing; using System.Runtime.InteropServices; using System.Xml; using System.IO; using Volian.Controls.Library; using VEPROMS.CSLA.Library; using C1.Win.C1FlexGrid; using C1.Win.C1SpellChecker; using System.Text.RegularExpressions; using System.Xml.Serialization; using Volian.Base.Library; using JR.Utils.GUI.Forms; namespace Volian.Controls.Library { public delegate void VlnFlexGridEvent(object sender, EventArgs args); public delegate void VlnFlexGridCursorMovementEvent(object sender, VlnFlexGridCursorMovementEventArgs args); public delegate string VlnFlexGridPasteEvent(object sender, VlnFlexGridPasteEventArgs args); public delegate void VlnFlexGridkeyEvent(object sender, KeyEventArgs args); public partial class vlnPanel : Panel { private int _Opacity = 128; //public int Opacity //{ // get { return _Opacity; } // set { _Opacity = value; } //} public vlnPanel() { InitializeComponent(); } public vlnPanel(IContainer container) { container.Add(this); InitializeComponent(); } //protected override CreateParams CreateParams //{ // get // { // CreateParams prams = base.CreateParams; // prams.ExStyle |= 0x020; // transparent // return prams; // } //} //protected override void OnPaint(PaintEventArgs pe) //{ // pe.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(_Opacity, this.BackColor)), this.ClientRectangle); //} } public partial class VlnFlexGrid : C1.Win.C1FlexGrid.C1FlexGrid { private static readonly log4net.ILog _MyLog = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); private bool _Disposed = false; private static int _CountCreated = 0; private static int _CountDisposed = 0; private static int _CountFinalized = 0; private static int IncrementCountCreated { get { return ++_CountCreated; } } private int _CountWhenCreated = IncrementCountCreated; public static int CountCreated { get { return _CountCreated; } } public static int CountNotDisposed { get { return _CountCreated - _CountDisposed; } } public static int CountNotFinalized { get { return _CountCreated - _CountFinalized; } } private bool _Finalized = false; ~VlnFlexGrid() { if(!_Finalized) _CountFinalized++; _Finalized = true; } private C1SpellChecker _SpellChecker; public C1SpellChecker SpellChecker { get { return _SpellChecker; } set { _SpellChecker = value; } } //public string GridStackTrace //{ // get // { // string st = Volian.Base.Library.vlnStackTrace.GetStack(); // st = StripFunnyCharacters(st); // return st; // Console.WriteLine(st); // return st.Replace(@"\","|"); // } // set // { // ; // } //} //private string StripFunnyCharacters(string st) //{ // StringBuilder sb = new StringBuilder(); // foreach (char c in st) // { // if ((c < ' ' || c > 255) && !"\r\n\t".Contains(c.ToString())) // sb.Append(string.Format("x{0:X4}", (int)c)); // else // sb.Append(c); // } // return sb.ToString(); //} private DocVersionInfo _MyDVI = null; public DocVersionInfo MyDVI { get { ItemInfo procInfo = _MyItemInfo.MyProcedure as ItemInfo; //_MyEditItem.MyItemInfo.MyProcedure as ItemInfo; if (procInfo == null) _MyDVI = null; else _MyDVI = procInfo.ActiveParent as DocVersionInfo; return _MyDVI; } } private static UserInfo _MyUserInfo = null; public static UserInfo MyUserInfo { get { return _MyUserInfo; } set { _MyUserInfo = value; GridItem.MyUserInfo = value; } } // C2021-005 used by the table cell editor to pass font size information private float _SelectedFontSize; public float SelectedFontSize { get { return _SelectedFontSize; } set { if (Parent is GridItem) { _SelectedFontSize = (float)value; // initialize the font size dropdown (Parent as GridItem).MyStepPanel.MyStepTabPanel.MyStepTabRibbon.SetFontSizeDropDownText(value); _DoubleClickedCell = false; } } } public bool IsDirty { get { return IsGridChanged(this._MyItemInfo.MyContent.MyGrid.Data, this.GetXMLData(), true); } } private bool IsGridChanged(string oldXml, string newXml, bool checkFormat) { if (this.TableCellEditor.Text.Contains("")) return false; XmlDocument XdOld = new XmlDocument(); oldXml = _ReplaceTextFont.Replace(oldXml, "$1" + FontChangeFmt + "$4"); // B2021-032: use original font XdOld.LoadXml(AdjustHeightAndWidthForDPI(oldXml)); XmlDocument XdNew = new XmlDocument(); XdNew.LoadXml(AdjustHeightAndWidthForDPI(newXml)); //check volian borders 1st if (checkFormat && XdNew.SelectSingleNode("C1FlexGrid/Control/MyBorderDetailString").InnerText != XdOld.SelectSingleNode("C1FlexGrid/Control/MyBorderDetailString").InnerText) return true; //check row/col sizes 2nd if (checkFormat && ( GetRowColSizeString(XdNew) != GetRowColSizeString(XdOld))) return true; //check for cell data changes 3rd if (GetCellDataString(XdNew) != GetCellDataString(XdOld)) return true; //check for cell format changes 4th if (checkFormat && GetCellFormatString(XdNew) != GetCellFormatString(XdOld)) return true; //check for text alignment changes 5th // put check in for bug fix B2014-106 if (checkFormat && GetCellTextAlignString(XdNew) != GetCellTextAlignString(XdOld)) return true; //check for merged cells 6th if (GetCellMergeString(XdNew) != GetCellMergeString(XdOld)) return true; // C2021-004 check volian shading 7th XmlNode oldNode = XdOld.SelectSingleNode("C1FlexGrid/Control/MyShadingDetailString"); // old shading information XmlNode newNode = XdNew.SelectSingleNode("C1FlexGrid/Control/MyShadingDetailString"); // new shading information if ((oldNode == null || oldNode.InnerText == null) || checkFormat && newNode.InnerText != oldNode.InnerText) return true; return false; } private string GetRowColSizeString(XmlDocument xd) { string defCW = xd.SelectSingleNode("C1FlexGrid/ColumnInfo/DefaultSize").InnerText; string defRH = xd.SelectSingleNode("C1FlexGrid/RowInfo/DefaultSize").InnerText; int cols = ColumnCount(xd); int rows = RowCount(xd); List rh = new List(); for (int i = 0; i < rows; i++) rh.Add(defRH); List cw = new List(); for (int i = 0; i < cols; i++) cw.Add(defCW); XmlNodeList nlr = xd.SelectNodes("C1FlexGrid/Rows/Row"); foreach (XmlNode nr in nlr) { int idx = int.Parse(nr.Attributes.GetNamedItem("index").InnerText); rh[idx] = nr.SelectSingleNode("Height").InnerText; } XmlNodeList nlc = xd.SelectNodes("C1FlexGrid/Columns/Column"); foreach (XmlNode nc in nlc) { int idx = int.Parse(nc.Attributes.GetNamedItem("index").InnerText); cw[idx] = nc.SelectSingleNode("Width").InnerText; } string rhcw = "RowHeights: "; string sep = string.Empty; foreach (string s in rh) { rhcw += sep + s; sep = ","; } rhcw += " - ColWidths: "; sep = string.Empty; foreach (string s in cw) { rhcw += sep + s; sep = ","; } return rhcw; } private int ColumnCount(XmlDocument xd) { XmlNode xn = xd.SelectSingleNode("C1FlexGrid/ColumnInfo/Count"); int cols = 0; if (xn != null) cols = int.Parse(xn.InnerText); else { XmlNodeList nl = xd.SelectNodes("C1FlexGrid/Columns/Column"); cols = nl.Count; } return cols; } private int RowCount(XmlDocument xd) { XmlNode xn = xd.SelectSingleNode("C1FlexGrid/RowInfo/Count"); int rows = 0; if (xn != null) rows = int.Parse(xn.InnerText); else { XmlNodeList nl = xd.SelectNodes("C1FlexGrid/Rows/Row"); rows = nl.Count; } return rows; } private string GetCellDataString(XmlDocument xd) { int cols = ColumnCount(xd); int rows = RowCount(xd); List datum = new List(); for (int i = 0; i < rows * cols; i++) datum.Add("|"); XmlNodeList nl = xd.SelectNodes("C1FlexGrid/Cells/Cell/Data"); string data = string.Empty; foreach (XmlNode xn in nl) { RichTextBox rtb = new RichTextBox(); rtb.Rtf = xn.InnerText; XmlAttribute xa = xn.ParentNode.Attributes.GetNamedItem("index") as XmlAttribute; string[] rc = xa.InnerText.Split(','); int r = int.Parse(rc[0]); int c = int.Parse(rc[1]); int index = r * cols + c; datum[index] = "|" + (rtb.Text == "" ? "" : rtb.Text); } foreach (string s in datum) data += s; return data; } private string GetCellFormatString(XmlDocument xd) { int cols = ColumnCount(xd); int rows = RowCount(xd); List datum = new List(); for (int i = 0; i < rows * cols; i++) datum.Add("|"); XmlNodeList nl = xd.SelectNodes("C1FlexGrid/Cells/Cell/Data"); string data = string.Empty; foreach (XmlNode xn in nl) { RichTextBox rtb = new RichTextBox(); rtb.Rtf = xn.InnerText; XmlAttribute xa = xn.ParentNode.Attributes.GetNamedItem("index") as XmlAttribute; string[] rc = xa.InnerText.Split(','); int r = int.Parse(rc[0]); int c = int.Parse(rc[1]); int index = r * cols + c; datum[index] = "|" + (rtb.Text == "" ? "" : rtb.Rtf); } foreach (string s in datum) data += s; return data; } private string GetCellMergeString(XmlDocument xd) { if(xd.SelectSingleNode("C1FlexGrid/MergedRanges") == null) return string.Empty; return xd.SelectSingleNode("C1FlexGrid/MergedRanges").InnerXml; } private string GetCellTextAlignString(XmlDocument xd) { // Note that I could not save (and later compare) the entire Definition string // because the xml for the old and new table was always different. // The old xml table data would have, for example "white" for the background color, while // the new xml table data would have "255,255,255" for the background color. // Therefore this check is specific for only the TextAlign setting - jsj 9-30-2014 XmlNodeList nl = xd.SelectNodes("C1FlexGrid/Styles/Style/Definition"); string data = string.Empty; foreach (XmlNode xn in nl) { string str = xn.InnerText; string[] splStr = str.Split(';'); foreach (string s in splStr) if (s.StartsWith("TextAlign:")) data += "|" + s; // only save the TextAlign setting } return data; } private static GridCopyInfo _MyCopyInfo; public static GridCopyInfo MyCopyInfo { get { if (_MyCopyInfo == null) _MyCopyInfo = new GridCopyInfo(); return _MyCopyInfo; } } private Color _DefaultCellBackgroundcolor; public Color DefaultCellBackgroundcolor { get { return _DefaultCellBackgroundcolor; } } private Color _DefaultFixedBackgroundColor; public Color DefaultFixedBackgroundColor { get { return _DefaultFixedBackgroundColor; } } public void CopyToCopiedFlexGrid(GridCopyOption myCopyOption) { MyCopyInfo.MyCopiedFlexGrid = new VlnFlexGrid(); //make a copy of the grid being copied using (StringReader sr = new StringReader(this.GetXMLData())) { MyCopyInfo.MyCopiedFlexGrid.ReadXml(sr); this.BorderStyle = C1.Win.C1FlexGrid.Util.BaseControls.BorderStyleEnum.None; sr.Close(); } MyCopyInfo.MyCopyOption = myCopyOption; OnCopyOptionChanged(this, new EventArgs()); switch (MyCopyInfo.MyCopyOption) { case GridCopyOption.Row: MyCopyInfo.MyCopiedCellRange = MyCopyInfo.MyCopiedFlexGrid.GetCellRange(Selection.r1, 0, Selection.r2, Cols.Count - 1); break; case GridCopyOption.Column: MyCopyInfo.MyCopiedCellRange = MyCopyInfo.MyCopiedFlexGrid.GetCellRange(0, Selection.c1, Rows.Count - 1, Selection.c2); break; case GridCopyOption.Selection: MyCopyInfo.MyCopiedCellRange = MyCopyInfo.MyCopiedFlexGrid.GetCellRange(Selection.r1, Selection.c1, Selection.r2, Selection.c2); break; default: break; } } public event VlnFlexGridEvent CopyOptionChanged; public void OnCopyOptionChanged(object sender, EventArgs args) { if (CopyOptionChanged != null) CopyOptionChanged(sender, args); } [XmlElement("MyBorders")] [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] public string MyBorderDetailString { get { return MyBorders.ConvertToString(); } set { if (value != null) _MyBorders = VlnBorders.Get(value); else _MyBorders = null; } } private VlnBorders _MyBorders; [XmlIgnore] public VlnBorders MyBorders { get { if (_MyBorders == null) _MyBorders = new VlnBorders(GridLinePattern.Single, Rows.Count, Cols.Count); return _MyBorders; } set { _MyBorders = value; } } private ItemInfo _MyItemInfo; public ItemInfo GetMyItemInfo() { return _MyItemInfo; } //public ItemInfo MyItemInfo //{ // get { return _MyItemInfo; } // set { _MyItemInfo = value; } //} public bool TopRowHasBorder() { for (int c = 0; c < Cols.Count; c++) if (MyBorders.HorizontalLines[0, c] != GridLinePattern.None) return true; return false; } public void SetBorders(CellRange myRange, GridLinePattern top, GridLinePattern middle, GridLinePattern bottom, GridLinePattern left, GridLinePattern center, GridLinePattern right) { for (int r = myRange.r1; r <= myRange.r2; r++) for (int c = myRange.c1; c <= myRange.c2; c++) { CellRange cr = GetMergedRange(r, c); if (r == myRange.r1) // Top Border if(top != GridLinePattern.Mixed) MyBorders.HorizontalLines[cr.r1, cr.c1]=top; if (c == myRange.c1) // Left Border if(left != GridLinePattern.Mixed) MyBorders.VerticalLines[cr.r1, cr.c1]=left; if (r == myRange.r2) // Bottom Border if(bottom != GridLinePattern.Mixed) MyBorders.HorizontalLines[cr.r2 + 1, cr.c2]=bottom; if (c == myRange.c2) // Right Border if(right != GridLinePattern.Mixed) MyBorders.VerticalLines[cr.r2, cr.c2 + 1] = right; if (r == cr.r1 && c == cr.c1) // Look for inside lines { if (cr.r1 > myRange.r1 && cr.r1 <= myRange.r2) // Inside Horizontal Top if (middle != GridLinePattern.Mixed) { MyBorders.HorizontalLines[cr.r1, cr.c1] = middle; MyBorders.HorizontalLines[cr.r1, cr.c2] = middle; } if (cr.r2 > myRange.r1 && cr.r2 < myRange.r2) // Inside Horizontal Bottom if(middle != GridLinePattern.Mixed) MyBorders.HorizontalLines[cr.r2 + 1, cr.c2]=middle; if (cr.c1 > myRange.c1 && cr.c1 <= myRange.c2) // Inside Vertical Left if (center != GridLinePattern.Mixed) { MyBorders.VerticalLines[cr.r1, cr.c1] = center; MyBorders.VerticalLines[cr.r2, cr.c1] = center; } if (cr.c2 > myRange.c1 && cr.c2 < myRange.c2) // Inside Vertical Right if(center != GridLinePattern.Mixed) MyBorders.VerticalLines[cr.r2, cr.c2 + 1]=center; } c = cr.c2;//Skip to the end of the merged cells } } public void PasteBorders(int r, int c, int br, int bc) { MyBorders.HorizontalLines[r, c] = MyCopyInfo.MyCopiedFlexGrid.MyBorders.HorizontalLines[br,bc]; MyBorders.VerticalLines[r, c] = MyCopyInfo.MyCopiedFlexGrid.MyBorders.VerticalLines[br, bc]; MyBorders.HorizontalLines[r+1, c] = MyCopyInfo.MyCopiedFlexGrid.MyBorders.HorizontalLines[br+1, bc]; MyBorders.VerticalLines[r, c+1] = MyCopyInfo.MyCopiedFlexGrid.MyBorders.VerticalLines[br, bc+1]; } #region Table Cell Shading [XmlElement("MyShading")] [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] public string MyShadingDetailString { get { return MyShading.ConvertToString(); } set { if (value != null) _MyShading = VlnGridCellShading.Get(value); else _MyShading = null; } } private VlnGridCellShading _MyShading = null; [XmlIgnore] public VlnGridCellShading MyShading { get { if (_MyShading == null || _MyShading.TableShadingInfo.CellShadingColor.Length == 0) _MyShading = new VlnGridCellShading(Color.White, Rows.Count, Cols.Count); return _MyShading; } set { _MyShading = value; } } public void SetShading(CellRange myRange, Color shading) { Console.WriteLine("SetShading toString {0}", shading.ToString()); //Console.WriteLine("SetShading toArgb {0}", shading.ToArgb()); //Console.WriteLine("SetShading Name {0}", shading.Name); for (int r = myRange.r1; r <= myRange.r2; r++) for (int c = myRange.c1; c <= myRange.c2; c++) { CellRange cr = GetMergedRange(r, c); MyShading.TableShadingInfo[cr.r1, cr.c1] = MyShading.GetARGBstring(shading); c = cr.c2; //Skip to the end of the merged cells } } public void SetShading(CellRange myRange, ShadingOption fmtShadingOpt) { Console.WriteLine("SetShading toString {0}", fmtShadingOpt.ToString()); for (int r = myRange.r1; r <= myRange.r2; r++) for (int c = myRange.c1; c <= myRange.c2; c++) { CellRange cr = GetMergedRange(r, c); MyShading.TableShadingInfo[cr.r1, cr.c1] = fmtShadingOpt.GetARBGstringForTableCells(); c = cr.c2; //Skip to the end of the merged cells } } public void ShowTableCellShading() { for (int r = 0; r < Rows.Count; r++) for (int c = 0; c < Cols.Count; c++) { CellRange cr = GetMergedRange(r, c); Color clr = MyShading.GetColor(cr.r1, cr.c1); cr.StyleNew.BackColor = clr; } } public void PasteShading(int r, int c, int sr, int sc) { MyShading.TableShadingInfo[r, c] = MyCopyInfo.MyCopiedFlexGrid.MyShading.TableShadingInfo[sr, sc]; } #endregion[XmlIgnore] public bool HasVScroll { get { return RTBAPI.HasVertScroll(this); } } [XmlIgnore] public bool HasHScroll { get { return RTBAPI.HasHorzScroll(this); } } public event VlnFlexGridEvent OpenAnnotations; public void OnOpenAnnotations(object sender, EventArgs args) { if (OpenAnnotations != null) OpenAnnotations(sender, args); } public event VlnFlexGridCursorMovementEvent CursorMovement; internal void OnCursorMovement(object sender, VlnFlexGridCursorMovementEventArgs args) { if (CursorMovement != null) CursorMovement(sender, args); } public event VlnFlexGridPasteEvent AdjustPastedText; internal string OnAdjustPastedText(object sender, VlnFlexGridPasteEventArgs args) { if (AdjustPastedText != null) return AdjustPastedText(sender, args); return args.Text; } public event VlnFlexGridkeyEvent EnterKeyPressed; public void OnEnterKeyPressed(object sender, KeyEventArgs args) { if (EnterKeyPressed != null) EnterKeyPressed(sender, args); } private TableCellEditor _tableCellEditor; public TableCellEditor TableCellEditor { get { return _tableCellEditor; } set { _tableCellEditor = value; } } private TableClipBoardFuncts _clpbrdCpyPste; private int _minColSplitWidth = 10; //private int _minRowSplitHeight = 23; //private int _minSplitColWidth = 10; //private int _minSplitRowHeight = 20; private E_ViewMode _vwMode = E_ViewMode.Edit; [XmlIgnore] internal E_ViewMode VwMode { get { return _vwMode; } set { _vwMode = value; AllowEditing = _vwMode == E_ViewMode.Edit; } } private bool _IsRoTable = false; public bool IsRoTable { get { return _IsRoTable; } set { _IsRoTable = value; } } private int _RODbId; public int RODbId { get { return _RODbId; } set { _RODbId = value; } } private string _ROID; public string ROID { get { return _ROID; } set { _ROID = value; } } private float? _DPI = null; public float? DPI { get { if (_DPI == null) _DPI = 120; return _DPI; } set { if (DPI != value) { _DPI = value; } } } #region Grid Initialize public VlnFlexGrid() { InitializeComponent(); SetupGrid(4, 3); // use a default row and column count } public VlnFlexGrid(int rows, int cols) { InitializeComponent(); SetupGrid(rows, cols); } public VlnFlexGrid(IContainer container) { container.Add(this); InitializeComponent(); SetupGrid(1, 1); } public VlnFlexGrid(ContentItem ci) { InitializeComponent(); SetupGrid(4, 3); // use a default row and column count _MyItemInfo = ci.MyItem.MyItemInfo; } //public VlnFlexGrid(IContainer container) //{ // container.Add(this); // InitializeComponent(); // _tableCellEditor = new TableCellEditor(this); // _tableCellEditor.ContentsResized += new ContentsResizedEventHandler(_tableCellEditor_ContentsResized); //} //void _tableCellEditor_ContentsResized(object sender, ContentsResizedEventArgs e) //{ // if (_tableCellEditor._initializingEdit) return; // CellRange cr = GetMergedRange(Row, Col); // int oH = cr.UserData == null? 0 : (int)cr.UserData; // int nH = _tableCellEditor.ContentsRectangle.Height; // int Hadj = (nH - oH); // cr.UserData = _tableCellEditor.ContentsRectangle.Height; // int cellHeight = GetCellHeight(Row,Col); // int cellheightNLines = cellHeight / (Rows.DefaultSize - 3); // int nHNLines = nH / (Rows.DefaultSize - 3); // if (Hadj != 0) // { // int curHeight = (Rows[Row].Height == -1) ? Rows.DefaultSize : Rows[Row].Height; // //if (Hadj > 0 && cellHeight <= oH) // if (Hadj > 0 && cellheightNLines < nHNLines) // curHeight += (Rows.DefaultSize - 3); // if (Hadj < 0 && CanReduceRow()) // curHeight -= (Rows.DefaultSize-3); // Rows[Row].Height = curHeight; // AdjustGridControlSize(); // } // //cr.UserData = _tableCellEditor.ContentsRectangle.Height; // //int mh = GetMaxRowHeight(); // ////Rows[Row].Height = mh + 2; // //int h = 0; // //if (cr.r1 == cr.r2 && cr.c1 == cr.c2) // // h = Rows[Row].Height - 2; // //else // //{ // // for (int r = cr.r1; r <= cr.r2; r++) // // h += Rows[r].Height - 2; // //} // //Rows[Row].Height += (mh - h); // ////AdjustGridControlSize(); //} private int GetCellHeight(int row, int col) { return GetRangeHeight(GetMergedRange(row, col))-3; } public int GetRangeHeight(CellRange cr) { int height = 0; for (int r = cr.r1; r <= cr.r2; r++) height += (Rows[r].Height == -1) ? Rows.DefaultSize : Rows[r].Height; return height; } public int GetRangeTop(CellRange cr) { int top = 0; for (int r = 0; r < cr.r1; r++) top += (Rows[r].Height == -1) ? Rows.DefaultSize : Rows[r].Height; return top; } public int GetRangeWidth(CellRange cr) { int width = 0; for (int c = cr.c1; c <= cr.c2; c++) width += (Cols[c].Width == -1) ? Cols.DefaultSize : Cols[c].Width; return width; } public int GetRangeLeft(CellRange cr) { int left = 0; for (int c = 0; c < cr.c1; c++) left += (Cols[c].Width == -1) ? Cols.DefaultSize : Cols[c].Width; return left; } public int GetRangeRowsMin(CellRange cr) { int rowsMin = 1 + cr.r2 - cr.r1; for (int c = cr.c1; c <= cr.c2; c++) { int rows = 0; for (int r = cr.r1; r <= cr.r2; r++) { CellRange chk = GetMergedRange(r, c); if (chk.r1 == r && chk.c1 == c) rows++; } rowsMin = Math.Min(rowsMin, rows); } return rowsMin; } public int GetRangeRowsMax(CellRange cr) { int rowsMax = 0; for (int c = cr.c1; c <= cr.c2; c++) { int rows = 0; for (int r = cr.r1; r <= cr.r2; r++) { CellRange chk = GetMergedRange(r, c); if (chk.r1 == r && chk.c1 == c) rows++; } rowsMax = Math.Max(rowsMax, rows); } return rowsMax; } public int GetRangeColsMin(CellRange cr) { int colsMin = 1 + cr.c2 - cr.c1; for (int r = cr.r1; r <= cr.r2; r++) { int cols = 0; for (int c = cr.c1; c <= cr.c2; c++) { CellRange chk = GetMergedRange(r, c); if (chk.r1 == r && chk.c1 == c) cols++; } colsMin = Math.Min(colsMin, cols); } return colsMin; } public int GetRangeColsMax(CellRange cr) { int colsMax = 0; for (int c = cr.c1; c <= cr.c2; c++) { int cols = 0; for (int r = cr.r1; r <= cr.r2; r++) { CellRange chk = GetMergedRange(r, c); if (chk.r1 == r && chk.c1 == c) cols++; } colsMax = Math.Max(colsMax, cols); } return colsMax; } public string GetRangeRowList(CellRange cr) { StringBuilder sb = new StringBuilder(); string sep = ""; for (int r = cr.r1; r <= cr.r2; r++) { CellRange crm = GetMergedRange(r, cr.c1); if (crm.r1 == r) { sb.Append(sep + r.ToString()); sep = "."; } r = crm.r2; } return sb.ToString(); } private int BlankRowSpace() { int curRowHeight = (Rows[Row].Height == -1) ? Rows.DefaultSize - 3 : Rows[Row].Height - 3; if (curRowHeight <= (Rows.DefaultSize - 3)) return 0; // never have row less than default height int blankRowSpace = curRowHeight; for (int c = 0; c < Cols.Count; c++) { CellRange cr = GetMergedRange(Row, c); if (Row >= cr.r1 && Row <= cr.r2) { int cellHeight = GetCellHeight(Row, c); int dataHeight = (cr.UserData == null) ? cellHeight : (int)cr.UserData; int ud = dataHeight / (Rows.DefaultSize - 3); //if (cellHeight < dataHeight) // Console.WriteLine("r {0}, c {1}, cell{2}, data{3}", Row, c, cellHeight, dataHeight); blankRowSpace = Math.Min(blankRowSpace, Math.Max(0,cellHeight - dataHeight)); } } //Console.WriteLine("BlankRowSpace {0}", blankRowSpace); return blankRowSpace; } private int GetCellWidth(int row, int col) { int width = 0; CellRange cr = GetMergedRange(row, col); for (int c = cr.c1; c <= cr.c2; c++) { width += (Cols[c].Width == -1) ? Cols.DefaultSize - 3 : Cols[c].Width -3; } return width; } private int BlankColSpace() { int curColWidth = (Cols[Col].Width == -1) ? Cols.DefaultSize - 3 : Cols[Col].Width-3; //int curRowHeightNLines = curRowHeight / (Rows.DefaultSize - 3); if (curColWidth <= Cols.DefaultSize - 3) return 0; // never have col less than default width int blankColSpace = curColWidth; for (int r = 0; r < Rows.Count; r++) { using (StepRTB srtb = new StepRTB()) { CellRange cr = GetMergedRange(r, Col); srtb.Rtf = GetCellRTFString(cr.r1, cr.c1); if (Col >= cr.c1 && Col <= cr.c2) { int cellWidth = GetCellWidth(r, Col); //srtb.Width = cellWidth; srtb.AdjustWidthForContent(); //Application.DoEvents(); //int mergeCellHeightNLines = cellHeight / (Rows.DefaultSize - 3); //int dataHeight = (cr.UserData == null) ? cellHeight : (int)cr.UserData; //int ud = dataHeight / (Rows.DefaultSize - 3); //if (cellHeight < dataHeight) // Console.WriteLine("r {0}, c {1}, cell{2}, data{3}", Row, c, cellHeight, dataHeight); //blankColSpace = Math.Min(blankColSpace, Math.Max(0, cellWidth - srtb.MaxTextWidth)); blankColSpace = Math.Min(blankColSpace, Math.Max(0, cellWidth - srtb.Width)); } } } //Console.WriteLine("BlankRowSpace {0}", blankRowSpace); return blankColSpace; } //private bool CanReduceRow() //{ // int curRowHeight = (Rows[Row].Height == -1) ? Rows.DefaultSize - 3 : Rows[Row].Height - 3; // int curRowHeightNLines = curRowHeight / (Rows.DefaultSize - 3); // bool bReduce = (curRowHeight > (Rows.DefaultSize - 3)); // if (bReduce) // { // for (int c = 0; c < Cols.Count; c++) // { // CellRange cr = GetMergedRange(Row, c); // if (Row >= cr.r1 && Row <= cr.r2) // { // int mergeCellHeightNLines = GetCellHeight(Row, c) / (Rows.DefaultSize - 3); // //int ud = (cr.UserData == null) ? 0 : (int)cr.UserData; // //if ((c != Col) && curRowHeight <= ud && ud >= mergeCellHeight) // // bReduce = false; // int ud = ((cr.UserData == null) ? 0 : (int)cr.UserData) / (Rows.DefaultSize - 3); // if ((c != Col) && curRowHeightNLines <= ud && ud >= mergeCellHeightNLines) // bReduce = false; // } // } // } // //Console.WriteLine("canreduce {0}, {1}", Row, bReduce); // return bReduce; //} //private int GetMaxRowHeight() //{ // int maxRTFHeight = _minRowSplitHeight; //Rows.DefaultSize;// the smallest a row can be // Console.WriteLine("================================================================="); // for (int c = 0; c < Cols.Count; c++) // { // CellRange cr = GetMergedRange(Row, c);//GetCellRange(Row, c); // maxRTFHeight = Math.Max(maxRTFHeight, (int)cr.UserData); // if (c == 0) // Console.WriteLine("Height in Row[{0}] = {1}", Row, Rows[Row].Height); // Console.WriteLine("UserData Cell[{0},{1}] = {2}", Row, c, cr.UserData); // } // return maxRTFHeight; //} private bool IsInMergeRange(int row, int col) { //foreach (CellRange cr in this.MergedRanges) //{ // if (cr.Contains(row, col)) // return true; // in a merged range //} CellRange cr = GetMergedRange(row, col); return (cr.r1 == row && cr.c1 == col); } private bool _ReadingXml = false; public bool ReadingXml { get { return _ReadingXml; } } private static Regex _ReplaceVESymbFix = new Regex(@"({\\f[0-9]+[^ ]* )(FreeMono)(;})"); // FreeMono is now used for the edit screen only. VESymbFix and Consolas are used for printing private static Regex _ReplaceArialUnicodeMS = new Regex(@"({\\f[0-9]+[^ ]* )(" + Volian.Base.Library.vlnFont.ProportionalSymbolFont + @")(;})"); // C2017-036 get best available proportional font for symbols // B2017-173 VESymFix font was being replaced by the table's default font, causing empty squares for the symbols (pre FreeMono font) in tables //C2017-036 Added FreeSerif which may be used if Arial Unicode MS is not available private static Regex _ReplaceTextFont = new Regex(@"({\\f[0-9]+[^ ]* )(?((?!FreeMono)(?!FreeSerif)(?!Arial Unicode MS)(?!VESymbFix))([^;]*)|(!!!!))(;})"); // FreeMono is now used for the edit screen only. VESymbFix and Consolas are used for printing private bool FontIsFixed(Font myFont) { Graphics grph = Graphics.FromHwnd(this.Handle); SizeF sfW = grph.MeasureString("W", myFont); SizeF sfE = grph.MeasureString("!", myFont); if (sfW.Width == sfE.Width) return true; return false; } // B2021-032: Changes (summary of changes after approval) occur when table does not change. This occurs if the font // of the table changed in the format so that when the font was used the first time, the save code saw it // as a difference. Save the new font, so that it can be used when doing the comparison before saving data. private string _fontChangeFmt = null; public string FontChangeFmt { get => _fontChangeFmt; set => _fontChangeFmt = value; } public void LoadGrid(ItemInfo itemInfo) { int profileDepth = ProfileTimer.Push(">>>> VlnFlexGrid.LoadGrid"); // B2021-140 reset the shading information before loading in the next table // Need to do this because we use static for the tables when we print MyShading = null; MyShadingDetailString = null; _MyItemInfo = itemInfo; string str = itemInfo.MyContent.MyGrid.Data; VE_Font vefont = _MyItemInfo.GetItemFont(); // the following code is used to be sure that the font used for symbols is the correct font // based on whether the font for non-symbol text is fixed or proportional. Each steprtb has // a font for the non-symbol AND the symbol text, and these must be the correct association, i.e. // for fixed fonts, the symbol font is 'VESymbFix', for proportional fonts, the symbol font is // 'Arial Unicode MS'. The underlying flexgrid stores the fonts, and if the table font was // reset for some reason (for example from the drop-down font selection in the user interface), // this code 'cleans' up if there is a mismatch. FontFamily ff = null; if (StepRTB.MyFontFamily != null) { ff = StepRTB.MyFontFamily; if (StepRTB.MySymbolFontName != "FreeMono") // FreeMono is now used for the edit screen only. VESymbFix and Consolas are used for printing str = _ReplaceVESymbFix.Replace(str, "$1" + StepRTB.MySymbolFontName + "$3"); if (StepRTB.MySymbolFontName != Volian.Base.Library.vlnFont.ProportionalSymbolFont) // C2017-036 get best available proportional font for symbols str = _ReplaceArialUnicodeMS.Replace(str, "$1" + StepRTB.MySymbolFontName + "$3"); str = _ReplaceTextFont.Replace(str, "$1" + ff.Name + "$4"); } else { ff = vefont.WindowsFont.FontFamily; if (FontIsFixed(vefont.WindowsFont)) str = _ReplaceArialUnicodeMS.Replace(str, "$1" + "FreeMono" + "$3"); // FreeMono is now used for the edit screen only. VESymbFix and Consolas are used for printing else str = _ReplaceVESymbFix.Replace(str, "$1" + Volian.Base.Library.vlnFont.ProportionalSymbolFont + "$3"); // C2017-036 get best available proportional font for symbols str = _ReplaceTextFont.Replace(str, "$1" + ff.Name + "$4"); } FontChangeFmt = ff.Name; // B2021-032 // To prevent scroll bars from being flashed on/off // - save an image of the current grid // - set Visible to false // - draw the saved grid image // - do the the load/reload of the grid // - set Visible back to true. Visible = false; if (Parent is GridItem) { try { System.Drawing.Image img = this.CreateImage(); using (Graphics gr = (Parent as GridItem).CreateGraphics()) { gr.DrawImage(img, Left, Top); } } catch (Exception ex) { _MyLog.WarnFormat("Table Content Corrupted"); } } Clear(); MergedRanges.Clear(); _ReadingXml = true; //Console.WriteLine("LoadGrid - Before ReadXML"); ReadXml(str); //Console.WriteLine("LoadGrid - After ReadXML"); _ReadingXml = false; Select(-1, -1); // this keeps the cell from being selected when the grid is first displayed Visible = true; ProfileTimer.Pop(profileDepth); } private void ReadXml(string str) { // Get the height/width adjusted for the DPI. Depending on if the DPI setting for the current user's // monitor is different than the DPI setting saved in the grid record, table height/width of rows/columns // will be incorrect, i.e. lots of extra white space. The reason behind this is that the height/width // of table cells are stored as dots (from the monitor) in the underlying component one flexgrid. try { str = AdjustHeightAndWidthForDPI(str); str = Regex.Replace(str, "&(?![a-z])", "&"); //B2021-142 fix &'s in text screen - so they are considered text instead of xml using (StringReader sr = new StringReader(str)) { ReadXml(sr); this.BorderStyle = C1.Win.C1FlexGrid.Util.BaseControls.BorderStyleEnum.None; sr.Close(); } } catch { ; } } private string AdjustHeightAndWidthForDPI(string str) { // create a graphics to get the DPI and then compare it to the DPI that is stored in the grid. // if they are the same, we don't need to do anything. int DPIscreen = 0; using (Graphics gr = this.CreateGraphics()) { DPIscreen = (int)gr.DpiX; } XmlDocument xd = new XmlDocument(); str = Regex.Replace(str, "&(?![a-z])", "&"); //B2021-142 fix &'s in text screen - so they are considered text instead of xml xd.LoadXml(str); XmlNode xn = xd.SelectSingleNode("//DPI"); if (xn != null && xn.InnerText != DPIscreen.ToString()) { int DPIgrid = int.Parse(xn.InnerText); xn.InnerText = DPIscreen.ToString(); // adjust heights and widths based on the difference in DPIs between that what was saved // in the database(grid) and the current DPI from the screen. Without doing this the // heights/widths will be 'off', i.e. lots of white space. XmlNodeList xnl = xd.SelectNodes("//Height"); foreach (XmlNode xni in xnl) { int measurement = int.Parse(xni.InnerText); if (measurement != -1) xni.InnerText = ((measurement * DPIscreen) / DPIgrid).ToString(); } xnl = xd.SelectNodes("//Width"); foreach (XmlNode xni in xnl) { int measurement = int.Parse(xni.InnerText); if (measurement != -1) xni.InnerText = ((measurement * DPIscreen) / DPIgrid).ToString(); } xnl = xd.SelectNodes("//DefaultSize"); foreach (XmlNode xni in xnl) { int measurement = int.Parse(xni.InnerText); if (measurement != -1) xni.InnerText = ((measurement * DPIscreen) / DPIgrid).ToString(); } str = xd.OuterXml; } return str; } private void SetupGrid(int numrows, int numcols) //C1FlexGrid NewGrid() { // setup the default size of each cell in the table/grid this.Cols.DefaultSize = (int) DPI; this.Rows.DefaultSize = 20; // setup the number of rows and columns this.Rows.Count = numrows; this.Cols.Count = numcols; // make all the cell editable this.Rows.Fixed = 0; this.Cols.Fixed = 0; this.DrawMode = DrawModeEnum.OwnerDraw; this.ScrollBars = ScrollBars.None; // grid styles this.Styles.EmptyArea.BackColor = Color.Transparent; this.Styles.EmptyArea.Border.Style = BorderStyleEnum.None; this.Styles.Normal.Border.Color = Color.Black; this.Styles.Normal.TextAlign = C1.Win.C1FlexGrid.TextAlignEnum.LeftTop; //SetupCellStyles(); this.FocusRect = FocusRectEnum.Solid; this.Styles.Highlight.BackColor = Color.LightCyan; this.Styles.Highlight.ForeColor = Color.Black; this.Styles.Focus.BackColor = Color.LightCyan; this.HighLight = HighLightEnum.WithFocus; _DefaultCellBackgroundcolor = this.StyleBackColor; _DefaultFixedBackgroundColor = this.Styles.Fixed.BackColor; this.AllowMerging = C1.Win.C1FlexGrid.AllowMergingEnum.Custom; this.AllowResizing = C1.Win.C1FlexGrid.AllowResizingEnum.Both; _tableCellEditor = new TableCellEditor(this); _tableCellEditor.HeightChanged += new StepRTBEvent(_tableCellEditor_HeightChanged); _clpbrdCpyPste = new TableClipBoardFuncts(); _SpellChecker = _tableCellEditor.SpellCheckerInstance; this.AfterResizeRow += new C1.Win.C1FlexGrid.RowColEventHandler(this.Grid_AfterResize); this.StartEdit += new C1.Win.C1FlexGrid.RowColEventHandler(this._StartEdit); this.AfterEdit += new C1.Win.C1FlexGrid.RowColEventHandler(this._AfterEdit); this.AfterScroll += new C1.Win.C1FlexGrid.RangeEventHandler(this._AfterScroll); this.AfterResizeColumn += new C1.Win.C1FlexGrid.RowColEventHandler(this.Grid_AfterResize); this.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this._KeyPress); this.OwnerDrawCell += new OwnerDrawCellEventHandler(this.Grid_OwnerDrawCell); this.KeyDown += new KeyEventHandler(VlnFlexGrid_KeyDown); this.KeyUp +=new KeyEventHandler(VlnFlexGrid_KeyUp); TableCellEditor.EditMode = TableCellEditor.Visible; // need to comment out for compile for only jsj - 07FEB2011 this.MouseDown += new MouseEventHandler(VlnFlexGrid_MouseDown); this.MouseUp += VlnFlexGrid_MouseUp; this.DoubleClick += VlnFlexGrid_DoubleClick; } private bool _DoubleClickedCell = false; // C2021-005 need to know if user double-clicked on a cell private void VlnFlexGrid_DoubleClick(object sender, EventArgs e) { // if user did a double click then don't try to get the font size - go directly to editing the table cell text _DoubleClickedCell = true; } // C2021-005 needed the mouseup event to control the table cell selecting and grabbing of the font size public bool _GettingFontSize = false; private void VlnFlexGrid_MouseUp(object sender, MouseEventArgs e) { // C2021-005 Get the font size if user didn't double click and on a table if (!_DoubleClickedCell && Parent != null && Parent is GridItem && Cols.Fixed == 0 && Rows.Fixed == 0) (Parent as GridItem).MyStepPanel.MyStepTabPanel.MyStepTabRibbon.SetFontSizeDropDown(); } private bool _FirstEntry = false; public bool FirstEntry { get { return _FirstEntry; } set { _FirstEntry = value; } } void VlnFlexGrid_MouseDown(object sender, MouseEventArgs e) { int left = 0; int top = 0; int col = 0; int row = 0; int strow = Selection.r1; int stcol = Selection.c1; int erow = Selection.r2; int ecol = Selection.c2; while (e.X > left && col < Cols.Count) { left += Cols[col].Width > 0 ? Cols[col].Width : Cols.DefaultSize; col++; } while (e.Y > top && row < Rows.Count) { top += Rows[row].Height > 0 ? Rows[row].Height : Rows.DefaultSize; row++; } col--; row--; //Console.WriteLine("Mousedown Selection {0}", Selection); //Console.WriteLine("Mousedown Row, Col [{0},{1}]", row, col); erow = Math.Max(erow, row); ecol = Math.Max(ecol, col); if (_FirstEntry) Select(row, col); else Select(strow, stcol, erow, ecol); _FirstEntry = false; } void _tableCellEditor_HeightChanged(object sender, EventArgs args) { // B2022-028: images in table cells - don't come into this code if it is an image in a table cell: if (_tableCellEditor is StepRTB && (_tableCellEditor as StepRTB).ImageWidth > 0) return; if (_tableCellEditor._initializingEdit || !_tableCellEditor.Visible) return; int curHeight = GetCellHeight(Row, Col);//(Rows[Row].Height == -1) ? Rows.DefaultSize : Rows[Row].Height; CellRange cr = GetMergedRange(Row, Col); int oH = cr.UserData == null ? curHeight : (int)cr.UserData; int nH = _tableCellEditor.Height; //.ContentsRectangle.Height; int nW = _tableCellEditor.Width; // Width int Hadj = (nH - curHeight);//oH); cr.UserData = _tableCellEditor.Height; //.ContentsRectangle.Height; //int cellHeight = GetCellHeight(Row, Col); //int cellheightNLines = cellHeight / (Rows.DefaultSize - 3); //int nHNLines = nH / (Rows.DefaultSize - 3); if (Hadj != 0) { //if (Hadj > 0 && cellHeight <= oH) //if (Hadj > 0 && cellheightNLines < nHNLines) // curHeight += (Rows.DefaultSize - 3); //if (Hadj < 0 && CanReduceRow()) // curHeight -= (Rows.DefaultSize - 3); int blankRowSpace = BlankRowSpace(); if (Hadj < 0) Hadj = -Math.Min(-Hadj, blankRowSpace); //if (Hadj > 0) // Console.WriteLine("r {0}, nh {1}, curh{2}", Row, nH, curHeight); if (Hadj != 0) { int newHeight = Hadj + ((Rows[Row].Height < 0) ? Rows.DefaultSize : Rows[Row].Height); //Rows[Row].Height += Hadj;//= curHeight; Rows[Row].Height = newHeight; AdjustGridControlSize(); } } } void VlnFlexGrid_KeyUp(object sender, KeyEventArgs e) { if (e.Control) { if (e.Alt) { switch (e.KeyCode) { case Keys.M: OnOpenAnnotations(this, new EventArgs()); e.Handled = true; break; default: break; } } } } void VlnFlexGrid_KeyDown(object sender, KeyEventArgs e) { switch (e.KeyCode) { case Keys.Left: if (e.Shift) return; _tableCellEditor.StepRTB_ArrowPressed(e.Control ? E_ArrowKeys.CtrlLeft : E_ArrowKeys.Left); e.Handled = true; break; case Keys.Up: if (e.Shift) return; _tableCellEditor.StepRTB_ArrowPressed(e.Control ? E_ArrowKeys.CtrlUp : E_ArrowKeys.Up); e.Handled = true; break; case Keys.Right: if (e.Shift) return; if (IsRoTable) Select(Rows.Count - 1, Cols.Count - 1); _tableCellEditor.StepRTB_ArrowPressed(e.Control ? E_ArrowKeys.CtrlRight : E_ArrowKeys.Right); e.Handled = true; break; case Keys.Down: if (e.Shift) return; if (IsRoTable) Select(Rows.Count - 1, 0); _tableCellEditor.StepRTB_ArrowPressed(e.Control ? E_ArrowKeys.CtrlDown : E_ArrowKeys.Down); e.Handled = true; break; case Keys.Enter: if (!e.Control && !e.Shift && !e.Alt) { if (MyDVI != null && UserInfo.CanEdit(MyUserInfo,MyDVI)) OnEnterKeyPressed(sender, e); else { // if a Reviewer, then do a . Don't allow changes to a table if (IsRoTable) Select(Rows.Count - 1, 0); _tableCellEditor.StepRTB_ArrowPressed(e.Control ? E_ArrowKeys.CtrlDown : E_ArrowKeys.Down); e.Handled = true; } } break; } } //void VlnFlexGrid_LeaveEdit(object sender, RowColEventArgs e) //{ // //Console.WriteLine("LeaveEdit Style = {0}", this.GetCellRange(e.Row, e.Col).Style.Name); // this.GetCellRange(e.Row, e.Col).Style.ForeColor = Color.Black; //} private void Grid_OwnerDrawCell(object sender, C1.Win.C1FlexGrid.OwnerDrawCellEventArgs e) { using (RTF _rtf = new RTF()) { // use nearest solid color // (the RTF control doesn't dither, and doesn't support transparent backgrounds) Color solid = e.Graphics.GetNearestColor(e.Style.BackColor); DPI = e.Graphics.DpiX; if (e.Style.BackColor != solid) e.Style.BackColor = solid; // check whether the cell contains RTF // convert \'99 to \u8482? this is for the trade mark symbol. For some reason RTF is automatically // converting the unicode \u8482? to \'99, but once this is done, PROMS StepRTB (edit windows) do not show it // Also convert \~ to a hard spece. Again RTF is automatically converting \u160? to \~ but will then convert // the \~ to a regular space! string rtfText = RtfTools.RTFConvertedSymbolsToUnicode(this.GetDataDisplay(e.Row, e.Col));//.Replace(@"\~", @"\u160?").Replace(@"\'99", @"\u8482?"); GridItem gi = Parent as GridItem; if (gi != null) { DisplayText dt = new DisplayText(gi.MyItemInfo, rtfText, true); rtfText = dt.StartText; } // it does, so draw background e.DrawCell(DrawCellFlags.Background); if (rtfText.StartsWith(@"{\rtf")) { // Please add a comment if this value needs to be changed _rtf.Rtf = rtfText; // draw the RTF text if (e.Bounds.Width > 0 && e.Bounds.Height > 0) { _rtf.Width = e.Bounds.Width - 1; // This has also been -3 which matchs the rener command CellRange cr = GetMergedRange(e.Row, e.Col); cr.UserData = _rtf.Height; int hAdjust = 0; int hDiff = e.Bounds.Height - _rtf.Height; if (hDiff < 0) { Rows[e.Row].Height = _rtf.Height + 4; AdjustGridControlSize(); hDiff = 0; } if (e.Style != null) { switch (e.Style.TextAlign) { case TextAlignEnum.CenterBottom: case TextAlignEnum.GeneralBottom: case TextAlignEnum.LeftBottom: case TextAlignEnum.RightBottom: hAdjust = hDiff; break; case TextAlignEnum.CenterCenter: case TextAlignEnum.GeneralCenter: case TextAlignEnum.LeftCenter: case TextAlignEnum.RightCenter: hAdjust = hDiff / 2; //0; // hDiff / 2; break; default: break; } } if (IsRoTable) { _rtf.ForeColor = Color.Red; } else { _rtf.ForeColor = e.Style.ForeColor; } _rtf.BackColor = e.Style.BackColor; _rtf.Render(e.Graphics, new Rectangle(e.Bounds.X + 1, e.Bounds.Y + hAdjust, e.Bounds.Width - 3, e.Bounds.Height)); } } else _rtf.Text = rtfText; // spell check unless (we're just measuring) if (!e.Measuring) { CharRangeList errors = SpellChecker.CheckText(_rtf.Text);//(text); // underline errors if (errors.Count > 0) { CharacterRange[] ranges = new CharacterRange[1]; ranges[0] = new CharacterRange(0, 1); Pen pn = new Pen(Color.Green, 2); StringFormat sf = new StringFormat(e.Style.StringFormat); sf.SetMeasurableCharacterRanges(ranges); Rectangle rc = e.Style.GetTextRectangle(e.Bounds, null); Region[] rgns = e.Graphics.MeasureCharacterRanges(_rtf.Text, e.Style.Font, rc, sf);//(text, e.Style.Font, rc, sf); float btm = rgns[0].GetBounds(e.Graphics).Bottom; float top = rgns[0].GetBounds(e.Graphics).Top; int adj = (int)(btm - top); for (int i = 0; i < errors.Count; i++) { // The positioning of the the squigle line does not account for mixed font sizes // should we support having mixed fonts in the table cells, we will need to add // logic to support it. Point ptStart = _rtf.GetPositionFromCharIndex(errors[i].Start); Point ptEnd = _rtf.GetPositionFromCharIndex(errors[i].Start + errors[i].Length); SquigleLine(e.Graphics, e.Bounds.Left + ptStart.X, e.Bounds.Top + ptStart.Y + adj, e.Bounds.Left + ptEnd.X); } } } // and draw border last //e.DrawCell(DrawCellFlags.Border); // This can be used to draw more specific borders DrawCellBorder(e); // we're done with this cell e.Handled = true; } } private void SquigleLine(Graphics graphics, int x1, int y1, int x2) { for (Point pt = new Point(x1, y1); pt.X + 2 < x2; pt.X += 4) { //Console.WriteLine("squiggle point {0}", pt); graphics.DrawLines(Pens.Red, new Point[] { new Point(pt.X, pt.Y), new Point(pt.X + 2, pt.Y - 2), new Point(pt.X + 4, pt.Y) }); } } private static Color _BorderColor = Color.Black; public static Color BorderColor { get { return VlnFlexGrid._BorderColor; } set { VlnFlexGrid._BorderColor = value; } } private void DrawCellBorder(C1.Win.C1FlexGrid.OwnerDrawCellEventArgs e) { Graphics grGrid =e.Graphics; Rectangle bounds = e.Bounds; int row = e.Row; int col = e.Col; MyBorders.CheckAndFixBorderArraySize(this.Rows.Count, this.Cols.Count, GridLinePattern.Single); // C2018-031 check the cell border arrays CellRange cr = GetMergedRange(row, col); GridLinePattern topSide = MyBorders.HorizontalLines[cr.r1,cr.c1]; GridLinePattern rightOfTopSide = cr.c2 == Cols.Count - 1 ? GridLinePattern.None : MyBorders.HorizontalLines[cr.r1, cr.c2 + 1]; GridLinePattern leftOfTopSide = cr.c1 == 0? GridLinePattern.None : MyBorders.HorizontalLines[cr.r1, cr.c1 - 1]; GridLinePattern leftSide = MyBorders.VerticalLines[cr.r1, cr.c1]; GridLinePattern aboveLeftSide = cr.r1 == 0 ? GridLinePattern.None : MyBorders.VerticalLines[cr.r1 - 1, cr.c1]; GridLinePattern belowLeftSide = cr.r2 == Rows.Count - 1 ? GridLinePattern.None : MyBorders.VerticalLines[cr.r2 + 1, cr.c1]; GridLinePattern bottomSide = MyBorders.HorizontalLines[cr.r2+1, cr.c2]; GridLinePattern rightOfBottomSide = cr.c2 == Cols.Count - 1 ? GridLinePattern.None : MyBorders.HorizontalLines[cr.r2 + 1, cr.c2 + 1]; GridLinePattern rightSide = MyBorders.VerticalLines[cr.r2, cr.c2+1]; GridLinePattern belowRightSide = cr.r2 == Rows.Count - 1 ? GridLinePattern.None : MyBorders.VerticalLines[cr.r2 + 1, cr.c2 + 1]; GridLinePattern none = GridLinePattern.None; int x1 = bounds.Left; int y1 = bounds.Top; int x2 = bounds.Right - 1; int y2 = bounds.Bottom - 1; GridItem myGridItem = Parent as GridItem; Panel myPanel = Parent as Panel; if (myGridItem == null && myPanel == null) return; if (row == 0 || col == 0) // Top or Left Edge - Draw on parent { using (Graphics grParent = myGridItem != null ? myGridItem.CreateGraphics() : myPanel.CreateGraphics()) { if (row == 0) { if (col == 0) { // Draw the top left intersection DrawIntersection(grParent, Left - 3, Top-1, none, topSide,leftSide, none); } // Draw the top right intersection DrawIntersection(grParent, Left +x2 - 2, Top-1, none, rightOfTopSide,rightSide,topSide); // Draw the top side on the parent DrawLine(grParent, topSide, Left + x1, Top + y1 - 1, Left + x2-3, Top + y1 -1); } if (col == 0) { // Draw the bottom left intersection DrawIntersection(grParent, Left -3, Top + y2, leftSide,bottomSide,belowLeftSide,none); // Draw the left side DrawLine(grParent, leftSide, Left + x1 - 1, Top + y1, Left + x1 - 1, Top + y2-3); } } } // Draw the bottom right intersection DrawIntersection(grGrid, x2 - 2, y2, rightSide, rightOfBottomSide, belowRightSide, bottomSide); // Draw the bottom side DrawLine(grGrid, bottomSide, x1, y2, x2-3, y2); // Draw the right side DrawLine(grGrid, rightSide, x2, y1, x2, y2-3); } private static void DrawLine(Graphics gr, GridLinePattern pattern, int x1, int y1, int x2, int y2) { if (pattern == GridLinePattern.None) return; Pen pn = VlnBorders.LinePen(pattern, BorderColor); DrawLine(gr, pn, pattern, x1, y1, x2, y2); } private static void DrawLine(Graphics gr, Pen pn, int x1, int y1, int x2, int y2) { DrawLine(gr, pn, GridLinePattern.Single, x1, y1, x2, y2); } private static void DrawLine(Graphics gr, Pen pn, GridLinePattern pattern, int x1, int y1, int x2, int y2) { int dx = 0; int dy = 0; int dblx = 0; int dbly = 0; int xThick = 0; int yThick = 0; if (x1 == x2) // Vertical Line { dx = (int) (-pn.Width / 2); dblx = -2; if (pn.Width > 2) yThick = 1; } else // Horizontal Line { dy = (int) (-pn.Width / 2); dbly = -2; if (pn.Width > 2) xThick = 1; } gr.DrawLine(pn, x1 + dx, y1 + dy, x2 + dx + xThick, y2 + dy + yThick); if(pattern == GridLinePattern.Double) gr.DrawLine(pn, x1 + dx +dblx, y1 + dy + dbly, x2 + dx+dblx, y2 + dy+dbly); } private static void DrawIntersection(Graphics gr, int x, int y, GridLinePattern up, GridLinePattern right, GridLinePattern down, GridLinePattern left) { if (up == GridLinePattern.Double) if (right == GridLinePattern.Double) if (down == GridLinePattern.Double) if (left == GridLinePattern.Double) DrawIntersectionAllDoubles(gr, x, y); else DrawDrawIntersection3Doubles_URD(gr, x, y); else // Down is not double if (left == GridLinePattern.Double) DrawDrawIntersection3Doubles_URL(gr, x, y); else DrawDrawIntersection2Doubles_UR(gr, x, y, down, left); else // right is not double if (down == GridLinePattern.Double) if (left == GridLinePattern.Double) DrawDrawIntersection3Doubles_UDL(gr, x, y); else DrawDrawIntersection2Doubles_UD(gr, x, y, right, left); else // Down is not double if (left == GridLinePattern.Double) DrawIntersection2Doubles_UL(gr, x, y, right, down); else DrawIntersectionOneDoubleOrLess(gr, x, y, up, right, down, left); else if (right == GridLinePattern.Double) if (down == GridLinePattern.Double) if (left == GridLinePattern.Double) DrawDrawIntersection3Doubles_RDL(gr, x, y); else DrawDrawIntersection2Doubles_RD(gr, x, y, up, left); else // Down is not double if (left == GridLinePattern.Double) DrawDrawIntersection2Doubles_RL(gr, x, y, up, down); else DrawIntersectionOneDoubleOrLess(gr, x, y, up, right, down, left); else if (down == GridLinePattern.Double) if (left == GridLinePattern.Double) DrawDrawIntersection2Doubles_DL(gr, x, y, up, right); else DrawIntersectionOneDoubleOrLess(gr, x, y, up, right, down, left); else // These both use the same function with the same parameters if (left == GridLinePattern.Double) DrawIntersectionOneDoubleOrLess(gr, x, y, up, right, down, left); else DrawIntersectionOneDoubleOrLess(gr, x, y, up, right, down, left); } private static Pen pnDouble = VlnBorders.LinePen(GridLinePattern.Double, BorderColor); private static Pen pnThick = VlnBorders.LinePen(GridLinePattern.Thick, BorderColor); private static void DrawIntersectionAllDoubles(Graphics gr, int x, int y) { DrawLine(gr, pnDouble, x-1, y, x, y); DrawLine(gr, pnDouble, x, y - 2, x, y - 3); DrawLine(gr, pnDouble, x + 2, y - 2, x + 3, y - 2); DrawLine(gr, pnDouble, x + 2, y, x + 2, y + 1); } private static void DrawDrawIntersection3Doubles_URD(Graphics gr, int x, int y) { DrawLine(gr, pnDouble, x , y, x, y - 3); DrawLine(gr, pnDouble, x + 2, y - 2, x + 3, y - 2); DrawLine(gr, pnDouble, x + 2, y, x + 2, y + 1); } private static void DrawDrawIntersection3Doubles_URL(Graphics gr, int x, int y) { DrawLine(gr, pnDouble, x, y, x + 2, y); DrawLine(gr, pnDouble, x -1, y - 2, x , y - 2); DrawLine(gr, pnDouble, x + 2, y - 2, x + 3, y - 2); } private static void DrawDrawIntersection3Doubles_UDL(Graphics gr, int x, int y) { DrawLine(gr, pnDouble, x-1, y, x, y); DrawLine(gr, pnDouble, x , y - 2, x , y - 3); DrawLine(gr, pnDouble, x + 2, y-3, x + 2, y); } private static void DrawDrawIntersection3Doubles_RDL(Graphics gr, int x, int y) { DrawLine(gr, pnDouble, x-1, y, x, y); DrawLine(gr, pnDouble, x, y - 2, x + 2, y - 2); DrawLine(gr, pnDouble, x + 2, y, x + 2, y + 1); } private static void DrawDrawIntersection2Doubles_UR(Graphics gr, int x, int y, GridLinePattern lp1, GridLinePattern lp2) { if (lp1 == GridLinePattern.Thick && lp2 == GridLinePattern.Thick) DrawLine(gr, pnThick, x, y, x + 3, y); else { DrawLine(gr, pnDouble, x, y, x + 2, y); DrawLine(gr, pnDouble, x , y, x , y - 2); DrawLine(gr, pnDouble, x + 2, y - 2, x + 3, y - 2); } } private static void DrawDrawIntersection2Doubles_UD(Graphics gr, int x, int y, GridLinePattern lp1, GridLinePattern lp2) { if (lp1 == GridLinePattern.Thick && lp2 == GridLinePattern.Thick) DrawLine(gr, pnThick, x, y, x + 3, y); else { DrawLine(gr, pnDouble, x, y, x, y - 2); DrawLine(gr, pnDouble, x + 2, y, x + 2, y - 2); } } private static void DrawIntersection2Doubles_UL(Graphics gr, int x, int y, GridLinePattern lp1, GridLinePattern lp2) { if (lp1 == GridLinePattern.Thick && lp2 == GridLinePattern.Thick) DrawLine(gr, pnThick, x, y, x + 3, y); else { DrawLine(gr, pnDouble, x, y, x + 2, y); DrawLine(gr, pnDouble, x , y - 2, x, y - 3); DrawLine(gr, pnDouble, x + 2, y, x + 2, y - 2); } } private static void DrawDrawIntersection2Doubles_RD(Graphics gr, int x, int y, GridLinePattern lp1, GridLinePattern lp2) { if (lp1 == GridLinePattern.Thick && lp2 == GridLinePattern.Thick) DrawLine(gr, pnThick, x, y, x + 3, y); else { DrawLine(gr, pnDouble, x, y, x, y - 2); DrawLine(gr, pnDouble, x, y - 2, x + 2, y - 2); DrawLine(gr, pnDouble, x + 2, y, x + 2, y + 1); } } private static void DrawDrawIntersection2Doubles_RL(Graphics gr, int x, int y, GridLinePattern lp1, GridLinePattern lp2) { if (lp1 == GridLinePattern.Thick && lp2 == GridLinePattern.Thick) DrawLine(gr, pnThick, x, y, x + 2, y); else { DrawLine(gr, pnDouble, x, y, x + 2, y); DrawLine(gr, pnDouble, x, y - 2, x + 2, y - 2); } } private static void DrawDrawIntersection2Doubles_DL(Graphics gr, int x, int y, GridLinePattern lp1, GridLinePattern lp2) { if (lp1 == GridLinePattern.Thick && lp2 == GridLinePattern.Thick) DrawLine(gr, pnThick, x, y, x + 2, y); else { DrawLine(gr, pnDouble, x-1, y, x, y); DrawLine(gr, pnDouble, x, y - 2, x + 2, y - 2); DrawLine(gr, pnDouble, x + 2, y, x + 2, y - 2); } } private static void DrawIntersectionOneDoubleOrLess(Graphics gr, int x, int y, GridLinePattern up, GridLinePattern right, GridLinePattern down, GridLinePattern left) { Pen pnUp = VlnBorders.LinePen(up, BorderColor); Pen pnLeft = VlnBorders.LinePen(left, BorderColor); int widthUpDown = Math.Max(VlnBorders.LineWidth0(up), VlnBorders.LineWidth0(down)); int heightLeftRight = Math.Max(VlnBorders.LineWidth0(left), VlnBorders.LineWidth0(right)); if (heightLeftRight > 0 && widthUpDown > 0) { Pen pn = new Pen(BorderColor, widthUpDown); if(heightLeftRight > 1) DrawLine(gr, pn, x + 2, y + 1 - heightLeftRight, x + 2, y); else if(up == GridLinePattern.None) // Work around to set a pixel (actually set two) DrawLine(gr, pn, x + 2, y, x + 2, y + 1); } if (left != GridLinePattern.None) { DrawLine(gr, pnLeft, x, y, x + 2 - widthUpDown, y); if (left == GridLinePattern.Double) DrawLine(gr, pnLeft, x, y - 2, x + 2 - widthUpDown, y - 2); } if (up != GridLinePattern.None) { DrawLine(gr, pnUp, x + 2, y - 3 , x + 2, y +1 - heightLeftRight); if (up == GridLinePattern.Double) DrawLine(gr, pnUp, x, y - 3, x, y +1 - heightLeftRight); } } #endregion //Grid Initialize #region Grid and Cell Styles public void ChangeBackgroundColor(string bckgndColor) { CellRange cr = this.Selection; if (!bckgndColor.EndsWith(";")) bckgndColor+=";"; string strBckgndColor = string.Format("BackColor:{0}", bckgndColor); for (int rw = cr.r1; rw <= cr.r2; rw++) for (int cl = cr.c1; cl <= cr.c2; cl++) { CellRange tmp = this.GetCellRange(rw, cl, rw, cl); string StyleName = string.Format("R{0}C{1}Style", rw, cl); CellStyle cs = this.Styles.Add(StyleName, tmp.Style); cs.ParseString(strBckgndColor); tmp.Style = cs; } } public void ToggleCellTextAlignment() { // only used in test program CellRange cr = this.Selection; using (StepRTB srtb = new StepRTB()) { srtb.Rtf = this.GetCellRTFString(cr.r1, cr.c1); srtb.SelectAll(); int align = (int)srtb.SelectionAlignment; align = (align + 1) % 3; srtb.SelectionAlignment = (HorizontalAlignment)align; this.PutCellRTFString(cr.r1, cr.c1, srtb.Rtf); } } public void RTFTextAlignment(CellRange cr, HorizontalAlignment ha) { using ( StepRTB srtb = new StepRTB()) { for (int rw = cr.r1; rw <= cr.r2; rw++) for (int cl = cr.c1; cl <= cr.c2; cl++) { srtb.Rtf = this.GetCellRTFString(rw, cl); srtb.SelectAll(); srtb.SelectionAlignment = ha; this.PutCellRTFString(rw, cl, srtb.Rtf); } } } public void SetTableBorder(C1.Win.C1FlexGrid.Util.BaseControls.BorderStyleEnum border) { this.BorderStyle = border; this.AdjustGridControlSize(); } public void ChangeCellAlign(CellRange cr, TextAlignEnum newAlign) { //Console.WriteLine("CellRange = {0}, align={1}", cr, newAlign); for (int rw = cr.r1; rw <= cr.r2; rw++) for (int col = cr.c1; col <= cr.c2; col++) { CellRange tmp = this.GetCellRange(rw, col, rw, col); string StyleName = string.Format("R{0}C{1}Style", rw, col); CellStyle cs = null; if (Styles.Contains(StyleName)) cs = Styles[StyleName]; else cs = this.Styles.Add(StyleName, tmp.Style); cs.TextAlign = newAlign; tmp.Style = cs; } // If one column and one row, then go into edit mode. if (cr.r1 == cr.r2 && cr.c1 == cr.c2) SendKeys.Send("{F2}"); // Toggle Edit Mode with F2 } public void ChangeCellBorder(CellRange cr, BorderStyleEnum newBorder) { for (int rw = cr.r1; rw <= cr.r2; rw++) for (int col = cr.c1; col <= cr.c2; col++) { CellRange tmp = this.GetCellRange(rw, col, rw, col); string StyleName = string.Format("R{0}C{1}Style", rw, col); CellStyle cs = null; if (Styles.Contains(StyleName)) cs = Styles[StyleName]; else cs = this.Styles.Add(StyleName, tmp.Style); cs.Border.Style = newBorder; tmp.Style = cs; } } public void ListStyles() { for (int r = 0; r < Rows.Count; r++) for (int c = 0; c < Cols.Count; c++) { CellRange cr = GetMergedRange(r, c); if (cr.r1 == r && cr.c1 == c) { if (cr.Style != null) Console.WriteLine("{0}, {1}, {2}, {3}", r, c, cr.Style.Name, cr.Style.BackColor); } } } //public void VerticalCenterText() //{ // StepRTB myStepRTB = new StepRTB(); // CellRange selRange = this.Selection; // for (int r = selRange.r1; r <= selRange.r2; r++) // for (int c = selRange.c1; c <= selRange.c2; c++) // { // CellRange mr = this.GetMergedRange(r, c); // if (mr.r1 == r) // { // int editHeight = (int)mr.UserData; // int cellHeight = GetCellHeight(mr.r1, mr.c1); // if (editHeight < cellHeight) // { // myStepRTB.Rtf = (string)mr.Data; // RTBAPI.SetSpaceBefore(myStepRTB, (cellHeight - editHeight) / 2); // PutCellRTFString(mr.r1, mr.c1, myStepRTB.Rtf); // } // } // } //} //public void VerticalTopText() //{ // StepRTB myStepRTB = new StepRTB(); // CellRange selRange = this.Selection; // for (int r = selRange.r1; r <= selRange.r2; r++) // for (int c = selRange.c1; c <= selRange.c2; c++) // { // CellRange mr = this.GetMergedRange(r, c); // if (mr.r1 == r) // { // myStepRTB.Rtf = (string)mr.Data; // RTBAPI.SetSpaceBefore(myStepRTB, 0); // PutCellRTFString(mr.r1, mr.c1, myStepRTB.Rtf); // } // } //} //public void VerticalBottomText() //{ // StepRTB myStepRTB = new StepRTB(); // CellRange selRange = this.Selection; // for (int r = selRange.r1; r <= selRange.r2; r++) // for (int c = selRange.c1; c <= selRange.c2; c++) // { // CellRange mr = this.GetMergedRange(r, c); // if (mr.r1 == r) // { // int editHeight = (int)mr.UserData; // int cellHeight = GetCellHeight(mr.r1, mr.c1); // if (editHeight < cellHeight) // { // myStepRTB.Rtf = (string)mr.Data; // RTBAPI.SetSpaceBefore(myStepRTB, (cellHeight - editHeight)); // PutCellRTFString(mr.r1, mr.c1, myStepRTB.Rtf); // } // } // } //} //public void SetupCellStyles() //{ // //CellStyle cs; // //cs = this.Styles.Add("Dotted"); // //cs.Border.Style = BorderStyleEnum.Dotted; // //cs = this.Styles.Add("Double"); // //cs.Border.Style = BorderStyleEnum.Double; // //cs = this.Styles.Add("Fillet"); // //cs.Border.Style = BorderStyleEnum.Fillet; // //cs = this.Styles.Add("Flat"); // //cs.Border.Style = BorderStyleEnum.Flat; // //cs = this.Styles.Add("Groove"); // //cs.Border.Style = BorderStyleEnum.Groove; // //cs = this.Styles.Add("Inset"); // //cs.Border.Style = BorderStyleEnum.Inset; // //cs = this.Styles.Add("None"); // //cs.Border.Style = BorderStyleEnum.None; // //cs = this.Styles.Add("Raised"); // //cs.Border.Style = BorderStyleEnum.Raised; // //cs = this.Styles.Add("CenterRight"); // //cs.TextAlign = TextAlignEnum.RightCenter; //.LeftCenter; // this is being ignored - probably due to RTF conversion // //cs = this.Styles.Add("Yellow"); // //cs.BackColor = Color.Yellow; // //cs = this.Styles.Add("Margins"); // //cs.Margins.Bottom = 5; // //cs.Margins.Top = 10; // //cs.Margins.Left = 15; // //cs.Margins.Right = 20; //} #endregion //Grid and Cell Styles #region Grid Size Adjustments /// /// Adjust the grid control size based on the cell sizes. /// public void AdjustGridControlSize() { if (Parent is GridItem ? (Parent as GridItem).Initializing : false ) return; int difW = this.Width - this.ClientSize.Width; int difH = this.Height - this.ClientSize.Height; int wid = 0; if (this != null) { foreach (C1.Win.C1FlexGrid.Column col in this.Cols) wid += (col.Width >= 0) ? col.Width : this.Cols.DefaultSize; int height = 0; foreach (C1.Win.C1FlexGrid.Row row in this.Rows) //height += (row.Height >= 0) ? row.Height : this.Rows.DefaultSize + 2; height += (row.Height >= 0) ? row.Height : this.Rows.DefaultSize; this.Size = new Size(wid + difW, height + difH); } } // B2019-162 Allow grids to not automatically adjust the cell widths public void ConvertTextCellToRTF(int r, int c, bool adjustWidth) { using (StepRTB trtb = new StepRTB()) { string tstr = null; bool dummyCharWidth = false; bool AllowWidthShrink = false; trtb.SetTableGridCellRTFPrefix(this.Font); trtb.Clear(); tstr = (string)this[r, c]; trtb.Font = this.Font; if (tstr != null && tstr.Length > 0) { string tsave = tstr; // regular text has special characters to toggle Bold, Underline, and Italics // we need to subtract the width of these characters (allow column/row to shrink) //AllowWidthShrink = RemoveBoldUlineItalicChars(trtb.Rtf); AllowWidthShrink = tstr.Contains("#Link:"); // this will convert the special characters for Bold, Underline, and Italics // into RTF commands //trtb.Rtf = trtb.RtfPrefix + ConvertTableText(trtb.Rtf) + "}"; //string fromRTF = trtb.Rtf; //string prefix = trtb.RtfPrefix; //if (tstr.Contains("#Link:")) prefix += @"{\colortbl ;\red255\green0\blue0;}"; //if (tstr.Contains("#Link:")) // Console.WriteLine("here"); //string jText = trtb.RtfPrefix + ConvertTableText(tstr) + @"\par}"; //trtb.Rtf = jText; trtb.Rtf = trtb.RtfPrefix + ConvertTableText(tstr) + @"\par}"; //string fromStr = trtb.Rtf; //if (fromRTF.Contains("SimSun")) // Console.WriteLine("SimSun"); //else // Compare(fromRTF, fromStr, tsave); } else { trtb.Text = "X"; // this is to trick steprtf in giving a char width to fit one character // note that a space character was too small. dummyCharWidth = true; } // find the needed cell width trtb.AdjustWidthForContent(); // B2019-162 Allow grids to not automatically adjust the cell widths if(adjustWidth)trtb.AdjustWidthForContent(); if (dummyCharWidth) { trtb.Text = ""; // clear out the dummy character before saving dummyCharWidth = false; } this[r, c] = trtb.Rtf; // save the cleaned up and processed cell text as RTF this.Select(r, c, false); CellRange sel = this.Selection; //sel.UserData = trtb.ContentsRectangle.Height; // Now adjust the Height and Width in the defined merge ranges // B2019-162 Allow grids to not automatically adjust the cell widths AdjustMergeRangeHeightWidth(r, c, trtb, tstr, AllowWidthShrink,adjustWidth); //// Now see the the selected row,col is in the defined merge ranges //bool mrgrows = false; //bool mrgcols = false; //foreach (CellRange cr in this.MergedRanges) //{ // if (cr.Contains(r, c)) // { // if (cr.c1 != cr.c2) // mrgcols = true; // in a range of merged columns // if (cr.r1 != cr.r2) // mrgrows = true; // in a range of merged rows // continue; // } //} //if (!mrgcols || !mrgrows) //{ // // IF the row of the selected cell is NOT in merged range // // then go ahead and adjust the row height (if needed) // if (!mrgrows) // { // // add adjustment for grid and cell borders // int newheight = trtb.Height + 3; // //Console.WriteLine("{0} {1} {2} '{3}'", r, c, newheight,trtb.Text); // if (newheight > this.Rows[r].Height) // { // //Console.WriteLine("1 Row {0} Old Height = {1}, New Height = {2}", r, Rows[r].Height, newheight); // this.Rows[r].Height = newheight; // } // } // // IF the column of the selected cell is NOT in merged range // // then go ahead and adjust the column width (if needed) // if (!mrgcols) // { // // add adjustment for grid and cell borders // int newwidth = trtb.Width + 2; // if (newwidth > this.Cols[c].Width || AllowWidthShrink || r == 0) // this.Cols[c].Width = newwidth; // } //} //if (mrgrows && tstr != null) //{ // CellRange cr = GetMergedRange(r, c); // //Console.WriteLine("grid[{0},{1}] merge = {2}", r, c,cr); // if (cr.r1 == r && cr.c1 == c) // { // // if in merged rows, then make sure the cell's height is large enough // string[] strary = tstr.Split("\n".ToCharArray()); // // count number of lines of text // int nlines = strary.Length; // // count number of rows in merge range // int nrows = (cr.r2 - cr.r1) + 1; // //Console.WriteLine("2 Row {0} Height = {1}", cr.r1, Rows[cr.r1].Height); // while (nlines > nrows) // { // // add length to first row in merged range // int h = this.Rows[cr.r1].Height; // int defH = Rows.DefaultSize - 3; // //h = (h == -1) ? _minRowHeight * 2 : h + _minRowHeight; // h = (h == -1) ? (defH * 2) + 3 : h + defH; // //h = (h == -1) ? (Rows.DefaultSize + 2) * 2 : h + Rows.DefaultSize + 2; // //Console.WriteLine("3 Row {0} Old Height = {1}, New Height = {2}", cr.r1, Rows[cr.r1].Height, h); // this.Rows[cr.r1].Height = h; // nrows++; // } // } //} } } //private void AdjustCellHeightWidth(int r, int c) //{ // using (StepRTB trtb = new StepRTB()) // { // string tstr = null; // bool dummyCharWidth = false; // bool AllowWidthShrink = false; // trtb.SetTableGridCellRTFPrefix(this.Font); // trtb.Clear(); // trtb.Font = this.Font; // trtb.Rtf = (string)this[r, c]; // tstr = trtb.Text; // if (tstr != null && tstr.Length > 0) // AllowWidthShrink = tstr.Contains("#Link:"); // else // { // trtb.Text = "X"; // this is to trick steprtf in giving a char width to fit one character // // note that a space character was too small. // dummyCharWidth = true; // } // // find the needed cell width // trtb.AdjustWidthForContent(); // if (dummyCharWidth) // { // trtb.Text = ""; // clear out the dummy character before saving // dummyCharWidth = false; // } // // Now adjust the Height and Width in the defined merge ranges // AdjustMergeRangeHeightWidth(r, c, trtb, tstr, AllowWidthShrink,true); // } //} // B2019-162 Allow grids to not automatically adjust the cell widths private void AdjustMergeRangeHeightWidth(int r, int c, StepRTB trtb, string tstr, bool AllowWidthShrink, bool adjustWidth) { bool mrgrows = false; bool mrgcols = false; foreach (CellRange cr in this.MergedRanges) { if (cr.Contains(r, c)) { if (cr.c1 != cr.c2) mrgcols = true; // in a range of merged columns if (cr.r1 != cr.r2) mrgrows = true; // in a range of merged rows continue; } } if (!mrgcols || !mrgrows) { // IF the row of the selected cell is NOT in merged range // then go ahead and adjust the row height (if needed) if (!mrgrows) { // add adjustment for grid and cell borders int newheight = trtb.Height + 3; //Console.WriteLine("{0} {1} {2} '{3}'", r, c, newheight,trtb.Text); if (newheight > this.Rows[r].Height) { //Console.WriteLine("1 Row {0} Old Height = {1}, New Height = {2}", r, Rows[r].Height, newheight); this.Rows[r].Height = newheight; } } // IF the column of the selected cell is NOT in merged range // then go ahead and adjust the column width (if needed) if (!mrgcols) { // add adjustment for grid and cell borders // B2019-162 Allow grids to not automatically adjust the cell widths if (adjustWidth) { int newwidth = trtb.Width + 3; // 2; if (newwidth > (this.Cols[c].Width == -1 ? this.Cols.DefaultSize : this.Cols[c].Width) || AllowWidthShrink || r == 0) this.Cols[c].Width = newwidth; } } } if (mrgrows && tstr != null) { CellRange cr = GetMergedRange(r, c); if (cr.r1 == r && cr.c1 == c) { // if in merged rows, then make sure the cell's height is large enough string[] strary = tstr.Split("\n".ToCharArray()); // count number of lines of text int nlines = strary.Length; // count number of rows in merge range int nrows = (cr.r2 - cr.r1) + 1; //Console.WriteLine("2 Row {0} Height = {1}", cr.r1, Rows[cr.r1].Height); while (nlines > nrows) { // add length to first row in merged range int h = this.Rows[cr.r1].Height; int defH = Rows.DefaultSize - 3; h = (h == -1) ? (defH * 2) + 3 : h + defH; this.Rows[cr.r1].Height = h; nrows++; } } } } private int TotalColWidths() { int cwid = 0; foreach (Column c in Cols) { cwid += ((c.Width > 0) ? c.Width : Cols.DefaultSize); } return cwid; } /// /// This will adjust the column widths of the current table based upon the page width /// Note: This is for use in creating a new table - not to process an existing table. /// /// public void FitTableToPageWidth(int pgWidthPoints) { int grdWidth = TotalColWidths(); int pgwidth = (int)((pgWidthPoints / 72) * this._DPI); if (grdWidth > pgwidth) { int difWid = grdWidth - pgwidth; int colAdj = (difWid / Cols.Count) +(((difWid % Cols.Count) > 0) ? 1 : 0); foreach (Column c in Cols) { int cwid = (c.Width > 0) ? c.Width : Cols.DefaultSize; if ((cwid - colAdj) > 0) c.Width = cwid - colAdj; } } } //private void AdjustCellHeightWidth(int r, int c) //{ // StepRTB trtb = new StepRTB(); // string tstr = null; // bool dummyCharWidth = false; // bool AllowWidthShrink = false; // trtb.SetTableGridCellRTFPrefix(this.Font); // trtb.Clear(); // trtb.Font = this.Font; // trtb.Rtf = (string)this[r, c]; // tstr = trtb.Text; // if (tstr != null && tstr.Length > 0) // AllowWidthShrink = tstr.Contains("#Link:"); // else // { // trtb.Text = "X"; // this is to trick steprtf in giving a char width to fit one character // // note that a space character was too small. // dummyCharWidth = true; // } // // find the needed cell width // trtb.AdjustWidthForContent(); // if (dummyCharWidth) // { // trtb.Text = ""; // clear out the dummy character before saving // dummyCharWidth = false; // } // this.Select(r, c, false); // CellRange sel = this.Selection; // // Now see the the selected row,col is in the defined merge ranges // bool mrgrows = false; // bool mrgcols = false; // foreach (CellRange cr in this.MergedRanges) // { // if (cr.Contains(r, c)) // { // if (cr.c1 != cr.c2) // mrgcols = true; // in a range of merged columns // if (cr.r1 != cr.r2) // mrgrows = true; // in a range of merged rows // continue; // } // } // if (!mrgcols || !mrgrows) // { // // IF the row of the selected cell is NOT in merged range // // then go ahead and adjust the row height (if needed) // if (!mrgrows) // { // // add adjustment for grid and cell borders // int newheight = trtb.Height + 3; // //Console.WriteLine("{0} {1} {2} '{3}'", r, c, newheight,trtb.Text); // if (newheight > this.Rows[r].Height) // { // //Console.WriteLine("1 Row {0} Old Height = {1}, New Height = {2}", r, Rows[r].Height, newheight); // this.Rows[r].Height = newheight; // } // } // // IF the column of the selected cell is NOT in merged range // // then go ahead and adjust the column width (if needed) // if (!mrgcols) // { // // add adjustment for grid and cell borders // int newwidth = trtb.Width + 2; // if (newwidth > this.Cols[c].Width || AllowWidthShrink || r == 0) // this.Cols[c].Width = newwidth; // } // } // if (mrgrows && tstr != null) // { // CellRange cr = GetMergedRange(r, c); // if (cr.r1 == r && cr.c1 == c) // { // // if in merged rows, then make sure the cell's height is large enough // string[] strary = tstr.Split("\n".ToCharArray()); // // count number of lines of text // int nlines = strary.Length; // // count number of rows in merge range // int nrows = (cr.r2 - cr.r1) + 1; // //Console.WriteLine("2 Row {0} Height = {1}", cr.r1, Rows[cr.r1].Height); // while (nlines > nrows) // { // // add length to first row in merged range // int h = this.Rows[cr.r1].Height; // int defH = Rows.DefaultSize - 3; // h = (h == -1) ? (defH * 2) + 3 : h + defH; // this.Rows[cr.r1].Height = h; // nrows++; // } // } // } //} //private void Compare(string fromRTF, string fromStr, string rawstr) //{ // int istart = fromRTF.IndexOf(" ",fromRTF.IndexOf("viewkind")); // int jstart = fromStr.IndexOf(" ",fromStr.IndexOf("viewkind")); // for (int i = istart; i < fromRTF.Length; i++) // { // int j = i - istart + jstart; // //else if (fromRTF[i] != fromStr[j]) // if (fromRTF[i] != fromStr[j]) // { // if (fromRTF.Substring(i, 1) == @"~" && fromStr.Substring(j, 3) == @"'a0") // { // //i++; // jstart += 2; // } // else // { // Console.WriteLine("fromStr:\r\n'{0}'\r\nfromRTF:\r\n'{1}'", fromStr, fromRTF); // ShowRawString(rawstr, "rawstr"); // Console.WriteLine("Str:'{0}' , RTF:'{1}'", fromStr.Substring(j, Math.Min(10,fromStr.Length-j-1)), fromRTF.Substring(i, Math.Min(10,fromRTF.Length-i-1))); // return; // } // } // } //} #region DEBUG //private void ShowRawString(string str, string title) //{ // Console.WriteLine("Raw Start --{0}:\n", title); // foreach (char c in str) // { // int ic= (int)c; // if (c!='\n'&&( ic > 126 || ic < 32)) // Console.Write("<<{0:x4}>>", ic); // else // Console.Write(c); // } // Console.WriteLine("\n-- Raw End:{0}", title); //} #endregion private void Grid_AfterResize(object sender, C1.Win.C1FlexGrid.RowColEventArgs e) { this.AdjustGridControlSize(); } #endregion // Grid Size Adjustments #region Cell Text // B2019-162 Allow grids to not automatically adjust the cell widths public void MakeRTFcells() { MakeRTFcells(true); } // B2019-162 Allow grids to not automatically adjust the cell widths public void MakeRTFcells(bool adjustwidth) { // This will spin through all the cells in the grid: // - convert the text to RTF if needed // - adjust the grid dimensions based on the cell info. for (int r = 0; r < this.Rows.Count; r++) { this.Rows[r].Height = Rows.DefaultSize;//_minRowHeight;//20;//10; for (int c = 0; c < this.Cols.Count; c++) { // B2019-162 Allow grids to not automatically adjust the cell widths this.ConvertTextCellToRTF(r, c, adjustwidth); } } // B2019-162 Allow grids to not automatically adjust the cell widths if(adjustwidth) TrimColumnWidths(); RemoveBlankSpaceFromRows(); SetupCellUserData(); this.AdjustGridControlSize(); } public void FixTableCellsHeightWidth() { RemoveBlankSpaceFromColumns(); RemoveBlankSpaceFromRows(); } private void RemoveBlankSpaceFromRows() { for (int r = 0; r < Rows.Count; r++) { Select(r, 0); int blankRowSpace = BlankRowSpace(); if (blankRowSpace > 0) Rows[r].Height -= blankRowSpace; } } private void RemoveBlankSpaceFromColumns() { for (int c = 0; c < Cols.Count; c++) { Select(0, c); int blankColSpace = BlankColSpace(); if (blankColSpace > 0) Cols[c].Width -= blankColSpace; } } private void TrimColumnWidths() { for (int c = 0; c < Cols.Count; c++) { Select(0, c); int newColWidth = MinColWidth(); Cols[c].Width = newColWidth; } } private int MinColWidth() { int curColWidth = 0; for (int r = 0; r < Rows.Count; r++) { CellRange cr = GetMergedRange(r, Col); // find the needed cell width if (Col == cr.c1) { using (StepRTB srtb = new StepRTB()) { srtb.Rtf = GetCellRTFString(cr.r1, cr.c1); srtb.AdjustWidthForContent(); curColWidth = Math.Max(curColWidth, srtb.Width + 3); } } } return curColWidth; } //private bool RemoveBoldUlineItalicChars(string str) //{ // int rtn = 0; // // Underline next word // rtn += str.IndexOf(@"\'17"); // // Bold next word // rtn += str.IndexOf(@"\'13"); // // Italics On // rtn += str.IndexOf(@"\'1B4"); // // Italics Off // rtn += str.IndexOf(@"\'1B5"); // // underline On // rtn += str.IndexOf(@"\'ab"); // // underline Off // rtn += str.IndexOf(@"\'bb"); // return rtn > 0; //} private string ConvertTableText(string str) { string rtn = str; //ShowRawString(str, "ConvertTableText IN"); rtn = rtn.Replace(@"START]\v0", @"START]\cf1\v0"); rtn = rtn.Replace(@"\v #Link:", @"\cf0\v #Link:"); rtn = rtn.Replace("\n", "\\par\r\n"); rtn = rtn.Replace("\xB3", @"\f1\u9474?\f0"); // Vert Bar rtn = rtn.Replace("\xF2", @"\f1\u8805?\f0 "); // greater than or equal rtn = rtn.Replace("\x7F", @"\f1\u916?\f0 "); // delta rtn = rtn.Replace("\xF3", @"\f1\u8804?\f0 "); // less than or equal rtn = rtn.Replace("\xE4", @"\f1\u931?\f0 "); // sigma rtn = rtn.Replace("\xE7", @"\f1\u947?\f0 "); // gamma rtn = rtn.Replace("\xFE", @"\f1\u9604?\f0 "); // accum 2584 rtn = rtn.Replace("\x7", @"\f1\u9679?\f0 "); // bullet 25CF rtn = rtn.Replace("\xF7", @"\f1\u8776?\f0 "); // approx eq rtn = rtn.Replace("\xF0", @"\f1\u8773?\f0 "); // similar eq 2245 rtn = rtn.Replace("\xFB", @"\f1\u8730?\f0 "); // square root rtn = rtn.Replace("\xE2", @"\f1\u961?\f0 "); // rho 3C1 rtn = rtn.Replace("\xE3", @"\f1\u960?\f0 "); // pi rtn = rtn.Replace("\xE6", @"\f1\u956?\f0 "); // micro rtn = rtn.Replace("\xEB", @"\f1\u948?\f0 "); // lower case delta rtn = rtn.Replace("\xE5", @"\f1\u963?\f0 "); // lower case sigma rtn = rtn.Replace("\x90", @"\f1\u274?\f0 "); // energy, 112 rtn = rtn.Replace("\xEE", @"\f1\u949?\f0 "); // epsilon rtn = rtn.Replace("\xE9", @"\f1\u952?\f0 "); // theta, 3B8 rtn = rtn.Replace("\xEC", @"\f1\u8857?\f0 "); // dot in oval, 2299 rtn = rtn.Replace("\xA8", @"\f1\u964?\f0 "); // tau, 3C4 rtn = rtn.Replace("\xA9", @"\f1\u9830?\f0 "); // diamond, 2666 rtn = rtn.Replace("\x18", @"\f1\u8593?\f0 "); // Up Arrow rtn = rtn.Replace("\x19", @"\f1\u8595?\f0 "); // Down Arrow rtn = rtn.Replace("\xFF", @"\u160?"); // hardspace //rtn = rtn.Replace(@"\'a0", @"\u160?"); //rtn = rtn.Replace("\xff", @"\u160?"); //rtn = rtn.Replace("\xA0", @"\u160?"); // underline On rtn = rtn.Replace("\xab", @"\ul"); // underline Off rtn = rtn.Replace("\xbb", @"\ulnone"); //rtn = rtn.Replace("\xef\xe6", @"\up2 "); //rtn = rtn.Replace("\xef\xe7", @"\up0 "); rtn = rtn.Replace("\x9566", @"\up2 "); rtn = rtn.Replace("\x9567", @"\up0 "); rtn = rtn.Replace("{", @"\{"); rtn = rtn.Replace("}", @"\}"); rtn = rtn.Replace("\xd5", @"\b"); rtn = rtn.Replace("\xd6", @"\b0"); //ShowRawString(rtn, "ConvertTableText OUT"); return rtn; } private static string SomethingNextWord(string str, string nxtwordcmd, string cmdOn, string cmdOff) { string rtn = ""; int bidx = 0; int fidx = str.IndexOf(nxtwordcmd, bidx); char[] term = " \r\n\x02".ToCharArray(); while (fidx > 0) { rtn += str.Substring(bidx, fidx - bidx) + cmdOn; bidx = fidx + 4; if (bidx < str.Length) { fidx = str.IndexOfAny(term, bidx); if (fidx > 0) { rtn += str.Substring(bidx, fidx - bidx) + cmdOff + str.Substring(fidx, 1); bidx = fidx + 1; } } if (bidx < str.Length) fidx = str.IndexOf(nxtwordcmd, bidx); else fidx = -1; } if (bidx < str.Length) rtn += str.Substring(bidx); return rtn; } private void _StartEdit(object sender, C1.Win.C1FlexGrid.RowColEventArgs e) { // start editing the cell with the custom editor if(!IsRoTable ) _tableCellEditor.StartEditing(e.Row, e.Col, _GettingFontSize); // C2021-005 added _GettingFontSize to prevent showing the editor e.Cancel = true; } // after edit handler (built-in editors) private void _AfterEdit(object sender, C1.Win.C1FlexGrid.RowColEventArgs e) { this.GetCellRange(e.Row, e.Col).Style.ForeColor = Color.Black; this.AdjustGridControlSize(); GC.Collect(GC.GetGeneration(this)); // there is a memory leak in Regex this fixes it. (called in StepRTB.cs FindLinks) } // if the custom editor is visible, make it follow the cell being edited private void _AfterScroll(object sender, C1.Win.C1FlexGrid.RangeEventArgs e) { this._tableCellEditor.UpdatePosition(); } // save last key pressed for the custom editor private void _KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e) { this._tableCellEditor.SetPendingKey(e.KeyChar); } public string GetCellRTFString(int row, int col) { string rtnstr = ""; foreach (CellRange r in this.MergedRanges) { if (r.ContainsRow(row) && r.ContainsCol(col)) { rtnstr = (string)this[r.r1, r.c1]; return rtnstr; } } rtnstr = (string)this[row, col]; return rtnstr; } public void PutCellRTFString(int row, int col, string str) { foreach (CellRange r in this.MergedRanges) { if (r.ContainsRow(row) && r.ContainsCol(col)) { this[r.r1, r.c1] = str; return; } } this[row, col] = str; return; } public void ClearSelectedCellText() { CellRange cr = this.Selection; cr.Clear(ClearFlags.Content); } public void SetupCellUserData() { for (int r = 0; r < Rows.Count; r++) for (int c = 0; c < Cols.Count; c++) { string rtfText = GetDataDisplay(r, c); if (rtfText.StartsWith(@"{\rtf")) { using (StepRTB _rtf = new StepRTB()) { _rtf.Width = Cols[c].Width; _rtf.Rtf = rtfText; CellRange cr = GetCellRange(r, c); cr.UserData = _rtf.ContentsRectangle.Height; } } } } #endregion //Cell Text #region Merged / Split Range public void MergeSelection() { this.MergedRanges.Add(this.Selection,true); this.Invalidate(); this.Select(Selection.r1, Selection.c1); } public bool IsInMergeRange() { C1.Win.C1FlexGrid.CellRange sel = GetMergedRange(this.Selection.r1, this.Selection.c1); return MergedRanges.Contains(sel); } public void SplitSelection(bool bSplitCols) { //Console.WriteLine("SplitSelection this.selection {0}", this.Selection); //Debug_WritelineMySelection(); //C1.Win.C1FlexGrid.CellRange sel = this.GetMergedRange(this.Selection.r1, this.Selection.c1); //Console.WriteLine("SplitSelection myselection {0}", MySelection); //foreach (CellRange sel in MySelection) //{ // //Console.WriteLine("SplitSelection foreach sel {0}", sel); // if (sel.IsSingleCell) // this.MergedRanges.Remove(sel); // if (!(this.MergedRanges.Contains(sel)) && !didit) // if (bSplitCols) // SplitSelectionColumns(); // else // SplitSelectionRows(); // didit = true; //} if (bSplitCols) SplitSelectionColumns(); else SplitSelectionRows(); //Debug_WritelineMySelection(); //foreach (CellRange sel in MySelection) //{ // //Console.WriteLine("SplitSelection foreach sel {0}", sel); // if (this.MergedRanges.Contains(sel)) // SplitMergedRange(sel, bSplitCols); //} //this.Refresh(); //RefreshMergeRangeCollection(); this.AdjustGridControlSize(); } private void SplitMergedRange(CellRange sel, bool bSplitCols) { int sR = sel.r1; int eR = sel.r2; int sC = sel.c1; int eC = sel.c2; if (bSplitCols && (IsMergedCols(sel) && !IsMergedRows(sel)) || (!bSplitCols && (IsMergedRows(sel) && !IsMergedCols(sel)))) MergedRanges.Remove(sel); else { CellRange saveSelection = Selection; if (bSplitCols && IsMergedRows(sel)) { MergedRanges.Remove(sel); for (int c = sC; c <= eC; c++) { Select(sR, c, eR, c); MergeSelection(); } } else if (!bSplitCols && IsMergedCols(sel)) { MergedRanges.Remove(sel); for (int r = sR; r <= eR; r++) { Select(r, sC, r, eC); MergeSelection(); } } Select(saveSelection); } } private bool IsMergedRows(CellRange sel) { return (sel.r1 != sel.r2); } private bool IsMergedCols(CellRange sel) { return (sel.c1 != sel.c2); } private void SplitSelectionColumns() { bool hasNonMergedColumn = false; //Console.WriteLine("SplitSelectionColumns this.selection {0}", this.Selection); //Debug_WritelineMySelection(); CellRange cr = this.Selection; int numSelCols = (cr.c2 - cr.c1) + 1; foreach (CellRange sel in MySelection) { if (!this.MergedRanges.Contains(sel)) hasNonMergedColumn = true; else { CellRange mr = GetMergedRange(sel.r1, sel.c1); if (mr.c1 == mr.c2) hasNonMergedColumn = true; } } // for each column in the selection, add a new column if (hasNonMergedColumn) { for (int c = cr.c2; c >= cr.c1; c--) { Select(cr.r1, c, cr.r2, c); InsertColumnAfter(); } } // include new columns in selection this.Select(cr.r1, cr.c1, cr.r2, cr.c2 + ((hasNonMergedColumn) ? numSelCols : 0)); //if a merged range is part of the selectin, try to split it foreach (CellRange sel in MySelection) { //Console.WriteLine("SplitSelection foreach sel {0}", sel); if (this.MergedRanges.Contains(sel)) SplitMergedRange(sel, true); } cr = this.Selection; if (hasNonMergedColumn) { for (int r = 0; r < this.Rows.Count; r++) for (int c = cr.c1; c <= cr.c2; c += 2) { if (!this.IsCellSelected(r, c)) { CellRange crTmp = GetMergedRange(r, c); if (crTmp.IsSingleCell) { CellRange tcr = this.GetCellRange(r, c, r, c + 1); this.MergedRanges.Add(tcr); this.Invalidate(); } //CellRange tcr = this.GetCellRange(r, c, r, c + 1); //this.MergedRanges.Add(tcr); } } // Adjust selected column widths for (int c = cr.c1; c <= cr.c2; c++) { int recWidth = (Cols[c].Width < 0) ? Cols.DefaultSize : Cols[c].Width; // this.GetCellRect(cr.r1, c).Width; int newWidth = Math.Max(recWidth / 2, _minColSplitWidth); this.Cols[c].Width = newWidth; //Console.WriteLine("Cell[{0},{1}].Width = {2}", cr.r1, c, recWidth); //Console.WriteLine("Cell[{0},{1}].NewWidth = {2}", cr.r1, c, newWidth); } } } private void SplitSelectionRows() { bool hasNonMergedRow = false; CellRange cr = this.Selection; int numSelRows = (cr.r2 - cr.r1) + 1; //Console.WriteLine("numSelRows = {0}", numSelRows); //Console.WriteLine("Inital Selection [{0},{1}] - [{2},{3}]", cr.r1, cr.c1, cr.r2, cr.c2); foreach (CellRange sel in MySelection) { if (!this.MergedRanges.Contains(sel)) hasNonMergedRow = true; else { CellRange mr = GetMergedRange(sel.r1, sel.c1); if (mr.r1 == mr.r2) hasNonMergedRow = true; } } // for each row in the selection, add a new row if (hasNonMergedRow) { for (int r = cr.r2; r >= cr.r1; r--) { //Console.WriteLine("Inserted new Row at [{0},{1}]", r, cr.c1); Select(r, cr.c1, r, cr.c2); InsertRowAfter(); } // B2017-197 move the Select inside if (hasNonMergedRow) // was getting a selection out of range error when spliting rows that contained mergered rows // only need to do this if we inserted rows // include new rows in selection this.Select(cr.r1, cr.c1, cr.r2 + numSelRows, cr.c2); } //if a merged range is part of the selectin, try to split it foreach (CellRange sel in MySelection) { //Console.WriteLine("SplitSelection foreach sel {0}", sel); if (this.MergedRanges.Contains(sel)) SplitMergedRange(sel, false); } cr = this.Selection; //Console.WriteLine(" After Insert [{0},{1}] - [{2},{3}]", cr.r1, cr.c1, cr.r2, cr.c2); if (hasNonMergedRow) { for (int c = 0; c < this.Cols.Count; c++) for (int r = cr.r1; r <= cr.r2; r += 2) { if (!this.IsCellSelected(r, c)) { CellRange crTmp = GetMergedRange(r, c); if (crTmp.IsSingleCell) { CellRange tcr = this.GetCellRange(r, c, r + 1, c); this.MergedRanges.Add(tcr); this.Invalidate(); } } } // Adjust selected Row Heights for (int r = cr.r1; r <= cr.r2; r++) { int recHeight = this.GetCellRect(r, cr.c1).Height; this.Rows[r].Height = Math.Max(recHeight / 2, Rows.DefaultSize); //this.Rows[r].Height = Math.Max(recHeight / 2, _minRowSplitHeight); //Console.WriteLine("Cell[{0},{1}].Height = {2}", r, cr.c1, recHeight); } } //foreach (CellRange crng in this.MergedRanges) // Console.WriteLine("merge ranges [{0},{1}] - [{2},{3}]", crng.r1, crng.c1, crng.r2, crng.c2); } private void AdjustMergedRows(int row, bool above, bool removing) { AdjustMergedRows(row, 1, above, removing); } private void AdjustMergedRows(int row, int cnt, bool above, bool removing) { CellRangeCollection crc = new CellRangeCollection(this); if (removing) { foreach (CellRange r in this.MergedRanges) { CellRange cr = r; if (r.ContainsRow(row)) { if (r.TopRow != r.BottomRow) { cr.r2 -= cnt; crc.Add(cr); } } else { if (row <= r.r1) { if (row < r.r1) cr.r1 -= cnt; cr.r2 -= cnt; } crc.Add(cr); } } } else // adding foreach (CellRange r in this.MergedRanges) { CellRange cr = r; int inspos = (above) ? row : row - 1; if (r.ContainsRow(inspos)) { bool adjustMergeValues = true; if (cr.r1 == row && cr.r2 == row + cnt -1) adjustMergeValues = false; // don't add to existing merge range - we will add a new merge range for this copy for (int insCnt = 0; insCnt < cnt; insCnt++) { if ((above && cr.r1 == inspos) || (!above && cr.r2 == inspos)) { string tstr = ""; int newrow = 0; if (above) { if (this[cr.r1 + cnt, cr.c1] != null) tstr = this[cr.r1 + cnt, cr.c1].ToString(); newrow = cr.r1; } else { if (this[cr.r2, cr.c1] != null) tstr = this[cr.r2, cr.c1].ToString(); newrow = cr.r2 + cnt; } if (tstr != null && tstr.Length > 0) for (int x = cr.c1; x <= cr.c2; x++) this[newrow, x] = tstr; } if (adjustMergeValues) cr.r2++; } } else { if (inspos < cr.r1) { cr.r1 += cnt; cr.r2 += cnt; } } crc.Add(cr); } this.MergedRanges.Clear(); foreach (CellRange r in crc) { if ((r.r1 != r.r2) || (r.c1 != r.c2)) this.MergedRanges.Add(r); } } private void AdjustMergedColumns(int col, bool left, bool removing) { AdjustMergedColumns(col, 1, left, removing); //adjusting for just one column } private void AdjustMergedColumns(int col, int cnt, bool left, bool removing) { CellRangeCollection crc = new CellRangeCollection(this); if (removing) { foreach (CellRange r in this.MergedRanges) { CellRange cr = r; if (r.ContainsCol(col)) { if (r.LeftCol != r.RightCol) { cr.c2 -= cnt; crc.Add(cr); } } else { if (col < cr.c1) { cr.c1-=cnt; cr.c2-=cnt; } crc.Add(cr); } } } else // adding foreach (CellRange r in this.MergedRanges) { CellRange cr = r; int inspos = (left) ? col : col - 1; if (r.ContainsCol(inspos)) { for (int insCnt = 0; insCnt < cnt; insCnt++) { string tstr = ""; int newcol = 0; if (left) { if (inspos == cr.c1) tstr = (this[cr.r1, cr.c1 + 1] == null) ? "" : this[cr.r1, cr.c1 + 1].ToString(); else tstr = (this[cr.r1, cr.c1] == null) ? "" : this[cr.r1, cr.c1].ToString(); newcol = cr.c1; } else { if (this[cr.r1, cr.c2] != null) tstr = this[cr.r1, cr.c2].ToString(); newcol = cr.c2 + 1; } for (int x = cr.r1; x <= cr.r2; x++) this[x, newcol] = tstr; cr.c2++; } } else if (col <= r.c1) { cr.c1+=cnt; cr.c2+=cnt; } crc.Add(cr); } this.MergedRanges.Clear(); foreach (CellRange r in crc) { if ((r.r1 != r.r2) || (r.c1 != r.c2)) this.MergedRanges.Add(r); } } private bool RowIsInMergeRange(int row) { bool rtn = false; if (row >= 0) { CellRange cr = this.Selection; //rtn = true; // KBR: is this wrong, i.e. should it be like ColIsInMergeRange int c = cr.c1; while (!rtn && (c <= cr.c2)) { int idx = this.MergedRanges.IndexOf(row, c); rtn = (idx > -1); c++; } } return rtn; } private bool ColIsInMergeRange(int col) { bool rtn = false; if (col >= 0) { CellRange cr = this.Selection; //rtn = true; int r = cr.r1; while (!rtn && (r <= cr.r2)) { int idx = this.MergedRanges.IndexOf(r, col); rtn = (idx > -1); r++; } } return rtn; } #endregion //Merged / Split Range #region Grid Add and Remove Row / Column private int GetRowInsertPosition(Boolean before) { int rtnrow; CellRange selcr = this.Selection; CellRange cr = selcr; int idx = this.MergedRanges.IndexOf(cr.r1, cr.c2); if (idx > -1) cr = this.MergedRanges[idx]; // we want first or last row in merge range rtnrow = (before) ? cr.r1 : cr.r2; // The following is an adjustment needed when we are copying an entire row that includes some merged cells if (selcr.c1 != selcr.c2) { while (!before && rtnrow > selcr.r2) rtnrow--; while (before && rtnrow < selcr.r2) rtnrow++; } return rtnrow; } private int GetColInsertPosition(Boolean before) { int rtncol; CellRange selcr = this.Selection; CellRange cr = selcr; int idx = this.MergedRanges.IndexOf(cr.r1, cr.c2); if (idx > -1) cr = this.MergedRanges[idx]; // we want the first of last col in merge range rtncol = (before) ? cr.c1 : cr.c2; // The following is an adjustment needed when we are copying an entire column that includes some merged cells if (selcr.r1 != selcr.r2) { while (!before && rtncol > selcr.c2) rtncol--; while (before && rtncol < selcr.c2) rtncol++; } return rtncol; } public void InsertColumnBefore() { int newcol = this.GetColInsertPosition(true); this.Cols.Insert(newcol); // set new column width to same width as column from where it was inserted this.Cols[newcol].Width = this.Cols[newcol + 1].Width; MyBorders.InsertColumn(newcol); MyShading.InsertColumn(newcol); // C2021-004 table cell shading this.AdjustMergedColumns(newcol, true, false); this.AdjustGridControlSize(); } public void InsertColumnAfter() { int colidx = this.GetColInsertPosition(false); if (colidx == this.Cols.Count - 1) // last column this.Cols.Add(1); else this.Cols.Insert(colidx + 1); MyBorders.InsertColumn(colidx); MyShading.InsertColumn(colidx); // C2021-004 table cell shading // set new column width to same width as column from where it was inserted this.Cols[colidx + 1].Width = this.Cols[colidx].Width; this.AdjustMergedColumns(colidx + 1, false, false); this.AdjustGridControlSize(); } public void InsertRowBefore() { int newrow = this.GetRowInsertPosition(true); this.Rows.Insert(newrow); // set new row Height to same heidht as row from where it was inserted this.Rows[newrow].Height = (Rows[newrow + 1].Height == -1) ? Rows.DefaultSize : Rows[newrow + 1].Height; //this.Rows[newrow].Height = this.Rows[newrow + 1].Height; MyBorders.InsertRow(newrow); MyShading.InsertRow(newrow); // C2021-004 table cell shading this.AdjustMergedRows(newrow, true, false); this.AdjustGridControlSize(); } public void InsertRowAfter() { int rowidx = this.GetRowInsertPosition(false); if (rowidx == this.Rows.Count - 1) // last row this.Rows.Add(1); else this.Rows.Insert(rowidx + 1); // set new row Height to same heidht as row from where it was inserted this.Rows[rowidx + 1].Height = (Rows[rowidx].Height == -1) ? Rows.DefaultSize : Rows[rowidx].Height; //this.Rows[rowidx + 1].Height = this.Rows[rowidx].Height; MyBorders.InsertRow(rowidx + 1); MyShading.InsertRow(rowidx + 1); // C2021-004 table cell shading this.AdjustMergedRows(rowidx + 1, false, false); this.AdjustGridControlSize(); } public bool AllRowsSelected() { int maxrow = Selection.r2; foreach (CellRange cr in MySelection) maxrow = Math.Max(maxrow, cr.r2); return (Selection.r1 == 0 && maxrow == Rows.Count - 1); } public bool AllColumnsSelected() { int maxcol = Selection.c2; foreach (CellRange cr in MySelection) maxcol = Math.Max(maxcol, cr.c2); return (Selection.c1 == 0 && maxcol == Cols.Count - 1); } public void RemoveSelectedColumn() { string msg = ""; string title = ""; CellRange saveCR = Selection; this.SelectionMode = SelectionModeEnum.ColumnRange; //this.Select(this.Selection.r1, this.Selection.c1); this.Select(0, Selection.c1, Rows.Count - 1, Selection.c2); this.SelectionMode = SelectionModeEnum.Default; if (Selection.c1 != Selection.c2) { msg = "Remove selected columns?"; title = "Delete Columns"; } else { msg = "Remove this column?"; title = "Delete Column"; } DialogResult dr = FlexibleMessageBox.Show(msg, title, MessageBoxButtons.YesNo); if (dr == DialogResult.Yes) RemoveColumns(this.Selection.r1, this.Selection.c1, 1+this.Selection.c2-this.Selection.c1); else Select(saveCR); } public void RemoveSelectedRow() { string msg = ""; string title = ""; CellRange saveCR = Selection; this.SelectionMode = SelectionModeEnum.RowRange; this.Select(Selection.r1, 0, Selection.r2, Cols.Count - 1); this.SelectionMode = SelectionModeEnum.Default; if (Selection.r1 != Selection.r2) { msg = "Remove selected rows?"; title = "Delete Rows"; } else { msg = "Remove this row?"; title = "Delete Row"; } DialogResult dr = FlexibleMessageBox.Show(msg, title, MessageBoxButtons.YesNo); if (dr == DialogResult.Yes) this.RemoveRows(this.Selection.r1, this.Selection.c1, 1 + this.Selection.r2 - this.Selection.r1); else Select(saveCR); } private void RemoveRows(int strow, int stcol, int cnt) { bool mergedRow = false; for (int i = 0; i < cnt; i++) { for (int cl = 0; cl < this.Cols.Count && !mergedRow; cl++) { int idx = this.MergedRanges.IndexOf(strow, cl); if (idx > -1) { CellRange cr = this.MergedRanges[idx]; if (cr.r1 < cr.r2) mergedRow = true; } cl++; } this.Rows.Remove(strow); this.AdjustMergedRows(strow, false, true); mergedRow = false; } MyBorders.DeleteRows(strow, cnt); MyShading.DeleteRows(strow, cnt); // C2021-004 table cell shading this.AdjustGridControlSize(); } private void RemoveColumns(int strow, int stcol, int cnt) { bool mergedCol = false; for (int i = 0; i < cnt; i++) { for (int rw = 0; rw < this.Rows.Count && !mergedCol; rw++) { int idx = this.MergedRanges.IndexOf(rw, stcol); if (idx > -1) { CellRange cr = this.MergedRanges[idx]; if (cr.c1 < cr.c2) mergedCol = true; } } this.Cols.Remove(stcol); this.AdjustMergedColumns(stcol, false, true); mergedCol = false; } MyBorders.DeleteColumns(stcol, cnt); MyShading.DeleteColumns(stcol, cnt); // C2021-004 table cell shading this.AdjustGridControlSize(); } #endregion //Grid Add and Remove Row / Column #region Copy/Paste public void CopyRow() { _tableCellEditor.Hide(); // B2017-200 force save of changes from active edit session DialogResult dr = DialogResult.Yes; SelectRow(); if (Selection.r1 != Selection.r2) { //dr = MessageBox.Show("You selected a row that includes merged cells.\n\nThese additional rows must be included.\n\nCopy these rows?", "Copy Rows", MessageBoxButtons.YesNo); dr = FlexibleMessageBox.Show("Your selection was expanded due to merged cell regions.\n\nContinue with the copy?", "Copy Rows", MessageBoxButtons.YesNo); } if (dr == DialogResult.Yes) CopyToCopiedFlexGrid(GridCopyOption.Row); //TestSetBackgroundColor(); } //public void TestSetBackgroundColor() //{ // for (int r = Selection.r1; r <= Selection.r2; r++) // for (int c = Selection.c1; c <= Selection.c2; c++) // { // CellRange cr = GetMergedRange(r, c); // if (cr.Style == null) cr.Style = this.Styles.Add("Shading"); // if (cr.Style != null && cr.Style.BackColor != Color.DarkGreen && cr.Style.Name != "Fixed") // { // { // cr.Style.BackColor = Color.DarkGreen; // } // } // } //} public void CopyColumn() { _tableCellEditor.Hide(); // B2017-200 force save of changes from active edit session SelectCol(); DialogResult dr = DialogResult.Yes; if (Selection.c1 != Selection.c2) { //dr = MessageBox.Show("You selected a column that includes merged cells.\n\nThese additional columns must be included.\n\nCopy these columns?", "Copy Columns", MessageBoxButtons.YesNo); dr = FlexibleMessageBox.Show("Your selection was expanded due to merged cell regions.\n\nContinue with the copy?", "Copy Columns", MessageBoxButtons.YesNo); } if (dr == DialogResult.Yes) CopyToCopiedFlexGrid(GridCopyOption.Column); } public void CopyCellSelection() { _tableCellEditor.Hide(); // B2017-200 force save of changes from active edit session DialogResult dr = DialogResult.Yes; CellRange cr = Selection; MakeSelectionEven(); if (!cr.Equals(Selection)) { dr = FlexibleMessageBox.Show("Your selection was expanded due to merged cell regions.\n\nContinue with the copy?", "Copy Selection", MessageBoxButtons.YesNo); } if (dr == DialogResult.Yes) CopyToCopiedFlexGrid(GridCopyOption.Selection); } public enum enmPastePos : int { Before = 1, Replace = 0, After = -1 } public void PasteRows(enmPastePos pp) { if (MyCopyInfo.MyCopiedFlexGrid == null || MyCopyInfo.MyCopyOption != GridCopyOption.Row) return; int rowsToAdd = MyCopyInfo.MyCopiedCellRange.r2 - MyCopyInfo.MyCopiedCellRange.r1 + 1; int colsToAdd = Math.Max((MyCopyInfo.MyCopiedCellRange.c2 - MyCopyInfo.MyCopiedCellRange.c1 + 1) - Cols.Count, 0); int selR1 = Selection.r1; int selR2 = Selection.r2; int rowOffset = selR1 + (pp == enmPastePos.After ?(selR2-selR1)+1 : 0) - MyCopyInfo.MyCopiedCellRange.r1; // If the rows we are copying has more columns than the current table, then append then needed columns to the grid if (colsToAdd > 0) { Cols.Add(colsToAdd); AdjustMergedColumns(Cols.Count - 1, colsToAdd, false, false); MyBorders.InsertColumns(Cols.Count - colsToAdd - 1, colsToAdd); MyShading.InsertColumns(Cols.Count - colsToAdd - 1, colsToAdd); // C2021-004 table cell shading } switch (pp) { case enmPastePos.Before: this.Rows.InsertRange(selR1, rowsToAdd); AdjustMergedRows(selR1, rowsToAdd, true, false); MyBorders.InsertRows(Rows.Count - rowsToAdd - 1, rowsToAdd); MyShading.InsertRows(Rows.Count - rowsToAdd - 1, rowsToAdd); // C2021-004 table cell shading break; case enmPastePos.After: if (selR2+1 < Rows.Count - 1) { this.Rows.InsertRange(selR2 + 1, rowsToAdd); AdjustMergedRows(selR1+1, rowsToAdd, false, false); } else this.Rows.Add(rowsToAdd); MyBorders.InsertRows(Rows.Count - rowsToAdd - 1, rowsToAdd); MyShading.InsertRows(Rows.Count - rowsToAdd - 1, rowsToAdd); // C2021-004 table cell shading break; case enmPastePos.Replace: if (rowsToAdd > Rows.Count - Selection.r1) { int numToAdd = rowsToAdd - (Rows.Count = selR1); this.Rows.Add(numToAdd); AdjustMergedRows(selR1, numToAdd, false, false); } break; } RemoveMergedRanges(MyCopyInfo.MyCopiedCellRange.r1 + rowOffset, MyCopyInfo.MyCopiedCellRange.c1, MyCopyInfo.MyCopiedCellRange.r2 + rowOffset, MyCopyInfo.MyCopiedCellRange.c2); for (int r = MyCopyInfo.MyCopiedCellRange.r1; r <= MyCopyInfo.MyCopiedCellRange.r2; r++) { Rows[r + rowOffset].Height = MyCopyInfo.MyCopiedFlexGrid.Rows[r].Height; for (int c = MyCopyInfo.MyCopiedCellRange.c1; c <= Math.Min(MyCopyInfo.MyCopiedCellRange.c2 + colsToAdd, Cols.Count - 1); c++) { CellRange crm = MyCopyInfo.MyCopiedFlexGrid.GetMergedRange(r, c); if (r == crm.r1 && c == crm.c1) { Cols[c].Width = Math.Max(Cols[c].Width, MyCopyInfo.MyCopiedFlexGrid.Cols[c].Width); CellRange cr = GetCellRange(crm.r1 + rowOffset, crm.c1, crm.r2 + rowOffset, crm.c2); // if the paste is above - copy merge range for the destination // if the paste is below - put back the range for the source location if ((crm.r2 > crm.r1) || (crm.c2 > crm.c1)) MergedRanges.Add(cr); // B2022-046 if the cell contains an RO or Transition then replace the usage id with to force a new usage id in the link if (MyCopyInfo.MyCopiedFlexGrid[r, c] != null) this[r + rowOffset, c] = ItemInfo.ReplaceLinkWithNewID(MyCopyInfo.MyCopiedFlexGrid[r, c].ToString().Replace("\r\n", "")); else this[r + rowOffset, c] = MyCopyInfo.MyCopiedFlexGrid[r, c]; MatchStyle(crm, cr); PasteBorders(r + rowOffset, c, r, c); PasteShading(r + rowOffset, c, r, c); // C2021-004 paste the shading information // if the paste is above - put back the range for the source location // if the paste is below - copy merge range for the destination int r1 = crm.r1 + rowsToAdd - rowOffset; int r2 = crm.r2 + rowsToAdd - rowOffset; CellRange ncr = GetCellRange(r1, crm.c1, r2, crm.c2); if ((crm.r2 > crm.r1) || (crm.c2 > crm.c1)) MergedRanges.Add(ncr); } } } this.AdjustGridControlSize(); CopyToCopiedFlexGrid(MyCopyInfo.MyCopyOption); } private void MatchStyle(CellRange crm, CellRange cr) { if (crm.Style != null) { ChangeCellAlign(cr, crm.Style.TextAlign); ChangeCellBorder(cr, crm.Style.Border.Style); } //else //{ // cr.Style = null; // - didn't like the null //} } private void RemoveMergedRanges(int r1, int c1, int r2, int c2) { for (int r = r1; r <= r2; r++) for (int c = c1; c <= c2; c++) { CellRange cr = GetMergedRange(r, c); if (cr.r1 < cr.r2 || cr.c1 < cr.c2) MergedRanges.Remove(cr); } } public void PasteColumns(enmPastePos pp) { if (MyCopyInfo.MyCopiedFlexGrid == null || MyCopyInfo.MyCopyOption != GridCopyOption.Column) return; int colsToAdd = MyCopyInfo.MyCopiedCellRange.c2 - MyCopyInfo.MyCopiedCellRange.c1 + 1; int rowsToAdd = Math.Max((MyCopyInfo.MyCopiedCellRange.r2 - MyCopyInfo.MyCopiedCellRange.r1 + 1) - Rows.Count, 0); int selC1 = Selection.c1; int selC2 = Selection.c2; int colOffset = selC1 + (pp == enmPastePos.After ? (selC2-selC1)+1 : 0) - MyCopyInfo.MyCopiedCellRange.c1; // If the columns we are copying has more rows than the current table, then append the needed rows to the grid if (rowsToAdd > 0) { Rows.Add(rowsToAdd); AdjustMergedRows(Rows.Count, false, false); MyBorders.InsertRows(Rows.Count - rowsToAdd - 1,rowsToAdd); MyShading.InsertRows(Rows.Count - rowsToAdd - 1, rowsToAdd); // C2021-004 table cell shading } switch (pp) { case enmPastePos.Before: this.Cols.InsertRange(selC1, colsToAdd); AdjustMergedColumns(selC1, colsToAdd, true, false); MyBorders.InsertColumns(Cols.Count - colsToAdd - 1, colsToAdd); MyShading.InsertColumns(Cols.Count - colsToAdd - 1, colsToAdd); // C2021-004 table cell shading break; case enmPastePos.After: if (selC2+1 < Cols.Count - 1) { this.Cols.InsertRange(selC2+1, colsToAdd); AdjustMergedColumns(selC1+1, colsToAdd, false, false); } else this.Cols.Add(colsToAdd); MyBorders.InsertColumns(Cols.Count - colsToAdd - 1, colsToAdd); MyShading.InsertColumns(Cols.Count - colsToAdd - 1, colsToAdd); // C2021-004 table cell shading break; case enmPastePos.Replace: if (colsToAdd > Cols.Count - selC1) { int numToAdd = colsToAdd - (Cols.Count - selC1); this.Cols.Add(numToAdd); AdjustMergedColumns(selC1, numToAdd, true, false); } break; } RemoveMergedRanges(MyCopyInfo.MyCopiedCellRange.r1, MyCopyInfo.MyCopiedCellRange.c1 + colOffset, MyCopyInfo.MyCopiedCellRange.r2, MyCopyInfo.MyCopiedCellRange.c2 + colOffset); // Fix the merge ranges for (int c = MyCopyInfo.MyCopiedCellRange.c1; c <= MyCopyInfo.MyCopiedCellRange.c2; c++) { Cols[c + colOffset].Width = MyCopyInfo.MyCopiedFlexGrid.Cols[c].Width; for (int r = MyCopyInfo.MyCopiedCellRange.r1; r <= Math.Min(MyCopyInfo.MyCopiedCellRange.r2 + rowsToAdd, Rows.Count - 1); r++) { CellRange crm = MyCopyInfo.MyCopiedFlexGrid.GetMergedRange(r, c); if (r == crm.r1 && c == crm.c1) { Rows[r].Height = Math.Max(Rows[r].Height, MyCopyInfo.MyCopiedFlexGrid.Rows[r].Height); CellRange cr = GetCellRange(crm.r1, crm.c1 + colOffset, crm.r2, crm.c2 + colOffset); // if the paste is to the left - copy merge range for the destination // if the paste is to the right - put back the range for the source location if ((crm.r2 > crm.r1) || (crm.c2 > crm.c1)) MergedRanges.Add(cr); // copy cell text to the destination, copy the style, copy the cell borders // B2022-046 if the cell contains an RO or Transition then replace the usage id with to force a new usage id in the link if (MyCopyInfo.MyCopiedFlexGrid[r, c] != null) this[r, c + colOffset] = ItemInfo.ReplaceLinkWithNewID(MyCopyInfo.MyCopiedFlexGrid[r, c].ToString().Replace("\r\n", "")); else this[r, c + colOffset] = MyCopyInfo.MyCopiedFlexGrid[r, c]; MatchStyle(crm, cr); PasteBorders(r, c + colOffset, r, c); PasteShading(r, c + colOffset, r, c); // C2021-004 paste the shading information // if the paste is to the left - put back the range for the source location // if the paste is to the right - copy merge range for the destination int c1 = crm.c1 + colsToAdd - colOffset; int c2 = crm.c2 + colsToAdd - colOffset; CellRange ncr = GetCellRange(crm.r1, c1, crm.r2, c2); if ((crm.r2 > crm.r1) || (crm.c2 > crm.c1)) MergedRanges.Add(ncr); } } } this.AdjustGridControlSize(); CopyToCopiedFlexGrid(MyCopyInfo.MyCopyOption); } public void PasteCopiedCells() { // Warn the user that this type of paste will replace the currently selected (highlighted) table cells and give the option to abort. DialogResult dr = FlexibleMessageBox.Show("This will replace the cells that are currently selected (highlighted). \n\nContinue with the paste?", "Paste Table Cells", MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (dr == DialogResult.No) return; int nSelRows = Selection.r2 - Selection.r1 + 1; int nSelCols = Selection.c2 - Selection.c1 + 1; int nCpyRows = MyCopyInfo.MyCopiedCellRange.r2 - MyCopyInfo.MyCopiedCellRange.r1 + 1; int nCpyCols = MyCopyInfo.MyCopiedCellRange.c2 - MyCopyInfo.MyCopiedCellRange.c1 + 1; int colsToAdd = Math.Max(nCpyCols - nSelCols, 0); int rowsToAdd = Math.Max(nCpyRows - nSelRows, 0); int rowOffset = Selection.r1 - MyCopyInfo.MyCopiedCellRange.r1; int colOffset = Selection.c1 - MyCopyInfo.MyCopiedCellRange.c1; int selR2 = Selection.r2; int selC2 = Selection.c2; // If there are more cells to copy than what is seleceted in the target table // Add extra rows and columns as needed if (rowsToAdd > 0) { if (selR2 < Rows.Count - 1) { this.Rows.InsertRange(selR2 + 1, rowsToAdd); AdjustMergedRows(selR2 + 1, false, false); } else this.Rows.Add(rowsToAdd); MyBorders.InsertRows(selR2,rowsToAdd); MyShading.InsertRows(selR2, rowsToAdd); // C2021-004 table cell shading } if (colsToAdd > 0) { if (selC2 < Cols.Count - 1) { this.Cols.InsertRange(selC2 + 1, colsToAdd); AdjustMergedColumns(selC2 + 1, false, false); } else this.Cols.Add(colsToAdd); MyBorders.InsertColumns(selC2,colsToAdd); MyShading.InsertColumns(selC2, colsToAdd); // C2021-004 table cell shading } RemoveMergedRanges(MyCopyInfo.MyCopiedCellRange.r1 + rowOffset, MyCopyInfo.MyCopiedCellRange.c1 + colOffset, MyCopyInfo.MyCopiedCellRange.r2 + rowOffset, MyCopyInfo.MyCopiedCellRange.c2 + colOffset); for (int c = MyCopyInfo.MyCopiedCellRange.c1; c <= Math.Min(MyCopyInfo.MyCopiedCellRange.c2, Cols.Count - 1 - colOffset); c++) Cols[c + colOffset].Width = Math.Max(MyCopyInfo.MyCopiedFlexGrid.Cols[c].Width, Cols[c + colOffset].Width); for (int r = MyCopyInfo.MyCopiedCellRange.r1; r <= Math.Min(MyCopyInfo.MyCopiedCellRange.r2, Rows.Count - 1 - rowOffset); r++) { Rows[r + rowOffset].Height = Math.Max(MyCopyInfo.MyCopiedFlexGrid.Rows[r].Height, Rows[r + rowOffset].Height); for (int c = MyCopyInfo.MyCopiedCellRange.c1; c <= Math.Min(MyCopyInfo.MyCopiedCellRange.c2, Cols.Count - 1 - colOffset); c++) { CellRange crm = MyCopyInfo.MyCopiedFlexGrid.GetMergedRange(r, c); if (r == crm.r1 && c == crm.c1) { CellRange cr = GetCellRange(crm.r1 + rowOffset, crm.c1 + colOffset, crm.r2 + rowOffset, crm.c2 + colOffset); if ((crm.r2 > crm.r1) || (crm.c2 > crm.c1)) MergedRanges.Add(cr); // B2022-046 if the cell contains an RO or Transition then replace the usage id with to force a new usage id in the link if (MyCopyInfo.MyCopiedFlexGrid[r, c] != null) this[r + rowOffset, c + colOffset] = ItemInfo.ReplaceLinkWithNewID(MyCopyInfo.MyCopiedFlexGrid[r, c].ToString().Replace("\r\n", "")); else this[r + rowOffset, c + colOffset] = MyCopyInfo.MyCopiedFlexGrid[r, c]; MatchStyle(crm, cr); PasteBorders(r + rowOffset, c + colOffset, r, c); PasteShading(r + rowOffset, c + colOffset, r, c); // C2021-004 paste the shading information } } } this.AdjustGridControlSize(); CopyToCopiedFlexGrid(MyCopyInfo.MyCopyOption); } #endregion // Copy/Paste #region Selection public bool SelectNextCell() { int r = this.Row; int c = this.Col; CellRange cr = GetMergedRange(r, c); do { c = cr.c2 + 1; if (c >= this.Cols.Count) { r = r + 1; c = 0; if (r >= this.Rows.Count) return false; } cr = GetMergedRange(r, c); } while (r != cr.r1 || c != cr.c1); Select(r, c); return true; } public bool SelectPrevCell() { int r = this.Row; int c = this.Col; CellRange cr = GetMergedRange(r, c); do { c = cr.c1 - 1; if (c < 0) { r = r - 1; c = this.Cols.Count-1; if (r < 0) return false; } cr = GetMergedRange(r, c); c = cr.c1; } while (r != cr.r1); Select(r, c); return true; } #endregion #region SearchableText public string GetSearchableText() { StringBuilder sb = new StringBuilder(); int r = 0; int c = 0; int w = Cols.Count; int h = Rows.Count; while (r < h) { CellRange cr = GetMergedRange(r, c); if (cr.r1 == r && cr.c1 == c) { if (this[r, c] != null) { string strp = DisplayText.StaticStripRtfCommands((string)this[r, c], true); // C2020-001: added 'true', in a table sb.Append(strp.Replace("\r\n", " ")); } sb.Append("\r\n"); } c = c + 1; if (c == w) { c = 0; r = r + 1; } } return sb.ToString(); } #endregion #region Import / Export Grid /// /// Prompts user with Save File dialog. /// Grid will be saved to an XML file. /// /// public void ExportToXML(string initDir) { SaveFileDialog sfd = new SaveFileDialog(); sfd.DefaultExt = ".xml"; sfd.Filter = "XML files (*.xml)|*.xml|All files (*.*)|*.* "; //sfd.InitialDirectory = @"C:\Development\SampleTableData"; sfd.InitialDirectory = initDir; sfd.Title = "Save XML File"; sfd.ShowDialog(); this.WriteXml(sfd.FileName); } public string GetXMLData() { string retstr = null; using (StringWriter sw = new StringWriter()) { this.WriteXml(sw); retstr = sw.GetStringBuilder().ToString(); sw.Close(); } return retstr; } /// /// Prompts user with Save File dialog. /// Grid will be saved to an Excel file. /// /// //public void ExportToExcel(string initDir) //{ // SaveFileDialog sfd = new SaveFileDialog(); // sfd.DefaultExt = ".xls"; // sfd.Filter = "Excel files (*.xls)|*.xls|All files (*.*)|*.* "; // //sfd.InitialDirectory = @"C:\Development\SampleTableData"; // sfd.InitialDirectory = initDir; // sfd.Title = "Save Excel File"; // sfd.ShowDialog(); // this.SaveExcel(sfd.FileName); //} /// /// Prompts user with Open File dialog. /// XML file will be imported to a table grid. /// /// /// public string ImportXML(string initDir) { string rtn = ""; OpenFileDialog ofd = new OpenFileDialog(); ofd.DefaultExt = ".xml"; ofd.Filter = "XML files (*.xml)|*.xml|All files (*.*)|*.* "; //ofd.InitialDirectory = @"C:\Development\SampleTableData"; ofd.InitialDirectory = initDir; ofd.Multiselect = false; ofd.Title = "Select XML File"; ofd.ShowDialog(); this.Clear(); this.MergedRanges.Clear(); this.ReadXml(ofd.FileName); this.BorderStyle = C1.Win.C1FlexGrid.Util.BaseControls.BorderStyleEnum.None; this.KeyActionTab = KeyActionEnum.MoveAcross; this.AdjustGridControlSize(); rtn = ofd.SafeFileName; return rtn; } /// /// Prompts user with Open File dialog. /// Excel file will be imported to a table grid. /// /// /// //public string ImportExcel(string initDir) //{ // string rtn = ""; // //VlnFlexGrid grd = rbtDefaultTable.Checked ? vlnFlexGrid2 : vlnFlexGrid3; //GetActiveGrid(); // OpenFileDialog ofd = new OpenFileDialog(); // ofd.DefaultExt = ".xls"; // ofd.Filter = "Excel files (*.xls)|*.xls|All files (*.*)|*.*"; // //ofd.InitialDirectory = @"C:\Development\SampleTableData"; // ofd.InitialDirectory = initDir; // ofd.Multiselect = false; // ofd.Title = "Select Excel File"; // ofd.ShowDialog(); // this.Clear(); // this.MergedRanges.Clear(); // this.LoadExcel(ofd.FileName); // this.AdjustGridControlSize(); // rtn = ofd.SafeFileName; // return rtn; //} public static List ROTableUpdate(object sender, ROFstInfoROTableUpdateEventArgs args) { string xml = null; string srchtxt = null; Content content = (Content)sender; bool isdirty = false; using (VlnFlexGrid myGrid = new VlnFlexGrid(content.ContentItems[0])) { using (StringReader sr = new StringReader(args.OldGridXml)) { myGrid.ReadXml(sr); sr.Close(); } string roid = content.ContentRoUsages[0].ROID; //myGrid.ROID; int rodbid = content.ContentRoUsages[0].RODbID; //myGrid.RODbId; myGrid.Visible = false; myGrid.ConvertTableROToGrid(args.ROText, rodbid, roid); myGrid.FixTableCellsHeightWidth(); myGrid.AdjustGridControlSize(); myGrid.Visible = true; using (StringWriter sw = new StringWriter()) { myGrid.WriteXml(sw); xml = sw.GetStringBuilder().ToString(); sw.Close(); } srchtxt = myGrid.GetSearchableText(); isdirty = myGrid.IsGridChanged(args.OldGridXml, xml, false); } List retlist = new List(); retlist.Add(srchtxt); if(isdirty) retlist.Add(xml); else retlist.Add(args.OldGridXml); return retlist; } public void ConvertTableROToGrid(string valtext, int rodbid, string roid) { VE_Font vefont = _MyItemInfo.GetItemFont(); this.Font = vefont.WindowsFont; this.MergedRanges.Clear(); this.Clear(); this.IsRoTable = true; this.ParseTableFromText(valtext, GridLinePattern.Single); this.AutoSizeCols(); this.AutoSizeRows(); this.MakeRTFcells(); this.RODbId = rodbid; this.ROID = roid; } private Regex _ReplaceSpaceNewLine = new Regex(@"(?<=\\[^' \\?\r\n\t]*) (?=\r\n)"); private Regex _ReplaceTokenSpaceToken = new Regex(@"(?<=\\[^' \\?\r\n\t]*) (?=\\)"); private Regex _RemoveComments = new Regex(@"\\v .*?\\v0( |$)"); private string PrepROTableText(string stepText) { // we need to convert some RTF command to DOS so that we can // figure out the table size stepText = stepText.Replace("\r", ""); stepText = stepText.Replace("\xF8", @"\'f8"); stepText = stepText.Replace(@"\par ", "\r\n"); stepText = _ReplaceTokenSpaceToken.Replace(stepText, ""); //Change Token Order to match RTB output stepText = stepText.Replace(@"\v0\b0", @"\b0\v0"); stepText = stepText.Replace(@"\b0\ulnone", @"\ulnone\b0"); stepText = _ReplaceSpaceNewLine.Replace(stepText, ""); // Now change the Unicode symbols to DOS symbols stepText = stepText.Replace(@"\u8209?", "-"); stepText = stepText.Replace(@"\u9586?", "\\"); stepText = stepText.Replace(@"\u9474?", "\xB3"); // Vert Line graphic character stepText = stepText.Replace(@"\'b0", "\xB0"); stepText = stepText.Replace(@"\up2 ", "\x9566"); stepText = stepText.Replace(@"\up0 ", "\x9567"); stepText = stepText.Replace(@"\ulnone", "\xBB"); stepText = stepText.Replace(@"\ul", "\xAB"); stepText = stepText.Replace(@"\{", "{"); stepText = stepText.Replace(@"\}", "}"); stepText = stepText.Replace(@"\b0", "\xD6"); stepText = stepText.Replace(@"\b", "\xD5"); stepText = stepText.Replace(@"\u160?", "\xA0"); //hard space stepText = stepText.Replace(@"\u916?", "\x7F"); // delta stepText = stepText.Replace(@"\u8805?", "\xF2"); //greater than or equal stepText = stepText.Replace(@"\u8804?", "\xF3"); // less than or equal stepText = stepText.Replace(@"\u931?", "\xE4"); // sigma stepText = stepText.Replace(@"\u947?", "\xE7"); // gamma stepText = stepText.Replace(@"\u9604?", "\xFE"); // accum 2584 stepText = stepText.Replace(@"\u9679?", "\x7"); // bullet 25CF stepText = stepText.Replace(@"\u8776?", "\xF7"); // approx eq stepText = stepText.Replace(@"\u8773?", "\xF0"); // similar eq 2245 stepText = stepText.Replace(@"\u8730?", "\xFB"); // square root stepText = stepText.Replace(@"\u961?", "\xE2"); // rho 3C1 stepText = stepText.Replace(@"\u960?", "\xE3"); // pi stepText = stepText.Replace(@"\u956?", "\xE6"); // micro stepText = stepText.Replace(@"\u948?", "\xEB"); // lower case delta stepText = stepText.Replace(@"\u963?", "\xE5"); // lower case sigma stepText = stepText.Replace(@"\u274?", "\x90"); // energy, 112 stepText = stepText.Replace(@"\u949?", "\xEE"); // epsilon stepText = stepText.Replace(@"\u952?", "\xE9"); // theta, 3B8 stepText = stepText.Replace(@"\u8857?", "\xEC"); // dot in oval, 2299 stepText = stepText.Replace(@"\u964?", "\xA8"); // tau, 3C4 stepText = stepText.Replace(@"\u9830?", "\xA9"); // diamond, 2666 stepText = stepText.Replace(@"\u8593?", "\x18"); // Up Arrow - changes to \xff stepText = stepText.Replace(@"\u8595?", "\x19"); // Down Arrow - changes to \xd6 // Fix "|" followed by a newline - this confuses the table converter stepText = stepText.Replace(@"|\r\n", @"| \r\n"); stepText = stepText.Replace(@"|\n\r", @"| \n\r"); stepText = stepText.Replace(@"|\n", @"| \n"); // if the entire row is underlined, then remove the underline and insert a row of dashes stepText = ConvertUnderlineToRow(stepText); return stepText; } private bool IsPrintableTableChar(char c) { string printablSymbols = "\xB3\xA0\x7F\xF2\xF3\xE4\xE7\xFE\x07\xF7\xF0\xFB\xE2\xE3\xE6\xEB\xE5\x90\xEE\xE9\xEC\xA8\xA9\x18\x19"; return (((c > '\x1F') && (c < '\x80')) || (printablSymbols.IndexOf(c) >= 0)); } private string ConvertUnderlineToRow(string stepText) { string rtnStr = ""; char[] sep = { '\n' }; string[] lines = stepText.Split(sep); foreach (string line in lines) { int idx = 0; int chrCnt = 0; int uOnPos = -1; int uOffPos = -1; bool ulineOn = false; //char curChar = line[idx]; string dashRow = ""; while (idx < line.Length && !IsPrintableTableChar(line[idx])) { if (line[idx] == '\xAB') //underline ON { ulineOn = true; uOnPos = idx; } idx++; } while (ulineOn && idx < line.Length) { if (IsPrintableTableChar(line[idx])) { if (line[idx] == '|' || line[idx] == '\xB3') { dashRow += new string('-', chrCnt); dashRow += "|"; chrCnt = 0; } else chrCnt++; idx++; } else { if (line[idx] == '\xBB') //underline OFF { uOffPos = idx; ulineOn = false; while ((idx < line.Length) && !IsPrintableTableChar(line[idx])) { if (line[idx] == '\xAB') ulineOn = true; idx++; } if (idx == line.Length) ulineOn = true; if (!ulineOn) dashRow = ""; } else idx++; } } string curLine = line; curLine = curLine.Replace('\xB3', '|'); // replace graphic vert bar with DOS vert bar if (ulineOn && idx == line.Length) // entire line is underlined, remove underline, insert row of dashes { curLine = curLine.Replace("\xAB", ""); // remove Underline ON curLine = curLine.Replace("\xBB", ""); // remove Underline OFF dashRow += new string('-', chrCnt); dashRow = "\n" + dashRow; } if (rtnStr.Length > 0) rtnStr += "\n"; rtnStr += curLine; rtnStr += dashRow; } return rtnStr; } /// /// This will parse a string containing the ascii text of the old style VE-PROMS (16-bit) tables. /// It will find the number of rows and columns base on newlines, vertical bars, and dashes. /// Then it will parse the the text, place them in cells, and attempt to merge cells were needed. /// /// public void ParseTableFromText(string buff,GridLinePattern border) { string txtbuff = PrepROTableText(buff); if (IsRoTable) txtbuff = _RemoveComments.Replace(txtbuff, ""); int curRow = 0; int curCol = 0; int maxRow = 0; int maxCol = 0; // Get Max Rows and Max Cols char[] test = "|\n\x02".ToCharArray(); int idx = 0; int idxst = 0; int colPos = 0; int strow = 0; Dictionary dicCols = new Dictionary(); do { idx = txtbuff.IndexOfAny(test, idxst); if (idx > -1) { switch (txtbuff[idx]) { case '|': // end of a column colPos = idxst - strow; if (!dicCols.ContainsKey(colPos)) dicCols.Add(colPos, curCol); else if (curCol > dicCols[colPos]) { dicCols.Remove(colPos); dicCols.Add(colPos, curCol); } curCol++; break; case '\x02': case '\n': // end of a row colPos = idxst - strow; if (!dicCols.ContainsKey(colPos)) dicCols.Add(colPos, curCol); else if (curCol > dicCols[colPos]) { dicCols.Remove(colPos); dicCols.Add(colPos, curCol); } curRow++; strow = idx + 1; if (curCol > maxCol) maxCol = curCol; curCol = 0; break; } idxst = idx + 1; if (idxst >= txtbuff.Length) idx = -1; } } while (idx != -1); if (idxst < txtbuff.Length) { colPos = idxst - strow; if (!dicCols.ContainsKey(colPos)) dicCols.Add(colPos, curCol); else if (curCol > dicCols[colPos]) { dicCols.Remove(colPos); dicCols.Add(colPos, curCol); } } maxRow = curRow; // +1; curRow = 0; curCol = 0; if (maxCol == 0) maxCol = dicCols.Count; // The resulting Table Grid size in rows and columns this.Cols.Count = maxCol + 1; this.Rows.Count = maxRow + 1; // make all rows and columns editable this.Rows.Fixed = 0; this.Cols.Fixed = 0; // TableCellInfo is used to assign merge ranges // Make a two dimensional array of TableCellinfo the same size as the table grid TableCellInfo[,] tci = new TableCellInfo[maxRow + 1, maxCol + 1]; for (int r = 0; r <= maxRow; r++) for (int c = 0; c <= maxCol; c++) tci[r, c] = new TableCellInfo(); // Read in each cell of the grid idx = 0; idxst = 0; colPos = 0; strow = 0; int prevCol = 0; int tstidx = 0; string tstr = ""; bool incRow = false; do { idx = txtbuff.IndexOfAny(test, idxst); if (idx > -1) { switch (txtbuff[idx]) { case '|': // end of column colPos = idxst - strow; // based on the position of the | char, find what column we are in. // note that this will tell us if any columns to the left were merged // the while loop will flag cell that need to be merged curCol = dicCols[colPos]; while (curCol > prevCol + 1) { tci[curRow, prevCol].MergeColRight = true; prevCol++; } prevCol = curCol; // parse out the text to be placed in the table cell tstr = txtbuff.Substring(idxst, idx - idxst); if (tstr.Length == 0) tstr += " "; // test for a string of '-' characters for (tstidx = 0; (tstidx < tstr.Length) && (tstr[tstidx] == '-'); tstidx++) ; if (tstidx < tstr.Length) // not a full line (row) of '-' chars { // take a peek at the start of the next piece of table text to parse // if it starts with a '-' char, then flag to merge the columns up to // this point with the same columns in the next row if (idx < txtbuff.Length - 1 && txtbuff[idx + 1] == '-') { for (int c = curCol; c >= 0; c--) if (!tci[curRow, c].ColEnd) tci[curRow, c].MergeRowBellow = true; } // if this column is in a merged grouping of rows, // get the cell text in the first cell of the merged grouping of cells // we will append the newly parsed text to this cell's text. int rw = curRow; while (rw - 1 >= 0 && tci[rw - 1, curCol].MergeRowBellow) rw--; int cl = curCol; while (cl - 1 >= 0 && tci[rw, cl-1].MergeColRight) cl--; //string jstr = (string)this[rw, curCol]; string jstr = (string)this[rw, cl]; if (jstr == null) jstr = tstr; else jstr += ((cl==curCol)? "\n" : "") + tstr; // multi line cell //jstr += "\n" + tstr; // multi line cell //this[rw, curCol] = jstr; this[rw, cl] = jstr; //// take a peek at the start of the next piece of table text to parse //// if it starts with a '-' char, then flag to merge the columns up to //// this point with the same columns in the next row //if (idx < txtbuff.Length - 1 && txtbuff[idx + 1] == '-') //{ // for (int c = curCol; c >= 0; c--) // if (!tci[curRow, c].ColEnd) // tci[curRow, c].MergeRowBellow = true; //} //int tcol = dicCols[idx]; //// if were are that the end of the 16-bit text line, but not in the last column, //// merge the remaining columns to the right //if (curCol < tcol) //{ // for (int i = curCol; i <= tcol; i++) // tci[curRow, i].MergeColRight = true; //} } else // parsed text contains all dashes { // take a peek at the start of the next piece of table text to parse // if it starts with a space, return, newline, or EndOfFile char, // then flag to merge the columns up to // this point with the same columns in the next row if (idx < txtbuff.Length - 1 && " \r\n\x02".IndexOf(txtbuff[idx + 1]) > 0) { int nextCol = (curCol + 1 > this.Cols.Count) ? curCol : curCol + 1; if (!tci[curRow, nextCol].ColEnd) tci[curRow, nextCol].MergeRowBellow = true; //for (int c = nextCol; c >= 0; c--) // if (!tci[curRow, c].ColEnd) // tci[curRow, c].MergeRowBellow = true; } tci[curRow, curCol].ColEnd = true; incRow = true; } break; case '\x02': // end of file case '\n': // new line of 16-bit table text colPos = idxst - strow; curCol = dicCols[colPos]; // see what column we are in - new line might occure before last grid column strow = idx + 1; // parse out the cell text tstr = txtbuff.Substring(idxst, idx - idxst); if (tstr.EndsWith("\r")) // strip off carrage return tstr = tstr.Substring(0, tstr.Length - 1); //tstr = tstr.TrimEnd(" ".ToCharArray()); if (tstr.Length == 0) tstr += " "; // test for a string of '-' characters for (tstidx = 0; (tstidx < tstr.Length) && (tstr[tstidx] == '-'); tstidx++) ; if (tstidx < tstr.Length) // not a full line (row) of '-' chars { //curCol = dicCols[colPos]; while (curCol > prevCol + 1) { tci[curRow, prevCol].MergeColRight = true; prevCol++; } // if this column is in a merged grouping of rows, // get the cell text in the first cell of the merged grouping of cells // we will append the newly parsed text to this cell's text. int rw = curRow; while (rw - 1 >= 0 && tci[rw - 1, curCol].MergeRowBellow) rw--; int cl = curCol; while (cl - 1 >= 0 && tci[rw, cl-1].MergeColRight) cl--; //string jstr = (string)this[rw, curCol]; string jstr = (string)this[rw, cl]; if (jstr == null) jstr = tstr; else jstr += ((cl == curCol) ? "\n" : "") + tstr; // multi line cell //jstr += "\n" + tstr; // multi line cell //this[rw, curCol] = jstr; this[rw, cl] = jstr; } else if (tstr.Length > 0) // parsed text is all dash characters { incRow = true; if (curRow > 0 && curCol > 0) // merge the column in the previous row with this one tci[curRow - 1, curCol].MergeRowBellow = false; } // if were are that the end of the 16-bit text line, but not in the last column, // merge the remaining columns to the right if ((curCol < maxCol) && (tstidx < tstr.Length)) { for (int i = curCol; i < maxCol; i++) tci[curRow, i].MergeColRight = true; } if (incRow) curRow++; curCol = 0; incRow = false; break; } idxst = idx + 1; if (idxst >= txtbuff.Length) idx = -1; } else if (idxst < txtbuff.Length - 1) // handle any remaining text not yet parsed { // find the curent column and merge remaining columns to the right colPos = idxst - strow; curCol = dicCols.Count==0?0:dicCols[colPos]; while (curCol > prevCol + 1) { tci[curRow, prevCol].MergeColRight = true; prevCol++; } // parse out the remaining text tstr = txtbuff.Substring(idxst); //tstr = tstr.TrimEnd(" ".ToCharArray()); if (tstr.Length == 0) tstr += " "; // test for a string of '-' characters for (tstidx = 0; (tstidx < tstr.Length) && (tstr[tstidx] == '-'); tstidx++) ; if (tstidx < tstr.Length) { // if this column is in a merged grouping of rows, // get the cell text in the first cell of the merged grouping of cells // we will append the newly parsed text to this cell's text. int rw = curRow; while (rw - 1 >= 0 && tci[rw - 1, curCol].MergeRowBellow) rw--; int cl = curCol; while (cl - 1 >= 0 && tci[rw, cl-1].MergeColRight) cl--; //string jstr = (string)this[rw, curCol]; string jstr = (string)this[rw, cl]; if (jstr == null) jstr = tstr; else jstr += ((cl == curCol) ? "\n" : "") + tstr; // multi line cell //jstr += "\n" + tstr; // multi line cell //this[rw, curCol] = jstr; this[rw, cl] = jstr; } } } while (idx != -1); // we are done parsing the 16-bit text. // now set the merge ranges in the table grid, based on the // information saved in that two dimensional array of TableCellinfo this.Rows.Count = curRow + 1; this.AllowMerging = C1.Win.C1FlexGrid.AllowMergingEnum.Custom; maxRow = curRow; int rR = 0; int rC = 0; for (int r = 0; r <= maxRow; r++) for (int c = 0; c <= maxCol; c++) { if (tci[r, c].MergeColRight) { rC = c; while ((rC < maxCol) && (tci[r, rC].MergeColRight)) rC++; if (rC > c) { this.MergedRanges.Add(this.GetCellRange(r, c, r, rC)); string cellstr = (this[r,c]==null)? " ": this[r, c].ToString(); for (int x = c + 1; x <= rC; x++) this[r, x] = cellstr; c = rC; } } } for (int c = 0; c <= maxCol; c++) for (int r = 0; r <= maxRow; r++) { if (tci[r, c].MergeRowBellow) { rR = r; while ((rR < maxRow) && (tci[rR, c].MergeRowBellow)) rR++; if (rR > r) { this.MergedRanges.Add(this.GetCellRange(r, c, rR, c)); string cellstr = this[r, c].ToString(); for (int x = r + 1; x <= rR; x++) this[x, c] = cellstr; r = rR; } } } for (int c = 0; c <= maxCol; c++) for (int r = 0; r <= maxRow; r++) { if (this[r, c] != null) { string cellstr = this[r, c].ToString(); this[r, c] = cellstr.TrimEnd("\r\n\t".ToCharArray()); //this[r, c] = cellstr.TrimEnd(" \r\n\t".ToCharArray()); CellRange cr = this.GetMergedRange(r, c); if (cr.r1 != cr.r2) TrimMergedRangeCellText(cr); } } MyBorders = new VlnBorders(border, Rows.Count, Cols.Count); MyShading = new VlnGridCellShading(Color.White, Rows.Count, Cols.Count); // C2021-004 setup shading information } private void TrimMergedRangeCellText(CellRange cr) { // count number of newlines string cellstr = this[cr.r1, cr.c1].ToString(); string[] strary = cellstr.Split("\n".ToCharArray()); int nlines = strary.Length; // count number of rows in merge range int nrows = (cr.r2 - cr.r1) + 1; int neededLines = (nlines - (nrows - 1)); bool bNeedToTrim = (nlines > neededLines); string jstr = ""; int LinesToGo = neededLines; if (bNeedToTrim) { int numBlanksEnd = 0; // find the number of blank lines at the end of this table cell for (int i = nlines-1; i >= 0; i--) { if (strary[i].Trim().Length == 0) numBlanksEnd++; else break; } int preBlanksLines = 0; //foreach (string tmpstr in strary) // we ignore the ending blank lines // this allows us to include any blank lines that are between text lines for (int i = 0; i < nlines - numBlanksEnd; i++) { string tmpstr = strary[i]; int tlen = tmpstr.Trim().Length; if (tlen > 0 || (LinesToGo < neededLines)) { if (jstr.Length > 0) jstr += "\n"; jstr += tmpstr; LinesToGo--; } else if (LinesToGo == (nlines - (nrows - 1))) preBlanksLines++; } while (LinesToGo > 0) { // need to put this type of hard space (not \xA0) to hold the newline position if (preBlanksLines > 0) { jstr = "\\~\n" + jstr; LinesToGo--; } if (numBlanksEnd > 0) { jstr += "\n\\~"; LinesToGo--; } } this[cr.r1, cr.c1] = jstr; } } #endregion //Import / Export Grid #region Bug Work Around protected override void OnMouseDown(System.Windows.Forms.MouseEventArgs e) { // Note: this fixes a bug that happens when the grid has more rows than columns // notified ComponentOne of the problem 6/25/09 via Email try { base.OnMouseDown(e); } catch (Exception ex) { while (ex != null) { Console.WriteLine("{0} {1} {2}", ex.GetType().Name, ex.Message, ex.StackTrace); ex = ex.InnerException; } } } #endregion //Bug Work Around //public void CenterTheCellText() //{ // // Cannot use this type of text allignment with RTF text cells // CellRange cr = this.Selection; // for (int rw = cr.r1; rw <= cr.r2; rw++) // for (int col = cr.c1; col <= cr.c2; col++) // { // CellRange tmp = this.GetCellRange(rw, col, rw, col); // string StyleName = string.Format("R{0}C{1}Style", rw, col); // CellStyle cs = this.Styles.Add(StyleName, tmp.Style); // cs.TextAlign = TextAlignEnum.CenterCenter; // tmp.Style = cs; // } //} #region Uneven Selections /// /// True if the top and bottom row of the selection is the same for every column /// public bool EvenSelection { get { if (Selection.c1 < 0 || Selection.c2 < 0 || Selection.r1 < 0 || Selection.r2 < 0) return true; // Even if there is no selection if (Selection.IsSingleCell) return true; // One cell by definition is Even int cMin = MinimumColumn(Selection.r1, Selection.c1); // Get the left column of the top row int cMax = MaximumColumn(Selection.r1, Selection.c2); // Get the right column of the top row for (int r = Selection.r1 + 1; r <= Selection.r2; r++) { // Uneven if the top row in this column doesn't match the first column if (MinimumColumn(r, Selection.c1) != cMin) return false; // Uneven if the bottom row in this column doesn't match the first column if (MaximumColumn(r, Selection.c2) != cMax) return false; } int rMin = MinimumRow(Selection.r1, Selection.c1); // Get the top row of the left column int rMax = MaximumRow(Selection.r2, Selection.c1); // Get the bottom row of the left column for (int c = Selection.c1 + 1; c <= Selection.c2; c++) { // Uneven if the top row in this column doesn't match the first column if (MinimumRow(Selection.r1, c) != rMin) return false; // Uneven if the bottom row in this column doesn't match the first column if (MaximumRow(Selection.r2, c) != rMax) return false; } return true; } } public void MakeSelectionEven() { if (Selection.IsSingleCell) return; // One cell by definition is Even MakeSelectionEven(Selection.r1, Selection.c1, Selection.r2, Selection.c2); } public void SelectRow() { MakeSelectionEven(Selection.r1, 0, Selection.r2, Cols.Count - 1); } public void SelectCol() { MakeSelectionEven(0, Selection.c1, Rows.Count - 1, Selection.c2); } public void MakeSelectionEven(int r1,int c1, int r2, int c2) { if (c1 < 0 || c2 < 0 || r1 < 0 || r2 < 0) return; // if there is no selection don't bother CellRange cr = GetEvenSelection(r1, c1, r2, c2); Select(cr); } public CellRange GetEvenSelection() { return GetEvenSelection(Selection.r1, Selection.c1, Selection.r2, Selection.c2); } public CellRange GetEvenSelection(int r1, int c1, int r2, int c2) { int cMinNew = MinimumColumn(r1, c1); // Get the left column of the top row int cMaxNew = MaximumColumn(r1, c2); // Get the right column of the top row int rMinNew = MinimumRow(r1, c1); // Get the top row of the left column int rMaxNew = MaximumRow(r2, c1); // Get the bottom row of the left column int cMin = cMinNew; int cMax = cMaxNew; int rMin = rMinNew; int rMax = rMaxNew; do { cMin = cMinNew; cMax = cMaxNew; rMin = rMinNew; rMax = rMaxNew; for (int r = rMin; r <= rMax; r++) { // Uneven if the top row in this column doesn't match the first column int myMin = MinimumColumn(r, cMin); if (myMin < cMinNew) cMinNew = myMin; // Uneven if the bottom row in this column doesn't match the first column int myMax = MaximumColumn(r, cMax); if (myMax > cMaxNew) cMaxNew = myMax; } for (int c = cMinNew; c <= cMaxNew; c++) { // if the top row in this column is less than the minimum save it int myMin = MinimumRow(rMin, c); if (myMin < rMinNew) rMinNew = myMin; // Uneven if the bottom row in this column doesn't match the first column int myMax = MaximumRow(rMax, c); if (myMax > rMax) rMaxNew = myMax; } } while (cMinNew < cMin || cMaxNew > cMax || rMinNew < rMin || rMaxNew > rMax); CellRange cr = GetCellRange(rMinNew, cMinNew, rMaxNew, cMaxNew); return cr; } private int MinimumColumn(int r, int c) { return GetMergedRange(r, c).c1; } private int MaximumColumn(int r, int c) { return GetMergedRange(r, c).c2; } private int MinimumRow(int r, int c) { return GetMergedRange(r, c).r1; } private int MaximumRow(int r, int c) { return GetMergedRange(r, c).r2; } public Color StyleBackColor { get {return Styles.Normal.BackColor;} set { Styles.Normal.BackColor = value; Styles.Alternate.BackColor = value; for (int c = 0; c < Cols.Count; c++) for (int r = 0; r < Rows.Count; r++) { CellRange cr = GetMergedRange(r, c); if (cr.Style != null && cr.Style.BackColor != value && cr.Style.Name != "Fixed") { cr.Style.BackColor = value; } } } } /// /// Returns a list of cells or merged cells within the selection /// public List MySelection { get { List ranges = new List(); for (int c = Selection.c1; c <= Selection.c2; c++) for (int r = Selection.r1; r <= Selection.r2; r++) { CellRange cr = GetMergedRange(r, c); if (!ranges.Contains(cr)) ranges.Add(cr); } //} return ranges; } } /// /// This is a test to see if MySelection works. /// public void BoldMySelection() { foreach (CellRange cr in MySelection) { using (StepRTB rtb = new StepRTB()) { rtb.Rtf = GetCellRTFString(cr.r1, cr.c1); rtb.SelectAll(); rtb.SelectionFont = new Font(rtb.SelectionFont, FontStyle.Bold); this[cr.r1, cr.c1] = rtb.Rtf; } } } public void ShowMySelection() { int r1 = MySelection[0].r1; int r2 = MySelection[0].r2; int c1 = MySelection[0].c1; int c2 = MySelection[0].c2; foreach (CellRange cr in MySelection) { r1 = Math.Min(r1, cr.r1); c1 = Math.Min(c1, cr.c1); r2 = Math.Max(r2, cr.r2); c2 = Math.Max(c2, cr.c2); } Select(r1,c1,r2,c2); } public void Debug_WritelineMySelection() { int r1 = MySelection[0].r1; int r2 = MySelection[0].r2; int c1 = MySelection[0].c1; int c2 = MySelection[0].c2; Console.WriteLine("Initial MySelection[0] {0}", MySelection[0]); foreach (CellRange cr in MySelection) { r1 = Math.Min(r1, cr.r1); c1 = Math.Min(c1, cr.c1); r2 = Math.Max(r2, cr.r2); c2 = Math.Max(c2, cr.c2); Console.WriteLine("Foreach range ({0},{1}) - ({2},{3})", r1, c1, r2, c2); } } #endregion } /// /// This is used for storing the grid selection for copy/past Row/Column /// public enum GridCopyOption { Row, Column, Selection }; #region RTF Class for Cell rendering /// /// RTF Should only be used if the contents of the richtextbox are to be converted to an image. /// public class RTF : StepRTB { // messages used by RichEd20.dll internal const int WM_USER = 0x0400, EM_FORMATRANGE = WM_USER + 57; // FORMATRANGE is used by RichEd20.dll to render RTF internal struct FORMATRANGE { internal IntPtr hdc, hdcTarget; internal Rectangle rc, rcPage; internal int cpMin, cpMax; } // render the control directly into a given Graphics object // (this does not honor clipping set in the target Graphics object; it that is // a problem, use the RenderClipped method instead). public void Render(Graphics g, Rectangle rc) { // convert rect from pixels to twips rc.X = (int)(rc.X * 1440 / g.DpiX); rc.Y = (int)(rc.Y * 1440 / g.DpiY); rc.Width = rc.X + (int)((rc.Width) * 1440 / g.DpiX); rc.Height = rc.Y + (int)((rc.Height) * 1440 / g.DpiY); // get dc IntPtr hdc = g.GetHdc(); // set up FORMATRANGE struct FORMATRANGE fmt = new FORMATRANGE(); fmt.hdc = fmt.hdcTarget = hdc; fmt.rc = fmt.rcPage = rc; fmt.cpMin = 0; fmt.cpMax = -1; // render RTF int render = 1; SendMessageFormatRange(Handle, EM_FORMATRANGE, render, ref fmt); // clean up SendMessage(Handle, EM_FORMATRANGE, render, 0); // done with dc g.ReleaseHdc(hdc); } // render RTF into a Graphics object using a temporary bitmap to ensure // clipping works correctly. public void RenderClipped(Graphics g, Rectangle rc) { // create temp bitmap Rectangle rcSrc = new Rectangle(0, 0, rc.Width, rc.Height); using (Bitmap bmp = new Bitmap(rc.Width, rc.Height)) { // render RTF into bitmap using (Graphics gBmp = Graphics.FromImage(bmp)) { Render(gBmp, rcSrc); // transfer bitmap to original Graphics object // (this honors clipping set in the target Graphics object) g.DrawImage(bmp, rc, rcSrc, GraphicsUnit.Pixel); } } } // SendMessage [DllImport("USER32.DLL", CharSet = CharSet.Auto)] static private extern int SendMessage( IntPtr hWnd, uint wMsg, int wParam, int lParam); [DllImport("USER32.DLL", CharSet = CharSet.Auto, EntryPoint = "SendMessage")] static private extern int SendMessageFormatRange( IntPtr hWnd, uint wMsg, int wParam, ref FORMATRANGE lParam); } #endregion //RTF Class for Cell rendering # region TableCellInfo for text parse class TableCellInfo { private bool _MergeRowBellow; public bool MergeRowBellow { get { return _MergeRowBellow; } set { _MergeRowBellow = value; } } private bool _MergeColRight; public bool MergeColRight { get { return _MergeColRight; } set { _MergeColRight = value; } } private bool _ColEnd; public bool ColEnd { get { return _ColEnd; } set { _ColEnd = value; } } private string _Text; public string Text { get { return _Text; } set { _Text = value; } } } #endregion //TableCellInfo for text parse #region TableCellEditor /// /// TableCellEditor inherits from a StepRTB and is used as a custom cell editor /// for the C1FlexGrid control. /// public class TableCellEditor : StepRTB //System.Windows.Forms.RichTextBox //System.Windows.Forms.TextBox // System.Windows.Forms.ComboBox { private VlnFlexGrid _owner; private int _row, _col; private char _pendingKey; private bool _cancel; public bool _initializingEdit; // constructor: attach to owner grid public TableCellEditor(VlnFlexGrid owner) { Visible = false; AutoSize = false; BackColor = Color.SkyBlue; BorderStyle = BorderStyle.None; ScrollBars = RichTextBoxScrollBars.None; _initializingEdit = false; _pendingKey = (char)0; _cancel = false; _owner = owner; _owner.Controls.Add(this); this.CursorMovement += new StepRTBCursorMovementEvent(TableCellEditor_CursorMovement); this.CursorKeyPress += new StepRTBCursorKeysEvent(TableCellEditor_CursorKeyPress); this.Leave += new EventHandler(_editor_Leave); this.SelectionChanged += TableCellEditor_SelectionChanged; //this.HeightChanged += new StepRTBEvent(_HeightChanged); } // C2021-005 selecting characters in the cell text editor private void TableCellEditor_SelectionChanged(object sender, EventArgs e) { if (!_initializingEdit) { float fnSz = GetRTFFontSize(); // returns the font size in pts from the text's RTF _owner.SelectedFontSize = fnSz; // will trigger the changing of the font size from VlnFlexGrid class // B2022-137 Table performance improvements - moved ShowTableCellShading to the onLeave call //_owner.ShowTableCellShading(); //C2021-004 display any background color change when you move off a cell } } protected override void Dispose(bool disposing) { base.Dispose(disposing); } // start editing: move to cell and activate // C2021-005 added the showEditor - set to true when we are getting the font size of the text public void StartEditing(int row, int col, bool showEditor) { ItemInfo pinfo = MyItemInfo.MyProcedure as ItemInfo; DocVersionInfo dvi = (pinfo == null) ? null : pinfo.ActiveParent as DocVersionInfo; _initializingEdit = true; ReadOnly = IsRoTable || !UserInfo.CanEdit(MyUserInfo, dvi); // reviewer cannot make changes to a table // save coordinates of cell being edited _row = row; _col = col; //this.Clear(); //jsj // assume we'll save the edits _cancel = false; // move editor over the current cell Rectangle rc = _owner.GetCellRect(row, col, true); rc.Width--; rc.Height--; Bounds = rc; // initialize control content Text = ""; FindAllLinks(); // jsj 1-5-2011 if (_pendingKey > ' ' && !ReadOnly) { if(_pendingKey == '\\') SendKeys.Send("\\"); // B2016-162 Send a backslash which will be converted to "\u9586?" else Text = _pendingKey.ToString(); } else if (_owner[row, col] != null) { string tmp = _owner[row, col].ToString(); // convert \'99 to \u8482? this is for the trade mark symbol. For some reason RTF is automatically // converting the unicode \u8482? to \'99, but once this is done, PROMS StepRTB (edit windows) do not show it // Also convert \~ to a hard spece. Again RTF is automatically converting \u160? to \~ but will then convert // the \~ to a regular space! if (tmp.StartsWith(@"{\rtf")) Rtf = RtfTools.RTFConvertedSymbolsToUnicode(tmp);//.Replace(@"\~", @"\u160?").Replace(@"\'99", @"\u8482?"); else Text = tmp; } Select(Text.Length, 0); Size sz = new Size(rc.Width, rc.Height); //this.Size = sz; this.Width = rc.Width; if (!showEditor) // C2021-005 if we are getting the font size don't show the editor { // make editor visible Visible = true; } // and get the focus //Select(); Focus(); _initializingEdit = false; } void TableCellEditor_CursorKeyPress(object sender, KeyEventArgs args) { //throw new Exception("The method or operation is not implemented."); } void TableCellEditor_CursorMovement(object sender, StepRTBCursorMovementEventArgs args) { int row = _owner.Selection.r1; int col = _owner.Selection.c1; CellRange cr = _owner.GetMergedRange(row, col); //Console.WriteLine("keystroke {0} selection {1},{2}", args.Key, row, col); //vlnStackTrace.ShowStack("keystroke {0} selection {1},{2}", args.Key, row, col); _owner.Select(); // See if we are in a merged range of cells. // if so, use the merged range instead of the selected range // so that we can jump to the top/bottom/left/right of the range // before attempting the move to the next grid cell. //int idx = _owner.MergedRanges.IndexOf(row, col); //if (idx > -1) cr = _owner.MergedRanges[idx]; switch (args.Key) { case VEPROMS.CSLA.Library.E_ArrowKeys.CtrlDown: case VEPROMS.CSLA.Library.E_ArrowKeys.Down: row = cr.r2; if (row < _owner.Rows.Count - 1) _owner.Select(_owner.GetMergedRange(row + 1, col)); else _owner.OnCursorMovement(this, new VlnFlexGridCursorMovementEventArgs(args.Key)); break; case VEPROMS.CSLA.Library.E_ArrowKeys.CtrlLeft: case VEPROMS.CSLA.Library.E_ArrowKeys.Left: col = cr.c1; if (col > 0) _owner.Select(_owner.GetMergedRange(row, col - 1)); else if(row > 0) _owner.Select(_owner.GetMergedRange(row - 1, _owner.Cols.Count - 1)); else _owner.OnCursorMovement(this, new VlnFlexGridCursorMovementEventArgs(args.Key)); break; case VEPROMS.CSLA.Library.E_ArrowKeys.CtrlRight: case VEPROMS.CSLA.Library.E_ArrowKeys.Right: col = cr.c2; if (col < _owner.Cols.Count - 1) _owner.Select(_owner.GetMergedRange(row, col + 1)); else if (cr.r2 < _owner.Rows.Count - 1) { CellRange crDest = _owner.GetMergedRange(cr.r2 + 1, 0); if (cr.r2 < crDest.r1) // It will move to the correct place _owner.Select(crDest); else if (crDest.r2 < _owner.Rows.Count -1) //B2017066 check against count -1 to avoid index out of range error _owner.Select(_owner.GetMergedRange(crDest.r2 + 1, 0)); else _owner.OnCursorMovement(this, new VlnFlexGridCursorMovementEventArgs(args.Key)); } else _owner.OnCursorMovement(this, new VlnFlexGridCursorMovementEventArgs(args.Key)); break; case VEPROMS.CSLA.Library.E_ArrowKeys.CtrlUp: case VEPROMS.CSLA.Library.E_ArrowKeys.Up: row = cr.r1; if (row > 0) _owner.Select(_owner.GetMergedRange(row - 1, col)); else _owner.OnCursorMovement(this, new VlnFlexGridCursorMovementEventArgs(args.Key)); break; default: break; } //Console.WriteLine("selection {0}", _owner.Selection); //_owner.Focus(); // focus was jumping out of the grid this keeps it in. } // after edit handler (custom editor) void _editor_Leave(object sender, EventArgs e) { _owner.Invalidate(); _owner.AdjustGridControlSize(); } //void _HeightChanged(object sender, EventArgs args) //{ // _owner.Invalidate(); //} // save key that started the editing mode public void SetPendingKey(char chr) { _pendingKey = chr; } // expose internal variables public bool Cancel { get { return _cancel; } } public int Row { get { return _row; } } public int Col { get { return _col; } } // move editor after the grid has scrolled public void UpdatePosition() { // get cell rect now Rectangle rcCell = _owner.GetCellRect(_row, _col, false); // intersect with scrollable part of the grid Rectangle rcScroll = _owner.ClientRectangle; rcScroll.X = _owner.Cols[_owner.Cols.Fixed].Left; rcScroll.Y = _owner.Rows[_owner.Rows.Fixed].Top; rcScroll.Width -= rcScroll.X; rcScroll.Height -= rcScroll.Y; rcCell = Rectangle.Intersect(rcCell, rcScroll); // and move the control if (rcCell.Width > 0) rcCell.Width--; if (rcCell.Height > 0) rcCell.Height--; Bounds = rcCell; Size sz = new Size(_owner.GetCellRect(_row, _col).Width, _owner.GetCellRect(_row, _col).Height); this.Size = sz; } // lost focus: hide the editor override protected void OnLeave(System.EventArgs e) { // base processing base.OnLeave(e); // copy text to owner grid if (!_cancel) { _owner[_row, _col] = Rtf; //Text; } // no more pending keys _pendingKey = (char)0; // done for now, hide editor Visible = false; _owner.ShowTableCellShading(); // B2022-137 restore shading if table after editing a cell } // we will handle the Tab key ourselves override protected bool IsInputKey(Keys keyData) { if (keyData == Keys.Tab) return true; return base.IsInputKey(keyData); } //// some keys end the editing //override protected void OnKeyDown(System.Windows.Forms.KeyEventArgs e) //{ // switch (e.KeyCode) // { // case Keys.Escape: // cancel edits // _cancel = true; // _owner.Select(); // e.Handled = true; // return; // case Keys.Enter: // finish editing // case Keys.Tab: // case Keys.Up: // case Keys.Down: // case Keys.PageUp: // case Keys.PageDown: // _owner.Select(); // e.Handled = true; // MoveCursor(e.KeyCode); // return; // default: // default processing // base.OnKeyDown(e); // return; // } //} //// move cursor after done editing //protected void MoveCursor(Keys key) //{ // int row = _owner.Row; // int col = _owner.Col; // switch (key) // { // case Keys.Tab: col++; break; // case Keys.Up: row--; break; // //case Keys.Return: row++; break; // case Keys.Down: row++; break; // //case Keys.PageUp: row -= 10; break; // //case Keys.PageDown: row += 10; break; // } // // validate new selection // if (row < _owner.Rows.Fixed) row = _owner.Rows.Fixed; // if (col < _owner.Cols.Fixed) col = _owner.Cols.Fixed; // if (row > _owner.Rows.Count - 1) row = _owner.Rows.Count - 1; // if (col > _owner.Cols.Count - 1) col = _owner.Cols.Count - 1; // // apply new selection // _owner.Select(row, col); //} //// suppress some keys to avoid annoying beep //override protected void OnKeyPress(System.Windows.Forms.KeyPressEventArgs e) //{ // switch (e.KeyChar) // { // case (char)27: // Keys.Escape: // case (char)13: // Keys.Enter: // case (char)9: // Keys.Tab: // e.Handled = true; // return; // } // base.OnKeyPress(e); //} } #endregion // TableCellEditor #region TableClipBoardFuncts Class class TableClipBoardFuncts { DataFormats.Format dfmtTableCellRange = DataFormats.GetFormat("TableCellRange"); private SelectedTableCells mySeldTableCellsObject; private DataObject myDataObject; public TableClipBoardFuncts() { //mySeldTableCellsObject = new DataObject(dfmtTableCellRange.Name, seldTableCells); } public void Put(CellRange cr) { // Copies myObject into the clipboard. // Clip get the value (text) of all the cells in the selected range // This is saved as one RTF string. Clipboard.SetDataObject(cr.Clip, true); // the "true" make the copy persistent //Console.WriteLine("\nClip: '{0}' \n'{1}'", cr.Clip,cr.DataDisplay); //mySeldTableCellsObject = new SelectedTableCells(); //mySeldTableCellsObject.CpbrdCellRange = cr; // myDataObject = new DataObject(dfmtTableCellRange.Name, mySeldTableCellsObject); // try // { // Clipboard.SetDataObject(myDataObject); //,true); // } // catch (Exception ex) // { // Console.WriteLine(ex.Message); // } } public ArrayList Get() { // Retrieves the data from the clipboard. IDataObject myRetrievedObject = Clipboard.GetDataObject(); string jj = (string)myRetrievedObject.GetData(DataFormats.Text); return GetCellStrings(jj); } //public CellRange get_cr_Paste() //{ // mySeldTableCellsObject = new SelectedTableCells(); // CellRange cr = new CellRange(); // SelectedTableCells sc; // IDataObject myRetrievedObject = Clipboard.GetDataObject(); // try // { // //object obj = myRetrievedObject.GetData(dfmtTableCellRange.Name); // object obj = myRetrievedObject.GetData("TableCellRange"); // //sc = (SelectedTableCells)myRetrievedObject.GetData(dfmtTableCellRange.Name); // sc = (SelectedTableCells)obj; // cr = sc.CpbrdCellRange; // } // catch (Exception ex) // { // Console.WriteLine(ex.Message); // } // return cr; //} private ArrayList GetCellStrings(string instr) { // The table cells placed on the clipboard is saved as one long RTF string. // "\r\n\t" defines a cell border // "\r\n\r" defines beginning of next line (row) // This function will separate each cell text and place them in an array. // This allow the clipboard information to be pasted independently from // how it was selected. // Bug fix: the CellRange.Clip (see cr.clip in the Put() function above) is replacing // new lines with spaces. We need to put them back. instr = instr.Replace(@"}} \", "}}\r\n\\"); string tstr = ""; // this will contain the parsed out cell text ArrayList arylstCellStrings = new ArrayList(); int sidx = 0; // start index int tidx = 0; if (instr != null) { int idx = instr.IndexOf(@"{\rtf",sidx+1); // cell boarder while (idx > 0) { tstr = instr.Substring(sidx, idx - sidx); tstr = tstr.Substring(0, tstr.LastIndexOf('}') + 1); //Console.WriteLine("\ntstr: '{0}'", tstr); arylstCellStrings.Add(tstr); sidx = idx; idx = instr.IndexOf(@"{\rtf",sidx+1); } if (sidx < instr.Length) { tstr = instr.Substring(sidx); arylstCellStrings.Add(tstr); } } return arylstCellStrings; } //private ArrayList GetCellStrings(string instr) //{ // // The table cells placed on the clipboard is saved as one long RTF string. // // "\r\n\t" defines a cell border // // "\r\n\r" defines beginning of next line (row) // // This function will separate each cell text and place them in an array. // // This allow the clipboard information to be pasted independently from // // how it was selected. // string tstr = ""; // this will contain the parsed out cell text // ArrayList arylstCellStrings = new ArrayList(); // int sidx = 0; // start index // int tidx = 0; // if (instr != null) // { // int idx = instr.IndexOf("\r\n\t"); // cell boarder // if (idx < 0) idx = instr.IndexOf("\r\n\r"); // new line (needed for multiple lines in one cell) // while (idx > 0) // { // tstr = instr.Substring(sidx, idx - sidx); // tidx = tstr.IndexOf("\r\n\r"); // if (tidx > 0) // { // idx = instr.IndexOf("\r\n\r", sidx); // tstr = instr.Substring(sidx, idx - sidx); // } // arylstCellStrings.Add(tstr.Substring(tstr.IndexOf("{\\rtf"))); // sidx = idx + 3; // if (sidx < instr.Length) // { // idx = instr.IndexOf("\r\n\t", sidx); // if (idx < 0) idx = instr.IndexOf("\r\n\r", sidx); // } // } // if (sidx < instr.Length) // { // tstr = instr.Substring(sidx); // arylstCellStrings.Add(tstr.Substring(tstr.IndexOf("{\\rtf"))); // } // } // return arylstCellStrings; //} } [Serializable] public class SelectedTableCells : Object { private CellRange _cpbrdCellRange; public CellRange CpbrdCellRange { get { return _cpbrdCellRange; } set { _cpbrdCellRange = value; } } public SelectedTableCells() { } } #endregion // TableClipBoardFuncts Class public class VlnFlexGridCursorMovementEventArgs { private E_ArrowKeys _Key; public E_ArrowKeys Key { get { return _Key; } set { _Key = value; } } public VlnFlexGridCursorMovementEventArgs(E_ArrowKeys key) { _Key = key; } } public class VlnFlexGridPasteEventArgs { private string _Text; public string Text { get { return _Text; } set { _Text = value; } } public VlnFlexGridPasteEventArgs(string text) { _Text = text; } } public class GridCopyInfo { private GridCopyOption _MyCopyOption = GridCopyOption.Selection; public GridCopyOption MyCopyOption { get { return _MyCopyOption; } set { //Console.WriteLine("MyCopyOption = {0}", _MyCopyOption); //if (_MyCopyOption != value) // Console.WriteLine("Changed Option to {0}", value); _MyCopyOption = value; } } private VlnFlexGrid _MyCopiedFlexGrid = null; public VlnFlexGrid MyCopiedFlexGrid { get { return _MyCopiedFlexGrid; } set { _MyCopiedFlexGrid = value; } } private CellRange _MyCopiedCellRange; public CellRange MyCopiedCellRange { get { return _MyCopiedCellRange; } set { _MyCopiedCellRange = value; } } } }