Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Analysis.Views/3.3/DataTableView.cs @ 3979

Last change on this file since 3979 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.Linq;
24using System.Collections.Generic;
25using System.Windows.Forms.DataVisualization.Charting;
26using HeuristicLab.Collections;
27using HeuristicLab.Core.Views;
28using HeuristicLab.MainForm;
29using System.Windows.Forms;
30using System.Drawing;
31
32namespace HeuristicLab.Analysis.Views {
33  /// <summary>
34  /// The visual representation of a <see cref="Variable"/>.
35  /// </summary>
36  [View("DataTable View")]
37  [Content(typeof(DataTable), true)]
38  public sealed partial class DataTableView : NamedItemView {
39    private List<Series> invisibleSeries;
40    private Dictionary<IObservableList<double>, DataRow> valuesRowsTable;
41    /// <summary>
42    /// Gets or sets the variable to represent visually.
43    /// </summary>
44    /// <remarks>Uses property <see cref="ViewBase.Item"/> of base class <see cref="ViewBase"/>.
45    /// No own data storage present.</remarks>
46    public new DataTable Content {
47      get { return (DataTable)base.Content; }
48      set { base.Content = value; }
49    }
50
51    /// <summary>
52    /// Initializes a new instance of <see cref="VariableView"/> with caption "Variable".
53    /// </summary>
54    public DataTableView() {
55      InitializeComponent();
56      valuesRowsTable = new Dictionary<IObservableList<double>, DataRow>();
57      invisibleSeries = new List<Series>();
58    }
59
60    /// <summary>
61    /// Removes the eventhandlers from the underlying <see cref="Variable"/>.
62    /// </summary>
63    /// <remarks>Calls <see cref="ViewBase.RemoveItemEvents"/> of base class <see cref="ViewBase"/>.</remarks>
64    protected override void DeregisterContentEvents() {
65      foreach (DataRow row in Content.Rows)
66        DeregisterDataRowEvents(row);
67      Content.Rows.ItemsAdded -= new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsAdded);
68      Content.Rows.ItemsRemoved -= new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsRemoved);
69      Content.Rows.ItemsReplaced -= new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsReplaced);
70      Content.Rows.CollectionReset -= new CollectionItemsChangedEventHandler<DataRow>(Rows_CollectionReset);
71      base.DeregisterContentEvents();
72    }
73
74    /// <summary>
75    /// Adds eventhandlers to the underlying <see cref="Variable"/>.
76    /// </summary>
77    /// <remarks>Calls <see cref="ViewBase.AddItemEvents"/> of base class <see cref="ViewBase"/>.</remarks>
78    protected override void RegisterContentEvents() {
79      base.RegisterContentEvents();
80      Content.Rows.ItemsAdded += new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsAdded);
81      Content.Rows.ItemsRemoved += new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsRemoved);
82      Content.Rows.ItemsReplaced += new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsReplaced);
83      Content.Rows.CollectionReset += new CollectionItemsChangedEventHandler<DataRow>(Rows_CollectionReset);
84      foreach (DataRow row in Content.Rows)
85        RegisterDataRowEvents(row);
86    }
87
88    protected override void OnContentChanged() {
89      base.OnContentChanged();
90      invisibleSeries.Clear();
91      chart.Titles.Clear();
92      chart.Series.Clear();
93      if (Content != null) {
94        chart.Titles.Add(new Title(Content.Name, Docking.Top));
95        foreach (DataRow row in Content.Rows)
96          AddDataRow(row);
97      }
98    }
99
100    protected override void SetEnabledStateOfControls() {
101      base.SetEnabledStateOfControls();
102      chart.Enabled = Content != null;
103    }
104
105    private void AddDataRow(DataRow row) {
106      Series series = new Series(row.Name);
107      series.ChartType = SeriesChartType.FastLine;
108      series.ToolTip = row.Name + " X = #INDEX, Y = #VAL";
109      FillSeriesWithRowValues(series, row);
110      chart.Series.Add(series);
111      UpdateYCursorInterval();
112    }
113
114    private void UpdateYCursorInterval() {
115      double interestingValuesRange = (from series in chart.Series
116                                       where series.Enabled
117                                       let values = (from point in series.Points
118                                                     where !point.IsEmpty
119                                                     select point.YValues[0])
120                                                     .DefaultIfEmpty(1.0)
121                                       let range = values.Max() - values.Min()
122                                       where range > 0.0
123                                       select range)
124                                       .DefaultIfEmpty(1.0)
125                                       .Min();
126
127      double digits = (int)Math.Log10(interestingValuesRange) - 3;
128      double yZoomInterval = Math.Pow(10, digits);
129      this.chart.ChartAreas[0].CursorY.Interval = yZoomInterval;
130    }
131
132    private void RemoveDataRow(DataRow row) {
133      Series series = chart.Series[row.Name];
134      chart.Series.Remove(series);
135      if (invisibleSeries.Contains(series))
136        invisibleSeries.Remove(series);
137    }
138
139    #region Content Events
140    private void RegisterDataRowEvents(DataRow row) {
141      row.NameChanged += new EventHandler(Row_NameChanged);
142      valuesRowsTable.Add(row.Values, row);
143      row.Values.ItemsAdded += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsAdded);
144      row.Values.ItemsRemoved += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsRemoved);
145      row.Values.ItemsReplaced += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsReplaced);
146      row.Values.ItemsMoved += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsMoved);
147      row.Values.CollectionReset += new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_CollectionReset);
148    }
149    private void DeregisterDataRowEvents(DataRow row) {
150      row.Values.ItemsAdded -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsAdded);
151      row.Values.ItemsRemoved -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsRemoved);
152      row.Values.ItemsReplaced -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsReplaced);
153      row.Values.ItemsMoved -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsMoved);
154      row.Values.CollectionReset -= new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_CollectionReset);
155      valuesRowsTable.Remove(row.Values);
156      row.NameChanged -= new EventHandler(Row_NameChanged);
157    }
158    protected override void Content_NameChanged(object sender, EventArgs e) {
159      if (InvokeRequired)
160        Invoke(new EventHandler(Content_NameChanged), sender, e);
161      else {
162        chart.Titles[0].Text = Content.Name;
163        base.Content_NameChanged(sender, e);
164      }
165    }
166    private void Rows_ItemsAdded(object sender, CollectionItemsChangedEventArgs<DataRow> e) {
167      if (InvokeRequired)
168        Invoke(new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsAdded), sender, e);
169      else {
170        foreach (DataRow row in e.Items) {
171          AddDataRow(row);
172          RegisterDataRowEvents(row);
173        }
174      }
175    }
176    private void Rows_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<DataRow> e) {
177      if (InvokeRequired)
178        Invoke(new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsRemoved), sender, e);
179      else {
180        foreach (DataRow row in e.Items) {
181          DeregisterDataRowEvents(row);
182          RemoveDataRow(row);
183        }
184      }
185    }
186    private void Rows_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<DataRow> e) {
187      if (InvokeRequired)
188        Invoke(new CollectionItemsChangedEventHandler<DataRow>(Rows_ItemsReplaced), sender, e);
189      else {
190        foreach (DataRow row in e.OldItems) {
191          DeregisterDataRowEvents(row);
192          RemoveDataRow(row);
193        }
194        foreach (DataRow row in e.Items) {
195          AddDataRow(row);
196          RegisterDataRowEvents(row);
197        }
198      }
199    }
200    private void Rows_CollectionReset(object sender, CollectionItemsChangedEventArgs<DataRow> e) {
201      if (InvokeRequired)
202        Invoke(new CollectionItemsChangedEventHandler<DataRow>(Rows_CollectionReset), sender, e);
203      else {
204        foreach (DataRow row in e.OldItems) {
205          DeregisterDataRowEvents(row);
206          RemoveDataRow(row);
207        }
208        foreach (DataRow row in e.Items) {
209          AddDataRow(row);
210          RegisterDataRowEvents(row);
211        }
212      }
213    }
214    private void Row_NameChanged(object sender, EventArgs e) {
215      if (InvokeRequired)
216        Invoke(new EventHandler(Row_NameChanged), sender, e);
217      else {
218        DataRow row = (DataRow)sender;
219        chart.Series[row.Name].Name = row.Name;
220      }
221    }
222    private void Values_ItemsAdded(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {
223      if (InvokeRequired)
224        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsAdded), sender, e);
225      else {
226        DataRow row = null;
227        valuesRowsTable.TryGetValue((IObservableList<double>)sender, out row);
228        if (row != null) {
229          Series rowSeries = chart.Series[row.Name];
230          if (!invisibleSeries.Contains(rowSeries)) {
231            foreach (IndexedItem<double> item in e.Items) {
232              var value = item.Value;
233              if (IsInvalidValue(item.Value)) {
234                DataPoint point = new DataPoint();
235                point.IsEmpty = true;
236                rowSeries.Points.Insert(item.Index, point);
237              } else {
238                rowSeries.Points.InsertY(item.Index, value);
239              }
240            }
241            UpdateYCursorInterval();
242          }
243        }
244      }
245    }
246    private void Values_ItemsRemoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {
247      if (InvokeRequired)
248        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsRemoved), sender, e);
249      else {
250        DataRow row = null;
251        valuesRowsTable.TryGetValue((IObservableList<double>)sender, out row);
252        if (row != null) {
253          Series rowSeries = chart.Series[row.Name];
254          if (!invisibleSeries.Contains(rowSeries)) {
255            List<DataPoint> points = new List<DataPoint>();
256            foreach (IndexedItem<double> item in e.Items)
257              points.Add(rowSeries.Points[item.Index]);
258            foreach (DataPoint point in points)
259              rowSeries.Points.Remove(point);
260            UpdateYCursorInterval();
261          }
262        }
263      }
264    }
265    private void Values_ItemsReplaced(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {
266      if (InvokeRequired)
267        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsReplaced), sender, e);
268      else {
269        DataRow row = null;
270        valuesRowsTable.TryGetValue((IObservableList<double>)sender, out row);
271        if (row != null) {
272          Series rowSeries = chart.Series[row.Name];
273          if (!invisibleSeries.Contains(rowSeries)) {
274            foreach (IndexedItem<double> item in e.Items) {
275              if (IsInvalidValue(item.Value))
276                rowSeries.Points[item.Index].IsEmpty = true;
277              else {
278                rowSeries.Points[item.Index].YValues = new double[] { item.Value };
279                rowSeries.Points[item.Index].IsEmpty = false;
280              }
281            }
282            UpdateYCursorInterval();
283          }
284        }
285      }
286    }
287    private void Values_ItemsMoved(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {
288      if (InvokeRequired)
289        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_ItemsMoved), sender, e);
290      else {
291        DataRow row = null;
292        valuesRowsTable.TryGetValue((IObservableList<double>)sender, out row);
293        if (row != null) {
294          Series rowSeries = chart.Series[row.Name];
295          if (!invisibleSeries.Contains(rowSeries)) {
296            foreach (IndexedItem<double> item in e.Items) {
297              if (IsInvalidValue(item.Value))
298                rowSeries.Points[item.Index].IsEmpty = true;
299              else {
300                rowSeries.Points[item.Index].YValues = new double[] { item.Value };
301                rowSeries.Points[item.Index].IsEmpty = false;
302              }
303            }
304            UpdateYCursorInterval();
305          }
306        }
307      }
308    }
309
310    private void Values_CollectionReset(object sender, CollectionItemsChangedEventArgs<IndexedItem<double>> e) {
311      if (InvokeRequired)
312        Invoke(new CollectionItemsChangedEventHandler<IndexedItem<double>>(Values_CollectionReset), sender, e);
313      else {
314        DataRow row = null;
315        valuesRowsTable.TryGetValue((IObservableList<double>)sender, out row);
316        if (row != null) {
317          Series rowSeries = chart.Series[row.Name];
318          if (!invisibleSeries.Contains(rowSeries)) {
319            rowSeries.Points.Clear();
320            foreach (IndexedItem<double> item in e.Items) {
321              if (IsInvalidValue(item.Value))
322                rowSeries.Points[item.Index].IsEmpty = true;
323              else {
324                rowSeries.Points[item.Index].YValues = new double[] { item.Value };
325                rowSeries.Points[item.Index].IsEmpty = false;
326              }
327            }
328          }
329          UpdateYCursorInterval();
330        }
331      }
332    }
333    #endregion
334    #region chart events
335    private void chart_MouseDown(object sender, MouseEventArgs e) {
336      HitTestResult result = chart.HitTest(e.X, e.Y);
337      if (result.ChartElementType == ChartElementType.LegendItem) {
338        ToggleSeriesVisible(result.Series);
339      }
340    }
341
342    private void ToggleSeriesVisible(Series series) {
343      if (!invisibleSeries.Contains(series)) {
344        series.Points.Clear();
345        invisibleSeries.Add(series);
346      } else {
347        invisibleSeries.Remove(series);
348        if (Content != null) {
349
350          var row = (from r in Content.Rows
351                     where r.Name == series.Name
352                     select r).Single();
353          FillSeriesWithRowValues(series, row);
354          this.chart.Legends[series.Legend].ForeColor = Color.Black;
355          UpdateYCursorInterval();
356        }
357      }
358    }
359
360    private void FillSeriesWithRowValues(Series series, DataRow row) {
361      for (int i = 0; i < row.Values.Count; i++) {
362        var value = row.Values[i];
363        if (IsInvalidValue(value)) {
364          DataPoint point = new DataPoint();
365          point.IsEmpty = true;
366          series.Points.Add(point);
367        } else {
368          series.Points.Add(value);
369        }
370      }
371    }
372
373    private void chart_MouseMove(object sender, MouseEventArgs e) {
374      HitTestResult result = chart.HitTest(e.X, e.Y);
375      if (result.ChartElementType == ChartElementType.LegendItem)
376        this.Cursor = Cursors.Hand;
377      else
378        this.Cursor = Cursors.Default;
379    }
380    private void chart_CustomizeLegend(object sender, CustomizeLegendEventArgs e) {
381      foreach (LegendItem legendItem in e.LegendItems) {
382        var series = chart.Series[legendItem.SeriesName];
383        if (series != null) {
384          bool seriesIsInvisible = invisibleSeries.Contains(series);
385          foreach (LegendCell cell in legendItem.Cells) {
386            cell.ForeColor = seriesIsInvisible ? Color.Gray : Color.Black;
387          }
388        }
389      }
390    }
391
392    #endregion
393
394    private bool IsInvalidValue(double x) {
395      return double.IsNaN(x) || x < (double)decimal.MinValue || x > (double)decimal.MaxValue;
396    }
397  }
398}
Note: See TracBrowser for help on using the repository browser.