From da6df7ff1ec449907e93135457adb542557ee0a0 Mon Sep 17 00:00:00 2001 From: John Date: Mon, 20 Jul 2009 15:48:48 +0000 Subject: [PATCH] --- .../VlnFlexGrid.Designer.cs | 36 + PROMS/Volian.Controls.Library/VlnFlexGrid.cs | 1873 +++++++++++++++++ 2 files changed, 1909 insertions(+) create mode 100644 PROMS/Volian.Controls.Library/VlnFlexGrid.Designer.cs create mode 100644 PROMS/Volian.Controls.Library/VlnFlexGrid.cs 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 +}