diff --git a/PROMS/Volian.Controls.Library/VlnFlexGrid.Designer.cs b/PROMS/Volian.Controls.Library/VlnFlexGrid.Designer.cs
new file mode 100644
index 00000000..2b8fe8cd
--- /dev/null
+++ b/PROMS/Volian.Controls.Library/VlnFlexGrid.Designer.cs
@@ -0,0 +1,36 @@
+namespace Volian.Controls.Library
+{
+ partial class VlnFlexGrid
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing && (components != null))
+ {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Component Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent()
+ {
+ components = new System.ComponentModel.Container();
+ }
+
+ #endregion
+ }
+}
diff --git a/PROMS/Volian.Controls.Library/VlnFlexGrid.cs b/PROMS/Volian.Controls.Library/VlnFlexGrid.cs
new file mode 100644
index 00000000..b11c3ec5
--- /dev/null
+++ b/PROMS/Volian.Controls.Library/VlnFlexGrid.cs
@@ -0,0 +1,1873 @@
+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 Volian.Controls.Library;
+using C1.Win.C1FlexGrid;
+
+namespace Volian.Controls.Library
+{
+ public partial class VlnFlexGrid : C1.Win.C1FlexGrid.C1FlexGrid
+ {
+ private TableCellEditor _tableCellEditor;
+ private TableClipBoardFuncts _clpbrdCpyPste;
+
+ #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();
+ _tableCellEditor = new TableCellEditor(this);
+ }
+
+ private void SetupGrid(int numrows, int numcols) //C1FlexGrid NewGrid()
+ {
+ // setup the default size of each cell in the table/grid
+ this.Cols.DefaultSize = 40;
+ 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.LeftCenter;
+
+ 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.Always;
+
+ this.AllowMerging = C1.Win.C1FlexGrid.AllowMergingEnum.Custom;
+
+ this.AllowResizing = C1.Win.C1FlexGrid.AllowResizingEnum.Both;
+
+ _tableCellEditor = new TableCellEditor(this);
+ _clpbrdCpyPste = new TableClipBoardFuncts();
+
+ //this.Enter += new System.EventHandler(this.Grid_Enter);
+ 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);
+
+ }
+
+ private void Grid_OwnerDrawCell(object sender, C1.Win.C1FlexGrid.OwnerDrawCellEventArgs e)
+ {
+ 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);
+ if (e.Style.BackColor != solid)
+ e.Style.BackColor = solid;
+
+ // check whether the cell contains RTF
+ string rtfText = this.GetDataDisplay(e.Row, e.Col);
+ if (rtfText.StartsWith(@"{\rtf"))
+ {
+ // it does, so draw background
+ e.DrawCell(DrawCellFlags.Background);
+
+ // draw the RTF text
+ if (e.Bounds.Width > 0 && e.Bounds.Height > 0)
+ {
+ _rtf.Rtf = rtfText;
+ _rtf.ForeColor = e.Style.ForeColor;
+ _rtf.BackColor = e.Style.BackColor;
+ _rtf.Render(e.Graphics, e.Bounds);
+ }
+
+ // and draw border last
+ e.DrawCell(DrawCellFlags.Border);
+
+ // we're done with this cell
+ e.Handled = true;
+ }
+ }
+
+ #endregion //Grid Initialize
+
+ #region Grid and Cell Styles
+
+ public void CellBackgroundYellow()
+ {
+ CellRange cr = this.Selection;
+ cr.Style = this.Styles["Yellow"];
+ }
+
+ public void ToggleCellTextAlignment()
+ {
+ CellRange cr = this.Selection;
+ 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 TableBorderNone()
+ {
+ this.BorderStyle = C1.Win.C1FlexGrid.Util.BaseControls.BorderStyleEnum.None;
+ this.AdjustGridControlSize();
+ }
+
+ public void TableBorderFixedSingle()
+ {
+ this.BorderStyle = C1.Win.C1FlexGrid.Util.BaseControls.BorderStyleEnum.FixedSingle;
+ this.AdjustGridControlSize();
+ }
+
+ public void TableBorderFixed3d()
+ {
+ this.BorderStyle = C1.Win.C1FlexGrid.Util.BaseControls.BorderStyleEnum.Fixed3D;
+ this.AdjustGridControlSize();
+ }
+
+ public void TableBorderLight3D()
+ {
+ this.BorderStyle = C1.Win.C1FlexGrid.Util.BaseControls.BorderStyleEnum.Light3D;
+ this.AdjustGridControlSize();
+ }
+
+ public void TableBorderXpThemes()
+ {
+ this.BorderStyle = C1.Win.C1FlexGrid.Util.BaseControls.BorderStyleEnum.XpThemes;
+ this.AdjustGridControlSize();
+ }
+
+ private CellRange GetSelectedCellRange()
+ {
+ return this.GetCellRange(this.Selection.TopRow, this.Selection.LeftCol, this.Selection.BottomRow, this.Selection.RightCol);
+ }
+
+ public void SelectedCellsBorderNone()
+ {
+ CellRange cr = GetSelectedCellRange();
+ cr.Style = this.Styles["None"];
+ }
+
+ public void SelectedCellsBorderFlat()
+ {
+ CellRange cr = this.GetCellRange(this.Selection.TopRow, this.Selection.LeftCol, this.Selection.BottomRow, this.Selection.RightCol);
+ cr.Style = this.Styles["Flat"];
+ }
+
+ public void SelectedCellsBorderDouble()
+ {
+ CellRange cr = this.GetCellRange(this.Selection.TopRow, this.Selection.LeftCol, this.Selection.BottomRow, this.Selection.RightCol);
+ cr.Style = this.Styles["Double"];
+ }
+
+ public void SelectedCellsBorderRaised()
+ {
+ CellRange cr = this.GetCellRange(this.Selection.TopRow, this.Selection.LeftCol, this.Selection.BottomRow, this.Selection.RightCol);
+ cr.Style = this.Styles["Raised"];
+ }
+
+ public void SelectedCellsBorderInset()
+ {
+ CellRange cr = this.GetCellRange(this.Selection.TopRow, this.Selection.LeftCol, this.Selection.BottomRow, this.Selection.RightCol);
+ cr.Style = this.Styles["Inset"];
+ }
+
+ public void SelectedCellsBorderGroove()
+ {
+ CellRange cr = this.GetCellRange(this.Selection.TopRow, this.Selection.LeftCol, this.Selection.BottomRow, this.Selection.RightCol);
+ cr.Style = this.Styles["Groove"];
+ }
+
+ public void SelectedCellsBorderFillet()
+ {
+ CellRange cr = this.GetCellRange(this.Selection.TopRow, this.Selection.LeftCol, this.Selection.BottomRow, this.Selection.RightCol);
+ cr.Style = this.Styles["Fillet"];
+ }
+
+ public void SelectedCellsBorderDotted()
+ {
+ CellRange cr = this.GetCellRange(this.Selection.TopRow, this.Selection.LeftCol, this.Selection.BottomRow, this.Selection.RightCol);
+ cr.Style = this.Styles["Dotted"];
+ }
+
+ 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()
+ {
+ 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;
+
+ this.Size = new Size(wid + difW, height + difH);
+ }
+ this.Refresh();
+ }
+
+ public void AdjustGridHeightWidth(int r, int c)
+ {
+ StepRTB trtb = new StepRTB();
+ string tstr = null;
+ bool dummyCharWidth = false;
+ bool AllowWidthShrink = false;
+ trtb.Clear();
+ tstr = (string)this[r, c];
+ trtb.Font = this.Font;
+ if (tstr != null && tstr.Length > 0)
+ {
+ if (tstr.StartsWith(@"{\rtf"))
+ trtb.Rtf = tstr; // already RTF text
+ else
+ trtb.Text = tstr; // this will convert regular text to RTF text
+
+ // 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);
+
+ // this will convert the special characters for Bold, Underline, and Italics
+ // into RTF commands
+ trtb.Rtf = ConvertTableText(trtb.Rtf);
+ }
+ 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[r, c] = trtb.Rtf; // save the cleaned up and processed cell text as RTF
+
+ this.Select(r, c, false);
+
+ // 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 + 2;// (int)numGridLineBorderAdj.Value;
+
+ //Console.WriteLine("{0} {1} {2} '{3}'", r, c, newheight,trtb.Text);
+ if (newheight > this.Rows[r].Height)
+ this.Rows[r].Height = newheight;
+ }
+ // IF the column of the selected sell 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;//(int)numGridLineBorderAdj.Value;
+
+ if (newwidth > this.Cols[c].Width || AllowWidthShrink || r == 0)
+ this.Cols[c].Width = newwidth;
+ }
+ }
+ }
+
+ private void Grid_AfterResize(object sender, C1.Win.C1FlexGrid.RowColEventArgs e)
+ {
+ this.AdjustGridControlSize();
+ }
+
+
+ #endregion // Grid Size Adjustments
+
+ #region Cell Text
+ public void MakeRTFcells()
+ {
+ // 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 = 20;//10;
+ for (int c = 0; c < this.Cols.Count; c++)
+ this.AdjustGridHeightWidth(r, c);
+ }
+ this.AdjustGridControlSize();
+ }
+
+ 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 = "";
+
+ // Underline next word
+ rtn = SomethingNextWord(str, @"\'17", @"\ul ", @"\ulnone ");
+
+ // Bold next word
+ rtn = SomethingNextWord(rtn, @"\'13", @"\b ", @"\b0 ");
+
+ // Italics On
+ rtn = rtn.Replace(@"\'1B4", @"\i ");
+
+ // Italics Off
+ rtn = rtn.Replace(@"\'1B5", @"\i0 ");
+
+ // underline On
+ rtn = rtn.Replace(@"\'ab", @"\ul ");
+ // underline Off
+ rtn = rtn.Replace(@"\'bb", @"\ulnone ");
+
+ return rtn;
+ }
+
+ // This converts Underline or bold next word character to the corresponding on/off commands
+ 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
+ _tableCellEditor.StartEditing(e.Row, e.Col);
+ e.Cancel = true;
+ }
+
+ // after edit handler (built-in editors)
+ private void _AfterEdit(object sender, C1.Win.C1FlexGrid.RowColEventArgs e)
+ {
+ this.AdjustGridControlSize();
+ }
+
+ // 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;
+ }
+
+ #endregion //Cell Text
+
+ #region Merged / Split Range
+
+ public void MergeSelection()
+ {
+ //string tstr = "";
+ //C1.Win.C1FlexGrid.CellRange sel = this.Selection;
+ //tstr = sel.Clip; // clip hold the data for the selected cells (used for un-merge)
+ this.MergedRanges.Add(this.Selection);
+ this.Invalidate();
+ }
+
+ public void SplitSelection()
+ {
+ C1.Win.C1FlexGrid.CellRange sel = this.GetMergedRange(this.Selection.r1, this.Selection.c1);
+ if (this.MergedRanges.Contains(sel))
+ this.MergedRanges.Remove(sel);
+ this.Invalidate();
+ }
+
+ private void AdjustMergedRows(int row, 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--;
+ crc.Add(cr);
+ }
+ }
+ else
+ {
+ if (row <= r.r1)
+ {
+ if (row < r.r1)
+ cr.r1--;
+ cr.r2--;
+ }
+ crc.Add(cr);
+ }
+ }
+ }
+ else // adding
+ foreach (CellRange r in this.MergedRanges)
+ {
+ CellRange cr = r;
+ int inspos = (above) ? row : row - 1;
+ if (r.ContainsRow(inspos))
+ {
+ if ((above && cr.r1 == inspos) || (!above && cr.r2 == inspos))
+ {
+ string tstr = "";
+ int newrow = 0;
+ if (above)
+ {
+ if (this[cr.r1 + 1, cr.c1] != null)
+ tstr = this[cr.r1 + 1, cr.c1].ToString();
+ newrow = cr.r1;
+ }
+ else
+ {
+ if (this[cr.r2, cr.c1] != null)
+ tstr = this[cr.r2, cr.c1].ToString();
+ newrow = cr.r2 + 1;
+ }
+ if (tstr != null && tstr.Length > 0)
+ for (int x = cr.c1; x <= cr.c2; x++)
+ this[newrow, x] = tstr;
+ }
+ cr.r2++;
+ }
+ else
+ {
+ if (inspos < cr.r1)
+ {
+ cr.r1++;
+ cr.r2++;
+ }
+ }
+ crc.Add(cr);
+ }
+ this.MergedRanges.Clear();
+ foreach (CellRange r in crc)
+ this.MergedRanges.Add(r);
+ }
+
+ private void AdjustMergedColumns(int col, 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--;
+ crc.Add(cr);
+ }
+ }
+ else
+ {
+ if (col < cr.c1)
+ {
+ cr.c1--;
+ cr.c2--;
+ }
+ crc.Add(cr);
+ }
+ }
+ }
+ else // adding
+ foreach (CellRange r in this.MergedRanges)
+ {
+ CellRange cr = r;
+ int inspos = (left) ? col : col - 1;
+ if (r.ContainsCol(inspos))
+ {
+ string tstr = "";
+ int newcol = 0;
+ if (left)
+ {
+ if (inspos == cr.c1)
+ tstr = this[cr.r1, cr.c1 + 1].ToString();
+ else
+ tstr = 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++;
+ cr.c2++;
+ }
+ crc.Add(cr);
+ }
+ this.MergedRanges.Clear();
+ foreach (CellRange r in crc)
+ this.MergedRanges.Add(r);
+ }
+
+ private bool RowIsInMergeRange(int row)
+ {
+ bool rtn = false;
+ if (row >= 0)
+ {
+ CellRange cr = this.Selection;
+ rtn = true;
+ 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(col, r);
+ 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 cr = this.Selection;
+ 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;
+
+ return rtnrow;
+ }
+
+ private int GetColInsertPosition(Boolean before)
+ {
+ int rtncol;
+ CellRange cr = this.Selection;
+ 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;
+
+ return rtncol;
+ }
+
+ public void InsertColumnBefore()
+ {
+ int newcol = this.GetColInsertPosition(true);
+ this.Cols.Insert(newcol);
+ 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);
+ this.AdjustMergedColumns(colidx + 1, false, false);
+ this.AdjustGridControlSize();
+ }
+
+ public void InsertRowBefore()
+ {
+ int newrow = this.GetRowInsertPosition(true);
+ this.Rows.Insert(newrow);
+ 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);
+ this.AdjustMergedRows(rowidx + 1, false, false);
+ this.AdjustGridControlSize();
+ }
+
+ public void RemoveSelectedColumn()
+ {
+ this.SelectionMode = SelectionModeEnum.Column;
+ this.Select(this.Selection.r1, this.Selection.c1);
+ DialogResult dr = MessageBox.Show("Remove this column?", "Remove Column", MessageBoxButtons.YesNo);
+ if (dr == DialogResult.Yes)
+ RemoveColumns(this.Selection.r1, this.Selection.c1, 1);
+ this.SelectionMode = SelectionModeEnum.Default;
+ }
+
+ public void RemoveSelectedRow()
+ {
+ this.SelectionMode = SelectionModeEnum.Row;
+ this.Select(this.Selection.r1, this.Selection.c1);
+ DialogResult dr = MessageBox.Show("Remove this Row?", "Remove Row", MessageBoxButtons.YesNo);
+ if (dr == DialogResult.Yes)
+ this.RemoveRows(this.Selection.r1, this.Selection.c1, 1);
+ this.SelectionMode = SelectionModeEnum.Default;
+ }
+
+ private void RemoveRows(int strow, int stcol, int cnt)
+ {
+ for (int i = 0; i < cnt; i++)
+ {
+ if (this.RowIsInMergeRange(strow))
+ {
+ for (int cl = 0; cl < this.Cols.Count; cl++)
+ {
+ int idx = this.MergedRanges.IndexOf(strow, cl);
+ if (idx > -1)
+ {
+ CellRange cr = this.MergedRanges[idx];
+ if (cr.r1 < cr.r2)
+ this[cr.r1 + 1, cr.c1] = this[cr.r1, cr.c1];
+ }
+ cl++;
+ }
+ }
+ this.Rows.Remove(strow);
+ this.AdjustMergedRows(strow, false, true);
+ }
+ this.AdjustGridControlSize();
+ }
+
+ private void RemoveColumns(int strow, int stcol, int cnt)
+ {
+ for (int i = 0; i < cnt; i++)
+ {
+ if (this.ColIsInMergeRange(stcol))
+ {
+ for (int rw = 0; rw < this.Rows.Count; rw++)
+ {
+ int idx = this.MergedRanges.IndexOf(rw, stcol);
+ if (idx > -1)
+ {
+ CellRange cr = this.MergedRanges[idx];
+ if (cr.c1 < cr.c2)
+ this[cr.r1, cr.c1 + 1] = this[cr.r1, cr.c1];
+ }
+ }
+ }
+ this.Cols.Remove(stcol);
+ this.AdjustMergedColumns(stcol, false, true);
+ }
+ this.AdjustGridControlSize();
+ }
+
+ public void RemoveSelectedCells()
+ {
+ bool didremove = false;
+ int lastRow = this.Rows.Count - 1;
+ int lastCol = this.Cols.Count - 1;
+ CellRange cr = this.Selection;
+
+ // r2 is last row (or in merge range containing last row)
+ // r1 is first row or r1-m (m is in merge range) is first row
+ // we can remove columns c1 through c2
+
+ int idx = this.MergedRanges.IndexOf(cr.r2, cr.c2);
+ CellRange mr = new CellRange();
+ if (idx > -1) mr = this.MergedRanges[idx];
+ if (cr.r2 == lastRow || idx > -1 && mr.r2 == lastRow)//RowIsInMergeRange(grd,cr.r2))
+ {
+ if (cr.r1 == 0 || this.RowIsInMergeRange(cr.r1 - 1))
+ {
+ this.RemoveColumns(cr.r1, cr.c1, cr.RightCol - cr.LeftCol + 1);// remove selected columns
+ didremove = true;
+ }
+ }
+
+
+ // c2 is last column (or in merge range containing last column)
+ // c1 is first column or c1-m (m is merge range) is first column
+ // we can remove rows r1 through r2
+
+ if (cr.c2 == lastCol || idx > -1 && mr.c2 == lastCol)//ColIsInMergeRange(grd,cr.c1-1))
+ {
+ if (cr.c1 == 0 || this.ColIsInMergeRange(cr.c1 - 1))
+ {
+ // remove selected rows
+ this.RemoveRows(cr.r1, cr.c1, cr.BottomRow - cr.TopRow + 1);
+ didremove = true;
+ }
+ }
+
+ if (!didremove)
+ MessageBox.Show("Cannot Removed Part of a Row or Column.", "Invalid Selection");
+
+ return;
+ }
+
+ #endregion //Grid Add and Remove Row / Column
+
+ #region Clipboard
+
+ public void ClipBoardCopyRow()
+ {
+ this.SelectionMode = SelectionModeEnum.Row;
+ this.Select(this.Selection.r1, 0, this.Selection.r2, this.Cols.Count - 1, true);
+ DialogResult dr = MessageBox.Show("Copy these Rows?", "Copy Rows", MessageBoxButtons.YesNo);
+ if (dr == DialogResult.Yes)
+ _clpbrdCpyPste.Put(this.Selection);
+ this.SelectionMode = SelectionModeEnum.Default;
+ }
+
+ public void ClipBoardCopyColumn()
+ {
+ this.SelectionMode = SelectionModeEnum.Column;
+ this.Select(0, this.Selection.c1, this.Rows.Count - 1, this.Selection.c2, true);
+ DialogResult dr = MessageBox.Show("Copy these columns?", "Copy Columns", MessageBoxButtons.YesNo);
+ if (dr == DialogResult.Yes)
+ _clpbrdCpyPste.Put(this.Selection);
+ this.SelectionMode = SelectionModeEnum.Default;
+ }
+
+ public void ClipBoardCopySelection()
+ {
+ this.Select(this.Selection.r1, this.Selection.c1, this.Selection.r2, this.Selection.c2);
+ DialogResult dr = MessageBox.Show("Copy Selected Cells?", "Copy Selection", MessageBoxButtons.YesNo);
+ if (dr == DialogResult.Yes)
+ _clpbrdCpyPste.Put(this.Selection);
+ }
+
+
+ private void CopyTextFromCellRange(ArrayList arylst, int srow, int scol, int erow, int ecol)
+ {
+ StepRTB trtb = new StepRTB();
+ int aryidx = 0;
+ for (int r = srow; r <= erow; r++)
+ {
+ for (int c = scol; c <= ecol; c++)
+ {
+ if (aryidx >= arylst.Count)
+ trtb.Text = "";
+ else
+ {
+ trtb.Rtf = (string)(arylst[aryidx++]);
+ trtb.AdjustWidthForContent();
+ }
+ this[r, c] = trtb.Rtf;
+ this.AdjustGridHeightWidth(r, c);
+ }
+ }
+ }
+
+
+ public enum enmPastePos : int
+ {
+ Before = 1, Replace = 0, After = -1
+ }
+
+ public void ClipBoardPasteRows(enmPastePos pp)
+ {
+ // Get a list of strings representing the text (rtf text) in each cell
+ // that was saved to the clipboard (row/column order)
+ ArrayList aryCellList = _clpbrdCpyPste.Get();
+
+ if (aryCellList != null && aryCellList.Count > 0)
+ {
+ // get row/column starting position in which new rows will be added
+ int startrow = this.Selection.r1 + ((pp == enmPastePos.After) ? 1 : 0);
+ int startcol = this.Selection.c1;
+ // get the number of rows needed based on what was save to the clipboard
+ int numrows = Math.Max(1, (aryCellList.Count / this.Cols.Count));
+ // insert that number of new rows.
+ if (pp != enmPastePos.Replace) // insert new rows before or after
+ for (int r = 0; r < numrows; r++)
+ if (pp == enmPastePos.After) // create new rows after
+ this.InsertRowAfter();
+ else
+ this.InsertRowBefore();
+ // copy each grid cell text (aryCellList) into the newly inserted rows
+ CopyTextFromCellRange(aryCellList, startrow, startcol, startrow + numrows - 1, startcol + this.Cols.Count - 1);
+ this.AdjustGridControlSize();
+ }
+ }
+
+ public void ClipBoardPasteColumns(enmPastePos pp)
+ {
+ // Get a list of strings representing the text (rtf text) in each cell
+ // that was saved to the clipboard (row/column order)
+ ArrayList aryCellList = _clpbrdCpyPste.Get();
+
+ if (aryCellList != null && aryCellList.Count > 0)
+ {
+ // get row/column starting position in which new rows will be added
+ int startrow = 0;//grd.Selection.r1+((pp == enmPastePos.After) ? 1 : 0);
+ int startcol = this.Selection.c1 + ((pp == enmPastePos.After) ? 1 : 0);
+ // get the number of rows needed based on what was save to the clipboard
+ int numcols = Math.Max(1, (aryCellList.Count / this.Rows.Count));
+ // insert that number of new rows.
+ if (pp != enmPastePos.Replace) // insert new rows before or after
+ for (int c = 0; c < numcols; c++)
+ if (pp == enmPastePos.After) // create new rows after
+ this.InsertColumnAfter();
+ else
+ this.InsertColumnBefore();
+ // copy each grid cell text (aryCellList) into the newly inserted rows
+ this.CopyTextFromCellRange(aryCellList, startrow, startcol, startrow + this.Rows.Count - 1, startcol + numcols - 1);
+ this.AdjustGridControlSize();
+ }
+ }
+
+ public void ClipBoardPasteIntoSelection()
+ {
+ // Get a list of strings representing the text (rtf text) in each cell
+ // that was saved to the clipboard (row/column order)
+ ArrayList aryCellList = _clpbrdCpyPste.Get();
+
+ if (aryCellList != null && aryCellList.Count > 0)
+ {
+ // copy each grid cell text (aryCellList) into the selected cells
+ this.CopyTextFromCellRange(aryCellList, this.Selection.r1, this.Selection.c1, this.Selection.r2, this.Selection.c2);
+ this.AdjustGridControlSize();
+ }
+ }
+
+ #endregion //Clipboard
+
+ #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);
+ }
+
+ ///
+ /// 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.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;
+ }
+
+ ///
+ /// 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 celll, and attempt to merge cells were needed.
+ ///
+ ///
+ public void ParseTableFromText(string 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);
+ maxRow = curRow + 1;
+ curRow = 0;
+ curCol = 0;
+ // 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
+ {
+ // 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--;
+ string jstr = (string)this[rw, curCol];
+ if (jstr == null)
+ jstr = tstr;
+ else
+ jstr += "\n" + tstr; // multi line cell
+ this[rw, curCol] = 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;
+ }
+ }
+ else // parsed text contains all dashes
+ {
+ 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;
+ // see what column we are in - new line might occure before last grid column
+ curCol = dicCols[colPos];
+ 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);
+ 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
+ {
+ // 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--;
+ string jstr = (string)this[rw, curCol];
+ if (jstr == null)
+ jstr = tstr;
+ else
+ jstr += "\n" + tstr; // multi line cell
+
+ this[rw, curCol] = jstr;
+ }
+ else if (tstr.Length > 0) // parsed text is all dash characters
+ {
+ incRow = true;
+ if (curRow > 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[colPos];
+ while (curCol > prevCol + 1)
+ {
+ tci[curRow, prevCol].MergeColRight = true;
+ prevCol++;
+ }
+ // parse out the remaining text
+ tstr = txtbuff.Substring(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)
+ {
+ // 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--;
+ string jstr = (string)this[rw, curCol];
+ if (jstr == null)
+ jstr = tstr;
+ else
+ jstr += "\n" + tstr; // multi line cell
+ this[rw, curCol] = 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].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;
+ }
+ }
+ }
+ }
+ #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
+ }
+ #region RTF Class for Cell rendering
+ class RTF : StepRTB //RichTextBox
+ {
+ // 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;
+
+ // constructor: attach to owner grid
+ public TableCellEditor(VlnFlexGrid owner)
+ {
+ Visible = false;
+ AutoSize = false;
+ BackColor = Color.Beige;
+ BorderStyle = BorderStyle.None;
+
+ _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.HeightChanged += new StepRTBEvent(_HeightChanged);
+ }
+
+ // start editing: move to cell and activate
+ public void StartEditing(int row, int col)
+ {
+ // save coordinates of cell being edited
+ _row = row;
+ _col = col;
+ this.Clear();
+ // 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 = "";
+ if (_pendingKey > ' ')
+ Text = _pendingKey.ToString();
+ else if (_owner[row, col] != null)
+ {
+ string tmp = _owner[row, col].ToString();
+ if (tmp.StartsWith(@"{\rtf"))
+ Rtf = tmp;
+ else
+ Text = tmp;
+ }
+ Select(Text.Length, 0);
+
+ Size sz = new Size(rc.Width, rc.Height);
+
+ this.Size = sz;
+
+ // make editor visible
+ Visible = true;
+
+ // and get the focus
+ Select();
+ }
+
+ 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.Selection;
+ //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(row + 1, col);
+ break;
+ case VEPROMS.CSLA.Library.E_ArrowKeys.CtrlLeft:
+ case VEPROMS.CSLA.Library.E_ArrowKeys.Left:
+ col = cr.c1;
+ if (col > 0)
+ _owner.Select(row, col - 1);
+ 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(row, col + 1);
+ break;
+ case VEPROMS.CSLA.Library.E_ArrowKeys.CtrlUp:
+ case VEPROMS.CSLA.Library.E_ArrowKeys.Up:
+ row = cr.r1;
+ if (row > 0)
+ _owner.Select(row - 1, col);
+ 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;
+ }
+
+ // 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");
+
+ 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
+ }
+
+ public ArrayList Get()
+ {
+ // Retrieves the data from the clipboard.
+ IDataObject myRetrievedObject = Clipboard.GetDataObject();
+ string jj = (string)myRetrievedObject.GetData(DataFormats.Text);
+ return GetCellStrings(jj);
+ }
+
+ 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
+}