Fix bug #395
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / DataGridViewCheckBoxCell.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 //
25
26
27 using System;
28 using System.ComponentModel;
29 using System.Drawing;
30 using System.Windows.Forms.VisualStyles;
31
32 namespace System.Windows.Forms {
33
34         public class DataGridViewCheckBoxCell : DataGridViewCell, IDataGridViewEditingCell {
35
36                 private object editingCellFormattedValue;
37                 private bool editingCellValueChanged;
38                 private object falseValue;
39                 private FlatStyle flatStyle;
40                 private object indeterminateValue;
41                 private bool threeState;
42                 private object trueValue;
43 //              private Type valueType;
44                 private PushButtonState check_state;
45
46                 public DataGridViewCheckBoxCell ()
47                 {
48                         check_state = PushButtonState.Normal;
49                         editingCellFormattedValue = false;
50                         editingCellValueChanged = false;
51                         falseValue = null;
52                         flatStyle = FlatStyle.Standard;
53                         indeterminateValue = null;
54                         threeState = false;
55                         trueValue = null;
56                         ValueType = null;
57                 }
58
59                 public DataGridViewCheckBoxCell (bool threeState) : this()
60                 {
61                         this.threeState = threeState;
62                         editingCellFormattedValue = CheckState.Unchecked;
63                 }
64
65                 public virtual object EditingCellFormattedValue {
66                         get { return editingCellFormattedValue; }
67                         set {
68                                 if (FormattedValueType == null || value == null || value.GetType() != FormattedValueType || !(value is Boolean) || !(value is CheckState)) {
69                                         throw new ArgumentException("Cannot set this property.");
70                                 }
71                                 editingCellFormattedValue = value;
72                         }
73                 }
74
75                 public virtual bool EditingCellValueChanged {
76                         get { return editingCellValueChanged; }
77                         set { editingCellValueChanged = value; }
78                 }
79
80                 public override Type EditType {
81                         get { return null; }
82                 }
83
84                 [DefaultValue (null)]
85                 public object FalseValue {
86                         get { return falseValue; }
87                         set { falseValue = value; }
88                 }
89
90                 [DefaultValue (FlatStyle.Standard)]
91                 public FlatStyle FlatStyle {
92                         get { return flatStyle; }
93                         set {
94                                 if (!Enum.IsDefined(typeof(FlatStyle), value)) {
95                                         throw new InvalidEnumArgumentException("Value is not valid FlatStyle.");
96                                 }
97                                 if (value == FlatStyle.Popup) {
98                                         throw new Exception("FlatStyle cannot be set to Popup in this control.");
99                                 }
100                         }
101                 }
102
103                 public override Type FormattedValueType {
104                         get {
105                                 if (ThreeState) {
106                                         return typeof(CheckState);
107                                 }
108                                 return typeof(Boolean);
109                         }
110                 }
111
112                 [DefaultValue (null)]
113                 public object IndeterminateValue {
114                         get { return indeterminateValue; }
115                         set { indeterminateValue = value; }
116                 }
117
118                 [DefaultValue (false)]
119                 public bool ThreeState {
120                         get { return threeState; }
121                         set { threeState = value; }
122                 }
123
124                 [DefaultValue (null)]
125                 public object TrueValue {
126                         get { return trueValue; }
127                         set { trueValue = value; }
128                 }
129
130                 public override Type ValueType {
131                         get {
132                                 if (base.ValueType == null) {
133                                         if (OwningColumn != null && OwningColumn.ValueType != null) {
134                                                 return OwningColumn.ValueType;
135                                         }
136                                         if (ThreeState) {
137                                                 return typeof(CheckState);
138                                         }
139                                         return typeof(Boolean);
140                                 }
141                                 return base.ValueType;
142                         }
143                         set { base.ValueType = value; }
144                 }
145
146                 public override object Clone ()
147                 {
148                         DataGridViewCheckBoxCell cell = (DataGridViewCheckBoxCell) base.Clone();
149                         cell.editingCellValueChanged = this.editingCellValueChanged;
150                         cell.editingCellFormattedValue = this.editingCellFormattedValue;
151                         cell.falseValue = this.falseValue;
152                         cell.flatStyle = this.flatStyle;
153                         cell.indeterminateValue = this.indeterminateValue;
154                         cell.threeState = this.threeState;
155                         cell.trueValue = this.trueValue;
156                         cell.ValueType = this.ValueType;
157                         return cell;
158                 }
159
160                 public virtual object GetEditingCellFormattedValue (DataGridViewDataErrorContexts context)
161                 {
162                         if (FormattedValueType == null) {
163                                 throw new InvalidOperationException("FormattedValueType is null.");
164                         }
165                         if ((context & DataGridViewDataErrorContexts.ClipboardContent) != 0) {
166                                 return Convert.ToString(Value);
167                         }
168
169                         if (editingCellFormattedValue == null)
170                                 if (threeState)
171                                         return CheckState.Indeterminate;
172                                 else
173                                         return false;
174
175                         return editingCellFormattedValue;
176                 }
177
178                 public override object ParseFormattedValue (object formattedValue, DataGridViewCellStyle cellStyle, TypeConverter formattedValueTypeConverter, TypeConverter valueTypeConverter)
179                 {
180                         if (cellStyle == null) {
181                                 throw new ArgumentNullException("CellStyle is null");
182                         }
183                         if (FormattedValueType == null) {
184                                 throw new FormatException("FormattedValueType is null.");
185                         }
186                         if (formattedValue == null || formattedValue.GetType() != FormattedValueType) {
187                                 throw new ArgumentException("FormattedValue is null or is not instance of FormattedValueType.");
188                         }
189                         
190                         return base.ParseFormattedValue (formattedValue, cellStyle, formattedValueTypeConverter, valueTypeConverter);
191                 }
192
193                 public virtual void PrepareEditingCellForEdit (bool selectAll)
194                 {
195                         editingCellFormattedValue = GetCurrentValue ();
196                 }
197
198                 public override string ToString ()
199                 {
200                         return string.Format ("DataGridViewCheckBoxCell {{ ColumnIndex={0}, RowIndex={1} }}", ColumnIndex, RowIndex);
201                 }
202
203                 protected override bool ContentClickUnsharesRow (DataGridViewCellEventArgs e)
204                 {
205                         return this.IsInEditMode;
206                 }
207
208                 protected override bool ContentDoubleClickUnsharesRow (DataGridViewCellEventArgs e)
209                 {
210                         return this.IsInEditMode;
211                 }
212
213                 protected override AccessibleObject CreateAccessibilityInstance ()
214                 {
215                         return new DataGridViewCheckBoxCellAccessibleObject(this);
216                 }
217
218                 protected override Rectangle GetContentBounds (Graphics graphics, DataGridViewCellStyle cellStyle, int rowIndex)
219                 {
220                         if (DataGridView == null)
221                                 return Rectangle.Empty;
222
223                         return new Rectangle ((Size.Width - 13) / 2, (Size.Height - 13) / 2, 13, 13);
224                 }
225
226                 protected override Rectangle GetErrorIconBounds (Graphics graphics, DataGridViewCellStyle cellStyle, int rowIndex)
227                 {
228                         if (DataGridView == null || string.IsNullOrEmpty (ErrorText))
229                                 return Rectangle.Empty;
230
231                         Size error_icon = new Size (12, 11);
232                         return new Rectangle (new Point (Size.Width - error_icon.Width - 5, (Size.Height - error_icon.Height) / 2), error_icon);
233                 }
234
235                 protected override object GetFormattedValue (object value, int rowIndex, ref DataGridViewCellStyle cellStyle, TypeConverter valueTypeConverter, TypeConverter formattedValueTypeConverter, DataGridViewDataErrorContexts context)
236                 {
237                         if (DataGridView == null || value == null)
238                                 if (threeState)
239                                         return CheckState.Indeterminate;
240                                 else
241                                         return false;
242                                         
243                         return value;
244                 }
245
246                 protected override Size GetPreferredSize (Graphics graphics, DataGridViewCellStyle cellStyle, int rowIndex, Size constraintSize)
247                 {
248                         return new Size (21, 20);
249                 }
250
251                 protected override bool KeyDownUnsharesRow (KeyEventArgs e, int rowIndex)
252                 {
253                         // true if the user pressed the SPACE key without modifier keys; otherwise, false
254                         return e.KeyData == Keys.Space;
255                 }
256
257                 protected override bool KeyUpUnsharesRow (KeyEventArgs e, int rowIndex)
258                 {
259                         // true if the user released the SPACE key; otherwise false
260                         return e.KeyData == Keys.Space;
261                 }
262
263                 protected override bool MouseDownUnsharesRow (DataGridViewCellMouseEventArgs e)
264                 {
265                         return (e.Button == MouseButtons.Left);
266                 }
267
268                 protected override bool MouseEnterUnsharesRow (int rowIndex)
269                 {
270                         // true if the cell was the last cell receiving a mouse click; otherwise, false.
271                         return false;
272                 }
273
274                 protected override bool MouseLeaveUnsharesRow (int rowIndex)
275                 {
276                         // true if the button displayed by the cell is in the pressed state; otherwise, false.
277                         return check_state == PushButtonState.Pressed;
278                 }
279
280                 protected override bool MouseUpUnsharesRow (DataGridViewCellMouseEventArgs e)
281                 {
282                         // true if the mouse up was caused by the release of the left mouse button; otherwise false.
283                         return e.Button == MouseButtons.Left;
284                 }
285
286                 protected override void OnContentClick (DataGridViewCellEventArgs e)
287                 {
288                         if (ReadOnly)
289                                 return;
290
291                         if (!IsInEditMode)
292                                 DataGridView.BeginEdit (false);
293                         
294                         ToggleCheckState ();
295                 }
296
297                 private void ToggleCheckState ()
298                 {
299                         CheckState cs = GetCurrentValue ();
300
301                         if (threeState) {
302                                 if (cs == CheckState.Indeterminate)
303                                         editingCellFormattedValue = CheckState.Unchecked;
304                                 else if (cs == CheckState.Checked)
305                                         editingCellFormattedValue = CheckState.Indeterminate;
306                                 else
307                                         editingCellFormattedValue = CheckState.Checked;
308                         } else {
309                                 if (cs == CheckState.Checked)
310                                         editingCellFormattedValue = false;
311                                 else
312                                         editingCellFormattedValue = true;
313                         }
314
315                         editingCellValueChanged = true;
316                         DataGridView.InvalidateCell (this);
317                 }
318
319                 protected override void OnContentDoubleClick (DataGridViewCellEventArgs e)
320                 {
321                 }
322
323                 protected override void OnKeyDown (KeyEventArgs e, int rowIndex)
324                 {
325                         // when activated by the SPACE key, this method updates the cell's user interface
326                         if (!ReadOnly && (e.KeyData & Keys.Space) == Keys.Space) {
327                                 check_state = PushButtonState.Pressed;
328                                 DataGridView.InvalidateCell (this);
329                         }
330                 }
331
332                 protected override void OnKeyUp (KeyEventArgs e, int rowIndex)
333                 {
334                         // when activated by the SPACE key, this method updates the cell's user interface
335                         if (!ReadOnly && (e.KeyData & Keys.Space) == Keys.Space) {
336                                 check_state = PushButtonState.Normal;
337                                 if (!IsInEditMode)
338                                         DataGridView.BeginEdit (false);
339                                 ToggleCheckState ();
340                         }
341                 }
342
343                 protected override void OnLeave (int rowIndex, bool throughMouseClick)
344                 {
345                         if (!ReadOnly && check_state != PushButtonState.Normal) {
346                                 check_state = PushButtonState.Normal;
347                                 DataGridView.InvalidateCell (this);
348                         }
349                 }
350
351                 protected override void OnMouseDown (DataGridViewCellMouseEventArgs e)
352                 {
353                         // if activated by depresing the left mouse button, this method updates the cell's user interface
354                         if (!ReadOnly && (e.Button & MouseButtons.Left) == MouseButtons.Left) {
355                                 check_state = PushButtonState.Pressed;
356                                 DataGridView.InvalidateCell (this);
357                         }
358                 }
359
360                 protected override void OnMouseLeave (int rowIndex)
361                 {
362                         // if the cell's button is not in its normal state, this method causes the cell's user interface to be updated.
363                         if (!ReadOnly && check_state != PushButtonState.Normal) {
364                                 check_state = PushButtonState.Normal;
365                                 DataGridView.InvalidateCell (this);
366                         }
367                 }
368
369                 protected override void OnMouseMove (DataGridViewCellMouseEventArgs e)
370                 {
371                         if (!ReadOnly && check_state != PushButtonState.Normal && check_state != PushButtonState.Hot) {
372                                 check_state = PushButtonState.Hot;
373                                 DataGridView.InvalidateCell (this);
374                         }
375                 }
376
377                 protected override void OnMouseUp (DataGridViewCellMouseEventArgs e)
378                 {
379                         // if activated by the left mouse button, this method updates the cell's user interface
380                         if (!ReadOnly && (e.Button & MouseButtons.Left) == MouseButtons.Left) {
381                                 check_state = PushButtonState.Normal;
382                                 DataGridView.InvalidateCell (this);
383                         }
384                 }
385
386                 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)
387                 {
388                         base.Paint (graphics, clipBounds, cellBounds, rowIndex, elementState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);
389                 }
390
391                 internal override void PaintPartContent (Graphics graphics, Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, DataGridViewCellStyle cellStyle, object formattedValue)
392                 {
393                         CheckBoxState state;
394                         CheckState value = GetCurrentValue ();
395
396                         if ((CheckState)value == CheckState.Unchecked)
397                                 state = (CheckBoxState)check_state;
398                         else if ((CheckState)value == CheckState.Checked)
399                                 state = (CheckBoxState)((int)check_state + 4);
400                         else if (threeState)
401                                 state = (CheckBoxState)((int)check_state + 8);
402                         else
403                                 state = (CheckBoxState)check_state;
404                                         
405                         Point p = new Point (cellBounds.X + (Size.Width - 13) / 2, cellBounds.Y + (Size.Height - 13) / 2);
406                         CheckBoxRenderer.DrawCheckBox (graphics, p, state);
407                 }
408                 
409                 private CheckState GetCurrentValue ()
410                 {
411                         CheckState cs = CheckState.Indeterminate;
412                         
413                         object current_obj;
414                         
415                         if (editingCellValueChanged)
416                                 current_obj = editingCellFormattedValue;
417                         else
418                                 current_obj = Value;
419
420                         if (current_obj == null)
421                                 cs = CheckState.Indeterminate;
422                         else if (current_obj is bool)
423                         {
424                                 if ((bool)current_obj == true)
425                                         cs = CheckState.Checked;
426                                 else if ((bool)current_obj == false)
427                                         cs = CheckState.Unchecked;
428                         }
429                         else if (current_obj is CheckState)
430                                 cs = (CheckState)current_obj;
431
432                         return cs;
433                 }
434                 
435                 protected class DataGridViewCheckBoxCellAccessibleObject : DataGridViewCellAccessibleObject {
436
437                         public DataGridViewCheckBoxCellAccessibleObject (DataGridViewCell owner) : base(owner)
438                         {
439                         }
440
441                         public override string DefaultAction {
442                                 get {
443                                         if (Owner.ReadOnly) {
444                                                 return "";
445                                         }
446                                         // return "Press to check" if the check box is not selected
447                                         // and "Press to uncheck" if the check box is selected
448                                         throw new NotImplementedException();
449                                 }
450                         }
451
452                         public override void DoDefaultAction ()
453                         {
454                                 // change the state of the check box
455                         }
456
457                         public override int GetChildCount ()
458                         {
459                                 return -1;
460                         }
461
462                 }
463
464         }
465
466 }
467