source: stable/HeuristicLab.Data.Views/3.3/StringConvertibleArrayView.cs @ 15584

Last change on this file since 15584 was 15584, checked in by swagner, 3 years ago

#2640: Updated year of copyrights in license headers on stable

File size: 12.3 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2018 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("StringConvertibleArray View")]
35  [Content(typeof(IStringConvertibleArray), true)]
36  public partial class StringConvertibleArrayView : AsynchronousContentView {
37    public new IStringConvertibleArray Content {
38      get { return (IStringConvertibleArray)base.Content; }
39      set { base.Content = value; }
40    }
41
42    public override bool ReadOnly {
43      get {
44        if ((Content != null) && Content.ReadOnly) return true;
45        return base.ReadOnly;
46      }
47      set { base.ReadOnly = value; }
48    }
49
50    public StringConvertibleArrayView() {
51      InitializeComponent();
52      errorProvider.SetIconAlignment(lengthTextBox, ErrorIconAlignment.MiddleLeft);
53      errorProvider.SetIconPadding(lengthTextBox, 2);
54    }
55
56    protected override void DeregisterContentEvents() {
57      Content.ElementNamesChanged -= new EventHandler(Content_ElementNamesChanged);
58      Content.ItemChanged -= new EventHandler<EventArgs<int>>(Content_ItemChanged);
59      Content.Reset -= new EventHandler(Content_Reset);
60      base.DeregisterContentEvents();
61    }
62
63    protected override void RegisterContentEvents() {
64      base.RegisterContentEvents();
65      Content.ItemChanged += new EventHandler<EventArgs<int>>(Content_ItemChanged);
66      Content.Reset += new EventHandler(Content_Reset);
67      Content.ElementNamesChanged += new EventHandler(Content_ElementNamesChanged);
68    }
69
70    protected override void OnContentChanged() {
71      base.OnContentChanged();
72      if (Content == null) {
73        lengthTextBox.Text = "";
74        dataGridView.Rows.Clear();
75        dataGridView.Columns.Clear();
76      } else
77        UpdateData();
78    }
79
80    protected override void SetEnabledStateOfControls() {
81      base.SetEnabledStateOfControls();
82      lengthTextBox.Enabled = Content != null;
83      dataGridView.Enabled = Content != null;
84      lengthTextBox.ReadOnly = ReadOnly || (Content != null && !Content.Resizable);
85      dataGridView.ReadOnly = ReadOnly;
86    }
87
88    private void UpdateData() {
89      lengthTextBox.Text = Content.Length.ToString();
90      lengthTextBox.Enabled = true;
91      dataGridView.Rows.Clear();
92      dataGridView.Columns.Clear();
93      if (Content.Length > 0) {
94        dataGridView.ColumnCount++;
95        dataGridView.Columns[0].FillWeight = float.Epsilon;  // sum of all fill weights must not be larger than 65535
96        dataGridView.RowCount = Content.Length;
97        for (int i = 0; i < Content.Length; i++) {
98          dataGridView.Rows[i].Cells[0].Value = Content.GetValue(i);
99        }
100        dataGridView.Columns[0].Width = dataGridView.Columns[0].GetPreferredWidth(DataGridViewAutoSizeColumnMode.AllCells, true);
101      }
102      UpdateRowHeaders();
103      dataGridView.AutoResizeRowHeadersWidth(DataGridViewRowHeadersWidthSizeMode.AutoSizeToDisplayedHeaders);
104      dataGridView.Enabled = true;
105    }
106
107    public virtual void UpdateRowHeaders() {
108      int i = 0;
109      foreach (string elementName in Content.ElementNames) {
110        dataGridView.Rows[i].HeaderCell.Value = elementName;
111        i++;
112      }
113      for (; i < dataGridView.RowCount; i++) {
114        dataGridView.Rows[i].HeaderCell.Value = string.Empty;
115      }
116    }
117
118    private void Content_ElementNamesChanged(object sender, EventArgs e) {
119      if (InvokeRequired)
120        Invoke(new EventHandler(Content_ElementNamesChanged), sender, e);
121      else
122        UpdateRowHeaders();
123    }
124
125    private void Content_ItemChanged(object sender, EventArgs<int> e) {
126      if (InvokeRequired)
127        Invoke(new EventHandler<EventArgs<int>>(Content_ItemChanged), sender, e);
128      else {
129        // if a resize of the array occurs and some other class handles the event and provides default values
130        //then the itemChanged will occur before the reset event. hence the check was added
131        if (dataGridView.RowCount <= e.Value) return;
132        dataGridView.Rows[e.Value].Cells[0].Value = Content.GetValue(e.Value);
133        Size size = dataGridView.Rows[e.Value].Cells[0].PreferredSize;
134        dataGridView.Columns[0].Width = Math.Max(dataGridView.Columns[0].Width, size.Width);
135      }
136    }
137    private void Content_Reset(object sender, EventArgs e) {
138      if (InvokeRequired)
139        Invoke(new EventHandler(Content_Reset), sender, e);
140      else
141        UpdateData();
142    }
143
144    #region TextBox Events
145    private void lengthTextBox_Validating(object sender, CancelEventArgs e) {
146      int i = 0;
147      if (!int.TryParse(lengthTextBox.Text, out i) || (i < 0)) {
148        e.Cancel = true;
149        errorProvider.SetError(lengthTextBox, "Invalid Array Length (Valid Values: Positive Integers Larger or Equal to 0)");
150        lengthTextBox.SelectAll();
151      }
152    }
153    private void lengthTextBox_Validated(object sender, EventArgs e) {
154      if (!Content.ReadOnly) Content.Length = int.Parse(lengthTextBox.Text);
155      errorProvider.SetError(lengthTextBox, string.Empty);
156    }
157    private void lengthTextBox_KeyDown(object sender, KeyEventArgs e) {
158      if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Return)
159        lengthLabel.Focus();  // set focus on label to validate data
160      if (e.KeyCode == Keys.Escape) {
161        lengthTextBox.Text = Content.Length.ToString();
162        lengthLabel.Focus();  // set focus on label to validate data
163      }
164    }
165    #endregion
166
167    #region DataGridView Events
168    private void dataGridView_CellValidating(object sender, DataGridViewCellValidatingEventArgs e) {
169      string errorMessage;
170      if (Content != null && !Content.Validate(e.FormattedValue.ToString(), out errorMessage)) {
171        e.Cancel = true;
172        dataGridView.Rows[e.RowIndex].ErrorText = errorMessage;
173      }
174    }
175    private void dataGridView_CellParsing(object sender, DataGridViewCellParsingEventArgs e) {
176      string value = e.Value.ToString();
177      e.ParsingApplied = Content.SetValue(value, e.RowIndex);
178      if (e.ParsingApplied) e.Value = Content.GetValue(e.RowIndex);
179    }
180    private void dataGridView_CellEndEdit(object sender, DataGridViewCellEventArgs e) {
181      dataGridView.Rows[e.RowIndex].ErrorText = string.Empty;
182    }
183    private void dataGridView_KeyDown(object sender, KeyEventArgs e) {
184      if (!ReadOnly && e.Control && e.KeyCode == Keys.V)
185        PasteValuesToDataGridView();
186      else if (e.Control && e.KeyCode == Keys.C)
187        CopyValuesFromDataGridView();
188      else if (e.Control && e.KeyCode == Keys.A)
189        dataGridView.SelectAll();
190    }
191    private void CopyValuesFromDataGridView() {
192      if (dataGridView.SelectedCells.Count == 0) return;
193      StringBuilder s = new StringBuilder();
194      int minRowIndex = dataGridView.SelectedCells[0].RowIndex;
195      int maxRowIndex = dataGridView.SelectedCells[dataGridView.SelectedCells.Count - 1].RowIndex;
196
197      if (minRowIndex > maxRowIndex) {
198        int temp = minRowIndex;
199        minRowIndex = maxRowIndex;
200        maxRowIndex = temp;
201      }
202
203      var elementNames = Content.ElementNames.ToList();
204      for (int i = minRowIndex; i <= maxRowIndex; i++) {
205        DataGridViewColumn column = dataGridView.Columns.GetFirstColumn(DataGridViewElementStates.Visible);
206        DataGridViewCell cell = dataGridView[column.Index, i];
207        if (cell.Selected) {
208          if (i < elementNames.Count) {
209            s.Append(elementNames[i]);
210            s.Append("\t");
211          } else if (elementNames.Count > 0) {
212            s.Append("Index " + i);
213            s.Append("\t");
214          }
215          s.Append(Content.GetValue(i));
216          s.Append(Environment.NewLine);
217        }
218      }
219      Clipboard.SetText(s.ToString());
220    }
221    private void PasteValuesToDataGridView() {
222      Tuple<string, string>[] values = null;
223      try {
224        values = SplitClipboardString(Clipboard.GetText()).ToArray();
225      } catch (ArgumentException ex) {
226        MessageBox.Show(this, ex.Message, "Error while parsing clipboard text.", MessageBoxButtons.OK, MessageBoxIcon.Error);
227        return;
228      }
229      int rowIndex = 0;
230      if (dataGridView.CurrentCell != null)
231        rowIndex = dataGridView.CurrentCell.RowIndex;
232
233      if (Content.Length < rowIndex + values.Length) Content.Length = rowIndex + values.Length;
234      for (int row = 0; row < values.Length; row++) {
235        Content.SetValue(values[row].Item2, row + rowIndex);
236      }
237      if (values.Any(x => !string.IsNullOrEmpty(x.Item1))) {
238        var elementNames = Content.ElementNames.ToList();
239        for (int row = 0; row < values.Length; row++) {
240          if (row + rowIndex < elementNames.Count)
241            elementNames[row + rowIndex] = values[row].Item1;
242          else elementNames.Add(values[row].Item1);
243        }
244        Content.ElementNames = elementNames;
245      }
246    }
247    private IEnumerable<Tuple<string, string>> SplitClipboardString(string clipboardText) {
248      if (clipboardText.EndsWith(Environment.NewLine))
249        clipboardText = clipboardText.Remove(clipboardText.Length - Environment.NewLine.Length);  //remove last newline constant
250
251      var lines = clipboardText.Split(new [] { Environment.NewLine }, StringSplitOptions.None);
252      var tabSep = new[] { '\t' };
253      if (lines.Length > 2) {
254        // Case 1: Each line contains either "elementName \t value" or just "value" (one or two vertical vectors)
255        foreach (var l in lines) {
256          var row = l.Split(tabSep, StringSplitOptions.RemoveEmptyEntries);
257          if (row.Length > 2) throw new ArgumentException("Clipboard may have either at most two rows or at most two columns.");
258          if (row.Length == 2) yield return Tuple.Create(row[0], row[1]);
259          else if (row.Length == 1) yield return Tuple.Create(string.Empty, row[0]);
260          else yield return Tuple.Create(string.Empty, string.Empty);
261        }
262      } else if (lines.Length == 2) {
263        var firstLine = lines[0].Split(tabSep, StringSplitOptions.None);
264        var secondLine = lines[1].Split(tabSep, StringSplitOptions.None);
265        if (firstLine.Length <= 2 && secondLine.Length <= 2) {
266          // Case 2a: The two lines contain either "elementName \t value" or just "value" (one or two vertical vectors)
267          yield return firstLine.Length >= 2 ? Tuple.Create(firstLine[0], firstLine[1]) : Tuple.Create(string.Empty, firstLine[0]);
268          yield return secondLine.Length >= 2 ? Tuple.Create(secondLine[0], secondLine[1]) : Tuple.Create(string.Empty, secondLine[0]);
269        } else {
270          // Case 2b: The first line contains the elementNames, the second line contains the values (two horizontal vectors)
271          var max = Math.Max(firstLine.Length, secondLine.Length);
272          for (var i = 0; i < max; i++) {
273            var elemName = i < firstLine.Length ? firstLine[i] : string.Empty;
274            var value = i < secondLine.Length ? secondLine[i] : string.Empty;
275            yield return Tuple.Create(elemName, value);
276          }
277        }
278      } else if (lines.Length == 1) {
279        // Case 3: The line contains the values (one horizontal vector)
280        var entries = lines[0].Split(tabSep, StringSplitOptions.None);
281        foreach (var e in entries) {
282          yield return Tuple.Create(string.Empty, e);
283        }
284      }
285    }
286    #endregion
287  }
288}
Note: See TracBrowser for help on using the repository browser.