#region License Information /* HeuristicLab * Copyright (C) 2002-2013 Heuristic and Evolutionary Algorithms Laboratory (HEAL) * * This file is part of HeuristicLab. * * HeuristicLab is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * HeuristicLab is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with HeuristicLab. If not, see . */ #endregion using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Windows.Forms; using HeuristicLab.Data; using HeuristicLab.DataPreprocessing.Filter; using HeuristicLab.MainForm; namespace HeuristicLab.DataPreprocessing.Views { [View("Data Grid Content View")] [Content(typeof(IDataGridContent), true)] public partial class DataGridContentView : CopyOfStringConvertibleMatrixView { private bool notOwnEvent = true; private bool isSearching = false; private SearchAndReplaceDialog findAndReplaceDialog; private IFindPreprocessingItemsIterator searchIterator; private string currentSearchText; private ComparisonOperation currentComparisonOperation; private Tuple currentCell; public new IDataGridContent Content { get { return (IDataGridContent)base.Content; } set { base.Content = value; } } private IList _highlightedRowIndices; public IList HighlightedRowIndices { get { return _highlightedRowIndices; } set { _highlightedRowIndices = value; Refresh(); } } private IDictionary> _highlightedCellsBackground; public IDictionary> HightlightedCellsBackground { get { return _highlightedCellsBackground; } set { _highlightedCellsBackground = value; Refresh(); } } public DataGridContentView() { InitializeComponent(); dataGridView.CellMouseClick += dataGridView_CellMouseClick; dataGridView.CellPainting += new System.Windows.Forms.DataGridViewCellPaintingEventHandler(dataGridView_CellPainting); dataGridView.KeyDown += dataGridView_KeyDown; contextMenuCell.Items.Add(ShowHideColumns); _highlightedRowIndices = new List(); _highlightedCellsBackground = new Dictionary>(); currentCell = null; } protected override void dataGridView_SelectionChanged(object sender, EventArgs e) { if (Content != null) { if (!isSearching) { base.dataGridView_SelectionChanged(sender, e); Content.DataGridLogic.SetSelection(GetSelectedCells()); } } } protected override void OnContentChanged() { base.OnContentChanged(); // ToDo: Temporarily disabled because needs to much performance //DataGridView.AutoResizeColumns(); //DataGridView.AutoResizeRowHeadersWidth(DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders); DataGridView.RowHeadersWidth = 70; if (Content == null && findAndReplaceDialog != null) { findAndReplaceDialog.Close(); } } protected override void RegisterContentEvents() { base.RegisterContentEvents(); Content.Changed += Content_Changed; Content.FilterLogic.FilterChanged += FilterLogic_FilterChanged; } protected override void DeregisterContentEvents() { base.DeregisterContentEvents(); Content.Changed -= Content_Changed; Content.FilterLogic.FilterChanged -= FilterLogic_FilterChanged; } void FilterLogic_FilterChanged(object sender, EventArgs e) { OnContentChanged(); searchIterator = null; if (findAndReplaceDialog != null && !findAndReplaceDialog.IsDisposed) { if (Content.FilterLogic.IsFiltered) { findAndReplaceDialog.DisableReplace(); } else { findAndReplaceDialog.EnableReplace(); } } btnReplace.Enabled = !Content.FilterLogic.IsFiltered; } void Content_Changed(object sender, DataPreprocessingChangedEventArgs e) { if (notOwnEvent) { switch (e.Type) { case DataPreprocessingChangedEventType.ChangeColumn: case DataPreprocessingChangedEventType.ChangeItem: dataGridView.Refresh(); break; default: OnContentChanged(); break; } } searchIterator = null; } protected override void dataGridView_CellValidating(object sender, DataGridViewCellValidatingEventArgs e) { if (!dataGridView.ReadOnly) { string errorMessage; if (Content != null) { if (dataGridView.IsCurrentCellInEditMode && Content.FilterLogic.IsFiltered) { errorMessage = "A filter is active, you cannot modify data. Press ESC to exit edit mode."; } else { Content.DataGridLogic.Validate(e.FormattedValue.ToString(), out errorMessage, e.ColumnIndex); } if (!String.IsNullOrEmpty(errorMessage)) { e.Cancel = true; dataGridView.Rows[e.RowIndex].ErrorText = errorMessage; } } } } protected override void dataGridView_CellParsing(object sender, DataGridViewCellParsingEventArgs e) { triggersOwnEvent(() => base.dataGridView_CellParsing(sender, e)); } protected override void PasteValuesToDataGridView() { triggersOwnEvent(() => base.PasteValuesToDataGridView()); } protected override void SetEnabledStateOfControls() { base.SetEnabledStateOfControls(); rowsTextBox.ReadOnly = true; columnsTextBox.ReadOnly = true; } private void btnApplySort_Click(object sender, System.EventArgs e) { triggersOwnEvent(() => { Content.ManipulationLogic.ReOrderToIndices(virtualRowIndices); OnContentChanged(); }); } private void triggersOwnEvent(Action action) { notOwnEvent = false; action(); notOwnEvent = true; } #region FindAndReplaceDialog private void CreateFindAndReplaceDialog() { if (findAndReplaceDialog == null || findAndReplaceDialog.IsDisposed) { findAndReplaceDialog = new SearchAndReplaceDialog(); findAndReplaceDialog.Show(this); if (AreMultipleCellsSelected()) { ResetHighlightedCellsBackground(); HightlightedCellsBackground = GetSelectedCells(); dataGridView.ClearSelection(); } findAndReplaceDialog.FindAllEvent += findAndReplaceDialog_FindAllEvent; findAndReplaceDialog.FindNextEvent += findAndReplaceDialog_FindNextEvent; findAndReplaceDialog.ReplaceAllEvent += findAndReplaceDialog_ReplaceAllEvent; findAndReplaceDialog.ReplaceNextEvent += findAndReplaceDialog_ReplaceEvent; findAndReplaceDialog.FormClosing += findAndReplaceDialog_FormClosing; searchIterator = null; DataGridView.SelectionChanged += DataGridView_SelectionChanged_FindAndReplace; if (Content.FilterLogic.IsFiltered) { findAndReplaceDialog.DisableReplace(); } } } private void DataGridView_SelectionChanged_FindAndReplace(object sender, EventArgs e) { if (Content != null) { if (!isSearching && AreMultipleCellsSelected()) { ResetHighlightedCellsBackground(); HightlightedCellsBackground = GetSelectedCells(); searchIterator = null; } } } void findAndReplaceDialog_FormClosing(object sender, FormClosingEventArgs e) { ResetHighlightedCellsBackground(); searchIterator = null; DataGridView.SelectionChanged -= DataGridView_SelectionChanged_FindAndReplace; } void findAndReplaceDialog_ReplaceEvent(object sender, EventArgs e) { if (searchIterator != null && searchIterator.GetCurrent() != null) { Replace(TransformToDictionary(currentCell)); } } void findAndReplaceDialog_ReplaceAllEvent(object sender, EventArgs e) { Replace(FindAll(findAndReplaceDialog.GetSearchText())); } void findAndReplaceDialog_FindNextEvent(object sender, EventArgs e) { if (searchIterator == null || currentSearchText != findAndReplaceDialog.GetSearchText() || currentComparisonOperation != findAndReplaceDialog.GetComparisonOperation()) { searchIterator = new FindPreprocessingItemsIterator(FindAll(findAndReplaceDialog.GetSearchText())); currentSearchText = findAndReplaceDialog.GetSearchText(); currentComparisonOperation = findAndReplaceDialog.GetComparisonOperation(); } if (IsOneCellSelected()) { var first = GetSelectedCells().First(); searchIterator.SetStartCell(first.Key, first.Value[0]); } bool moreOccurences = false; currentCell = searchIterator.GetCurrent(); moreOccurences = searchIterator.MoveNext(); if (IsOneCellSelected() && currentCell != null) { var first = GetSelectedCells().First(); if (currentCell.Item1 == first.Key && currentCell.Item2 == first.Value[0]) { if (!moreOccurences) { searchIterator.Reset(); } currentCell = searchIterator.GetCurrent(); moreOccurences = searchIterator.MoveNext(); if (!moreOccurences) { searchIterator.Reset(); } } } dataGridView.ClearSelection(); if (currentCell != null) { dataGridView[currentCell.Item1, currentCell.Item2].Selected = true; } } private bool AreMultipleCellsSelected() { return GetSelectedCellCount() > 1; } private bool IsOneCellSelected() { return GetSelectedCellCount() == 1; } private int GetSelectedCellCount() { int count = 0; foreach (var column in GetSelectedCells()) { count += column.Value.Count(); } return count; } void findAndReplaceDialog_FindAllEvent(object sender, EventArgs e) { dataGridView.ClearSelection(); isSearching = true; SuspendRepaint(); var selectedCells = FindAll(findAndReplaceDialog.GetSearchText()); foreach (var column in selectedCells) { foreach (var cell in column.Value) { dataGridView[column.Key, cell].Selected = true; } } ResumeRepaint(true); isSearching = false; Content.DataGridLogic.SetSelection(selectedCells); //update statistic in base base.dataGridView_SelectionChanged(sender, e); } private Core.ConstraintOperation GetConstraintOperation(ComparisonOperation comparisonOperation) { Core.ConstraintOperation constraintOperation = Core.ConstraintOperation.Equal; switch (comparisonOperation) { case ComparisonOperation.Equal: constraintOperation = Core.ConstraintOperation.Equal; break; case ComparisonOperation.Greater: constraintOperation = Core.ConstraintOperation.Greater; break; case ComparisonOperation.GreaterOrEqual: constraintOperation = Core.ConstraintOperation.GreaterOrEqual; break; case ComparisonOperation.Less: constraintOperation = Core.ConstraintOperation.Less; break; case ComparisonOperation.LessOrEqual: constraintOperation = Core.ConstraintOperation.LessOrEqual; break; case ComparisonOperation.NotEqual: constraintOperation = Core.ConstraintOperation.NotEqual; break; } return constraintOperation; } private IDictionary> FindAll(string match) { bool searchInSelection = HightlightedCellsBackground.Values.Sum(list => list.Count) > 1; ComparisonOperation comparisonOperation = findAndReplaceDialog.GetComparisonOperation(); var comparisonFilter = new ComparisonFilter(Content.FilterLogic.PreprocessingData, GetConstraintOperation(comparisonOperation), new StringValue(match), true); var filters = new List() { comparisonFilter }; var foundCells = new Dictionary>(); for (int i = 0; i < Content.FilterLogic.PreprocessingData.Columns; i++) { comparisonFilter.ConstraintColumn = i; bool[] filteredRows = Content.FilterLogic.GetFilterResult(filters, true); var foundIndices = new List(); for (int idx = 0; idx < filteredRows.Length; ++idx) { var notFilteredThusFound = !filteredRows[idx]; if (notFilteredThusFound) { foundIndices.Add(idx); } } foundCells[i] = foundIndices; IList selectedList; if (searchInSelection && HightlightedCellsBackground.TryGetValue(i, out selectedList)) { foundCells[i] = foundCells[i].Intersect(selectedList).ToList(); } else if (searchInSelection) { foundCells[i].Clear(); } } return foundCells; } private void Replace(IDictionary> cells) { if (findAndReplaceDialog != null) { switch (findAndReplaceDialog.GetReplaceAction()) { case ReplaceAction.Value: Content.ManipulationLogic.ReplaceIndicesByValue(cells, findAndReplaceDialog.GetReplaceText()); break; case ReplaceAction.Average: Content.ManipulationLogic.ReplaceIndicesByAverageValue(cells, false); break; case ReplaceAction.Median: Content.ManipulationLogic.ReplaceIndicesByMedianValue(cells, false); break; case ReplaceAction.Random: Content.ManipulationLogic.ReplaceIndicesByRandomValue(cells, false); break; case ReplaceAction.MostCommon: Content.ManipulationLogic.ReplaceIndicesByMostCommonValue(cells, false); break; case ReplaceAction.Interpolation: Content.ManipulationLogic.ReplaceIndicesByLinearInterpolationOfNeighbours(cells); break; } } } private IDictionary> TransformToDictionary(Tuple tuple) { var highlightCells = new Dictionary>(); highlightCells.Add(tuple.Item1, new List() { tuple.Item2 }); return highlightCells; } private void ResetHighlightedCellsBackground() { HightlightedCellsBackground = new Dictionary>(); } #endregion FindAndReplaceDialog private void dataGridView_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e) { if (Content == null) return; if (e.Button == System.Windows.Forms.MouseButtons.Right) { if (e.ColumnIndex == -1 || e.RowIndex == -1) { replaceValueOverColumnToolStripMenuItem.Visible = false; contextMenuCell.Show(MousePosition); } else { if (!dataGridView.SelectedCells.Contains(dataGridView[e.ColumnIndex, e.RowIndex])) { dataGridView.ClearSelection(); dataGridView[e.ColumnIndex, e.RowIndex].Selected = true; } var columnIndices = new HashSet(); for (int i = 0; i < dataGridView.SelectedCells.Count; i++) { columnIndices.Add(dataGridView.SelectedCells[i].ColumnIndex); } replaceValueOverSelectionToolStripMenuItem.Enabled = AreMultipleCellsSelected(); averageToolStripMenuItem_Column.Enabled = averageToolStripMenuItem_Selection.Enabled = medianToolStripMenuItem_Column.Enabled = medianToolStripMenuItem_Selection.Enabled = randomToolStripMenuItem_Column.Enabled = randomToolStripMenuItem_Selection.Enabled = !Content.DataGridLogic.AreAllStringColumns(columnIndices); smoothingToolStripMenuItem_Column.Enabled = interpolationToolStripMenuItem_Column.Enabled = !dataGridView.SelectedCells.Contains(dataGridView[e.ColumnIndex, 0]) && !dataGridView.SelectedCells.Contains(dataGridView[e.ColumnIndex, Content.Rows - 1]) && !Content.DataGridLogic.AreAllStringColumns(columnIndices); replaceValueOverColumnToolStripMenuItem.Visible = true; contextMenuCell.Show(MousePosition); } } } protected void dataGridView_CellPainting(object sender, DataGridViewCellPaintingEventArgs e) { if (Content == null) return; if (e.RowIndex < 0) return; if (e.ColumnIndex < 0) return; if (e.State.HasFlag(DataGridViewElementStates.Selected)) return; if (!e.PaintParts.HasFlag(DataGridViewPaintParts.Background)) return; if (HighlightedRowIndices == null) return; int rowIndex = virtualRowIndices[e.RowIndex]; Color backColor = e.CellStyle.BackColor; if (HightlightedCellsBackground.ContainsKey(e.ColumnIndex) && HightlightedCellsBackground[e.ColumnIndex].Contains(e.RowIndex)) { backColor = Color.LightGray; } using (Brush backColorBrush = new SolidBrush(backColor)) { Rectangle bounds = new Rectangle(e.CellBounds.X, e.CellBounds.Y, e.CellBounds.Width, e.CellBounds.Height); e.Graphics.FillRectangle(backColorBrush, bounds); } using (Brush gridBrush = new SolidBrush(Color.LightGray)) { Pen gridLinePen = new Pen(gridBrush); e.Graphics.DrawLine(gridLinePen, e.CellBounds.Left, e.CellBounds.Bottom - 1, e.CellBounds.Right - 1, e.CellBounds.Bottom - 1); e.Graphics.DrawLine(gridLinePen, e.CellBounds.Right - 1, e.CellBounds.Top, e.CellBounds.Right - 1, e.CellBounds.Bottom); } e.PaintContent(e.CellBounds); e.Handled = true; } void dataGridView_KeyDown(object sender, KeyEventArgs e) { var selectedRows = dataGridView.SelectedRows; if (e.KeyCode == Keys.Delete && selectedRows.Count > 0) { List rows = new List(); for (int i = 0; i < selectedRows.Count; ++i) { rows.Add(selectedRows[i].Index); } triggersOwnEvent(() => { Content.DataGridLogic.DeleteRow(rows); OnContentChanged(); }); } else if (e.Control && e.KeyCode == Keys.F) { CreateFindAndReplaceDialog(); findAndReplaceDialog.ActivateSearch(); } else if (e.Control && e.KeyCode == Keys.R) { CreateFindAndReplaceDialog(); findAndReplaceDialog.ActivateReplace(); } } protected override int[] Sort(IEnumerable> sortedColumns) { btnApplySort.Enabled = sortedColumns.Any(); return base.Sort(sortedColumns); } protected override void ClearSorting() { btnApplySort.Enabled = false; base.ClearSorting(); } private IDictionary> GetSelectedCells() { IDictionary> selectedCells = new Dictionary>(); for (int i = 0; i < dataGridView.SelectedCells.Count; i++) { var columnIndex = dataGridView.SelectedCells[i].ColumnIndex; if (!selectedCells.ContainsKey(columnIndex)) { selectedCells.Add(columnIndex, new List()); } selectedCells[columnIndex].Add(dataGridView.SelectedCells[i].RowIndex); } return selectedCells; } private void ReplaceWithAverage_Column_Click(object sender, EventArgs e) { Content.ManipulationLogic.ReplaceIndicesByAverageValue(GetSelectedCells(), false); } private void ReplaceWithAverage_Selection_Click(object sender, EventArgs e) { Content.ManipulationLogic.ReplaceIndicesByAverageValue(GetSelectedCells(), true); } private void ReplaceWithMedian_Column_Click(object sender, EventArgs e) { Content.ManipulationLogic.ReplaceIndicesByMedianValue(GetSelectedCells(), false); } private void ReplaceWithMedian_Selection_Click(object sender, EventArgs e) { Content.ManipulationLogic.ReplaceIndicesByMedianValue(GetSelectedCells(), true); } private void ReplaceWithRandom_Column_Click(object sender, EventArgs e) { Content.ManipulationLogic.ReplaceIndicesByRandomValue(GetSelectedCells(), false); } private void ReplaceWithRandom_Selection_Click(object sender, EventArgs e) { Content.ManipulationLogic.ReplaceIndicesByRandomValue(GetSelectedCells(), true); } private void ReplaceWithMostCommon_Column_Click(object sender, EventArgs e) { Content.ManipulationLogic.ReplaceIndicesByMostCommonValue(GetSelectedCells(), false); } private void ReplaceWithMostCommon_Selection_Click(object sender, EventArgs e) { Content.ManipulationLogic.ReplaceIndicesByMostCommonValue(GetSelectedCells(), true); } private void ReplaceWithInterpolation_Column_Click(object sender, EventArgs e) { Content.ManipulationLogic.ReplaceIndicesByLinearInterpolationOfNeighbours(GetSelectedCells()); } private void ReplaceWithSmoothing_Selection_Click(object sender, EventArgs e) { Content.ManipulationLogic.ReplaceIndicesBySmoothing(GetSelectedCells()); } private void btnSearch_Click(object sender, EventArgs e) { CreateFindAndReplaceDialog(); findAndReplaceDialog.ActivateSearch(); } private void btnReplace_Click(object sender, EventArgs e) { CreateFindAndReplaceDialog(); findAndReplaceDialog.ActivateReplace(); } } }