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

Last change on this file since 3444 was 3444, checked in by mkommend, 12 years ago

reacted on TimeSpans in sorting and added protected virtual Sort method for derived classes (e.g. RunCollectionTabularView) (ticket #968)

File size: 15.1 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    private 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      Caption = "StringConvertibleMatrix View";
56      errorProvider.SetIconAlignment(rowsTextBox, ErrorIconAlignment.MiddleLeft);
57      errorProvider.SetIconPadding(rowsTextBox, 2);
58      errorProvider.SetIconAlignment(columnsTextBox, ErrorIconAlignment.MiddleLeft);
59      errorProvider.SetIconPadding(columnsTextBox, 2);
60      sortedColumnIndizes = new List<KeyValuePair<int, SortOrder>>();
61      rowComparer = new RowComparer();
62    }
63    public StringConvertibleMatrixView(IStringConvertibleMatrix content)
64      : this() {
65      Content = content;
66    }
67
68    protected override void DeregisterContentEvents() {
69      Content.ItemChanged -= new EventHandler<EventArgs<int, int>>(Content_ItemChanged);
70      Content.Reset -= new EventHandler(Content_Reset);
71      Content.ColumnNamesChanged -= new EventHandler(Content_ColumnNamesChanged);
72      Content.RowNamesChanged -= new EventHandler(Content_RowNamesChanged);
73      base.DeregisterContentEvents();
74    }
75    protected override void RegisterContentEvents() {
76      base.RegisterContentEvents();
77      Content.ItemChanged += new EventHandler<EventArgs<int, int>>(Content_ItemChanged);
78      Content.Reset += new EventHandler(Content_Reset);
79      Content.ColumnNamesChanged += new EventHandler(Content_ColumnNamesChanged);
80      Content.RowNamesChanged += new EventHandler(Content_RowNamesChanged);
81    }
82
83    protected override void OnContentChanged() {
84      base.OnContentChanged();
85      if (Content == null) {
86        Caption = "StringConvertibleMatrix View";
87        rowsTextBox.Text = "";
88        columnsTextBox.Text = "";
89        dataGridView.Rows.Clear();
90        dataGridView.Columns.Clear();
91        virtualRowIndizes = new int[0];
92      } else {
93        Caption = "StringConvertibleMatrix (" + Content.GetType().Name + ")";
94        UpdateData();
95      }
96      SetEnabledStateOfControls();
97    }
98    protected override void OnReadOnlyChanged() {
99      base.OnReadOnlyChanged();
100      SetEnabledStateOfControls();
101    }
102    private void SetEnabledStateOfControls() {
103      if (Content == null) {
104        rowsTextBox.Enabled = false;
105        columnsTextBox.Enabled = false;
106        dataGridView.Enabled = false;
107      } else {
108        rowsTextBox.Enabled = true;
109        columnsTextBox.Enabled = true;
110        dataGridView.Enabled = true;
111        rowsTextBox.ReadOnly = ReadOnly;
112        columnsTextBox.ReadOnly = ReadOnly;
113        dataGridView.ReadOnly = ReadOnly;
114      }
115    }
116
117    private void UpdateData() {
118      sortedColumnIndizes.Clear();
119      Sort();
120      rowsTextBox.Text = Content.Rows.ToString();
121      rowsTextBox.Enabled = true;
122      columnsTextBox.Text = Content.Columns.ToString();
123      columnsTextBox.Enabled = true;
124      virtualRowIndizes = Enumerable.Range(0, Content.Rows).ToArray();
125      //DataGridViews with Rows but no columns are not allowed !
126      if (Content.Rows == 0 && dataGridView.RowCount != Content.Rows && !Content.ReadOnly)
127        Content.Rows = dataGridView.RowCount;
128      else
129        dataGridView.RowCount = Content.Rows;
130      if (Content.Columns == 0 && dataGridView.ColumnCount != Content.Columns && !Content.ReadOnly)
131        Content.Columns = dataGridView.ColumnCount;
132      else
133        dataGridView.ColumnCount = Content.Columns;
134
135      UpdateRowHeaders();
136      UpdateColumnHeaders();
137      dataGridView.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.ColumnHeader);
138      dataGridView.AutoResizeRowHeadersWidth(DataGridViewRowHeadersWidthSizeMode.AutoSizeToDisplayedHeaders);
139      dataGridView.Enabled = true;
140    }
141
142    private void UpdateColumnHeaders() {
143      for (int i = 0; i < Content.Columns; i++) {
144        if (Content.ColumnNames.Count() != 0)
145          dataGridView.Columns[i].HeaderText = Content.ColumnNames.ElementAt(i);
146        else
147          dataGridView.Columns[i].HeaderText = "Column " + (i + 1);
148      }
149      dataGridView.Invalidate();
150    }
151
152    private void UpdateRowHeaders() {
153      for (int i = dataGridView.FirstDisplayedScrollingRowIndex; i < dataGridView.FirstDisplayedScrollingRowIndex + dataGridView.DisplayedRowCount(true); i++) {
154        if (Content.RowNames.Count() != 0)
155          dataGridView.Rows[i].HeaderCell.Value = Content.RowNames.ElementAt(i);
156        else
157          dataGridView.Rows[i].HeaderCell.Value = "Row " + (i + 1);
158      }
159      dataGridView.Invalidate();
160    }
161
162    private void Content_RowNamesChanged(object sender, EventArgs e) {
163      if (InvokeRequired)
164        Invoke(new EventHandler(Content_RowNamesChanged), sender, e);
165      else
166        UpdateRowHeaders();
167    }
168    private void Content_ColumnNamesChanged(object sender, EventArgs e) {
169      if (InvokeRequired)
170        Invoke(new EventHandler(Content_ColumnNamesChanged), sender, e);
171      else
172        UpdateColumnHeaders();
173    }
174    private void Content_ItemChanged(object sender, EventArgs<int, int> e) {
175      if (InvokeRequired)
176        Invoke(new EventHandler<EventArgs<int, int>>(Content_ItemChanged), sender, e);
177      else
178        dataGridView.InvalidateCell(e.Value2, e.Value);
179    }
180    private void Content_Reset(object sender, EventArgs e) {
181      if (InvokeRequired)
182        Invoke(new EventHandler(Content_Reset), sender, e);
183      else
184        UpdateData();
185    }
186
187    #region TextBox Events
188    private void rowsTextBox_Validating(object sender, CancelEventArgs e) {
189      int i = 0;
190      if (!int.TryParse(rowsTextBox.Text, out i) || (i <= 0)) {
191        e.Cancel = true;
192        errorProvider.SetError(rowsTextBox, "Invalid Number of Rows (Valid values are positive integers larger than 0)");
193        rowsTextBox.SelectAll();
194      }
195    }
196    private void rowsTextBox_Validated(object sender, EventArgs e) {
197      if (!Content.ReadOnly) Content.Rows = int.Parse(rowsTextBox.Text);
198      errorProvider.SetError(rowsTextBox, string.Empty);
199    }
200    private void rowsTextBox_KeyDown(object sender, KeyEventArgs e) {
201      if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Return)
202        rowsLabel.Focus();  // set focus on label to validate data
203      if (e.KeyCode == Keys.Escape) {
204        rowsTextBox.Text = Content.Rows.ToString();
205        rowsLabel.Focus();  // set focus on label to validate data
206      }
207    }
208    private void columnsTextBox_Validating(object sender, CancelEventArgs e) {
209      int i = 0;
210      if (!int.TryParse(columnsTextBox.Text, out i) || (i <= 0)) {
211        e.Cancel = true;
212        errorProvider.SetError(columnsTextBox, "Invalid Number of Columns (Valid values are positive integers larger than 0)");
213        columnsTextBox.SelectAll();
214      }
215    }
216    private void columnsTextBox_Validated(object sender, EventArgs e) {
217      if (!Content.ReadOnly) Content.Columns = int.Parse(columnsTextBox.Text);
218      errorProvider.SetError(columnsTextBox, string.Empty);
219    }
220    private void columnsTextBox_KeyDown(object sender, KeyEventArgs e) {
221      if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Return)
222        columnsLabel.Focus();  // set focus on label to validate data
223      if (e.KeyCode == Keys.Escape) {
224        columnsTextBox.Text = Content.Columns.ToString();
225        columnsLabel.Focus();  // set focus on label to validate data
226      }
227    }
228    #endregion
229
230    #region DataGridView Events
231    private void dataGridView_CellValidating(object sender, DataGridViewCellValidatingEventArgs e) {
232      if (!dataGridView.ReadOnly) {
233        string errorMessage;
234        if (!Content.Validate(e.FormattedValue.ToString(), out errorMessage)) {
235          e.Cancel = true;
236          dataGridView.Rows[e.RowIndex].ErrorText = errorMessage;
237        }
238      }
239    }
240    private void dataGridView_CellParsing(object sender, DataGridViewCellParsingEventArgs e) {
241      if (!dataGridView.ReadOnly) {
242        string value = e.Value.ToString();
243        int rowIndex = virtualRowIndizes[e.RowIndex];
244        e.ParsingApplied = Content.SetValue(value, rowIndex, e.ColumnIndex);
245        if (e.ParsingApplied) e.Value = Content.GetValue(rowIndex, e.ColumnIndex);
246      }
247    }
248    private void dataGridView_CellEndEdit(object sender, DataGridViewCellEventArgs e) {
249      dataGridView.Rows[e.RowIndex].ErrorText = string.Empty;
250    }
251    private void dataGridView_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e) {
252      if (e.RowIndex < Content.Rows && e.ColumnIndex < Content.Columns) {
253        int rowIndex = virtualRowIndizes[e.RowIndex];
254        e.Value = Content.GetValue(rowIndex, e.ColumnIndex);
255      }
256    }
257    private void dataGridView_Scroll(object sender, ScrollEventArgs e) {
258      UpdateRowHeaders();
259    }
260    private void dataGridView_Resize(object sender, EventArgs e) {
261      UpdateRowHeaders();
262    }
263
264    private void dataGridView_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e) {
265      if (Content != null) {
266        if (e.Button == MouseButtons.Left && Content.SortableView) {
267          bool addToSortedIndizes = (Control.ModifierKeys & Keys.Control) == Keys.Control;
268          SortOrder newSortOrder = SortOrder.Ascending;
269          if (sortedColumnIndizes.Any(x => x.Key == e.ColumnIndex)) {
270            SortOrder oldSortOrder = sortedColumnIndizes.Where(x => x.Key == e.ColumnIndex).First().Value;
271            int enumLength = Enum.GetValues(typeof(SortOrder)).Length;
272            newSortOrder = oldSortOrder = (SortOrder)Enum.Parse(typeof(SortOrder), ((((int)oldSortOrder) + 1) % enumLength).ToString());
273          }
274
275          if (!addToSortedIndizes)
276            sortedColumnIndizes.Clear();
277
278          if (sortedColumnIndizes.Any(x => x.Key == e.ColumnIndex)) {
279            int sortedIndex = sortedColumnIndizes.FindIndex(x => x.Key == e.ColumnIndex);
280            if (newSortOrder != SortOrder.None)
281              sortedColumnIndizes[sortedIndex] = new KeyValuePair<int, SortOrder>(e.ColumnIndex, newSortOrder);
282            else
283              sortedColumnIndizes.RemoveAt(sortedIndex);
284          } else
285            if (newSortOrder != SortOrder.None)
286              sortedColumnIndizes.Add(new KeyValuePair<int, SortOrder>(e.ColumnIndex, newSortOrder));
287          Sort();
288        } else if (e.Button == MouseButtons.Right) {
289          if (Content.ColumnNames.Count() != 0)
290            contextMenu.Show(MousePosition);
291        }
292      }
293    }
294
295    private void Sort() {
296      virtualRowIndizes = Sort(sortedColumnIndizes);
297      UpdateSortGlyph();
298      dataGridView.Invalidate();
299    }
300    protected virtual int[] Sort(IEnumerable<KeyValuePair<int, SortOrder>> sortedColumns) {
301      int[] newSortedIndex = Enumerable.Range(0, Content.Rows).ToArray();
302      if (sortedColumns.Count() != 0) {
303        rowComparer.SortedIndizes = sortedColumns;
304        rowComparer.Matrix = Content;
305        Array.Sort(newSortedIndex, rowComparer);
306      }
307      return newSortedIndex;
308    }
309    private void UpdateSortGlyph() {
310      foreach (DataGridViewColumn col in this.dataGridView.Columns)
311        col.HeaderCell.SortGlyphDirection = SortOrder.None;
312      foreach (KeyValuePair<int, SortOrder> p in sortedColumnIndizes)
313        this.dataGridView.Columns[p.Key].HeaderCell.SortGlyphDirection = p.Value;
314    }
315    #endregion
316
317    public class RowComparer : IComparer<int> {
318      public RowComparer() {
319      }
320
321      private List<KeyValuePair<int, SortOrder>> sortedIndizes;
322      public IEnumerable<KeyValuePair<int, SortOrder>> SortedIndizes {
323        get { return this.sortedIndizes; }
324        set { sortedIndizes = new List<KeyValuePair<int, SortOrder>>(value); }
325      }
326      private IStringConvertibleMatrix matrix;
327      public IStringConvertibleMatrix Matrix {
328        get { return this.matrix; }
329        set { this.matrix = value; }
330      }
331
332      public int Compare(int x, int y) {
333        int result = 0;
334        double double1, double2;
335        DateTime dateTime1, dateTime2;
336        TimeSpan timeSpan1, timeSpan2;
337        string string1, string2;
338
339        if (matrix == null)
340          throw new InvalidOperationException("Could not sort IStringConvertibleMatrix if the matrix member is null.");
341        if (sortedIndizes == null)
342          return 0;
343
344        foreach (KeyValuePair<int, SortOrder> pair in sortedIndizes.Where(p => p.Value != SortOrder.None)) {
345          string1 = matrix.GetValue(x, pair.Key);
346          string2 = matrix.GetValue(y, pair.Key);
347          if (double.TryParse(string1, out double1) && double.TryParse(string2, out double2))
348            result = double1.CompareTo(double2);
349          else if (DateTime.TryParse(string1, out dateTime1) && DateTime.TryParse(string2, out dateTime2))
350            result = dateTime1.CompareTo(dateTime2);
351          else if (TimeSpan.TryParse(string1, out timeSpan1) && TimeSpan.TryParse(string2, out timeSpan2))
352            result = timeSpan1.CompareTo(timeSpan2);
353          else {
354            if (string1 != null)
355              result = string1.CompareTo(string2);
356            else if (string2 != null)
357              result = string2.CompareTo(string1) * -1;
358          }
359          if (pair.Value == SortOrder.Descending)
360            result *= -1;
361          if (result != 0)
362            return result;
363        }
364        return result;
365      }
366    }
367
368    private void ShowHideColumns_Click(object sender, EventArgs e) {
369      new ColumnsVisibilityDialog(this.dataGridView.Columns.Cast<DataGridViewColumn>()).ShowDialog();
370    }
371  }
372}
Note: See TracBrowser for help on using the repository browser.