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                 }
160
161                 protected internal override void Edit (CurrencyManager source, int rowNum, Rectangle bounds, bool readOnly, string instantText,  bool cellIsVisible)
162                 {
163                         row = rowNum;
164                         oldState = GetState (source, rowNum);
165                         SetState (rowNum, oldState | CheckState.Selected);
166                         grid.Invalidate (grid.GetCurrentCellBounds ());
167                 }
168
169                 [MonoTODO]
170                 protected internal override void EnterNullValue ()
171                 {
172
173                 }
174
175                 private bool ValueEquals (object value, object obj)
176                 {
177                         return value == null ? obj == null : value.Equals (obj);
178                 }
179
180                 protected internal override object GetColumnValueAtRow (CurrencyManager lm, int row)
181                 {
182                         object obj = base.GetColumnValueAtRow (lm, row);
183
184                         if (ValueEquals (nullvalue, obj)) {
185                                 return Convert.DBNull;
186                         }
187
188                         if (ValueEquals (truevalue, obj)) {
189                                 return true;
190                         }
191
192                         return false;
193                 }
194
195                 protected internal override int GetMinimumHeight ()
196                 {
197                         return ThemeEngine.Current.DataGridMinimumColumnCheckBoxHeight;
198                 }
199
200                 protected internal override int GetPreferredHeight (Graphics g, object value)
201                 {
202                         return ThemeEngine.Current.DataGridMinimumColumnCheckBoxHeight;
203                 }
204
205                 protected internal override Size GetPreferredSize (Graphics g, object value)
206                 {
207                         return new Size (ThemeEngine.Current.DataGridMinimumColumnCheckBoxWidth, ThemeEngine.Current.DataGridMinimumColumnCheckBoxHeight);
208                 }
209
210                 protected internal override void Paint (Graphics g, Rectangle bounds, CurrencyManager source, int rowNum)
211                 {
212                         Paint (g, bounds, source, rowNum, false);
213                 }
214
215                 protected internal override void Paint (Graphics g, Rectangle bounds, CurrencyManager source, int rowNum, bool alignToRight)
216                 {
217                         Paint (g, bounds, source, rowNum, ThemeEngine.Current.ResPool.GetSolidBrush (DataGridTableStyle.BackColor),
218                                 ThemeEngine.Current.ResPool.GetSolidBrush (DataGridTableStyle.ForeColor), alignToRight);
219                 }
220
221                 protected internal override void Paint (Graphics g, Rectangle bounds, CurrencyManager source, int rowNum, Brush backBrush, Brush foreBrush, bool alignToRight)
222                 {
223                         Size chkbox_size = GetPreferredSize (g, null);
224                         Rectangle rect = new Rectangle ();                      
225                         ButtonState state;
226                         CheckState check_state = GetState (source, rowNum);
227
228                         chkbox_size.Width -= 2;
229                         chkbox_size.Height -= 2;
230
231                         rect.X = bounds.X + ((bounds.Width - chkbox_size.Width) / 2);
232                         rect.Y = bounds.Y + ((bounds.Height - chkbox_size.Height) / 2);
233                         rect.Width = chkbox_size.Width;
234                         rect.Height = chkbox_size.Height;                       
235                         
236                         // If the cell is selected
237                         if ((check_state & CheckState.Selected) == CheckState.Selected) { 
238                                 backBrush = ThemeEngine.Current.ResPool.GetSolidBrush (grid.SelectionBackColor);
239                                 check_state &= ~CheckState.Selected;
240                         }
241                                                 
242                         g.FillRectangle (backBrush, bounds);                    
243                         
244                         switch (check_state) {
245                         case CheckState.Checked:
246                                 state = ButtonState.Checked;
247                                 break;
248                         case CheckState.Null:
249                                 state = ButtonState.Checked | ButtonState.Inactive;
250                                 break;
251                         case CheckState.UnChecked:
252                         default:
253                                 state = ButtonState.Normal;
254                                 break;
255                         }
256
257                         ThemeEngine.Current.CPDrawCheckBox (g, rect, state);
258                         PaintGridLine (g, bounds);
259                 }
260
261                 protected internal override void SetColumnValueAtRow (CurrencyManager lm, int row, object obj)
262                 {
263                         object value = null;
264
265                         if (ValueEquals (nullvalue, obj))
266                                 value = Convert.DBNull;
267                         else if (ValueEquals (truevalue, obj))
268                                 value = true;
269                         else if (ValueEquals (falsevalue, obj))
270                                 value = false;
271                         /* else error? */
272
273                         base.SetColumnValueAtRow (lm, row, value);
274                 }
275                 #endregion      // Public Instance Methods
276
277                 #region Private Instance Methods
278                 private object FromStateToValue (CheckState state)
279                 {
280                         if ((state & CheckState.Checked) == CheckState.Checked)
281                                 return truevalue;
282                         else if ((state & CheckState.Null) == CheckState.Null)
283                                 return nullvalue;
284                         else
285                                 return falsevalue;
286                 }
287
288                 private CheckState FromValueToState (object obj)
289                 {
290                         if (ValueEquals (truevalue, obj))
291                                 return CheckState.Checked;
292                         else if (ValueEquals (nullvalue, obj))
293                                 return CheckState.Null;
294                         else
295                                 return CheckState.UnChecked;
296                 }
297
298                 private CheckState GetState (CurrencyManager source, int row)
299                 {
300                         CheckState state;
301
302                         if (checkboxes_state[row] == null) {
303                                 object value = GetColumnValueAtRow (source, row);
304                                 state = FromValueToState (value);
305                                 checkboxes_state.Add (row, state);
306                         } else {
307                                 state = (CheckState) checkboxes_state[row];
308                         }
309
310                         return state;
311                 }
312
313                 private CheckState GetNextState (CheckState state)
314                 {
315                         CheckState new_state;
316                         bool selected = ((state & CheckState.Selected) == CheckState.Selected);
317
318                         switch (state & ~CheckState.Selected) {
319                         case CheckState.Checked:
320                                 new_state = CheckState.Null;
321                                 break;
322                         case CheckState.Null:
323                                 new_state = CheckState.UnChecked;
324                                 break;
325                         case CheckState.UnChecked:
326                         default:
327                                 new_state = CheckState.Checked;
328                                 break;
329                         }
330                         
331                         if (selected) {
332                                 new_state = new_state | CheckState.Selected;
333                         }
334
335                         return new_state;
336                 }
337
338                 internal override void OnKeyDown (KeyEventArgs ke, int row, int column)
339                 {
340                         switch (ke.KeyCode) {
341                         case Keys.Space:
342                                 NextState (row, column);
343                                 break;
344                         }
345                 }
346
347                 internal override void OnMouseDown (MouseEventArgs e, int row, int column)
348                 {
349                         this.row = row;
350                         NextState (row, column);
351                 }
352
353                 private void NextState (int row, int column)
354                 {
355                         grid.ColumnStartedEditing (new Rectangle());
356
357                         SetState (row, GetNextState (GetState (null, row)));
358
359                         grid.Invalidate (grid.GetCellBounds (row, column));
360                 }
361
362                 private void SetState (int row, CheckState state)
363                 {
364                         checkboxes_state[row] = state;
365                 }
366
367                 #endregion Private Instance Methods
368
369                 #region Events
370                 public event EventHandler AllowNullChanged;
371                 public event EventHandler FalseValueChanged;
372                 public event EventHandler TrueValueChanged;
373                 #endregion      // Events
374         }
375 }