* TabControl.cs: Show the tooltip depending on the value
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / DataGridViewComboBoxCell.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) 2005 Novell, Inc. (http://www.novell.com)
21 //
22 // Author:
23 //      Pedro Martínez Juliá <pedromj@gmail.com>
24 //      Ivan N. Zlatev <contact@i-nz.net>
25 //
26
27
28 #if NET_2_0
29
30 using System.Collections;
31 using System.ComponentModel;
32 using System.Drawing;
33
34 namespace System.Windows.Forms {
35
36         public class DataGridViewComboBoxCell : DataGridViewCell {
37
38                 private bool autoComplete;
39                 private object dataSource;
40                 private string displayMember;
41                 private DataGridViewComboBoxDisplayStyle displayStyle;
42                 private bool displayStyleForCurrentCellOnly;
43                 private int dropDownWidth;
44                 private FlatStyle flatStyle;
45                 private ObjectCollection items;
46                 private int maxDropDownItems;
47                 private bool sorted;
48                 private string valueMember;
49                 private DataGridViewComboBoxColumn owningColumnTemlate;
50
51                 public DataGridViewComboBoxCell () : base() {
52                         autoComplete = true;
53                         dataSource = null;
54                         displayStyle = DataGridViewComboBoxDisplayStyle.DropDownButton;
55                         displayStyleForCurrentCellOnly = false;
56                         dropDownWidth = 1;
57                         flatStyle = FlatStyle.Standard;
58                         items = new ObjectCollection(this);
59                         maxDropDownItems = 8;
60                         sorted = false;
61                         owningColumnTemlate = null;
62                 }
63
64                 [DefaultValue (true)]
65                 public virtual bool AutoComplete {
66                         get { return autoComplete; }
67                         set { autoComplete = value; }
68                 }
69
70                 public virtual object DataSource {
71                         get { return dataSource; }
72                         set {
73                                 if (value is IList || value is IListSource || value == null) {
74                                         dataSource = value;
75                                         return;
76                                 }
77                                 throw new Exception("Value is no IList, IListSource or null.");
78                         }
79                 }
80
81                 [DefaultValue ("")]
82                 public virtual string DisplayMember {
83                         get { return displayMember; }
84                         set { displayMember = value; }
85                 }
86
87                 [DefaultValue (DataGridViewComboBoxDisplayStyle.DropDownButton)]
88                 public DataGridViewComboBoxDisplayStyle DisplayStyle {
89                         get { return displayStyle; }
90                         set { displayStyle = value; }
91                 }
92
93                 [DefaultValue (false)]
94                 public bool DisplayStyleForCurrentCellOnly {
95                         get { return displayStyleForCurrentCellOnly; }
96                         set { displayStyleForCurrentCellOnly = value; }
97                 }
98
99                 [DefaultValue (1)]
100                 public virtual int DropDownWidth {
101                         get { return dropDownWidth; }
102                         set {
103                                 if (value < 1) {
104                                         throw new ArgumentOutOfRangeException("Value is less than 1.");
105                                 }
106                                 dropDownWidth = value;
107                         }
108                 }
109
110                 public override Type EditType {
111                         get { return typeof(DataGridViewComboBoxEditingControl); }
112                 }
113
114                 [DefaultValue (FlatStyle.Standard)]
115                 public FlatStyle FlatStyle {
116                         get { return flatStyle; }
117                         set {
118                                 if (!Enum.IsDefined(typeof(FlatStyle), value)) {
119                                         throw new InvalidEnumArgumentException("Value is not valid FlatStyle.");
120                                 }
121                                 flatStyle = value;
122                         }
123                 }
124
125                 public override Type FormattedValueType {
126                         get { return typeof(string); }
127                 }
128
129                 [Browsable (false)]
130                 public virtual ObjectCollection Items {
131                         get {
132                                 if (DataGridView != null && DataGridView.BindingContext != null 
133                                     && DataSource != null && !String.IsNullOrEmpty (ValueMember)) {
134                                         items.ClearInternal ();
135                                         CurrencyManager dataManager = (CurrencyManager) DataGridView.BindingContext[DataSource];
136                                         if (dataManager != null && dataManager.Count > 0) {
137                                                 foreach (object item in dataManager.List)
138                                                         items.AddInternal (item);
139                                         }
140                                 }
141
142                                 return items;
143                         }
144                 }
145
146                 [DefaultValue (8)]
147                 public virtual int MaxDropDownItems {
148                         get { return maxDropDownItems; }
149                         set {
150                                 if (value < 1 || value > 100) {
151                                         throw new ArgumentOutOfRangeException("Value is less than 1 or greater than 100.");
152                                 }
153                                 maxDropDownItems = value;
154                         }
155                 }
156
157                 [DefaultValue (false)]
158                 public virtual bool Sorted {
159                         get { return sorted; }
160                         set {
161                                 /*
162                                 if () {
163                                         throw new ArgumentException("Cannot sort a cell attached to a data source.");
164                                 }
165                                 */
166                                 sorted = value;
167                         }
168                 }
169
170                 [DefaultValue ("")]
171                 public virtual string ValueMember {
172                         get { return valueMember; }
173                         set { valueMember = value; }
174                 }
175
176                 public override Type ValueType {
177                         get { return typeof(string); }
178                 }
179
180                 // Valid only for template Cells and used as a bridge to push items
181                 internal DataGridViewComboBoxColumn OwningColumnTemplate {
182                         get { return owningColumnTemlate; }
183                         set { owningColumnTemlate = value; }
184                 }
185
186                 public override object Clone () {
187                         DataGridViewComboBoxCell cell = (DataGridViewComboBoxCell) base.Clone();
188                         cell.autoComplete = this.autoComplete;
189                         cell.dataSource = this.dataSource;
190                         cell.displayStyle = this.displayStyle;
191                         cell.displayMember = this.displayMember;
192                         cell.valueMember = this.valueMember;
193                         cell.displayStyleForCurrentCellOnly = this.displayStyleForCurrentCellOnly;
194                         cell.dropDownWidth = this.dropDownWidth;
195                         cell.flatStyle = this.flatStyle;
196                         cell.items.AddRangeInternal(this.items);
197                         cell.maxDropDownItems = this.maxDropDownItems;
198                         cell.sorted = this.sorted;
199                         return cell;
200                 }
201
202                 public override void DetachEditingControl () {
203                         this.DataGridView.EditingControlInternal = null;
204                 }
205
206                 public override void InitializeEditingControl (int rowIndex, object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle) {
207                         base.InitializeEditingControl (rowIndex, initialFormattedValue, dataGridViewCellStyle);
208                         
209                         ComboBox editingControl = DataGridView.EditingControl as ComboBox;
210                         
211                         editingControl.DropDownStyle = ComboBoxStyle.DropDownList;
212                         editingControl.Sorted = Sorted;
213                         editingControl.DataSource = null;
214                         editingControl.ValueMember = null;
215                         editingControl.DisplayMember = null;
216                         editingControl.Items.Clear();
217                         editingControl.SelectedIndex = -1;
218
219                         if (DataSource != null) {
220                                 editingControl.DataSource = DataSource;
221                                 editingControl.ValueMember = ValueMember;
222                                 editingControl.DisplayMember = DisplayMember;
223                         } else {
224                                 editingControl.Items.AddRange (this.Items);
225                                 if (FormattedValue != null && editingControl.Items.IndexOf (FormattedValue) != -1)
226                                         editingControl.SelectedItem = FormattedValue;
227                         }
228                 }
229
230                 internal void SyncItems ()
231                 {
232                         if (DataSource != null || OwningColumnTemplate == null)
233                                 return;
234
235                         if (OwningColumnTemplate.DataGridView != null) {
236                                 DataGridViewComboBoxEditingControl editor = OwningColumnTemplate.DataGridView.EditingControl
237                                                                             as DataGridViewComboBoxEditingControl;
238                                 if (editor != null) {
239                                         object selectedItem = editor.SelectedItem;
240                                         editor.Items.Clear ();
241                                         editor.Items.AddRange (items);
242                                         if (editor.Items.IndexOf (selectedItem) != -1)
243                                                 editor.SelectedItem = selectedItem;
244                                 }
245                         }
246
247                         // Push the new items to the column
248                         OwningColumnTemplate.SyncItems (Items);
249                 }
250
251                 public override bool KeyEntersEditMode (KeyEventArgs e)
252                 {
253                         if (e.KeyCode == Keys.Space)
254                                 return true;
255                         if ((int)e.KeyCode >= 48 && (int)e.KeyCode <= 90)
256                                 return true;
257                         if ((int)e.KeyCode >= 96 && (int)e.KeyCode <= 111)
258                                 return true;
259                         if (e.KeyCode == Keys.BrowserSearch || e.KeyCode == Keys.SelectMedia)
260                                 return true;
261                         if ((int)e.KeyCode >= 186 && (int)e.KeyCode <= 229)
262                                 return true;
263                         if (e.KeyCode == Keys.Attn || e.KeyCode == Keys.Packet)
264                                 return true;
265                         if ((int)e.KeyCode >= 248 && (int)e.KeyCode <= 254)
266                                 return true;
267                         if (e.KeyCode == Keys.F4)
268                                 return true;
269                         if ((e.Modifiers == Keys.Alt) && (e.KeyCode == Keys.Down || e.KeyCode == Keys.Up))
270                                 return true;
271
272                         return false;
273                 }
274
275                 public override object ParseFormattedValue (object formattedValue, DataGridViewCellStyle cellStyle, TypeConverter formattedValueTypeConverter, TypeConverter valueTypeConverter)
276                 {
277                         return base.ParseFormattedValue (formattedValue, cellStyle, formattedValueTypeConverter, valueTypeConverter);
278                 }
279
280                 public override string ToString () {
281                         return string.Format ("DataGridViewComboBoxCell {{ ColumnIndex={0}, RowIndex={1} }}", ColumnIndex, RowIndex);
282                 }
283
284                 protected override Rectangle GetContentBounds (Graphics graphics, DataGridViewCellStyle cellStyle, int rowIndex)
285                 {
286                         if (DataGridView == null)
287                                 return Rectangle.Empty;
288
289                         object o = FormattedValue;
290                         Size s = Size.Empty;
291
292                         if (o != null)
293                                 s = DataGridViewCell.MeasureTextSize (graphics, o.ToString (), cellStyle.Font, TextFormatFlags.Default);
294
295                         return new Rectangle (1, (OwningRow.Height - s.Height) / 2, s.Width - 3, s.Height);
296                 }
297
298                 protected override Rectangle GetErrorIconBounds (Graphics graphics, DataGridViewCellStyle cellStyle, int rowIndex)
299                 {
300                         if (DataGridView == null || string.IsNullOrEmpty (ErrorText))
301                                 return Rectangle.Empty;
302
303                         Size error_icon = new Size (12, 11);
304                         return new Rectangle (new Point (Size.Width - error_icon.Width - 23, (Size.Height - error_icon.Height) / 2), error_icon);
305                 }
306
307                 protected override object GetFormattedValue (object value, int rowIndex, ref DataGridViewCellStyle cellStyle, TypeConverter valueTypeConverter, TypeConverter formattedValueTypeConverter, DataGridViewDataErrorContexts context)
308                 {
309                         return base.GetFormattedValue (value, rowIndex, ref cellStyle, valueTypeConverter, formattedValueTypeConverter, context);
310                 }
311
312                 protected override Size GetPreferredSize (Graphics graphics, DataGridViewCellStyle cellStyle, int rowIndex, Size constraintSize)
313                 {
314                         object o = FormattedValue;
315
316                         if (o != null) {
317                                 Size s = DataGridViewCell.MeasureTextSize (graphics, o.ToString (), cellStyle.Font, TextFormatFlags.Default);
318                                 s.Height = Math.Max (s.Height, 22);
319                                 s.Width += 25;
320                                 return s;
321                         } else
322                                 return new Size (39, 22);
323                 }
324
325                 protected override void OnDataGridViewChanged () {
326                         // Here we're supposed to do something with DataSource, etc, according to MSDN.
327                         base.OnDataGridViewChanged ();
328                 }
329
330                 protected override void OnEnter (int rowIndex, bool throughMouseClick) {
331                         base.OnEnter (rowIndex, throughMouseClick);
332                 }
333
334                 protected override void OnLeave (int rowIndex, bool throughMouseClick) {
335                         base.OnLeave (rowIndex, throughMouseClick);
336                 }
337
338                 protected override void OnMouseClick (DataGridViewCellMouseEventArgs e) {
339                         base.OnMouseClick (e);
340                 }
341
342                 protected override void OnMouseEnter (int rowIndex) {
343                         base.OnMouseEnter (rowIndex);
344                 }
345
346                 protected override void OnMouseLeave (int rowIndex) {
347                         base.OnMouseLeave (rowIndex);
348                 }
349
350                 protected override void OnMouseMove (DataGridViewCellMouseEventArgs e) {
351                         //Console.WriteLine ("MouseMove (Location: {0}", e.Location);
352                         base.OnMouseMove (e);
353                 }
354
355                 protected override void Paint (Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates elementState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
356                 {
357                         // The internal paint routines are overridden instead of
358                         // doing the custom paint logic here
359                         base.Paint (graphics, clipBounds, cellBounds, rowIndex, elementState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);
360                 }
361
362                 internal override void PaintPartContent (Graphics graphics, Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, DataGridViewCellStyle cellStyle, object formattedValue)
363                 {
364                         Color color = Selected ? cellStyle.SelectionForeColor : cellStyle.ForeColor;
365                         TextFormatFlags flags = TextFormatFlags.EndEllipsis | TextFormatFlags.VerticalCenter | TextFormatFlags.TextBoxControl;
366         
367                         Rectangle text_area = ContentBounds;
368                         text_area.X += cellBounds.X;
369                         text_area.Y += cellBounds.Y;
370
371                         Rectangle button_area = CalculateButtonArea (cellBounds);
372
373                         // The background of the dropdown button should be gray, not
374                         // the background color of the cell.
375                         graphics.FillRectangle (SystemBrushes.Control, button_area);
376                         ThemeEngine.Current.CPDrawComboButton (graphics, button_area, ButtonState.Normal);
377
378                         if (formattedValue != null)
379                                 TextRenderer.DrawText (graphics, formattedValue.ToString (), cellStyle.Font, text_area, color, flags);
380                 }
381                 
382                 private Rectangle CalculateButtonArea (Rectangle cellBounds)
383                 {
384                         Rectangle button_area, text_area;
385                         int border = ThemeEngine.Current.Border3DSize.Width;
386                         const int button_width = 16;
387
388                         text_area = cellBounds;
389
390                         button_area = cellBounds;
391                         button_area.X = text_area.Right - button_width - border;
392                         button_area.Y = text_area.Y + border;
393                         button_area.Width = button_width;
394                         button_area.Height = text_area.Height - 2 * border;
395                         
396                         return button_area;
397                 }
398
399                 // IMPORTANT: Only call the internal methods from within DataGridViewComboBoxCell
400                 // for adding/removing/clearing because the other methods invoke an update of the 
401                 // column items collection and you might end up in an endless loop.
402                 //
403                 [ListBindable (false)]
404                 public class ObjectCollection : IList, ICollection, IEnumerable {
405
406                         private ArrayList list;
407                         private DataGridViewComboBoxCell owner;
408
409                         public ObjectCollection (DataGridViewComboBoxCell owner)
410                         {
411                                 this.owner = owner;
412                                 list = new ArrayList();
413                         }
414
415                         public int Count {
416                                 get { return list.Count; }
417                         }
418
419                         bool IList.IsFixedSize {
420                                 get { return list.IsFixedSize; }
421                         }
422
423                         public bool IsReadOnly {
424                                 get { return list.IsReadOnly; }
425                         }
426
427                         bool ICollection.IsSynchronized {
428                                 get { return list.IsSynchronized; }
429                         }
430
431                         object ICollection.SyncRoot {
432                                 get { return list.SyncRoot; }
433                         }
434
435                         public virtual object this [int index] {
436                                 get { return list[index]; }
437                                 set {
438                                         ThrowIfOwnerIsDataBound ();
439                                         list[index] = value;
440                                 }
441                         }
442
443                         public int Add (object item)
444                         {
445                                 ThrowIfOwnerIsDataBound ();
446                                 int index = AddInternal (item);
447                                 SyncOwnerItems ();
448                                 return index;
449                         }
450                         
451                         internal int AddInternal (object item)
452                         {
453                                 return list.Add (item);
454                         }
455
456                         internal void AddRangeInternal (ICollection items)
457                         {
458                                 list.AddRange (items);
459                         }
460
461                         public void AddRange (ObjectCollection value)
462                         {
463                                 ThrowIfOwnerIsDataBound ();
464                                 AddRangeInternal (value);
465                                 SyncOwnerItems ();
466                         }
467
468                         private void SyncOwnerItems ()
469                         {
470                                 ThrowIfOwnerIsDataBound ();
471                                 if (owner != null)
472                                         owner.SyncItems ();
473                         }
474
475                         public void ThrowIfOwnerIsDataBound ()
476                         {
477                                 if (owner != null && owner.DataGridView != null && owner.DataSource != null)
478                                         throw new ArgumentException ("Cannot modify collection if the cell is data bound.");
479                         }
480
481                         public void AddRange (params object[] items)
482                         {
483                                 ThrowIfOwnerIsDataBound ();
484                                 AddRangeInternal (items);
485                                 SyncOwnerItems ();
486                         }
487
488                         public void Clear ()
489                         {
490                                 ThrowIfOwnerIsDataBound ();
491                                 ClearInternal ();
492                                 SyncOwnerItems ();
493                         }
494
495                         internal void ClearInternal ()
496                         {
497                                 list.Clear ();
498                         }
499
500                         public bool Contains (object value)
501                         {
502                                 return list.Contains(value);
503                         }
504
505                         void ICollection.CopyTo (Array destination, int index)
506                         {
507                                 CopyTo ((object[]) destination, index);
508                         }
509
510                         public void CopyTo (object[] destination, int arrayIndex)
511                         {
512                                 list.CopyTo (destination, arrayIndex);
513                         }
514
515                         public IEnumerator GetEnumerator ()
516                         {
517                                 return list.GetEnumerator();
518                         }
519
520                         public int IndexOf (object value)
521                         {
522                                 return list.IndexOf(value);
523                         }
524
525                         public void Insert (int index, object item)
526                         {
527                                 ThrowIfOwnerIsDataBound ();
528                                 InsertInternal (index, item);
529                                 SyncOwnerItems ();
530                         }
531
532                         internal void InsertInternal (int index, object item)
533                         {
534                                 list.Insert (index, item);
535                         }
536
537                         public void Remove (object value)
538                         {
539                                 ThrowIfOwnerIsDataBound ();
540                                 RemoveInternal (value);
541                                 SyncOwnerItems ();
542                         }
543
544                         internal void RemoveInternal (object value)
545                         {
546                                 list.Remove (value);
547                         }
548
549                         public void RemoveAt (int index)
550                         {
551                                 ThrowIfOwnerIsDataBound ();
552                                 RemoveAtInternal (index);
553                                 SyncOwnerItems ();
554                         }
555
556                         internal void RemoveAtInternal (int index)
557                         {
558                                 list.RemoveAt (index);
559                         }
560
561                         int IList.Add (object item)
562                         {
563                                 return Add (item);
564                         }
565
566                 }
567
568         }
569
570 }
571
572 #endif