2006-12-26 Jonathan Pobst <monkey@jpobst.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / ListControl.cs
1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
8 //
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 //
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 //
20 // Copyright (c) 2004-2005 Novell, Inc.
21 //
22 // Authors:
23 //      Jordi Mas i Hernandez, jordi@ximian.com
24 //
25 //
26
27 // COMPLETE
28
29 using System;
30 using System.Drawing;
31 using System.Collections;
32 using System.ComponentModel;
33 using System.Reflection;
34
35 namespace System.Windows.Forms
36 {
37         public abstract class ListControl : Control
38         {
39                 private object data_source;
40                 private BindingMemberInfo value_member;
41                 private string display_member;
42                 private CurrencyManager data_manager;
43 #if NET_2_0
44                 private bool formatting_enabled;
45 #endif
46
47                 protected ListControl ()
48                 {                       
49                         data_source = null;
50                         value_member = new BindingMemberInfo (string.Empty);
51                         display_member = string.Empty;
52                         data_manager = null;
53                         SetStyle (ControlStyles.StandardClick | ControlStyles.UserPaint
54 #if NET_2_0
55                                 | ControlStyles.UseTextForAccessibility
56 #endif
57                                 , false);
58                 }
59
60                 #region Events
61                 static object DataSourceChangedEvent = new object ();
62                 static object DisplayMemberChangedEvent = new object ();
63                 static object SelectedValueChangedEvent = new object ();
64                 static object ValueMemberChangedEvent = new object ();
65
66                 public event EventHandler DataSourceChanged {
67                         add { Events.AddHandler (DataSourceChangedEvent, value); }
68                         remove { Events.RemoveHandler (DataSourceChangedEvent, value); }
69                 }
70
71                 public event EventHandler DisplayMemberChanged {
72                         add { Events.AddHandler (DisplayMemberChangedEvent, value); }
73                         remove { Events.RemoveHandler (DisplayMemberChangedEvent, value); }
74                 }
75
76                 public event EventHandler SelectedValueChanged {
77                         add { Events.AddHandler (SelectedValueChangedEvent, value); }
78                         remove { Events.RemoveHandler (SelectedValueChangedEvent, value); }
79                 }
80
81                 public event EventHandler ValueMemberChanged {
82                         add { Events.AddHandler (ValueMemberChangedEvent, value); }
83                         remove { Events.RemoveHandler (ValueMemberChangedEvent, value); }
84                 }
85
86                 #endregion // Events
87
88                 #region .NET 2.0 Public Properties
89 #if NET_2_0
90                 public bool FormattingEnabled {
91                         get { return formatting_enabled; }
92                         set { formatting_enabled = value; }
93                 }
94 #endif
95                 #endregion
96
97                 #region Public Properties
98
99                 [DefaultValue(null)]
100                 [RefreshProperties(RefreshProperties.Repaint)]
101                 [TypeConverter("System.Windows.Forms.Design.DataSourceConverter, " + Consts.AssemblySystem_Design)]
102                 public object DataSource {
103                         get { return data_source; }
104                         set {
105                                 if (data_source == value)
106                                         return;
107
108                                 if (value == null)
109                                         display_member = String.Empty;
110                                 else if (!(value is IList || value is IListSource))
111                                         throw new Exception ("Complex DataBinding accepts as a data source " +
112                                                              "either an IList or an IListSource");
113
114                                 data_source = value;
115                                 ConnectToDataSource ();
116                                 OnDataSourceChanged (EventArgs.Empty);
117                         }
118                 }
119
120                 [DefaultValue("")]
121                 [Editor("System.Windows.Forms.Design.DataMemberFieldEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))]
122                 [TypeConverter("System.Windows.Forms.Design.DataMemberFieldConverter, " + Consts.AssemblySystem_Design)]
123                 public string DisplayMember {
124                         get { 
125                                 return display_member;                          
126                         }
127                         set {
128                                 if (value == null)
129                                         value = String.Empty;
130
131                                 if (display_member == value) {
132                                         return;
133                                 }
134
135                                 display_member = value;
136                                 ConnectToDataSource ();                         
137                                 OnDisplayMemberChanged (EventArgs.Empty);
138                         }
139                 }
140
141                 public abstract int SelectedIndex {
142                         get;
143                         set;
144                 }
145
146                 [Bindable(BindableSupport.Yes)]
147                 [Browsable(false)]
148                 [DefaultValue(null)]
149                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
150                 public object SelectedValue {
151                         get {
152                                 if (data_manager == null) {
153                                         return null;
154                                 }                               
155                                 
156                                 object item = data_manager [SelectedIndex];
157                                 object fil = FilterItemOnProperty (item, ValueMember);
158                                 return fil;
159                         }
160                         set {
161                                 if (value == null)
162                                         return;
163
164                                 if (value is string) {
165                                         string valueString = value as string;
166                                         if (valueString == String.Empty)
167                                                 return;
168                                 }
169
170                                 if (data_manager != null) {
171                                         
172                                         PropertyDescriptorCollection col = data_manager.GetItemProperties ();
173                                         PropertyDescriptor prop = col.Find (ValueMember, true);
174                                                                                 
175                                         for (int i = 0; i < data_manager.Count; i++) {
176                                                  if (prop.GetValue (data_manager [i]) == value) {
177                                                         SelectedIndex = i;
178                                                         return;
179                                                 }
180                                         }
181                                         
182                                 }
183                         }
184                 }
185
186                 [DefaultValue("")]
187                 [Editor("System.Windows.Forms.Design.DataMemberFieldEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))]
188                 public string ValueMember  {
189                         get { return value_member.BindingMember; }
190                         set {
191                                 BindingMemberInfo new_value = new BindingMemberInfo (value);
192                                 
193                                 if (value_member.Equals (new_value)) {
194                                         return;
195                                 }
196                                 
197                                 value_member = new_value;
198                                 
199                                 if (display_member == string.Empty) {
200                                         DisplayMember = value_member.BindingMember;                                     
201                                 }
202                                 
203                                 ConnectToDataSource ();
204                                 OnValueMemberChanged (EventArgs.Empty);
205                         }
206                 }
207
208                 #endregion Public Properties
209
210                 #region Public Methods
211
212                 protected object FilterItemOnProperty (object item)
213                 {
214                         return FilterItemOnProperty (item, string.Empty);
215                 }
216
217                 protected object FilterItemOnProperty (object item, string field)
218                 {
219                         if (item == null)
220                                 return null;
221
222                         if (field == null || field == string.Empty)
223                                 return item;
224
225                         PropertyDescriptor prop = null;
226
227                         if (data_manager != null) {
228                                 PropertyDescriptorCollection col = data_manager.GetItemProperties ();
229                                 prop = col.Find (field, true);                          
230                         }
231                         
232                         if (prop == null)
233                                 return item;
234                         
235                         return prop.GetValue (item);
236                 }
237
238                 public string GetItemText (object item)
239                 {
240                         if (data_manager != null) {
241                                 object fil = FilterItemOnProperty (item, DisplayMember);
242                                 if (fil != null) {
243                                         return fil.ToString ();
244                                 }
245                         }
246                                                                 
247                         return item.ToString ();                        
248                 }
249
250                 protected CurrencyManager DataManager {
251                         get { return data_manager; }
252                 }
253
254                 // Used only by ListBox to avoid to break Listbox's member signature
255                 protected override bool IsInputKey (Keys keyData)
256                 {
257                         switch (keyData) {
258                         case Keys.Up:
259                         case Keys.Down:
260                         case Keys.PageUp:
261                         case Keys.PageDown:
262                         case Keys.Right:
263                         case Keys.Left:
264                         case Keys.End:
265                         case Keys.Home:
266                         case Keys.ControlKey:
267                         case Keys.Space:
268                         case Keys.ShiftKey:
269                                 return true;
270
271                         default:
272                                 return false;
273                         }
274                 }
275
276                 protected override void OnBindingContextChanged (EventArgs e)
277                 {
278                         base.OnBindingContextChanged (e);
279                         ConnectToDataSource ();
280
281                         if (DataManager != null) {
282                                 SetItemsCore (DataManager.List);
283                                 SelectedIndex = DataManager.Position;
284                         }
285                 }
286
287                 protected virtual void OnDataSourceChanged (EventArgs e)
288                 {
289                         EventHandler eh = (EventHandler)(Events [DataSourceChangedEvent]);
290                         if (eh != null)
291                                 eh (this, e);
292                 }
293
294                 protected virtual void OnDisplayMemberChanged (EventArgs e)
295                 {
296                         EventHandler eh = (EventHandler)(Events [DisplayMemberChangedEvent]);
297                         if (eh != null)
298                                 eh (this, e);
299                 }
300
301                 protected virtual void OnSelectedIndexChanged (EventArgs e)
302                 {
303                         if (data_manager == null)
304                                 return;
305                         if (data_manager.Position == SelectedIndex)
306                                 return;
307                         data_manager.Position = SelectedIndex;
308                 }
309
310                 protected virtual void OnSelectedValueChanged (EventArgs e)
311                 {
312                         EventHandler eh = (EventHandler)(Events [SelectedValueChangedEvent]);
313                         if (eh != null)
314                                 eh (this, e);
315                 }
316
317                 protected virtual void OnValueMemberChanged (EventArgs e)
318                 {
319                         EventHandler eh = (EventHandler)(Events [ValueMemberChangedEvent]);
320                         if (eh != null)
321                                 eh (this, e);
322                 }
323
324                 protected abstract void RefreshItem (int index);
325
326                 protected virtual void SetItemCore (int index,  object value)
327                 {
328
329                 }
330
331                 protected abstract void SetItemsCore (IList items);
332                 
333                 #endregion Public Methods
334                 
335                 #region Private Methods
336
337                 internal void BindDataItems ()
338                 {
339                         if (data_manager != null) {
340                                 SetItemsCore (data_manager.List);
341                         }
342                 }
343
344                 private void ConnectToDataSource ()
345                 {
346                         if (data_source == null) {
347                                 data_manager = null;
348                                 return;
349                         }
350
351                         if (BindingContext == null) {
352                                 return;
353                         }
354                         
355                         data_manager = (CurrencyManager) BindingContext [data_source];
356                         data_manager.PositionChanged += new EventHandler (OnPositionChanged);
357                         data_manager.ItemChanged += new ItemChangedEventHandler (OnItemChanged);
358                 }               
359
360                 private void OnItemChanged (object sender, ItemChangedEventArgs e)
361                 {
362                         /* if the list has changed, tell our subclass to re-bind */
363                         if (e.Index == -1)
364                                 SetItemsCore (data_manager.List);
365                         else
366                                 RefreshItem (e.Index);
367                 }
368
369                 private void OnPositionChanged (object sender, EventArgs e)
370                 {                       
371                         SelectedIndex = data_manager.Position;
372                 }
373
374                 #endregion Private Methods      
375         }
376
377 }
378