Free cookie consent management tool by TermsFeed Policy Generator

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

Last change on this file since 4652 was 4652, checked in by mkommend, 13 years ago

Added statistical information to the RunCollectionBoxPlotView and corrected minor bugs in the 'RunCollectionBubbleChartView' and the 'RunCollectionBoxPlotView' (ticket #1135).

File size: 20.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.Collections.Generic;
24using System.ComponentModel;
25using System.Drawing;
26using System.Linq;
27using System.Text;
28using System.Windows.Forms;
29using HeuristicLab.Common;
30using HeuristicLab.MainForm;
31using HeuristicLab.MainForm.WindowsForms;
32
33namespace HeuristicLab.Data.Views {
34  [View("StringConvertibleMatrix View")]
35  [Content(typeof(IStringConvertibleMatrix), true)]
36  public partial class StringConvertibleMatrixView : AsynchronousContentView {
37    private int[] virtualRowIndizes;
38    private List<KeyValuePair<int, SortOrder>> sortedColumnIndizes;
39    private RowComparer rowComparer;
40
41    public new IStringConvertibleMatrix Content {
42      get { return (IStringConvertibleMatrix)base.Content; }
43      set { base.Content = value; }
44    }
45
46    public override bool ReadOnly {
47      get {
48        if ((Content != null) && Content.ReadOnly) return true;
49        return base.ReadOnly;
50      }
51      set { base.ReadOnly = value; }
52    }
53
54    private bool showRowsAndColumnsTextBox;
55    public bool ShowRowsAndColumnsTextBox {
56      get { return showRowsAndColumnsTextBox; }
57      set {
58        if (value != showRowsAndColumnsTextBox) {
59          showRowsAndColumnsTextBox = value;
60          UpdateVisibilityOfTextBoxes();
61        }
62      }
63    }
64
65    public StringConvertibleMatrixView() {
66      InitializeComponent();
67      showRowsAndColumnsTextBox = true;
68      errorProvider.SetIconAlignment(rowsTextBox, ErrorIconAlignment.MiddleLeft);
69      errorProvider.SetIconPadding(rowsTextBox, 2);
70      errorProvider.SetIconAlignment(columnsTextBox, ErrorIconAlignment.MiddleLeft);
71      errorProvider.SetIconPadding(columnsTextBox, 2);
72      sortedColumnIndizes = new List<KeyValuePair<int, SortOrder>>();
73      rowComparer = new RowComparer();
74    }
75
76    protected override void DeregisterContentEvents() {
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      base.DeregisterContentEvents();
82    }
83    protected override void RegisterContentEvents() {
84      base.RegisterContentEvents();
85      Content.ItemChanged += new EventHandler<EventArgs<int, int>>(Content_ItemChanged);
86      Content.Reset += new EventHandler(Content_Reset);
87      Content.ColumnNamesChanged += new EventHandler(Content_ColumnNamesChanged);
88      Content.RowNamesChanged += new EventHandler(Content_RowNamesChanged);
89    }
90
91    protected override void OnContentChanged() {
92      base.OnContentChanged();
93      if (Content == null) {
94        rowsTextBox.Text = "";
95        columnsTextBox.Text = "";
96        dataGridView.Rows.Clear();
97        dataGridView.Columns.Clear();
98        virtualRowIndizes = new int[0];
99      } else
100        UpdateData();
101    }
102
103    protected override void SetEnabledStateOfControls() {
104      base.SetEnabledStateOfControls();
105      rowsTextBox.Enabled = Content != null;
106      columnsTextBox.Enabled = Content != null;
107      dataGridView.Enabled = Content != null;
108      rowsTextBox.ReadOnly = ReadOnly;
109      columnsTextBox.ReadOnly = ReadOnly;
110      dataGridView.ReadOnly = ReadOnly;
111    }
112
113    private void UpdateData() {
114      rowsTextBox.Text = Content.Rows.ToString();
115      rowsTextBox.Enabled = true;
116      columnsTextBox.Text = Content.Columns.ToString();
117      columnsTextBox.Enabled = true;
118      //DataGridViews with rows but no columns are not allowed !
119      if (Content.Rows == 0 && dataGridView.RowCount != Content.Rows && !Content.ReadOnly)
120        Content.Rows = dataGridView.RowCount;
121      else
122        dataGridView.RowCount = Content.Rows;
123      if (Content.Columns == 0 && dataGridView.ColumnCount != Content.Columns && !Content.ReadOnly)
124        Content.Columns = dataGridView.ColumnCount;
125      else
126        dataGridView.ColumnCount = Content.Columns;
127      ClearSorting();
128
129      UpdateColumnHeaders();
130      UpdateRowHeaders();
131      dataGridView.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.ColumnHeader);
132      dataGridView.AutoResizeRowHeadersWidth(DataGridViewRowHeadersWidthSizeMode.AutoSizeToDisplayedHeaders);
133      dataGridView.Enabled = true;
134    }
135
136    protected void UpdateColumnHeaders() {
137      for (int i = 0; i < dataGridView.ColumnCount; i++) {
138        if (Content.ColumnNames.Count() != 0)
139          dataGridView.Columns[i].HeaderText = Content.ColumnNames.ElementAt(i);
140        else
141          dataGridView.Columns[i].HeaderText = "Column " + (i + 1);
142      }
143    }
144    protected void UpdateRowHeaders() {
145      int index = dataGridView.FirstDisplayedScrollingRowIndex;
146      if (index == -1) index = 0;
147      int updatedRows = 0;
148      int count = dataGridView.DisplayedRowCount(true);
149
150      while (updatedRows < count) {
151        if (Content.RowNames.Count() != 0)
152          dataGridView.Rows[index].HeaderCell.Value = Content.RowNames.ElementAt(virtualRowIndizes[index]);
153        else
154          dataGridView.Rows[index].HeaderCell.Value = "Row " + (index + 1);
155        if (dataGridView.Rows[index].Visible)
156          updatedRows++;
157        index++;
158      }
159    }
160
161    private void Content_RowNamesChanged(object sender, EventArgs e) {
162      if (InvokeRequired)
163        Invoke(new EventHandler(Content_RowNamesChanged), sender, e);
164      else
165        UpdateRowHeaders();
166    }
167    private void Content_ColumnNamesChanged(object sender, EventArgs e) {
168      if (InvokeRequired)
169        Invoke(new EventHandler(Content_ColumnNamesChanged), sender, e);
170      else
171        UpdateColumnHeaders();
172    }
173    private void Content_ItemChanged(object sender, EventArgs<int, int> e) {
174      if (InvokeRequired)
175        Invoke(new EventHandler<EventArgs<int, int>>(Content_ItemChanged), sender, e);
176      else
177        dataGridView.InvalidateCell(e.Value2, e.Value);
178    }
179    private void Content_Reset(object sender, EventArgs e) {
180      if (InvokeRequired)
181        Invoke(new EventHandler(Content_Reset), sender, e);
182      else
183        UpdateData();
184    }
185
186    #region TextBox Events
187    private void rowsTextBox_Validating(object sender, CancelEventArgs e) {
188      if (ReadOnly || Locked)
189        return;
190      int i = 0;
191      if (!int.TryParse(rowsTextBox.Text, out i) || (i <= 0)) {
192        e.Cancel = true;
193        errorProvider.SetError(rowsTextBox, "Invalid Number of Rows (Valid values are positive integers larger than 0)");
194        rowsTextBox.SelectAll();
195      }
196    }
197    private void rowsTextBox_Validated(object sender, EventArgs e) {
198      if (!Content.ReadOnly) Content.Rows = int.Parse(rowsTextBox.Text);
199      errorProvider.SetError(rowsTextBox, string.Empty);
200    }
201    private void rowsTextBox_KeyDown(object sender, KeyEventArgs e) {
202      if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Return)
203        rowsLabel.Focus();  // set focus on label to validate data
204      if (e.KeyCode == Keys.Escape) {
205        rowsTextBox.Text = Content.Rows.ToString();
206        rowsLabel.Focus();  // set focus on label to validate data
207      }
208    }
209    private void columnsTextBox_Validating(object sender, CancelEventArgs e) {
210      if (ReadOnly || Locked)
211        return;
212      int i = 0;
213      if (!int.TryParse(columnsTextBox.Text, out i) || (i <= 0)) {
214        e.Cancel = true;
215        errorProvider.SetError(columnsTextBox, "Invalid Number of Columns (Valid values are positive integers larger than 0)");
216        columnsTextBox.SelectAll();
217      }
218    }
219    private void columnsTextBox_Validated(object sender, EventArgs e) {
220      if (!Content.ReadOnly) Content.Columns = int.Parse(columnsTextBox.Text);
221      errorProvider.SetError(columnsTextBox, string.Empty);
222    }
223    private void columnsTextBox_KeyDown(object sender, KeyEventArgs e) {
224      if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Return)
225        columnsLabel.Focus();  // set focus on label to validate data
226      if (e.KeyCode == Keys.Escape) {
227        columnsTextBox.Text = Content.Columns.ToString();
228        columnsLabel.Focus();  // set focus on label to validate data
229      }
230    }
231    #endregion
232
233    #region DataGridView Events
234    private void dataGridView_CellValidating(object sender, DataGridViewCellValidatingEventArgs e) {
235      if (!dataGridView.ReadOnly) {
236        string errorMessage;
237        if (Content != null && !Content.Validate(e.FormattedValue.ToString(), out errorMessage)) {
238          e.Cancel = true;
239          dataGridView.Rows[e.RowIndex].ErrorText = errorMessage;
240        }
241      }
242    }
243    private void dataGridView_CellParsing(object sender, DataGridViewCellParsingEventArgs e) {
244      if (!dataGridView.ReadOnly) {
245        string value = e.Value.ToString();
246        int rowIndex = virtualRowIndizes[e.RowIndex];
247        e.ParsingApplied = Content.SetValue(value, rowIndex, e.ColumnIndex);
248        if (e.ParsingApplied) e.Value = Content.GetValue(rowIndex, e.ColumnIndex);
249      }
250    }
251    private void dataGridView_CellEndEdit(object sender, DataGridViewCellEventArgs e) {
252      dataGridView.Rows[e.RowIndex].ErrorText = string.Empty;
253    }
254    private void dataGridView_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e) {
255      if (Content != null && e.RowIndex < Content.Rows && e.ColumnIndex < Content.Columns) {
256        int rowIndex = virtualRowIndizes[e.RowIndex];
257        e.Value = Content.GetValue(rowIndex, e.ColumnIndex);
258      }
259    }
260
261    private void dataGridView_Scroll(object sender, System.Windows.Forms.ScrollEventArgs e) {
262      this.UpdateRowHeaders();
263    }
264    private void dataGridView_Resize(object sender, EventArgs e) {
265      this.UpdateRowHeaders();
266    }
267
268    private void dataGridView_KeyDown(object sender, KeyEventArgs e) {
269      if (!ReadOnly && e.Control && e.KeyCode == Keys.V)
270        PasteValuesToDataGridView();
271      else if (e.Control && e.KeyCode == Keys.C)
272        CopyValuesFromDataGridView();
273    }
274
275    private void CopyValuesFromDataGridView() {
276      if (dataGridView.SelectedCells.Count == 0) return;
277      StringBuilder s = new StringBuilder();
278      int minRowIndex = dataGridView.SelectedCells[0].RowIndex;
279      int maxRowIndex = dataGridView.SelectedCells[dataGridView.SelectedCells.Count - 1].RowIndex;
280      int minColIndex = dataGridView.SelectedCells[0].ColumnIndex;
281      int maxColIndex = dataGridView.SelectedCells[dataGridView.SelectedCells.Count - 1].ColumnIndex;
282
283      if (minRowIndex > maxRowIndex) {
284        int temp = minRowIndex;
285        minRowIndex = maxRowIndex;
286        maxRowIndex = temp;
287      }
288      if (minColIndex > maxColIndex) {
289        int temp = minColIndex;
290        minColIndex = maxColIndex;
291        maxColIndex = temp;
292      }
293
294      bool addRowNames = dataGridView.AreAllCellsSelected(false) && Content.RowNames.Count() > 0;
295      bool addColumnNames = dataGridView.AreAllCellsSelected(false) && Content.ColumnNames.Count() > 0;
296
297      //add colum names
298      if (addColumnNames) {
299        if (addRowNames)
300          s.Append('\t');
301
302        DataGridViewColumn column = dataGridView.Columns.GetFirstColumn(DataGridViewElementStates.Visible);
303        while (column != null) {
304          s.Append(column.HeaderText);
305          s.Append('\t');
306          column = dataGridView.Columns.GetNextColumn(column, DataGridViewElementStates.Visible, DataGridViewElementStates.None);
307        }
308        s.Remove(s.Length - 1, 1); //remove last tab
309        s.Append(Environment.NewLine);
310      }
311
312      for (int i = minRowIndex; i <= maxRowIndex; i++) {
313        int rowIndex = this.virtualRowIndizes[i];
314        if (addRowNames) {
315          s.Append(Content.RowNames.ElementAt(rowIndex));
316          s.Append('\t');
317        }
318
319        DataGridViewColumn column = dataGridView.Columns.GetFirstColumn(DataGridViewElementStates.Visible);
320        while (column != null) {
321          DataGridViewCell cell = dataGridView[column.Index, i];
322          if (cell.Selected) {
323            s.Append(Content.GetValue(rowIndex, column.Index));
324            s.Append('\t');
325          }
326
327          column = dataGridView.Columns.GetNextColumn(column, DataGridViewElementStates.Visible, DataGridViewElementStates.None);
328        }
329        s.Remove(s.Length - 1, 1); //remove last tab
330        s.Append(Environment.NewLine);
331      }
332      Clipboard.SetText(s.ToString());
333    }
334
335    private void PasteValuesToDataGridView() {
336      string[,] values = SplitClipboardString(Clipboard.GetText());
337      int rowIndex = 0;
338      int columnIndex = 0;
339      if (dataGridView.CurrentCell != null) {
340        rowIndex = dataGridView.CurrentCell.RowIndex;
341        columnIndex = dataGridView.CurrentCell.ColumnIndex;
342      }
343
344      for (int row = 0; row < values.GetLength(1); row++) {
345        if (row + rowIndex >= Content.Rows)
346          Content.Rows = Content.Rows + 1;
347        for (int col = 0; col < values.GetLength(0); col++) {
348          if (col + columnIndex >= Content.Columns)
349            Content.Columns = Content.Columns + 1;
350          Content.SetValue(values[col, row], row + rowIndex, col + columnIndex);
351        }
352      }
353      ClearSorting();
354    }
355    private string[,] SplitClipboardString(string clipboardText) {
356      clipboardText = clipboardText.Remove(clipboardText.Length - Environment.NewLine.Length);  //remove last newline constant
357      string[,] values = null;
358      string[] lines = clipboardText.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
359      string[] cells;
360      for (int i = 0; i < lines.Length; i++) {
361        cells = lines[i].Split('\t');
362        if (values == null)
363          values = new string[cells.Length, lines.Length];
364        for (int j = 0; j < cells.Length; j++)
365          values[j, i] = string.IsNullOrEmpty(cells[j]) ? string.Empty : cells[j];
366      }
367      return values;
368    }
369
370    private void dataGridView_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e) {
371      if (Content != null) {
372        if (e.Button == MouseButtons.Left && Content.SortableView) {
373          bool addToSortedIndizes = (Control.ModifierKeys & Keys.Control) == Keys.Control;
374          SortOrder newSortOrder = SortOrder.Ascending;
375          if (sortedColumnIndizes.Any(x => x.Key == e.ColumnIndex)) {
376            SortOrder oldSortOrder = sortedColumnIndizes.Where(x => x.Key == e.ColumnIndex).First().Value;
377            int enumLength = Enum.GetValues(typeof(SortOrder)).Length;
378            newSortOrder = oldSortOrder = (SortOrder)Enum.Parse(typeof(SortOrder), ((((int)oldSortOrder) + 1) % enumLength).ToString());
379          }
380
381          if (!addToSortedIndizes)
382            sortedColumnIndizes.Clear();
383
384          if (sortedColumnIndizes.Any(x => x.Key == e.ColumnIndex)) {
385            int sortedIndex = sortedColumnIndizes.FindIndex(x => x.Key == e.ColumnIndex);
386            if (newSortOrder != SortOrder.None)
387              sortedColumnIndizes[sortedIndex] = new KeyValuePair<int, SortOrder>(e.ColumnIndex, newSortOrder);
388            else
389              sortedColumnIndizes.RemoveAt(sortedIndex);
390          } else
391            if (newSortOrder != SortOrder.None)
392              sortedColumnIndizes.Add(new KeyValuePair<int, SortOrder>(e.ColumnIndex, newSortOrder));
393          Sort();
394        }
395      }
396    }
397
398    protected virtual void ClearSorting() {
399      virtualRowIndizes = Enumerable.Range(0, Content.Rows).ToArray();
400      sortedColumnIndizes.Clear();
401      UpdateSortGlyph();
402    }
403
404    private void Sort() {
405      virtualRowIndizes = Sort(sortedColumnIndizes);
406      UpdateSortGlyph();
407      UpdateRowHeaders();
408      dataGridView.Invalidate();
409    }
410    protected virtual int[] Sort(IEnumerable<KeyValuePair<int, SortOrder>> sortedColumns) {
411      int[] newSortedIndex = Enumerable.Range(0, Content.Rows).ToArray();
412      if (sortedColumns.Count() != 0) {
413        rowComparer.SortedIndizes = sortedColumns;
414        rowComparer.Matrix = Content;
415        Array.Sort(newSortedIndex, rowComparer);
416      }
417      return newSortedIndex;
418    }
419    private void UpdateSortGlyph() {
420      foreach (DataGridViewColumn col in this.dataGridView.Columns)
421        col.HeaderCell.SortGlyphDirection = SortOrder.None;
422      foreach (KeyValuePair<int, SortOrder> p in sortedColumnIndizes)
423        this.dataGridView.Columns[p.Key].HeaderCell.SortGlyphDirection = p.Value;
424    }
425    #endregion
426
427    public class RowComparer : IComparer<int> {
428      public RowComparer() {
429      }
430
431      private List<KeyValuePair<int, SortOrder>> sortedIndizes;
432      public IEnumerable<KeyValuePair<int, SortOrder>> SortedIndizes {
433        get { return this.sortedIndizes; }
434        set { sortedIndizes = new List<KeyValuePair<int, SortOrder>>(value); }
435      }
436      private IStringConvertibleMatrix matrix;
437      public IStringConvertibleMatrix Matrix {
438        get { return this.matrix; }
439        set { this.matrix = value; }
440      }
441
442      public int Compare(int x, int y) {
443        int result = 0;
444        double double1, double2;
445        DateTime dateTime1, dateTime2;
446        TimeSpan timeSpan1, timeSpan2;
447        string string1, string2;
448
449        if (matrix == null)
450          throw new InvalidOperationException("Could not sort IStringConvertibleMatrix if the matrix member is null.");
451        if (sortedIndizes == null)
452          return 0;
453
454        foreach (KeyValuePair<int, SortOrder> pair in sortedIndizes.Where(p => p.Value != SortOrder.None)) {
455          string1 = matrix.GetValue(x, pair.Key);
456          string2 = matrix.GetValue(y, pair.Key);
457          if (double.TryParse(string1, out double1) && double.TryParse(string2, out double2))
458            result = double1.CompareTo(double2);
459          else if (DateTime.TryParse(string1, out dateTime1) && DateTime.TryParse(string2, out dateTime2))
460            result = dateTime1.CompareTo(dateTime2);
461          else if (TimeSpan.TryParse(string1, out timeSpan1) && TimeSpan.TryParse(string2, out timeSpan2))
462            result = timeSpan1.CompareTo(timeSpan2);
463          else {
464            if (string1 != null)
465              result = string1.CompareTo(string2);
466            else if (string2 != null)
467              result = string2.CompareTo(string1) * -1;
468          }
469          if (pair.Value == SortOrder.Descending)
470            result *= -1;
471          if (result != 0)
472            return result;
473        }
474        return result;
475      }
476    }
477
478    private void dataGridView_MouseClick(object sender, System.Windows.Forms.MouseEventArgs e) {
479      if (Content == null) return;
480      if (e.Button == MouseButtons.Right && Content.ColumnNames.Count() != 0)
481        contextMenu.Show(MousePosition);
482    }
483    private void ShowHideColumns_Click(object sender, EventArgs e) {
484      new ColumnsVisibilityDialog(this.dataGridView.Columns.Cast<DataGridViewColumn>()).ShowDialog();
485    }
486
487    private void UpdateVisibilityOfTextBoxes() {
488      rowsTextBox.Visible = columnsTextBox.Visible = showRowsAndColumnsTextBox;
489      rowsLabel.Visible = columnsLabel.Visible = showRowsAndColumnsTextBox;
490
491      int headerSize = columnsTextBox.Location.Y + columnsTextBox.Size.Height +
492        columnsTextBox.Margin.Bottom + dataGridView.Margin.Top;
493
494      int offset = showRowsAndColumnsTextBox ? headerSize : 0;
495      dataGridView.Location = new Point(0, offset);
496      dataGridView.Size = new Size(Size.Width, Size.Height - offset);
497    }
498  }
499}
Note: See TracBrowser for help on using the repository browser.