Warnings cleanup
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / DataGridBoolColumn.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-2007 Novell, Inc. (http://www.novell.com)
21 //
22 // Author:
23 //      Jordi Mas i Hernandez <jordi@ximian.com>
24 //      Chris toshok <toshok@ximian.com>
25 //
26 //
27
28 using System.ComponentModel;
29 using System.Drawing;
30 using System.Runtime.InteropServices;
31 using System.Diagnostics;
32 using System.Collections;
33
34 namespace System.Windows.Forms
35 {
36         public class DataGridBoolColumn : DataGridColumnStyle
37         {
38                 [Flags]
39                 private enum CheckState {
40                         Checked         = 0x00000001,
41                         UnChecked       = 0x00000002,
42                         Null            = 0x00000004,
43                         Selected        = 0x00000008
44                 }
45
46                 #region Local Variables
47                 private bool allow_null;
48                 private object false_value;
49                 private object null_value;
50                 private object true_value;
51                 int editing_row;
52                 CheckState editing_state;
53                 CheckState model_state;
54                 Size checkbox_size;
55
56                 #endregion      // Local Variables
57
58                 #region Constructors
59                 public DataGridBoolColumn () : this (null, false)
60                 {
61                 }
62
63                 public DataGridBoolColumn (PropertyDescriptor prop) : this (prop, false)
64                 {
65                 }
66
67                 public DataGridBoolColumn (PropertyDescriptor prop, bool isDefault)  : base (prop)
68                 {
69                         false_value = false;
70                         null_value = null;
71                         true_value = true;
72                         allow_null = true;
73                         is_default = isDefault;
74                         checkbox_size = new Size (ThemeEngine.Current.DataGridMinimumColumnCheckBoxWidth, ThemeEngine.Current.DataGridMinimumColumnCheckBoxHeight);
75                 }
76                 #endregion
77
78                 #region Public Instance Properties
79                 [DefaultValue(true)]
80                 public bool AllowNull {
81                         get {
82                                 return allow_null;
83                         }
84                         set {
85                                 if (value != allow_null) {
86                                         allow_null = value;
87
88                                         EventHandler eh = (EventHandler)(Events [AllowNullChangedEvent]);
89                                         if (eh != null)
90                                                 eh (this, EventArgs.Empty);
91                                 }
92                         }
93                 }
94
95                 [TypeConverter(typeof(System.ComponentModel.StringConverter))]
96 #if NET_2_0
97                 [DefaultValue (false)]
98 #endif
99                 public object FalseValue {
100                         get {
101                                 return false_value;
102                         }
103                         set {
104                                 if (value != false_value) {
105                                         false_value = value;
106
107                                         EventHandler eh = (EventHandler)(Events [FalseValueChangedEvent]);
108                                         if (eh != null)
109                                                 eh (this, EventArgs.Empty);
110                                 }
111                         }
112                 }
113
114                 [TypeConverter(typeof(System.ComponentModel.StringConverter))]
115                 public object NullValue {
116                         get {
117                                 return null_value;
118                         }
119                         set {
120                                 if (value != null_value) {
121                                         null_value = value;
122
123                                         // XXX no NullValueChangedEvent?  lame.
124                                 }
125                         }
126                 }
127
128                 [TypeConverter(typeof(System.ComponentModel.StringConverter))]
129 #if NET_2_0
130                 [DefaultValue (true)]
131 #endif
132                 public object TrueValue {
133                         get {
134                                 return true_value;
135                         }
136                         set {
137                                 if (value != true_value) {
138                                         true_value = value;
139
140                                         EventHandler eh = (EventHandler)(Events [TrueValueChangedEvent]);
141                                         if (eh != null)
142                                                 eh (this, EventArgs.Empty);
143                                 }
144                         }
145                 }
146                 #endregion      // Public Instance Properties
147
148                 #region Public Instance Methods
149                 protected internal override void Abort (int rowNum)
150                 {
151                         if (rowNum == editing_row) {
152                                 // XXX 
153                                 // this needs to not use the current cell
154                                 // bounds, but the bounds of the cell for this
155                                 // column/rowNum.
156                                 grid.Invalidate (grid.GetCurrentCellBounds ());
157                                 editing_row = -1;
158                         }
159                 }
160
161                 protected internal override bool Commit (CurrencyManager dataSource, int rowNum)
162                 {
163                         if (rowNum == editing_row) {
164                                 SetColumnValueAtRow (dataSource, rowNum, FromStateToValue (editing_state));
165                                 // XXX 
166                                 // this needs to not use the current cell
167                                 // bounds, but the bounds of the cell for this
168                                 // column/rowNum.
169                                 grid.Invalidate (grid.GetCurrentCellBounds ());
170                                 editing_row = -1;
171                         }
172                         return true;
173                 }
174
175                 [MonoTODO]
176                 protected internal override void ConcedeFocus ()
177                 {
178                 }
179
180 #if NET_2_0
181                 protected internal override void Edit (CurrencyManager source, int rowNum, Rectangle bounds, bool readOnly, string displayText,  bool cellIsVisible)
182                 {
183 #else
184                 protected internal override void Edit (CurrencyManager source, int rowNum, Rectangle bounds, bool readOnly, string instantText, bool cellIsVisible)
185                 {
186 #endif
187                         editing_row = rowNum;
188                         model_state = FromValueToState (GetColumnValueAtRow (source, rowNum));
189                         editing_state = model_state | CheckState.Selected;
190                         // XXX 
191                         // this needs to not use the current cell
192                         // bounds, but the bounds of the cell for this
193                         // column/rowNum.
194                         grid.Invalidate (grid.GetCurrentCellBounds ());
195                 }
196
197                 [MonoTODO]
198                 protected internal override void EnterNullValue ()
199                 {
200
201                 }
202
203                 private bool ValueEquals (object value, object obj)
204                 {
205                         return value == null ? obj == null : value.Equals (obj);
206                 }
207
208                 protected internal override object GetColumnValueAtRow (CurrencyManager lm, int row)
209                 {
210                         object obj = base.GetColumnValueAtRow (lm, row);
211
212                         if (ValueEquals (DBNull.Value, obj))
213                                 return null_value;
214
215                         if (ValueEquals (true, obj))
216                                 return true_value;
217
218                         return false_value;
219                 }
220
221                 protected internal override int GetMinimumHeight ()
222                 {
223                         return checkbox_size.Height;
224                 }
225
226                 protected internal override int GetPreferredHeight (Graphics g, object value)
227                 {
228                         return checkbox_size.Height;
229                 }
230
231                 protected internal override Size GetPreferredSize (Graphics g, object value)
232                 {
233                         return checkbox_size;
234                 }
235
236                 protected internal override void Paint (Graphics g, Rectangle bounds, CurrencyManager source, int rowNum)
237                 {
238                         Paint (g, bounds, source, rowNum, false);
239                 }
240
241                 protected internal override void Paint (Graphics g, Rectangle bounds, CurrencyManager source, int rowNum, bool alignToRight)
242                 {
243                         Paint (g, bounds, source, rowNum, ThemeEngine.Current.ResPool.GetSolidBrush (DataGridTableStyle.BackColor),
244                                 ThemeEngine.Current.ResPool.GetSolidBrush (DataGridTableStyle.ForeColor), alignToRight);
245                 }
246
247                 protected internal override void Paint (Graphics g, Rectangle bounds, CurrencyManager source, int rowNum, Brush backBrush, Brush foreBrush, bool alignToRight)
248                 {
249                         Rectangle rect = new Rectangle ();                      
250                         ButtonState state;
251                         CheckState check_state;
252
253                         if (rowNum == editing_row)
254                                 check_state = editing_state;
255                         else
256                                 check_state = FromValueToState (GetColumnValueAtRow (source, rowNum));
257
258                         rect.X = bounds.X + ((bounds.Width - checkbox_size.Width - 2) / 2);
259                         rect.Y = bounds.Y + ((bounds.Height - checkbox_size.Height - 2) / 2);
260                         rect.Width = checkbox_size.Width - 2;
261                         rect.Height = checkbox_size.Height - 2;
262                         
263                         // If the cell is selected
264                         if ((check_state & CheckState.Selected) == CheckState.Selected) { 
265                                 backBrush = ThemeEngine.Current.ResPool.GetSolidBrush (grid.SelectionBackColor);
266                                 check_state &= ~CheckState.Selected;
267                         }
268                                                 
269                         g.FillRectangle (backBrush, bounds);                    
270                         
271                         switch (check_state) {
272                         case CheckState.Checked:
273                                 state = ButtonState.Checked;
274                                 break;
275                         case CheckState.Null:
276                                 state = ButtonState.Checked | ButtonState.Inactive;
277                                 break;
278                         case CheckState.UnChecked:
279                         default:
280                                 state = ButtonState.Normal;
281                                 break;
282                         }
283
284                         ThemeEngine.Current.CPDrawCheckBox (g, rect, state);
285                         PaintGridLine (g, bounds);
286                 }
287
288                 protected internal override void SetColumnValueAtRow (CurrencyManager lm, int row, object value)
289                 {
290                         object final_value = null;
291
292                         if (ValueEquals (null_value, value))
293                                 final_value = DBNull.Value;
294                         else if (ValueEquals (true_value, value))
295                                 final_value = true;
296                         else if (ValueEquals (false_value, value))
297                                 final_value = false;
298                         /* else error? */
299
300                         base.SetColumnValueAtRow (lm, row, final_value);
301                 }
302                 #endregion      // Public Instance Methods
303
304                 #region Private Instance Methods
305                 private object FromStateToValue (CheckState state)
306                 {
307                         if ((state & CheckState.Checked) == CheckState.Checked)
308                                 return true_value;
309                         else if ((state & CheckState.Null) == CheckState.Null)
310                                 return null_value;
311                         else
312                                 return false_value;
313                 }
314
315                 private CheckState FromValueToState (object obj)
316                 {
317                         if (ValueEquals (true_value, obj))
318                                 return CheckState.Checked;
319                         else if (ValueEquals (null_value, obj))
320                                 return CheckState.Null;
321                         else
322                                 return CheckState.UnChecked;
323                 }
324
325                 private CheckState GetNextState (CheckState state)
326                 {
327                         CheckState new_state;
328
329                         switch (state & ~CheckState.Selected) {
330                         case CheckState.Checked:
331                                 if (AllowNull)
332                                         new_state = CheckState.Null;
333                                 else
334                                         new_state = CheckState.UnChecked;
335                                 break;
336                         case CheckState.Null:
337                                 new_state = CheckState.UnChecked;
338                                 break;
339                         case CheckState.UnChecked:
340                         default:
341                                 new_state = CheckState.Checked;
342                                 break;
343                         }
344                         
345                         new_state |= (state & CheckState.Selected);
346
347                         return new_state;
348                 }
349
350                 internal override void OnKeyDown (KeyEventArgs ke, int row, int column)
351                 {
352                         switch (ke.KeyCode) {
353                         case Keys.Space:
354                                 NextState (row, column);
355                                 break;
356                         }
357                 }
358
359                 internal override void OnMouseDown (MouseEventArgs e, int row, int column)
360                 {
361                         NextState (row, column);
362                 }
363
364                 private void NextState (int row, int column)
365                 {
366                         grid.ColumnStartedEditing (new Rectangle());
367
368                         editing_state = GetNextState (editing_state);
369
370                         grid.Invalidate (grid.GetCellBounds (row, column));
371                 }
372
373                 #endregion Private Instance Methods
374
375                 #region Events
376                 static object AllowNullChangedEvent = new object ();
377                 static object FalseValueChangedEvent = new object ();
378                 static object TrueValueChangedEvent = new object ();
379
380                 public event EventHandler AllowNullChanged {
381                         add { Events.AddHandler (AllowNullChangedEvent, value); }
382                         remove { Events.RemoveHandler (AllowNullChangedEvent, value); }
383                 }
384
385                 public event EventHandler FalseValueChanged {
386                         add { Events.AddHandler (FalseValueChangedEvent, value); }
387                         remove { Events.RemoveHandler (FalseValueChangedEvent, value); }
388                 }
389
390                 public event EventHandler TrueValueChanged {
391                         add { Events.AddHandler (TrueValueChangedEvent, value); }
392                         remove { Events.RemoveHandler (TrueValueChangedEvent, value); }
393                 }
394                 #endregion      // Events
395         }
396 }