Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/HeuristicLab.Data.Views/3.3/StringConvertibleArrayView.cs

Last change on this file was 18166, checked in by gkronber, 3 years ago

#3047: set SuppressKeyPress=true in all controls that handle the Enter key explicitly (except for dialogs).

File size: 12.3 KB
RevLine 
[2973]1#region License Information
2/* HeuristicLab
[17180]3 * Copyright (C) Heuristic and Evolutionary Algorithms Laboratory (HEAL)
[2973]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;
[14561]23using System.Collections.Generic;
[2973]24using System.ComponentModel;
25using System.Drawing;
[14299]26using System.Linq;
[7318]27using System.Text;
[2973]28using System.Windows.Forms;
29using HeuristicLab.Common;
30using HeuristicLab.MainForm;
31using HeuristicLab.MainForm.WindowsForms;
32
33namespace HeuristicLab.Data.Views {
[3048]34  [View("StringConvertibleArray View")]
35  [Content(typeof(IStringConvertibleArray), true)]
[3228]36  public partial class StringConvertibleArrayView : AsynchronousContentView {
[3048]37    public new IStringConvertibleArray Content {
38      get { return (IStringConvertibleArray)base.Content; }
[2973]39      set { base.Content = value; }
40    }
41
[3430]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
[3048]50    public StringConvertibleArrayView() {
[2973]51      InitializeComponent();
[2974]52      errorProvider.SetIconAlignment(lengthTextBox, ErrorIconAlignment.MiddleLeft);
53      errorProvider.SetIconPadding(lengthTextBox, 2);
[2973]54    }
55
56    protected override void DeregisterContentEvents() {
[9657]57      Content.ElementNamesChanged -= new EventHandler(Content_ElementNamesChanged);
[2973]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);
[9657]67      Content.ElementNamesChanged += new EventHandler(Content_ElementNamesChanged);
[2973]68    }
69
70    protected override void OnContentChanged() {
71      base.OnContentChanged();
72      if (Content == null) {
[2974]73        lengthTextBox.Text = "";
[2973]74        dataGridView.Rows.Clear();
75        dataGridView.Columns.Clear();
[3764]76      } else
[2973]77        UpdateData();
78    }
[3904]79
80    protected override void SetEnabledStateOfControls() {
81      base.SetEnabledStateOfControls();
[3454]82      lengthTextBox.Enabled = Content != null;
83      dataGridView.Enabled = Content != null;
[13695]84      lengthTextBox.ReadOnly = ReadOnly || (Content != null && !Content.Resizable);
[3454]85      dataGridView.ReadOnly = ReadOnly;
[3350]86    }
[2973]87
88    private void UpdateData() {
[2974]89      lengthTextBox.Text = Content.Length.ToString();
90      lengthTextBox.Enabled = true;
[2973]91      dataGridView.Rows.Clear();
92      dataGridView.Columns.Clear();
[2974]93      if (Content.Length > 0) {
[2973]94        dataGridView.ColumnCount++;
95        dataGridView.Columns[0].FillWeight = float.Epsilon;  // sum of all fill weights must not be larger than 65535
[2974]96        dataGridView.RowCount = Content.Length;
97        for (int i = 0; i < Content.Length; i++) {
[2973]98          dataGridView.Rows[i].Cells[0].Value = Content.GetValue(i);
99        }
100        dataGridView.Columns[0].Width = dataGridView.Columns[0].GetPreferredWidth(DataGridViewAutoSizeColumnMode.AllCells, true);
101      }
[9657]102      UpdateRowHeaders();
103      dataGridView.AutoResizeRowHeadersWidth(DataGridViewRowHeadersWidthSizeMode.AutoSizeToDisplayedHeaders);
[2973]104      dataGridView.Enabled = true;
105    }
106
[13570]107    public virtual void UpdateRowHeaders() {
[9695]108      int i = 0;
109      foreach (string elementName in Content.ElementNames) {
110        dataGridView.Rows[i].HeaderCell.Value = elementName;
111        i++;
[9657]112      }
[9695]113      for (; i < dataGridView.RowCount; i++) {
114        dataGridView.Rows[i].HeaderCell.Value = string.Empty;
115      }
[9657]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
[2973]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 {
[9714]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;
[2973]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
[2974]145    private void lengthTextBox_Validating(object sender, CancelEventArgs e) {
[2973]146      int i = 0;
[2974]147      if (!int.TryParse(lengthTextBox.Text, out i) || (i < 0)) {
[2973]148        e.Cancel = true;
[2974]149        errorProvider.SetError(lengthTextBox, "Invalid Array Length (Valid Values: Positive Integers Larger or Equal to 0)");
150        lengthTextBox.SelectAll();
[2973]151      }
152    }
[2974]153    private void lengthTextBox_Validated(object sender, EventArgs e) {
[3430]154      if (!Content.ReadOnly) Content.Length = int.Parse(lengthTextBox.Text);
[2974]155      errorProvider.SetError(lengthTextBox, string.Empty);
[2973]156    }
[2974]157    private void lengthTextBox_KeyDown(object sender, KeyEventArgs e) {
[18166]158      if (e.KeyCode == Keys.Enter || e.KeyCode == Keys.Return) {
[2974]159        lengthLabel.Focus();  // set focus on label to validate data
[18166]160        e.SuppressKeyPress = true;
161      } else if (e.KeyCode == Keys.Escape) {
[2974]162        lengthTextBox.Text = Content.Length.ToString();
163        lengthLabel.Focus();  // set focus on label to validate data
[18166]164        e.SuppressKeyPress = true;
[2973]165      }
166    }
167    #endregion
168
169    #region DataGridView Events
170    private void dataGridView_CellValidating(object sender, DataGridViewCellValidatingEventArgs e) {
171      string errorMessage;
[4030]172      if (Content != null && !Content.Validate(e.FormattedValue.ToString(), out errorMessage)) {
[2973]173        e.Cancel = true;
174        dataGridView.Rows[e.RowIndex].ErrorText = errorMessage;
175      }
176    }
177    private void dataGridView_CellParsing(object sender, DataGridViewCellParsingEventArgs e) {
178      string value = e.Value.ToString();
179      e.ParsingApplied = Content.SetValue(value, e.RowIndex);
180      if (e.ParsingApplied) e.Value = Content.GetValue(e.RowIndex);
181    }
182    private void dataGridView_CellEndEdit(object sender, DataGridViewCellEventArgs e) {
183      dataGridView.Rows[e.RowIndex].ErrorText = string.Empty;
184    }
[7318]185    private void dataGridView_KeyDown(object sender, KeyEventArgs e) {
186      if (!ReadOnly && e.Control && e.KeyCode == Keys.V)
187        PasteValuesToDataGridView();
188      else if (e.Control && e.KeyCode == Keys.C)
189        CopyValuesFromDataGridView();
190      else if (e.Control && e.KeyCode == Keys.A)
191        dataGridView.SelectAll();
192    }
193    private void CopyValuesFromDataGridView() {
194      if (dataGridView.SelectedCells.Count == 0) return;
195      StringBuilder s = new StringBuilder();
196      int minRowIndex = dataGridView.SelectedCells[0].RowIndex;
197      int maxRowIndex = dataGridView.SelectedCells[dataGridView.SelectedCells.Count - 1].RowIndex;
198
199      if (minRowIndex > maxRowIndex) {
200        int temp = minRowIndex;
201        minRowIndex = maxRowIndex;
202        maxRowIndex = temp;
203      }
204
[14561]205      var elementNames = Content.ElementNames.ToList();
[7318]206      for (int i = minRowIndex; i <= maxRowIndex; i++) {
207        DataGridViewColumn column = dataGridView.Columns.GetFirstColumn(DataGridViewElementStates.Visible);
208        DataGridViewCell cell = dataGridView[column.Index, i];
209        if (cell.Selected) {
[14561]210          if (i < elementNames.Count) {
211            s.Append(elementNames[i]);
212            s.Append("\t");
213          } else if (elementNames.Count > 0) {
214            s.Append("Index " + i);
215            s.Append("\t");
216          }
[7318]217          s.Append(Content.GetValue(i));
218          s.Append(Environment.NewLine);
219        }
220      }
221      Clipboard.SetText(s.ToString());
222    }
223    private void PasteValuesToDataGridView() {
[14561]224      Tuple<string, string>[] values = null;
225      try {
226        values = SplitClipboardString(Clipboard.GetText()).ToArray();
227      } catch (ArgumentException ex) {
228        MessageBox.Show(this, ex.Message, "Error while parsing clipboard text.", MessageBoxButtons.OK, MessageBoxIcon.Error);
229        return;
230      }
[7318]231      int rowIndex = 0;
232      if (dataGridView.CurrentCell != null)
233        rowIndex = dataGridView.CurrentCell.RowIndex;
234
235      if (Content.Length < rowIndex + values.Length) Content.Length = rowIndex + values.Length;
[14561]236      for (int row = 0; row < values.Length; row++) {
237        Content.SetValue(values[row].Item2, row + rowIndex);
238      }
239      if (values.Any(x => !string.IsNullOrEmpty(x.Item1))) {
240        var elementNames = Content.ElementNames.ToList();
241        for (int row = 0; row < values.Length; row++) {
242          if (row + rowIndex < elementNames.Count)
243            elementNames[row + rowIndex] = values[row].Item1;
244          else elementNames.Add(values[row].Item1);
245        }
246        Content.ElementNames = elementNames;
247      }
[7318]248    }
[14561]249    private IEnumerable<Tuple<string, string>> SplitClipboardString(string clipboardText) {
[7984]250      if (clipboardText.EndsWith(Environment.NewLine))
251        clipboardText = clipboardText.Remove(clipboardText.Length - Environment.NewLine.Length);  //remove last newline constant
[14561]252
[18166]253      var lines = clipboardText.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
[14561]254      var tabSep = new[] { '\t' };
255      if (lines.Length > 2) {
256        // Case 1: Each line contains either "elementName \t value" or just "value" (one or two vertical vectors)
257        foreach (var l in lines) {
258          var row = l.Split(tabSep, StringSplitOptions.RemoveEmptyEntries);
259          if (row.Length > 2) throw new ArgumentException("Clipboard may have either at most two rows or at most two columns.");
260          if (row.Length == 2) yield return Tuple.Create(row[0], row[1]);
261          else if (row.Length == 1) yield return Tuple.Create(string.Empty, row[0]);
262          else yield return Tuple.Create(string.Empty, string.Empty);
263        }
264      } else if (lines.Length == 2) {
265        var firstLine = lines[0].Split(tabSep, StringSplitOptions.None);
266        var secondLine = lines[1].Split(tabSep, StringSplitOptions.None);
267        if (firstLine.Length <= 2 && secondLine.Length <= 2) {
268          // Case 2a: The two lines contain either "elementName \t value" or just "value" (one or two vertical vectors)
269          yield return firstLine.Length >= 2 ? Tuple.Create(firstLine[0], firstLine[1]) : Tuple.Create(string.Empty, firstLine[0]);
270          yield return secondLine.Length >= 2 ? Tuple.Create(secondLine[0], secondLine[1]) : Tuple.Create(string.Empty, secondLine[0]);
271        } else {
272          // Case 2b: The first line contains the elementNames, the second line contains the values (two horizontal vectors)
273          var max = Math.Max(firstLine.Length, secondLine.Length);
274          for (var i = 0; i < max; i++) {
275            var elemName = i < firstLine.Length ? firstLine[i] : string.Empty;
276            var value = i < secondLine.Length ? secondLine[i] : string.Empty;
277            yield return Tuple.Create(elemName, value);
278          }
279        }
280      } else if (lines.Length == 1) {
281        // Case 3: The line contains the values (one horizontal vector)
282        var entries = lines[0].Split(tabSep, StringSplitOptions.None);
283        foreach (var e in entries) {
284          yield return Tuple.Create(string.Empty, e);
285        }
286      }
[7318]287    }
[2973]288    #endregion
289  }
290}
Note: See TracBrowser for help on using the repository browser.