1874 lines
52 KiB
C#
1874 lines
52 KiB
C#
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
|
|
|
|
/// <summary>
|
|
/// Adjust the grid control size based on the cell sizes.
|
|
/// </summary>
|
|
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
|
|
|
|
/// <summary>
|
|
/// Prompts user with Save File dialog.
|
|
/// Grid will be saved to an XML file.
|
|
/// </summary>
|
|
/// <param name="initDir"></param>
|
|
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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Prompts user with Save File dialog.
|
|
/// Grid will be saved to an Excel file.
|
|
/// </summary>
|
|
/// <param name="initDir"></param>
|
|
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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Prompts user with Open File dialog.
|
|
/// XML file will be imported to a table grid.
|
|
/// </summary>
|
|
/// <param name="initDir"></param>
|
|
/// <returns></returns>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Prompts user with Open File dialog.
|
|
/// Excel file will be imported to a table grid.
|
|
/// </summary>
|
|
/// <param name="initDir"></param>
|
|
/// <returns></returns>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
/// <param name="txtbuff"></param>
|
|
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<int, int> dicCols = new Dictionary<int, int>();
|
|
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
|
|
/// <summary>
|
|
/// TableCellEditor inherits from a StepRTB and is used as a custom cell editor
|
|
/// for the C1FlexGrid control.
|
|
/// </summary>
|
|
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
|
|
}
|