Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Data.Views/3.3/StringConvertibleArrayView.cs @ 15405

Last change on this file since 15405 was 14561, checked in by abeham, 8 years ago

#2674:

  • Corrected copy & paste from StringConvertibleArrays
    • There are four possible cases that are handled by this change (rows are newline separated, columns tab separated)
      1. There is just one column of values
      2. There is one column of element names and one column of values
      3. There is one row of values
      4. There is one row of element names and one row of values
    • A message box is shown if the user selects a 2 by n or n by 2 range with n > 2
File size: 12.3 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2016 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.