Index: src/Common/DelftTools.Controls.Swf/Table/TableViewPasteController.cs =================================================================== diff -u -r8f6ae890fed8e8eae3a32f9c0498a10f82e0ddf9 -r5fc71a385897af92ccb092f2f969b5709afab85a --- src/Common/DelftTools.Controls.Swf/Table/TableViewPasteController.cs (.../TableViewPasteController.cs) (revision 8f6ae890fed8e8eae3a32f9c0498a10f82e0ddf9) +++ src/Common/DelftTools.Controls.Swf/Table/TableViewPasteController.cs (.../TableViewPasteController.cs) (revision 5fc71a385897af92ccb092f2f969b5709afab85a) @@ -12,22 +12,27 @@ /// public class TableViewPasteController : ITableViewPasteController { - private bool isPasting; - private static readonly ILog Log = LogManager.GetLogger(typeof(TableViewPasteController)); + public event EventHandler> PasteFailed; + public event EventHandler PasteFinished; + private const int NewRowSelectedIndex = int.MinValue + 1; - private List PastedRows { get; set; } + private static readonly ILog Log = LogManager.GetLogger(typeof(TableViewPasteController)); - protected TableView TableView { get; private set; } - protected List PastedBlocks { private get; set; } - public TableViewPasteController(TableView tableView) { TableView = tableView; PastedRows = new List(); PastedBlocks = new List(); } + /// + /// Gets or sets the paste behaviour value + /// + public TableViewPasteBehaviourOptions PasteBehaviour { get; set; } + + public bool IsPasting { get; private set; } + /// /// This method does most of the work. It Pastes Clipboard content to the XtraGrid. /// If OptionsSelection.EnableAppearanceFocusedRow == true then it will paste row (if @@ -45,11 +50,13 @@ Log.Debug("Clipboard does not contain text, so it cannot be pasted to the grid."); return; } - + string[] clipboardLines = GetClipboardLines(); //nothing to paste. if (clipboardLines.Length == 0) + { return; + } PasteLines(clipboardLines); } @@ -60,7 +67,7 @@ /// public void PasteLines(string[] lines) { - isPasting = true; + IsPasting = true; lines = RemoveHeaderIfPresent(lines); @@ -72,9 +79,9 @@ { OnPasteFailed(message); - isPasting = false; + IsPasting = false; - return;//don't paste + return; //don't paste } //pastevalues returns the pasted selection @@ -101,38 +108,14 @@ PastedRows.Clear(); PastedBlocks.Clear(); - isPasting = false; + IsPasting = false; OnPasteFinished(); } - /// - /// Gets or sets the paste behaviour value - /// - public TableViewPasteBehaviourOptions PasteBehaviour { get; set; } + protected TableView TableView { get; private set; } + protected List PastedBlocks { private get; set; } - public bool IsPasting - { - get { return isPasting; } - } - - private string[] RemoveHeaderIfPresent(string[] lines) - { - if (lines.Length > 0 && string.Equals(lines[0], GetTableHeaderString())) - { - return lines.Skip(1).ToArray(); //skip header - } - return lines; - } - - private string GetTableHeaderString() - { - //The function xtragrid uses to get the header string is protected and uses dxColumn.GetTextCaption(), - //which may differ from dxColumn.GetCaption we use. In those cases this may break. Also if the ordering - //of columns is out of sync (can that happen?) - return String.Join("\t", TableView.Columns.Where(c => c.Visible).Select(c => c.Caption).ToArray()); - } - /// /// Overload without message parameter. /// @@ -158,32 +141,28 @@ { return GetRowSelectSelection(); } - - + var cells = TableView.SelectedCells; if (cells.Count == 0) { - //base selection on focused cell var focusedCell = TableView.GetFocusedCell(); if (focusedCell != null) { - return new RectangleSelection(focusedCell, focusedCell); + return new RectangleSelection(focusedCell, focusedCell); } //no focused cell must mean empty table..start pasting left,top return new RectangleSelection(topLeft, topLeft); - } - + //return a selection based on the first and last cell in the selection. Tricky..should check the most upper etc.. RectangleSelection selection = GetRectangleSelection(cells); - if (selection == null) { errorMessage = "Cannot paste into non rectangular selection"; } - + return selection; } @@ -198,7 +177,7 @@ else { //start pasting at the first row - topLeft = new TableViewCell(selectedRows[0], TableView.GetColumnByDisplayIndex(0)); + topLeft = new TableViewCell(selectedRows[0], TableView.GetColumnByDisplayIndex(0)); } return new RectangleSelection(topLeft, topLeft); @@ -223,28 +202,14 @@ top = TableView.RowCount; } //do a check if we have enought cells... - if (cells.Count != (right + 1 - left) * (bottom + 1 - top)) + if (cells.Count != (right + 1 - left)*(bottom + 1 - top)) + { return null; + } - return new RectangleSelection(new TableViewCell(top, TableView.GetColumnByDisplayIndex(left)),new TableViewCell(bottom,TableView.GetColumnByDisplayIndex(right)) ); + return new RectangleSelection(new TableViewCell(top, TableView.GetColumnByDisplayIndex(left)), new TableViewCell(bottom, TableView.GetColumnByDisplayIndex(right))); } - private void OnPasteFailed(string message) - { - Log.Warn(message); - - if (PasteFailed != null) - PasteFailed(this, new EventArgs(message)); - } - - private void OnPasteFinished() - { - if (PasteFinished != null) - { - PasteFinished(this, new EventArgs()); - } - } - /// /// Checks whether the target tableView is filtered or the target selection contains a sorted column /// @@ -270,30 +235,29 @@ var pasteColumnSpan = SplitToCells(clipboardLines[0]).Length; int[] pastedColumnIndexes = Enumerable.Range(targetSelection.Left, pasteColumnSpan).ToArray(); - //is there sorted column in our pasted columns? var sortedColumnExists = (from col in TableView.Columns - where col.SortOrder != SortOrder.None && pastedColumnIndexes.Contains(col.DisplayIndex) - select col).Any(); + where col.SortOrder != SortOrder.None && pastedColumnIndexes.Contains(col.DisplayIndex) + select col).Any(); if (sortedColumnExists) { - errorMessage = "Cannot paste into sorted column";//todo: add name of column here? + errorMessage = "Cannot paste into sorted column"; //todo: add name of column here? return false; } if (TableView.Columns.Any(col => !string.IsNullOrEmpty(col.FilterString))) { - errorMessage = "Cannot paste into filtered tableview.";//todo: add name of column here? + errorMessage = "Cannot paste into filtered tableview."; //todo: add name of column here? return false; - } + } return true; } /// /// Pastes values into target selection. /// protected virtual void PasteValues(string[] clipboardLines, RectangleSelection targetSelection, - bool allowNewRows, bool wrapInEditAction=true) + bool allowNewRows, bool wrapInEditAction = true) { if (wrapInEditAction) { @@ -305,67 +269,20 @@ } } - private void PasteValuesCore(string[] clipboardLines, RectangleSelection targetSelection, bool allowNewRows) - { - var startRowIndex = targetSelection.Top; - var startColumnIndex = targetSelection.Left; - if (startRowIndex < 0) - { - throw new ArgumentException(string.Format("Invalid row number {0}", startRowIndex), - "targetSelection"); - } - - //paste all the lines once... - int lastRowIndex = Math.Max(startRowIndex + clipboardLines.Length - 1, targetSelection.Bottom); - - int currentClipBoardLineIndex = 0; - int canceledNewRows = 0; - for (int j = startRowIndex; j <= lastRowIndex; j++) - { - string[] cols = SplitToCells(clipboardLines[currentClipBoardLineIndex]); - //Simply set values as text. - var pasteWidth = Math.Max(cols.Length, targetSelection.Right - targetSelection.Left + 1); - //paste cannot be wider than tablewidth - startColumnIndex - pasteWidth = Math.Min(pasteWidth, TableView.Columns.Count(c => c.Visible) - startColumnIndex); - - //do the pasting - bool checkCells = (PasteBehaviour == TableViewPasteBehaviourOptions.SkipRowWhenValueIsInvalid); - bool addNewRow = allowNewRows && (j >= TableView.RowCount); - var pasteStartRowIndex = j - canceledNewRows; - - var pasteResult = PasteCellsToRow(cols, pasteStartRowIndex, startColumnIndex, pasteWidth, addNewRow, - checkCells); - - if (addNewRow && pasteResult == -1) - { - canceledNewRows++; - } - - //update clipboard line index..loop - currentClipBoardLineIndex++; - if (currentClipBoardLineIndex == clipboardLines.Length) - { - //break;//do really want repeat data like below? - currentClipBoardLineIndex = 0; - } - } - } - /// /// Pastes the given contents to the table at row startRowIndex, increasing the number of rows if necessary and allowed. /// /// The row index at which the pasting effectively occured, -1 if no pasting was done. - protected int PasteCellsToRow(string[] content, int startRowIndex, int startColumnIndex, int pasteWidth, bool addNewRow, bool cellBased) { var index = startRowIndex; - if(addNewRow) + if (addNewRow) { TableView.AddNewRowToDataSource(); } else { - if(startRowIndex >= TableView.RowCount) + if (startRowIndex >= TableView.RowCount) { return -1; } @@ -379,11 +296,11 @@ var contentWidth = content.Length; for (var i = 0; i < pasteWidth; i++) { - if (!SafeSetCellValue(index, startColumnIndex + i, content[i % contentWidth])) + if (!SafeSetCellValue(index, startColumnIndex + i, content[i%contentWidth])) { Log.ErrorFormat("Can not paste value into cell [{0}, {1}]. Row {0} will be skipped", startRowIndex, startColumnIndex + i); - if(addNewRow) + if (addNewRow) { TableView.SelectRow(index); TableView.DeleteCurrentSelection(); @@ -399,9 +316,9 @@ var values = new List(); for (var i = 0; i < pasteWidth; i++) { - values.Add(content[i % contentWidth]); + values.Add(content[i%contentWidth]); } - if(!SafeSetRowCellValues(index, startColumnIndex, values)) + if (!SafeSetRowCellValues(index, startColumnIndex, values)) { Log.ErrorFormat("Skipping invalid row {0} from pasting", startRowIndex); @@ -426,6 +343,98 @@ return index; } + protected static string[] SplitToCells(string p) + { + //tab delimited data: excel, and xtragrid copy (todo think about how to implement pasting of space delimited data) + return p.Split(new[] + { + "\t" + }, StringSplitOptions.None); + } + + private List PastedRows { get; set; } + + private string[] RemoveHeaderIfPresent(string[] lines) + { + if (lines.Length > 0 && string.Equals(lines[0], GetTableHeaderString())) + { + return lines.Skip(1).ToArray(); //skip header + } + return lines; + } + + private string GetTableHeaderString() + { + //The function xtragrid uses to get the header string is protected and uses dxColumn.GetTextCaption(), + //which may differ from dxColumn.GetCaption we use. In those cases this may break. Also if the ordering + //of columns is out of sync (can that happen?) + return String.Join("\t", TableView.Columns.Where(c => c.Visible).Select(c => c.Caption).ToArray()); + } + + private void OnPasteFailed(string message) + { + Log.Warn(message); + + if (PasteFailed != null) + { + PasteFailed(this, new EventArgs(message)); + } + } + + private void OnPasteFinished() + { + if (PasteFinished != null) + { + PasteFinished(this, new EventArgs()); + } + } + + private void PasteValuesCore(string[] clipboardLines, RectangleSelection targetSelection, bool allowNewRows) + { + var startRowIndex = targetSelection.Top; + var startColumnIndex = targetSelection.Left; + if (startRowIndex < 0) + { + throw new ArgumentException(string.Format("Invalid row number {0}", startRowIndex), + "targetSelection"); + } + + //paste all the lines once... + int lastRowIndex = Math.Max(startRowIndex + clipboardLines.Length - 1, targetSelection.Bottom); + + int currentClipBoardLineIndex = 0; + int canceledNewRows = 0; + for (int j = startRowIndex; j <= lastRowIndex; j++) + { + string[] cols = SplitToCells(clipboardLines[currentClipBoardLineIndex]); + //Simply set values as text. + var pasteWidth = Math.Max(cols.Length, targetSelection.Right - targetSelection.Left + 1); + //paste cannot be wider than tablewidth - startColumnIndex + pasteWidth = Math.Min(pasteWidth, TableView.Columns.Count(c => c.Visible) - startColumnIndex); + + //do the pasting + bool checkCells = (PasteBehaviour == TableViewPasteBehaviourOptions.SkipRowWhenValueIsInvalid); + bool addNewRow = allowNewRows && (j >= TableView.RowCount); + var pasteStartRowIndex = j - canceledNewRows; + + var pasteResult = PasteCellsToRow(cols, pasteStartRowIndex, startColumnIndex, pasteWidth, addNewRow, + checkCells); + + if (addNewRow && pasteResult == -1) + { + canceledNewRows++; + } + + //update clipboard line index..loop + currentClipBoardLineIndex++; + if (currentClipBoardLineIndex == clipboardLines.Length) + { + //break;//do really want repeat data like below? + currentClipBoardLineIndex = 0; + } + } + } + private bool SafeSetRowCellValues(int index, int startColumnIndex, List values) { try @@ -496,39 +505,31 @@ private static string[] GetClipboardLines() { var strPasteText = Clipboard.GetText(); - var lines = strPasteText.Split(new[] {"\r\n"}, StringSplitOptions.None); + var lines = strPasteText.Split(new[] + { + "\r\n" + }, StringSplitOptions.None); return RemoveLastLineIfEmpty(lines); } private static string[] RemoveLastLineIfEmpty(string[] lines) { - if (lines[lines.Length-1] == "") + if (lines[lines.Length - 1] == "") { return lines.ToList().Take(lines.Length - 1).ToArray(); } return lines; } - protected static string[] SplitToCells(string p) - { - //tab delimited data: excel, and xtragrid copy (todo think about how to implement pasting of space delimited data) - return p.Split(new[] { "\t" }, StringSplitOptions.None); - } - - public event EventHandler> PasteFailed; - - public event EventHandler PasteFinished; - /// /// Rectangular selection on a tableview. /// protected class RectangleSelection { public RectangleSelection(TableViewCell topLeft, TableViewCell bottomRight) { - Top = topLeft.RowIndex; - Left = topLeft.Column == null? 0 : topLeft.Column.DisplayIndex; + Left = topLeft.Column == null ? 0 : topLeft.Column.DisplayIndex; Bottom = bottomRight.RowIndex; Right = bottomRight.Column == null ? 0 : bottomRight.Column.DisplayIndex; }