Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Data.Views/3.3/StringConvertibleMatrixView.cs @ 3904

Last change on this file since 3904 was 3904, checked in by mkommend, 14 years ago

Added SetEnabledStateOfControls as protected virtual method in !View. Therefore the overloading of OnReadOnlyChanged and OnLockedChanged got obsolete in most views, because the method got called in the !View respectively ContentView. (ticket #1021)

File size: 16.4 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2010 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
4 *
5 * This file is part of HeuristicLab.
6 *
7 * HeuristicLab is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * HeuristicLab is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
19 */
20#endregion
21
22using System;
23using System.ComponentModel;
24using System.Collections.Generic;
25using System.Drawing;
26using System.Linq;
27using System.Windows.Forms;
28using HeuristicLab.Common;
29using HeuristicLab.MainForm;
30using HeuristicLab.MainForm.WindowsForms;
31
32namespace HeuristicLab.Data.Views {
33  [View("StringConvertibleMatrix View")]
34  [Content(typeof(IStringConvertibleMatrix), true)]
35  public partial class StringConvertibleMatrixView : AsynchronousContentView {
36    protected int[] virtualRowIndizes;
37    private List<KeyValuePair<int, SortOrder>> sortedColumnIndizes;
38    private RowComparer rowComparer;
39
40    public new IStringConvertibleMatrix Content {
41      get { return (IStringConvertibleMatrix)base.Content; }
42      set { base.Content = value; }
43    }
44
45    public override bool ReadOnly {
46      get {
47        if ((Content != null) && Content.ReadOnly) return true;
48        return base.ReadOnly;
49      }
50      set { base.ReadOnly = value; }
51    }
52
53    public StringConvertibleMatrixView() {
54      InitializeComponent();
55      errorProvider.SetIconAlignment(rowsTextBox, ErrorIconAlignment.MiddleLeft);
56      errorProvider.SetIconPadding(rowsTextBox, 2);
57      errorProvider.SetIconAlignment(columnsTextBox, ErrorIconAlignment.MiddleLeft);
58      errorProvider.SetIconPadding(columnsTextBox, 2);
59      sortedColumnIndizes = new List<KeyValuePair<int, SortOrder>>();
60      rowComparer = new RowComparer();
61    }
62
63    protected override void DeregisterContentEvents() {
64      Content.ItemChanged -= new EventHandler<EventArgs<int, int>>(Content_ItemChanged);
65      Content.Reset -= new EventHandler(Content_Reset);
66      Content.ColumnNamesChanged -= new EventHandler(Content_ColumnNamesChanged);
67      Content.RowNamesChanged -= new EventHandler(Content_RowNamesChanged);
68      base.DeregisterContentEvents();
69    }
70    protected override void RegisterContentEvents() {
71      base.RegisterContentEvents();
72      Content.ItemChanged += new EventHandler<EventArgs<int, int>>(Content_ItemChanged);
73      Content.Reset += new EventHandler(Content_Reset);
74      Content.ColumnNamesChanged += new EventHandler(Content_ColumnNamesChanged);
75      Content.RowNamesChanged += new EventHandler(Content_RowNamesChanged);
76    }
77
78    protected override void OnContentChanged() {
79      base.OnContentChanged();
80      if (Content == null) {
81        rowsTextBox.Text = "";
82        columnsTextBox.Text = "";
83        dataGridView.Rows.Clear();
84        dataGridView.Columns.Clear();
85        virtualRowIndizes = new int[0];
86      } else
87        UpdateData();
88    }
89
90    protected override void SetEnabledStateOfControls() {
91      base.SetEnabledStateOfControls();
92      rowsTextBox.Enabled = Content != null;
93      columnsTextBox.Enabled = Content != null;
94      dataGridView.Enabled = Content != null;
95      rowsTextBox.ReadOnly = ReadOnly;
96      columnsTextBox.ReadOnly = ReadOnly;
97      dataGridView.ReadOnly = ReadOnly;
98    }
99
100    private void UpdateData() {
101      sortedColumnIndizes.Clear();
102      rowsTextBox.Text = Content.Rows.ToString();
103      rowsTextBox.Enabled = true;
104      columnsTextBox.Text = Content.Columns.ToString();
105      columnsTextBox.Enabled = true;
106      virtualRowIndizes = Enumerable.Range(0, Content.Rows).ToArray();
107      //DataGridViews with Rows but no columns are not allowed !
108      if (Content.Rows == 0 && dataGridView.RowCount != Content.Rows && !Content.ReadOnly)
109        Content.Rows = dataGridView.RowCount;
110      else
111        dataGridView.RowCount = Content.Rows;
112      if (Content.Columns == 0 && dataGridView.ColumnCount != Content.Columns && !Content.ReadOnly)
113        Content.Columns = dataGridView.ColumnCount;
114      else
115        dataGridView.ColumnCount = Content.Columns;
116
117      Sort();
118      UpdateRowHeaders();
119      UpdateColumnHeaders();
120      dataGridView.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.ColumnHeader);
121      dataGridView.AutoResizeRowHeadersWidth(DataGridViewRowHeadersWidthSizeMode.AutoSizeToDisplayedHeaders);
122      dataGridView.Enabled = true;
123    }
124
125    private void UpdateColumnHeaders() {
126      for (int i = 0; i < Content.Columns; i++) {
127        if (Content.ColumnNames.Count() != 0)
128          dataGridView.Columns[i].HeaderText = Content.ColumnNames.ElementAt(i);
129        else
130          dataGridView.Columns[i].HeaderText = "Column " + (i + 1);
131      }
132      dataGridView.Invalidate();
133    }
134
135    private void UpdateRowHeaders() {
136      for (int i = 0; i < dataGridView.RowCount; i++) {
137        if (Content.RowNames.Count() != 0)
138          dataGridView.Rows[i].HeaderCell.Value = Content.RowNames.ElementAt(virtualRowIndizes[i]);
139        else
140          dataGridView.Rows[i].HeaderCell.Value = "Row " + (i + 1);
141      }
142      dataGridView.Invalidate();
143    }
144
145    private void Content_RowNamesChanged(object sender, EventArgs e) {
146      if (InvokeRequired)
147        Invoke(new EventHandler(Content_RowNamesChanged), sender, e);
148      else
149        UpdateRowHeaders();
150    }
151    private void Content_ColumnNamesChanged(object sender, EventArgs e) {
152      if (InvokeRequired)
153        Invoke(new EventHandler(Content_ColumnNamesChanged), sender, e);
154      else
155        UpdateColumnHeaders();
156    }
157    private void Content_ItemChanged(object sender, EventArgs<int, int> e) {
158      if (InvokeRequired)
159        Invoke(new EventHandler<EventArgs<int, int>>(Content_ItemChanged), sender, e);
160      else
161        dataGridView.InvalidateCell(e.Value2, e.Value);
162    }
163    private void Content_Reset(object sender, EventArgs e) {
164      if (InvokeRequired)
165        Invoke(new EventHandler(Content_Reset), sender, e);
166      else
167        UpdateData();
168    }
169
170    #region TextBox Events
171    private void rowsTextBox_Validating(object sender, CancelEventArgs e) {
172      if (ReadOnly || Locked)
173        return;
174      int i = 0;
175      if (!int.TryParse(rowsTextBox.Text, out i) || (i <= 0)) {
176        e.Cancel = true;
177        errorProvider.SetError(rowsTextBox, "Invalid Number of Rows (Valid values are positive integers larger than 0)");
178        rowsTextBox.SelectAll();
179      }
180    }
181    private void rowsTextBox_Validated(object sender, EventArgs e) {
182      if (!Content.ReadOnly) Content.Rows = int.Parse(rowsTextBox.Text);
183      errorProvider.SetError(rowsTextBox, string.Empty);
184    }
185    private void rowsTextBox_KeyDown(object sender, KeyEventArgs e) {
186      if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Return)
187        rowsLabel.Focus();  // set focus on label to validate data
188      if (e.KeyCode == Keys.Escape) {
189        rowsTextBox.Text = Content.Rows.ToString();
190        rowsLabel.Focus();  // set focus on label to validate data
191      }
192    }
193    private void columnsTextBox_Validating(object sender, CancelEventArgs e) {
194      if (ReadOnly || Locked)
195        return;
196      int i = 0;
197      if (!int.TryParse(columnsTextBox.Text, out i) || (i <= 0)) {
198        e.Cancel = true;
199        errorProvider.SetError(columnsTextBox, "Invalid Number of Columns (Valid values are positive integers larger than 0)");
200        columnsTextBox.SelectAll();
201      }
202    }
203    private void columnsTextBox_Validated(object sender, EventArgs e) {
204      if (!Content.ReadOnly) Content.Columns = int.Parse(columnsTextBox.Text);
205      errorProvider.SetError(columnsTextBox, string.Empty);
206    }
207    private void columnsTextBox_KeyDown(object sender, KeyEventArgs e) {
208      if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Return)
209        columnsLabel.Focus();  // set focus on label to validate data
210      if (e.KeyCode == Keys.Escape) {
211        columnsTextBox.Text = Content.Columns.ToString();
212        columnsLabel.Focus();  // set focus on label to validate data
213      }
214    }
215    #endregion
216
217    #region DataGridView Events
218    private void dataGridView_CellValidating(object sender, DataGridViewCellValidatingEventArgs e) {
219      if (!dataGridView.ReadOnly) {
220        string errorMessage;
221        if (!Content.Validate(e.FormattedValue.ToString(), out errorMessage)) {
222          e.Cancel = true;
223          dataGridView.Rows[e.RowIndex].ErrorText = errorMessage;
224        }
225      }
226    }
227    private void dataGridView_CellParsing(object sender, DataGridViewCellParsingEventArgs e) {
228      if (!dataGridView.ReadOnly) {
229        string value = e.Value.ToString();
230        int rowIndex = virtualRowIndizes[e.RowIndex];
231        e.ParsingApplied = Content.SetValue(value, rowIndex, e.ColumnIndex);
232        if (e.ParsingApplied) e.Value = Content.GetValue(rowIndex, e.ColumnIndex);
233      }
234    }
235    private void dataGridView_CellEndEdit(object sender, DataGridViewCellEventArgs e) {
236      dataGridView.Rows[e.RowIndex].ErrorText = string.Empty;
237    }
238    private void dataGridView_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e) {
239      if (e.RowIndex < Content.Rows && e.ColumnIndex < Content.Columns) {
240        int rowIndex = virtualRowIndizes[e.RowIndex];
241        e.Value = Content.GetValue(rowIndex, e.ColumnIndex);
242      }
243    }
244    private void dataGridView_Scroll(object sender, ScrollEventArgs e) {
245      UpdateRowHeaders();
246    }
247    private void dataGridView_Resize(object sender, EventArgs e) {
248      UpdateRowHeaders();
249    }
250
251    private void dataGridView_KeyDown(object sender, KeyEventArgs e) {
252      if (!ReadOnly && e.Control && e.KeyCode == Keys.V) { //shortcut for values paste
253        string[,] values = SplitClipboardString(Clipboard.GetText());
254
255        int rowIndex = 0;
256        int columnIndex = 0;
257        if (dataGridView.CurrentCell != null) {
258          rowIndex = dataGridView.CurrentCell.RowIndex;
259          columnIndex = dataGridView.CurrentCell.ColumnIndex;
260        }
261
262        for (int row = 0; row < values.GetLength(1); row++) {
263          if (row + rowIndex >= Content.Rows)
264            Content.Rows = Content.Rows + 1;
265          for (int col = 0; col < values.GetLength(0); col++) {
266            if (col + columnIndex >= Content.Columns)
267              Content.Columns = Content.Columns + 1;
268            Content.SetValue(values[col, row], row + rowIndex, col + columnIndex);
269          }
270        }
271
272        ClearSorting();
273      }
274    }
275
276    private string[,] SplitClipboardString(string clipboardText) {
277      clipboardText = clipboardText.Remove(clipboardText.Length - Environment.NewLine.Length);  //remove last newline constant
278      string[,] values = null;
279      string[] lines = clipboardText.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
280      string[] cells;
281      for (int i = 0; i < lines.Length; i++) {
282        cells = lines[i].Split('\t');
283        if (values == null)
284          values = new string[cells.Length, lines.Length];
285        for (int j = 0; j < cells.Length; j++)
286          values[j, i] = string.IsNullOrEmpty(cells[j]) ? string.Empty : cells[j];
287      }
288      return values;
289    }
290
291    private void dataGridView_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e) {
292      if (Content != null) {
293        if (e.Button == MouseButtons.Left && Content.SortableView) {
294          bool addToSortedIndizes = (Control.ModifierKeys & Keys.Control) == Keys.Control;
295          SortOrder newSortOrder = SortOrder.Ascending;
296          if (sortedColumnIndizes.Any(x => x.Key == e.ColumnIndex)) {
297            SortOrder oldSortOrder = sortedColumnIndizes.Where(x => x.Key == e.ColumnIndex).First().Value;
298            int enumLength = Enum.GetValues(typeof(SortOrder)).Length;
299            newSortOrder = oldSortOrder = (SortOrder)Enum.Parse(typeof(SortOrder), ((((int)oldSortOrder) + 1) % enumLength).ToString());
300          }
301
302          if (!addToSortedIndizes)
303            sortedColumnIndizes.Clear();
304
305          if (sortedColumnIndizes.Any(x => x.Key == e.ColumnIndex)) {
306            int sortedIndex = sortedColumnIndizes.FindIndex(x => x.Key == e.ColumnIndex);
307            if (newSortOrder != SortOrder.None)
308              sortedColumnIndizes[sortedIndex] = new KeyValuePair<int, SortOrder>(e.ColumnIndex, newSortOrder);
309            else
310              sortedColumnIndizes.RemoveAt(sortedIndex);
311          } else
312            if (newSortOrder != SortOrder.None)
313              sortedColumnIndizes.Add(new KeyValuePair<int, SortOrder>(e.ColumnIndex, newSortOrder));
314          Sort();
315        } else if (e.Button == MouseButtons.Right) {
316          if (Content.ColumnNames.Count() != 0)
317            contextMenu.Show(MousePosition);
318        }
319      }
320    }
321
322    protected void ClearSorting() {
323      virtualRowIndizes = Enumerable.Range(0, Content.Rows).ToArray();
324      sortedColumnIndizes.Clear();
325      UpdateSortGlyph();
326    }
327
328    private void Sort() {
329      virtualRowIndizes = Sort(sortedColumnIndizes);
330      UpdateSortGlyph();
331      UpdateRowHeaders();
332      dataGridView.Invalidate();
333    }
334    protected virtual int[] Sort(IEnumerable<KeyValuePair<int, SortOrder>> sortedColumns) {
335      int[] newSortedIndex = Enumerable.Range(0, Content.Rows).ToArray();
336      if (sortedColumns.Count() != 0) {
337        rowComparer.SortedIndizes = sortedColumns;
338        rowComparer.Matrix = Content;
339        Array.Sort(newSortedIndex, rowComparer);
340      }
341      return newSortedIndex;
342    }
343    private void UpdateSortGlyph() {
344      foreach (DataGridViewColumn col in this.dataGridView.Columns)
345        col.HeaderCell.SortGlyphDirection = SortOrder.None;
346      foreach (KeyValuePair<int, SortOrder> p in sortedColumnIndizes)
347        this.dataGridView.Columns[p.Key].HeaderCell.SortGlyphDirection = p.Value;
348    }
349    #endregion
350
351    public class RowComparer : IComparer<int> {
352      public RowComparer() {
353      }
354
355      private List<KeyValuePair<int, SortOrder>> sortedIndizes;
356      public IEnumerable<KeyValuePair<int, SortOrder>> SortedIndizes {
357        get { return this.sortedIndizes; }
358        set { sortedIndizes = new List<KeyValuePair<int, SortOrder>>(value); }
359      }
360      private IStringConvertibleMatrix matrix;
361      public IStringConvertibleMatrix Matrix {
362        get { return this.matrix; }
363        set { this.matrix = value; }
364      }
365
366      public int Compare(int x, int y) {
367        int result = 0;
368        double double1, double2;
369        DateTime dateTime1, dateTime2;
370        TimeSpan timeSpan1, timeSpan2;
371        string string1, string2;
372
373        if (matrix == null)
374          throw new InvalidOperationException("Could not sort IStringConvertibleMatrix if the matrix member is null.");
375        if (sortedIndizes == null)
376          return 0;
377
378        foreach (KeyValuePair<int, SortOrder> pair in sortedIndizes.Where(p => p.Value != SortOrder.None)) {
379          string1 = matrix.GetValue(x, pair.Key);
380          string2 = matrix.GetValue(y, pair.Key);
381          if (double.TryParse(string1, out double1) && double.TryParse(string2, out double2))
382            result = double1.CompareTo(double2);
383          else if (DateTime.TryParse(string1, out dateTime1) && DateTime.TryParse(string2, out dateTime2))
384            result = dateTime1.CompareTo(dateTime2);
385          else if (TimeSpan.TryParse(string1, out timeSpan1) && TimeSpan.TryParse(string2, out timeSpan2))
386            result = timeSpan1.CompareTo(timeSpan2);
387          else {
388            if (string1 != null)
389              result = string1.CompareTo(string2);
390            else if (string2 != null)
391              result = string2.CompareTo(string1) * -1;
392          }
393          if (pair.Value == SortOrder.Descending)
394            result *= -1;
395          if (result != 0)
396            return result;
397        }
398        return result;
399      }
400    }
401
402    private void ShowHideColumns_Click(object sender, EventArgs e) {
403      new ColumnsVisibilityDialog(this.dataGridView.Columns.Cast<DataGridViewColumn>()).ShowDialog();
404    }
405  }
406}
Note: See TracBrowser for help on using the repository browser.