StephaneLenclud@231
|
1 |
using System;
|
StephaneLenclud@231
|
2 |
using System.Collections.Generic;
|
StephaneLenclud@231
|
3 |
using System.ComponentModel;
|
StephaneLenclud@231
|
4 |
using System.Data;
|
StephaneLenclud@231
|
5 |
using System.Diagnostics;
|
StephaneLenclud@231
|
6 |
using System.Drawing;
|
StephaneLenclud@231
|
7 |
using System.Linq;
|
StephaneLenclud@231
|
8 |
using System.Text;
|
StephaneLenclud@231
|
9 |
using System.Threading.Tasks;
|
StephaneLenclud@231
|
10 |
using System.Windows.Forms;
|
StephaneLenclud@231
|
11 |
using SharpLib.Display;
|
StephaneLenclud@231
|
12 |
using SharpLib.Ear;
|
StephaneLenclud@231
|
13 |
using System.Reflection;
|
StephaneLenclud@231
|
14 |
using Microsoft.VisualBasic.CompilerServices;
|
StephaneLenclud@231
|
15 |
using SharpLib.Utils;
|
StephaneLenclud@238
|
16 |
using CodeProject.Dialog;
|
StephaneLenclud@239
|
17 |
using System.IO;
|
StephaneLenclud@231
|
18 |
|
StephaneLenclud@231
|
19 |
namespace SharpDisplayManager
|
StephaneLenclud@231
|
20 |
{
|
StephaneLenclud@231
|
21 |
/// <summary>
|
StephaneLenclud@231
|
22 |
/// Object edit dialog form.
|
StephaneLenclud@231
|
23 |
/// </summary>
|
StephaneLenclud@239
|
24 |
public partial class FormEditObject<T> : Form where T: SharpLib.Ear.Object
|
StephaneLenclud@231
|
25 |
{
|
StephaneLenclud@231
|
26 |
public T Object = null;
|
StephaneLenclud@231
|
27 |
|
StephaneLenclud@231
|
28 |
public FormEditObject()
|
StephaneLenclud@231
|
29 |
{
|
StephaneLenclud@231
|
30 |
InitializeComponent();
|
StephaneLenclud@231
|
31 |
}
|
StephaneLenclud@231
|
32 |
|
StephaneLenclud@231
|
33 |
/// <summary>
|
StephaneLenclud@231
|
34 |
///
|
StephaneLenclud@231
|
35 |
/// </summary>
|
StephaneLenclud@231
|
36 |
/// <param name="sender"></param>
|
StephaneLenclud@231
|
37 |
/// <param name="e"></param>
|
StephaneLenclud@231
|
38 |
private void FormEditAction_Load(object sender, EventArgs e)
|
StephaneLenclud@231
|
39 |
{
|
StephaneLenclud@236
|
40 |
// Populate registered object types
|
StephaneLenclud@231
|
41 |
IEnumerable < Type > types = Reflection.GetConcreteClassesDerivedFrom<T>();
|
StephaneLenclud@231
|
42 |
foreach (Type type in types)
|
StephaneLenclud@231
|
43 |
{
|
StephaneLenclud@231
|
44 |
ItemObjectType item = new ItemObjectType(type);
|
StephaneLenclud@247
|
45 |
iComboBoxObjectType.Items.Add(item);
|
StephaneLenclud@231
|
46 |
}
|
StephaneLenclud@231
|
47 |
|
StephaneLenclud@231
|
48 |
if (Object == null)
|
StephaneLenclud@231
|
49 |
{
|
StephaneLenclud@231
|
50 |
// Creating new issue, select our first item
|
StephaneLenclud@247
|
51 |
iComboBoxObjectType.SelectedIndex = 0;
|
StephaneLenclud@231
|
52 |
}
|
StephaneLenclud@231
|
53 |
else
|
StephaneLenclud@231
|
54 |
{
|
StephaneLenclud@231
|
55 |
// Editing existing object
|
StephaneLenclud@246
|
56 |
// Look up our item in our object type combobox
|
StephaneLenclud@247
|
57 |
foreach (ItemObjectType item in iComboBoxObjectType.Items)
|
StephaneLenclud@231
|
58 |
{
|
StephaneLenclud@231
|
59 |
if (item.Type == Object.GetType())
|
StephaneLenclud@231
|
60 |
{
|
StephaneLenclud@247
|
61 |
iComboBoxObjectType.SelectedItem = item;
|
StephaneLenclud@231
|
62 |
}
|
StephaneLenclud@231
|
63 |
}
|
StephaneLenclud@246
|
64 |
|
StephaneLenclud@239
|
65 |
}
|
StephaneLenclud@231
|
66 |
}
|
StephaneLenclud@231
|
67 |
|
StephaneLenclud@247
|
68 |
/// <summary>
|
StephaneLenclud@247
|
69 |
///
|
StephaneLenclud@247
|
70 |
/// </summary>
|
StephaneLenclud@247
|
71 |
/// <param name="sender"></param>
|
StephaneLenclud@247
|
72 |
/// <param name="e"></param>
|
StephaneLenclud@231
|
73 |
private void buttonOk_Click(object sender, EventArgs e)
|
StephaneLenclud@231
|
74 |
{
|
StephaneLenclud@231
|
75 |
FetchPropertiesValue(Object);
|
StephaneLenclud@239
|
76 |
if (!Object.IsValid())
|
StephaneLenclud@239
|
77 |
{
|
StephaneLenclud@247
|
78 |
// Tell closing event to cancel
|
StephaneLenclud@239
|
79 |
DialogResult = DialogResult.None;
|
StephaneLenclud@239
|
80 |
}
|
StephaneLenclud@231
|
81 |
}
|
StephaneLenclud@231
|
82 |
|
StephaneLenclud@239
|
83 |
|
StephaneLenclud@247
|
84 |
/// <summary>
|
StephaneLenclud@247
|
85 |
///
|
StephaneLenclud@247
|
86 |
/// </summary>
|
StephaneLenclud@247
|
87 |
/// <param name="sender"></param>
|
StephaneLenclud@247
|
88 |
/// <param name="e"></param>
|
StephaneLenclud@239
|
89 |
private void FormEditObject_FormClosing(object sender, FormClosingEventArgs e)
|
StephaneLenclud@231
|
90 |
{
|
StephaneLenclud@247
|
91 |
//Check if we need to cancel the closing of our form.
|
StephaneLenclud@239
|
92 |
e.Cancel = DialogResult == DialogResult.None;
|
StephaneLenclud@246
|
93 |
|
StephaneLenclud@246
|
94 |
if (!e.Cancel)
|
StephaneLenclud@246
|
95 |
{
|
StephaneLenclud@246
|
96 |
//Exit edit mode
|
StephaneLenclud@246
|
97 |
Object.CurrentState = SharpLib.Ear.Object.State.Rest;
|
StephaneLenclud@246
|
98 |
Object.PropertyChanged -= PropertyChangedEventHandlerThreadSafe;
|
StephaneLenclud@246
|
99 |
}
|
StephaneLenclud@231
|
100 |
}
|
StephaneLenclud@231
|
101 |
|
StephaneLenclud@247
|
102 |
/// <summary>
|
StephaneLenclud@247
|
103 |
///
|
StephaneLenclud@247
|
104 |
/// </summary>
|
StephaneLenclud@247
|
105 |
/// <param name="sender"></param>
|
StephaneLenclud@247
|
106 |
/// <param name="e"></param>
|
StephaneLenclud@231
|
107 |
private void comboBoxActionType_SelectedIndexChanged(object sender, EventArgs e)
|
StephaneLenclud@231
|
108 |
{
|
StephaneLenclud@231
|
109 |
//Instantiate an action corresponding to our type
|
StephaneLenclud@260
|
110 |
Type objectType = ((ItemObjectType) iComboBoxObjectType.SelectedItem).Type;
|
StephaneLenclud@231
|
111 |
//Create another type of action only if needed
|
StephaneLenclud@260
|
112 |
if (Object == null || Object.GetType() != objectType)
|
StephaneLenclud@231
|
113 |
{
|
StephaneLenclud@266
|
114 |
string name = "";
|
StephaneLenclud@260
|
115 |
if (Object != null)
|
StephaneLenclud@260
|
116 |
{
|
StephaneLenclud@260
|
117 |
// Make sure we exit edit mode and unhook from events
|
StephaneLenclud@260
|
118 |
Object.CurrentState = SharpLib.Ear.Object.State.Rest;
|
StephaneLenclud@260
|
119 |
Object.PropertyChanged -= PropertyChangedEventHandlerThreadSafe;
|
StephaneLenclud@266
|
120 |
name = Object.Name;
|
StephaneLenclud@260
|
121 |
Object = null;
|
StephaneLenclud@260
|
122 |
}
|
StephaneLenclud@260
|
123 |
Object = (T)Activator.CreateInstance(objectType);
|
StephaneLenclud@266
|
124 |
//Keep the name when changing the type
|
StephaneLenclud@266
|
125 |
Object.Name = name;
|
StephaneLenclud@231
|
126 |
}
|
StephaneLenclud@239
|
127 |
|
StephaneLenclud@231
|
128 |
//Create input fields
|
StephaneLenclud@247
|
129 |
UpdateControls();
|
StephaneLenclud@231
|
130 |
}
|
StephaneLenclud@231
|
131 |
|
StephaneLenclud@231
|
132 |
|
StephaneLenclud@231
|
133 |
/// <summary>
|
StephaneLenclud@231
|
134 |
/// Get properties values from our generated input fields
|
StephaneLenclud@231
|
135 |
/// </summary>
|
StephaneLenclud@236
|
136 |
private void FetchPropertiesValue(T aObject)
|
StephaneLenclud@231
|
137 |
{
|
StephaneLenclud@231
|
138 |
int ctrlIndex = 0;
|
Stephane@243
|
139 |
//For each of our properties
|
StephaneLenclud@236
|
140 |
foreach (PropertyInfo pi in aObject.GetType().GetProperties())
|
StephaneLenclud@231
|
141 |
{
|
Stephane@243
|
142 |
//Get our property attribute
|
Stephane@243
|
143 |
AttributeObjectProperty[] attributes = ((AttributeObjectProperty[]) pi.GetCustomAttributes(typeof(AttributeObjectProperty), true));
|
StephaneLenclud@231
|
144 |
if (attributes.Length != 1)
|
StephaneLenclud@231
|
145 |
{
|
Stephane@243
|
146 |
//No attribute, skip this property then.
|
StephaneLenclud@231
|
147 |
continue;
|
StephaneLenclud@231
|
148 |
}
|
StephaneLenclud@231
|
149 |
AttributeObjectProperty attribute = attributes[0];
|
StephaneLenclud@231
|
150 |
|
Stephane@243
|
151 |
//Check that we support this type of property
|
StephaneLenclud@231
|
152 |
if (!IsPropertyTypeSupported(pi))
|
StephaneLenclud@231
|
153 |
{
|
StephaneLenclud@231
|
154 |
continue;
|
StephaneLenclud@231
|
155 |
}
|
StephaneLenclud@231
|
156 |
|
Stephane@243
|
157 |
//Now fetch our property value
|
StephaneLenclud@236
|
158 |
GetPropertyValueFromControl(iTableLayoutPanel.Controls[ctrlIndex+1], pi, aObject); //+1 otherwise we get the label
|
StephaneLenclud@231
|
159 |
|
StephaneLenclud@231
|
160 |
ctrlIndex+=2; //Jump over the label too
|
StephaneLenclud@231
|
161 |
}
|
StephaneLenclud@231
|
162 |
}
|
StephaneLenclud@231
|
163 |
|
StephaneLenclud@231
|
164 |
/// <summary>
|
StephaneLenclud@231
|
165 |
/// Extend this function to support reading new types of properties.
|
StephaneLenclud@231
|
166 |
/// </summary>
|
StephaneLenclud@236
|
167 |
/// <param name="aObject"></param>
|
StephaneLenclud@236
|
168 |
private void GetPropertyValueFromControl(Control aControl, PropertyInfo aInfo, T aObject)
|
StephaneLenclud@231
|
169 |
{
|
StephaneLenclud@231
|
170 |
if (aInfo.PropertyType == typeof(int))
|
StephaneLenclud@231
|
171 |
{
|
StephaneLenclud@231
|
172 |
NumericUpDown ctrl=(NumericUpDown)aControl;
|
StephaneLenclud@236
|
173 |
aInfo.SetValue(aObject,(int)ctrl.Value);
|
StephaneLenclud@231
|
174 |
}
|
StephaneLenclud@231
|
175 |
else if (aInfo.PropertyType.IsEnum)
|
StephaneLenclud@231
|
176 |
{
|
StephaneLenclud@231
|
177 |
// Instantiate our enum
|
StephaneLenclud@231
|
178 |
object enumValue= Activator.CreateInstance(aInfo.PropertyType);
|
StephaneLenclud@231
|
179 |
// Parse our enum from combo box
|
StephaneLenclud@231
|
180 |
enumValue = Enum.Parse(aInfo.PropertyType,((ComboBox)aControl).SelectedItem.ToString());
|
StephaneLenclud@231
|
181 |
//enumValue = ((ComboBox)aControl).SelectedValue;
|
StephaneLenclud@231
|
182 |
// Set enum value
|
StephaneLenclud@236
|
183 |
aInfo.SetValue(aObject, enumValue);
|
StephaneLenclud@231
|
184 |
}
|
StephaneLenclud@231
|
185 |
else if (aInfo.PropertyType == typeof(bool))
|
StephaneLenclud@231
|
186 |
{
|
StephaneLenclud@231
|
187 |
CheckBox ctrl = (CheckBox)aControl;
|
StephaneLenclud@236
|
188 |
aInfo.SetValue(aObject, ctrl.Checked);
|
StephaneLenclud@231
|
189 |
}
|
StephaneLenclud@231
|
190 |
else if (aInfo.PropertyType == typeof(string))
|
StephaneLenclud@231
|
191 |
{
|
StephaneLenclud@231
|
192 |
TextBox ctrl = (TextBox)aControl;
|
StephaneLenclud@236
|
193 |
aInfo.SetValue(aObject, ctrl.Text);
|
StephaneLenclud@231
|
194 |
}
|
StephaneLenclud@238
|
195 |
else if (aInfo.PropertyType == typeof(PropertyFile))
|
StephaneLenclud@238
|
196 |
{
|
StephaneLenclud@238
|
197 |
Button ctrl = (Button)aControl;
|
StephaneLenclud@238
|
198 |
PropertyFile value = new PropertyFile {FullPath=ctrl.Text};
|
StephaneLenclud@238
|
199 |
aInfo.SetValue(aObject, value);
|
StephaneLenclud@238
|
200 |
}
|
Stephane@243
|
201 |
else if (aInfo.PropertyType == typeof(PropertyComboBox))
|
Stephane@243
|
202 |
{
|
Stephane@243
|
203 |
ComboBox ctrl = (ComboBox)aControl;
|
Stephane@243
|
204 |
string currentItem = ctrl.SelectedItem.ToString();
|
StephaneLenclud@244
|
205 |
PropertyComboBox value = (PropertyComboBox)aInfo.GetValue(aObject);
|
StephaneLenclud@244
|
206 |
value.CurrentItem = currentItem;
|
StephaneLenclud@244
|
207 |
//Not strictly needed but makes sure the set method is called
|
StephaneLenclud@244
|
208 |
aInfo.SetValue(aObject, value);
|
Stephane@243
|
209 |
}
|
StephaneLenclud@250
|
210 |
else if (aInfo.PropertyType == typeof(PropertyButton))
|
StephaneLenclud@250
|
211 |
{
|
StephaneLenclud@250
|
212 |
Button ctrl = (Button)aControl;
|
StephaneLenclud@250
|
213 |
PropertyButton value = new PropertyButton { Text = ctrl.Text };
|
StephaneLenclud@250
|
214 |
aInfo.SetValue(aObject, value);
|
StephaneLenclud@250
|
215 |
}
|
Stephane@243
|
216 |
|
StephaneLenclud@231
|
217 |
//TODO: add support for other types here
|
StephaneLenclud@231
|
218 |
}
|
StephaneLenclud@231
|
219 |
|
StephaneLenclud@236
|
220 |
|
StephaneLenclud@231
|
221 |
/// <summary>
|
StephaneLenclud@236
|
222 |
/// Create a control for the given property.
|
StephaneLenclud@231
|
223 |
/// </summary>
|
StephaneLenclud@231
|
224 |
/// <param name="aInfo"></param>
|
StephaneLenclud@236
|
225 |
/// <param name="aAttribute"></param>
|
StephaneLenclud@236
|
226 |
/// <param name="aObject"></param>
|
StephaneLenclud@236
|
227 |
/// <returns></returns>
|
StephaneLenclud@236
|
228 |
private Control CreateControlForProperty(PropertyInfo aInfo, AttributeObjectProperty aAttribute, T aObject)
|
StephaneLenclud@231
|
229 |
{
|
StephaneLenclud@231
|
230 |
if (aInfo.PropertyType == typeof(int))
|
StephaneLenclud@231
|
231 |
{
|
StephaneLenclud@231
|
232 |
//Integer properties are using numeric editor
|
StephaneLenclud@231
|
233 |
NumericUpDown ctrl = new NumericUpDown();
|
StephaneLenclud@231
|
234 |
ctrl.AutoSize = true;
|
StephaneLenclud@231
|
235 |
ctrl.Minimum = Int32.Parse(aAttribute.Minimum);
|
StephaneLenclud@231
|
236 |
ctrl.Maximum = Int32.Parse(aAttribute.Maximum);
|
StephaneLenclud@231
|
237 |
ctrl.Increment = Int32.Parse(aAttribute.Increment);
|
StephaneLenclud@236
|
238 |
ctrl.Value = (int)aInfo.GetValue(aObject);
|
StephaneLenclud@247
|
239 |
// Hook-in change notification after setting the value
|
StephaneLenclud@247
|
240 |
ctrl.ValueChanged += ControlValueChanged;
|
StephaneLenclud@231
|
241 |
return ctrl;
|
StephaneLenclud@231
|
242 |
}
|
StephaneLenclud@231
|
243 |
else if (aInfo.PropertyType.IsEnum)
|
StephaneLenclud@231
|
244 |
{
|
StephaneLenclud@231
|
245 |
//Enum properties are using combo box
|
StephaneLenclud@231
|
246 |
ComboBox ctrl = new ComboBox();
|
Stephane@243
|
247 |
ctrl.AutoSize = true;
|
Stephane@243
|
248 |
ctrl.Sorted = true;
|
StephaneLenclud@231
|
249 |
ctrl.DropDownStyle = ComboBoxStyle.DropDownList;
|
StephaneLenclud@231
|
250 |
//Data source is fine but it gives us duplicate entries for duplicated enum values
|
StephaneLenclud@231
|
251 |
//ctrl.DataSource = Enum.GetValues(aInfo.PropertyType);
|
StephaneLenclud@231
|
252 |
|
StephaneLenclud@231
|
253 |
//Therefore we need to explicitly create our items
|
Stephane@243
|
254 |
Size cbSize = new Size(0, 0);
|
StephaneLenclud@231
|
255 |
foreach (string name in aInfo.PropertyType.GetEnumNames())
|
StephaneLenclud@231
|
256 |
{
|
StephaneLenclud@231
|
257 |
ctrl.Items.Add(name.ToString());
|
StephaneLenclud@231
|
258 |
Graphics g = this.CreateGraphics();
|
StephaneLenclud@231
|
259 |
//Since combobox autosize would not work we need to get measure text ourselves
|
Stephane@243
|
260 |
SizeF size = g.MeasureString(name.ToString(), ctrl.Font);
|
Stephane@243
|
261 |
cbSize.Width = Math.Max(cbSize.Width, (int)size.Width);
|
StephaneLenclud@231
|
262 |
cbSize.Height = Math.Max(cbSize.Height, (int)size.Height);
|
StephaneLenclud@231
|
263 |
}
|
StephaneLenclud@231
|
264 |
|
StephaneLenclud@231
|
265 |
//Make sure our combobox is large enough
|
StephaneLenclud@231
|
266 |
ctrl.MinimumSize = cbSize;
|
StephaneLenclud@231
|
267 |
|
StephaneLenclud@231
|
268 |
// Instantiate our enum
|
StephaneLenclud@231
|
269 |
object enumValue = Activator.CreateInstance(aInfo.PropertyType);
|
StephaneLenclud@236
|
270 |
enumValue = aInfo.GetValue(aObject);
|
StephaneLenclud@231
|
271 |
//Set the current item
|
StephaneLenclud@231
|
272 |
ctrl.SelectedItem = enumValue.ToString();
|
StephaneLenclud@247
|
273 |
// Hook-in change notification after setting the value
|
StephaneLenclud@247
|
274 |
ctrl.SelectedIndexChanged += ControlValueChanged;
|
StephaneLenclud@231
|
275 |
|
StephaneLenclud@231
|
276 |
return ctrl;
|
StephaneLenclud@231
|
277 |
}
|
StephaneLenclud@231
|
278 |
else if (aInfo.PropertyType == typeof(bool))
|
StephaneLenclud@231
|
279 |
{
|
StephaneLenclud@231
|
280 |
CheckBox ctrl = new CheckBox();
|
StephaneLenclud@231
|
281 |
ctrl.AutoSize = true;
|
StephaneLenclud@231
|
282 |
ctrl.Text = aAttribute.Description;
|
Stephane@243
|
283 |
ctrl.Checked = (bool)aInfo.GetValue(aObject);
|
StephaneLenclud@247
|
284 |
// Hook-in change notification after setting the value
|
StephaneLenclud@247
|
285 |
ctrl.CheckedChanged += ControlValueChanged;
|
StephaneLenclud@231
|
286 |
return ctrl;
|
StephaneLenclud@231
|
287 |
}
|
StephaneLenclud@231
|
288 |
else if (aInfo.PropertyType == typeof(string))
|
StephaneLenclud@231
|
289 |
{
|
StephaneLenclud@231
|
290 |
TextBox ctrl = new TextBox();
|
StephaneLenclud@231
|
291 |
ctrl.AutoSize = true;
|
StephaneLenclud@236
|
292 |
ctrl.Text = (string)aInfo.GetValue(aObject);
|
StephaneLenclud@247
|
293 |
// Hook-in change notification after setting the value
|
StephaneLenclud@247
|
294 |
ctrl.TextChanged += ControlValueChanged;
|
StephaneLenclud@231
|
295 |
return ctrl;
|
StephaneLenclud@231
|
296 |
}
|
StephaneLenclud@238
|
297 |
else if (aInfo.PropertyType == typeof(PropertyFile))
|
StephaneLenclud@238
|
298 |
{
|
StephaneLenclud@238
|
299 |
// We have a file property
|
StephaneLenclud@238
|
300 |
// Create a button that will trigger the open file dialog to select our file.
|
StephaneLenclud@238
|
301 |
Button ctrl = new Button();
|
StephaneLenclud@238
|
302 |
ctrl.AutoSize = true;
|
StephaneLenclud@238
|
303 |
ctrl.Text = ((PropertyFile)aInfo.GetValue(aObject)).FullPath;
|
StephaneLenclud@238
|
304 |
// Add lambda expression to Click event
|
StephaneLenclud@238
|
305 |
ctrl.Click += (sender, e) =>
|
StephaneLenclud@238
|
306 |
{
|
StephaneLenclud@238
|
307 |
// Create open file dialog
|
StephaneLenclud@238
|
308 |
OpenFileDialog ofd = new OpenFileDialog();
|
StephaneLenclud@238
|
309 |
ofd.RestoreDirectory = true;
|
StephaneLenclud@238
|
310 |
// Use file filter specified by our property
|
StephaneLenclud@238
|
311 |
ofd.Filter = aAttribute.Filter;
|
StephaneLenclud@238
|
312 |
// Show our dialog
|
StephaneLenclud@238
|
313 |
if (DlgBox.ShowDialog(ofd) == DialogResult.OK)
|
StephaneLenclud@238
|
314 |
{
|
StephaneLenclud@238
|
315 |
// Fetch selected file name
|
StephaneLenclud@238
|
316 |
ctrl.Text = ofd.FileName;
|
StephaneLenclud@238
|
317 |
}
|
StephaneLenclud@238
|
318 |
};
|
StephaneLenclud@238
|
319 |
|
StephaneLenclud@247
|
320 |
// Hook-in change notification after setting the value
|
StephaneLenclud@247
|
321 |
ctrl.TextChanged += ControlValueChanged;
|
StephaneLenclud@238
|
322 |
return ctrl;
|
StephaneLenclud@238
|
323 |
}
|
Stephane@243
|
324 |
else if (aInfo.PropertyType == typeof(PropertyComboBox))
|
Stephane@243
|
325 |
{
|
Stephane@243
|
326 |
//ComboBox property
|
Stephane@243
|
327 |
ComboBox ctrl = new ComboBox();
|
Stephane@243
|
328 |
ctrl.AutoSize = true;
|
Stephane@243
|
329 |
ctrl.Sorted = true;
|
Stephane@243
|
330 |
ctrl.DropDownStyle = ComboBoxStyle.DropDownList;
|
Stephane@243
|
331 |
//Data source is such a pain to set the current item
|
Stephane@243
|
332 |
//ctrl.DataSource = ((PropertyComboBox)aInfo.GetValue(aObject)).Items;
|
Stephane@243
|
333 |
|
Stephane@243
|
334 |
PropertyComboBox pcb = ((PropertyComboBox)aInfo.GetValue(aObject));
|
Stephane@243
|
335 |
foreach (string item in pcb.Items)
|
Stephane@243
|
336 |
{
|
Stephane@243
|
337 |
ctrl.Items.Add(item);
|
Stephane@243
|
338 |
}
|
Stephane@243
|
339 |
|
Stephane@243
|
340 |
ctrl.SelectedItem = ((PropertyComboBox)aInfo.GetValue(aObject)).CurrentItem;
|
Stephane@243
|
341 |
//
|
Stephane@243
|
342 |
return ctrl;
|
Stephane@243
|
343 |
}
|
StephaneLenclud@250
|
344 |
else if (aInfo.PropertyType == typeof(PropertyButton))
|
StephaneLenclud@250
|
345 |
{
|
StephaneLenclud@250
|
346 |
// We have a button property
|
StephaneLenclud@250
|
347 |
// Create a button that will trigger the custom action.
|
StephaneLenclud@250
|
348 |
Button ctrl = new Button();
|
StephaneLenclud@250
|
349 |
ctrl.AutoSize = true;
|
StephaneLenclud@250
|
350 |
ctrl.Text = ((PropertyButton)aInfo.GetValue(aObject)).Text;
|
StephaneLenclud@250
|
351 |
// Hook in click event
|
StephaneLenclud@250
|
352 |
ctrl.Click += ((PropertyButton)aInfo.GetValue(aObject)).ClickEventHandler;
|
StephaneLenclud@250
|
353 |
// Hook-in change notification after setting the value
|
StephaneLenclud@250
|
354 |
ctrl.TextChanged += ControlValueChanged;
|
StephaneLenclud@250
|
355 |
return ctrl;
|
StephaneLenclud@250
|
356 |
}
|
StephaneLenclud@250
|
357 |
|
StephaneLenclud@231
|
358 |
//TODO: add support for other control type here
|
StephaneLenclud@231
|
359 |
return null;
|
StephaneLenclud@231
|
360 |
}
|
StephaneLenclud@231
|
361 |
|
StephaneLenclud@231
|
362 |
/// <summary>
|
StephaneLenclud@231
|
363 |
/// Don't forget to extend that one and adding types
|
StephaneLenclud@231
|
364 |
/// </summary>
|
StephaneLenclud@231
|
365 |
/// <returns></returns>
|
StephaneLenclud@231
|
366 |
private bool IsPropertyTypeSupported(PropertyInfo aInfo)
|
StephaneLenclud@231
|
367 |
{
|
StephaneLenclud@231
|
368 |
if (aInfo.PropertyType == typeof(int))
|
StephaneLenclud@231
|
369 |
{
|
StephaneLenclud@231
|
370 |
return true;
|
StephaneLenclud@231
|
371 |
}
|
StephaneLenclud@231
|
372 |
else if (aInfo.PropertyType.IsEnum)
|
StephaneLenclud@231
|
373 |
{
|
StephaneLenclud@231
|
374 |
return true;
|
StephaneLenclud@231
|
375 |
}
|
StephaneLenclud@231
|
376 |
else if (aInfo.PropertyType == typeof(bool))
|
StephaneLenclud@231
|
377 |
{
|
StephaneLenclud@231
|
378 |
return true;
|
StephaneLenclud@231
|
379 |
}
|
StephaneLenclud@231
|
380 |
else if (aInfo.PropertyType == typeof(string))
|
StephaneLenclud@231
|
381 |
{
|
StephaneLenclud@231
|
382 |
return true;
|
StephaneLenclud@231
|
383 |
}
|
StephaneLenclud@238
|
384 |
else if (aInfo.PropertyType == typeof(PropertyFile))
|
StephaneLenclud@238
|
385 |
{
|
StephaneLenclud@238
|
386 |
return true;
|
StephaneLenclud@238
|
387 |
}
|
Stephane@243
|
388 |
else if (aInfo.PropertyType == typeof(PropertyComboBox))
|
Stephane@243
|
389 |
{
|
Stephane@243
|
390 |
return true;
|
Stephane@243
|
391 |
}
|
StephaneLenclud@250
|
392 |
else if (aInfo.PropertyType == typeof(PropertyButton))
|
StephaneLenclud@250
|
393 |
{
|
StephaneLenclud@250
|
394 |
return true;
|
StephaneLenclud@250
|
395 |
}
|
Stephane@243
|
396 |
|
StephaneLenclud@231
|
397 |
//TODO: add support for other type here
|
StephaneLenclud@231
|
398 |
|
StephaneLenclud@231
|
399 |
return false;
|
StephaneLenclud@231
|
400 |
}
|
StephaneLenclud@231
|
401 |
|
StephaneLenclud@231
|
402 |
/// <summary>
|
StephaneLenclud@231
|
403 |
/// Update our table layout.
|
StephaneLenclud@246
|
404 |
/// Will instantiated every field control as defined by our object.
|
StephaneLenclud@231
|
405 |
/// </summary>
|
StephaneLenclud@231
|
406 |
/// <param name="aLayout"></param>
|
StephaneLenclud@247
|
407 |
private void UpdateControls()
|
StephaneLenclud@231
|
408 |
{
|
StephaneLenclud@247
|
409 |
|
StephaneLenclud@231
|
410 |
toolTip.RemoveAll();
|
StephaneLenclud@231
|
411 |
//Debug.Print("UpdateTableLayoutPanel")
|
StephaneLenclud@231
|
412 |
//First clean our current panel
|
StephaneLenclud@231
|
413 |
iTableLayoutPanel.Controls.Clear();
|
StephaneLenclud@231
|
414 |
iTableLayoutPanel.RowStyles.Clear();
|
StephaneLenclud@231
|
415 |
iTableLayoutPanel.ColumnStyles.Clear();
|
StephaneLenclud@231
|
416 |
iTableLayoutPanel.RowCount = 0;
|
StephaneLenclud@231
|
417 |
|
StephaneLenclud@231
|
418 |
//We always want two columns: one for label and one for the field
|
StephaneLenclud@231
|
419 |
iTableLayoutPanel.ColumnCount = 2;
|
StephaneLenclud@231
|
420 |
iTableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
|
StephaneLenclud@231
|
421 |
iTableLayoutPanel.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
|
StephaneLenclud@231
|
422 |
|
StephaneLenclud@231
|
423 |
|
StephaneLenclud@247
|
424 |
if (Object == null)
|
StephaneLenclud@231
|
425 |
{
|
StephaneLenclud@231
|
426 |
//Just drop it
|
StephaneLenclud@231
|
427 |
return;
|
StephaneLenclud@231
|
428 |
}
|
StephaneLenclud@246
|
429 |
|
StephaneLenclud@247
|
430 |
UpdateStaticControls();
|
StephaneLenclud@247
|
431 |
|
StephaneLenclud@236
|
432 |
//IEnumerable<PropertyInfo> properties = aObject.GetType().GetProperties().Where(
|
StephaneLenclud@231
|
433 |
// prop => Attribute.IsDefined(prop, typeof(AttributeObjectProperty)));
|
StephaneLenclud@231
|
434 |
|
StephaneLenclud@246
|
435 |
//TODO: Do this whenever a field changes
|
StephaneLenclud@247
|
436 |
iLabelBrief.Text = Object.Brief();
|
StephaneLenclud@246
|
437 |
|
StephaneLenclud@231
|
438 |
|
StephaneLenclud@247
|
439 |
foreach (PropertyInfo pi in Object.GetType().GetProperties())
|
StephaneLenclud@231
|
440 |
{
|
StephaneLenclud@231
|
441 |
AttributeObjectProperty[] attributes = ((AttributeObjectProperty[])pi.GetCustomAttributes(typeof(AttributeObjectProperty), true));
|
StephaneLenclud@231
|
442 |
if (attributes.Length != 1)
|
StephaneLenclud@231
|
443 |
{
|
StephaneLenclud@231
|
444 |
continue;
|
StephaneLenclud@231
|
445 |
}
|
StephaneLenclud@231
|
446 |
|
StephaneLenclud@231
|
447 |
AttributeObjectProperty attribute = attributes[0];
|
StephaneLenclud@231
|
448 |
|
StephaneLenclud@231
|
449 |
//Before anything we need to check if that kind of property is supported by our UI
|
StephaneLenclud@231
|
450 |
//Create the editor
|
StephaneLenclud@247
|
451 |
Control ctrl = CreateControlForProperty(pi, attribute, Object);
|
StephaneLenclud@231
|
452 |
if (ctrl == null)
|
StephaneLenclud@231
|
453 |
{
|
StephaneLenclud@231
|
454 |
//Property type not supported
|
StephaneLenclud@231
|
455 |
continue;
|
StephaneLenclud@231
|
456 |
}
|
StephaneLenclud@231
|
457 |
|
StephaneLenclud@231
|
458 |
//Add a new row
|
StephaneLenclud@231
|
459 |
iTableLayoutPanel.RowCount++;
|
StephaneLenclud@231
|
460 |
iTableLayoutPanel.RowStyles.Add(new RowStyle(SizeType.AutoSize));
|
StephaneLenclud@231
|
461 |
//Create the label
|
StephaneLenclud@231
|
462 |
Label label = new Label();
|
StephaneLenclud@231
|
463 |
label.AutoSize = true;
|
StephaneLenclud@231
|
464 |
label.Dock = DockStyle.Fill;
|
StephaneLenclud@231
|
465 |
label.TextAlign = ContentAlignment.MiddleCenter;
|
StephaneLenclud@231
|
466 |
label.Text = attribute.Name;
|
StephaneLenclud@231
|
467 |
toolTip.SetToolTip(label, attribute.Description);
|
StephaneLenclud@231
|
468 |
iTableLayoutPanel.Controls.Add(label, 0, iTableLayoutPanel.RowCount-1);
|
StephaneLenclud@231
|
469 |
|
StephaneLenclud@231
|
470 |
//Add our editor to our form
|
StephaneLenclud@231
|
471 |
iTableLayoutPanel.Controls.Add(ctrl, 1, iTableLayoutPanel.RowCount - 1);
|
StephaneLenclud@231
|
472 |
//Add tooltip to editor too
|
StephaneLenclud@231
|
473 |
toolTip.SetToolTip(ctrl, attribute.Description);
|
StephaneLenclud@231
|
474 |
|
StephaneLenclud@246
|
475 |
}
|
StephaneLenclud@231
|
476 |
|
StephaneLenclud@246
|
477 |
//Entrer object edit mode
|
StephaneLenclud@246
|
478 |
Object.CurrentState = SharpLib.Ear.Object.State.Edit;
|
StephaneLenclud@246
|
479 |
Object.PropertyChanged += PropertyChangedEventHandlerThreadSafe;
|
StephaneLenclud@246
|
480 |
}
|
StephaneLenclud@246
|
481 |
|
StephaneLenclud@247
|
482 |
/// <summary>
|
StephaneLenclud@247
|
483 |
///
|
StephaneLenclud@247
|
484 |
/// </summary>
|
StephaneLenclud@247
|
485 |
/// <param name="sender"></param>
|
StephaneLenclud@247
|
486 |
/// <param name="e"></param>
|
StephaneLenclud@246
|
487 |
void PropertyChangedEventHandlerThreadSafe(object sender, PropertyChangedEventArgs e)
|
StephaneLenclud@246
|
488 |
{
|
StephaneLenclud@246
|
489 |
if (this.InvokeRequired)
|
StephaneLenclud@246
|
490 |
{
|
StephaneLenclud@246
|
491 |
//Not in the proper thread, invoke ourselves
|
StephaneLenclud@246
|
492 |
PropertyChangedEventHandler d = new PropertyChangedEventHandler(PropertyChangedEventHandlerThreadSafe);
|
StephaneLenclud@246
|
493 |
this.Invoke(d, new object[] { sender, e });
|
StephaneLenclud@246
|
494 |
}
|
StephaneLenclud@246
|
495 |
else
|
StephaneLenclud@246
|
496 |
{
|
StephaneLenclud@247
|
497 |
// We could test the name of the property that has changed as follow
|
StephaneLenclud@247
|
498 |
// It's currently not needed though
|
StephaneLenclud@247
|
499 |
//if (e.PropertyName == "Brief")
|
StephaneLenclud@246
|
500 |
|
StephaneLenclud@247
|
501 |
// Our object has changed behind our back.
|
StephaneLenclud@247
|
502 |
// That's currently only the case for HID events that are listening for inputs.
|
StephaneLenclud@250
|
503 |
if (Object is EventHid)
|
StephaneLenclud@250
|
504 |
{
|
StephaneLenclud@250
|
505 |
//HID can't do full control updates for some reason
|
StephaneLenclud@250
|
506 |
//We are getting spammed with HID events after a few clicks
|
StephaneLenclud@250
|
507 |
//We need to investigate, HID bug?
|
StephaneLenclud@250
|
508 |
UpdateStaticControls();
|
StephaneLenclud@250
|
509 |
}
|
StephaneLenclud@250
|
510 |
else
|
StephaneLenclud@250
|
511 |
{
|
StephaneLenclud@250
|
512 |
UpdateControls();
|
StephaneLenclud@250
|
513 |
}
|
StephaneLenclud@246
|
514 |
}
|
StephaneLenclud@231
|
515 |
}
|
StephaneLenclud@231
|
516 |
|
StephaneLenclud@231
|
517 |
private void buttonTest_Click(object sender, EventArgs e)
|
StephaneLenclud@231
|
518 |
{
|
StephaneLenclud@231
|
519 |
FetchPropertiesValue(Object);
|
StephaneLenclud@231
|
520 |
|
StephaneLenclud@231
|
521 |
//If our object has a test method with no parameters just run it then
|
StephaneLenclud@231
|
522 |
MethodInfo info = Object.GetType().GetMethod("Test");
|
StephaneLenclud@231
|
523 |
if ( info != null && info.GetParameters().Length==0)
|
StephaneLenclud@231
|
524 |
{
|
StephaneLenclud@231
|
525 |
info.Invoke(Object,null);
|
StephaneLenclud@231
|
526 |
}
|
StephaneLenclud@231
|
527 |
|
StephaneLenclud@231
|
528 |
}
|
StephaneLenclud@247
|
529 |
|
StephaneLenclud@247
|
530 |
|
StephaneLenclud@247
|
531 |
/// <summary>
|
StephaneLenclud@247
|
532 |
///
|
StephaneLenclud@247
|
533 |
/// </summary>
|
StephaneLenclud@247
|
534 |
/// <param name="sender"></param>
|
StephaneLenclud@247
|
535 |
/// <param name="e"></param>
|
StephaneLenclud@247
|
536 |
private void ControlValueChanged(object sender, EventArgs e)
|
StephaneLenclud@247
|
537 |
{
|
StephaneLenclud@247
|
538 |
UpdateObject();
|
StephaneLenclud@247
|
539 |
}
|
StephaneLenclud@247
|
540 |
|
StephaneLenclud@247
|
541 |
/// <summary>
|
StephaneLenclud@247
|
542 |
///
|
StephaneLenclud@247
|
543 |
/// </summary>
|
StephaneLenclud@247
|
544 |
private void UpdateObject()
|
StephaneLenclud@247
|
545 |
{
|
StephaneLenclud@247
|
546 |
// Update our object with the content of our controls
|
StephaneLenclud@247
|
547 |
FetchPropertiesValue(Object);
|
StephaneLenclud@247
|
548 |
|
StephaneLenclud@247
|
549 |
UpdateStaticControls();
|
StephaneLenclud@247
|
550 |
//
|
StephaneLenclud@247
|
551 |
//PerformLayout();
|
StephaneLenclud@247
|
552 |
}
|
StephaneLenclud@247
|
553 |
|
StephaneLenclud@247
|
554 |
/// <summary>
|
StephaneLenclud@247
|
555 |
///
|
StephaneLenclud@247
|
556 |
/// </summary>
|
StephaneLenclud@247
|
557 |
private void UpdateStaticControls()
|
StephaneLenclud@247
|
558 |
{
|
StephaneLenclud@247
|
559 |
// Update OK and test button status
|
StephaneLenclud@247
|
560 |
iButtonOk.Enabled = Object.IsValid();
|
StephaneLenclud@247
|
561 |
iButtonTest.Enabled = iButtonOk.Enabled;
|
StephaneLenclud@247
|
562 |
|
StephaneLenclud@247
|
563 |
// Update brief title
|
StephaneLenclud@247
|
564 |
iLabelBrief.Text = Object.Brief();
|
StephaneLenclud@247
|
565 |
|
StephaneLenclud@247
|
566 |
// Update object description
|
StephaneLenclud@260
|
567 |
iLabelDescription.Text = Object.AttributeDescription;
|
StephaneLenclud@247
|
568 |
}
|
StephaneLenclud@247
|
569 |
|
StephaneLenclud@247
|
570 |
/// <summary>
|
StephaneLenclud@247
|
571 |
///
|
StephaneLenclud@247
|
572 |
/// </summary>
|
StephaneLenclud@247
|
573 |
/// <param name="sender"></param>
|
StephaneLenclud@247
|
574 |
/// <param name="e"></param>
|
StephaneLenclud@247
|
575 |
private void iComboBoxObjectType_KeyPress(object sender, KeyPressEventArgs e)
|
StephaneLenclud@247
|
576 |
{
|
StephaneLenclud@247
|
577 |
//Special case for HID events
|
StephaneLenclud@247
|
578 |
if (Object is EventHid)
|
StephaneLenclud@247
|
579 |
{
|
StephaneLenclud@247
|
580 |
//Disable handling of key input as we are using key input for changing our event
|
StephaneLenclud@247
|
581 |
e.Handled = true;
|
StephaneLenclud@247
|
582 |
}
|
StephaneLenclud@247
|
583 |
}
|
StephaneLenclud@260
|
584 |
|
StephaneLenclud@260
|
585 |
private void iComboBoxObjectType_Enter(object sender, EventArgs e)
|
StephaneLenclud@260
|
586 |
{
|
StephaneLenclud@260
|
587 |
//Only edit HID event when our type combo box has the focus
|
StephaneLenclud@260
|
588 |
// TODO: That's an ugly workaround, fix that somehow. Maybe by only doing HID scan when a button property has the focus
|
StephaneLenclud@260
|
589 |
if (Object is EventHid)
|
StephaneLenclud@260
|
590 |
{
|
StephaneLenclud@260
|
591 |
Object.CurrentState = SharpLib.Ear.Object.State.Edit;
|
StephaneLenclud@260
|
592 |
}
|
StephaneLenclud@260
|
593 |
}
|
StephaneLenclud@260
|
594 |
|
StephaneLenclud@260
|
595 |
private void iComboBoxObjectType_Leave(object sender, EventArgs e)
|
StephaneLenclud@260
|
596 |
{
|
StephaneLenclud@260
|
597 |
//Only edit HID event when our type combo box has the focus
|
StephaneLenclud@260
|
598 |
// TODO: That's an ugly workaround, fix that somehow. Maybe by only doing HID scan when a button property has the focus
|
StephaneLenclud@260
|
599 |
if (Object is EventHid)
|
StephaneLenclud@260
|
600 |
{
|
StephaneLenclud@260
|
601 |
Object.CurrentState = SharpLib.Ear.Object.State.Rest;
|
StephaneLenclud@260
|
602 |
}
|
StephaneLenclud@260
|
603 |
}
|
StephaneLenclud@231
|
604 |
}
|
StephaneLenclud@231
|
605 |
}
|