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