2007-03-08 Chris Toshok <toshok@ximian.com>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / DataGrid.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,2006 Novell, Inc. (http://www.novell.com)
21 //
22 // Authors:
23 //      Jordi Mas i Hernandez   <jordi@ximian.com>
24 //      Chris Toshok            <toshok@ximian.com>
25 //
26 //
27
28 using System;
29 using System.ComponentModel;
30 using System.Data;
31 using System.Drawing;
32 using System.Runtime.InteropServices;
33 using System.Collections;
34 using System.Text;
35
36 namespace System.Windows.Forms
37 {
38         internal class DataGridRelationshipRow {
39                 DataGrid owner;
40
41                 public DataGridRelationshipRow (DataGrid owner)
42                 {
43                         this.owner = owner;
44                         IsSelected = false;
45                         IsExpanded = false;
46                         height = 0;
47                         VerticalOffset = 0;
48                         RelationHeight = 0;
49                         relation_area = Rectangle.Empty;
50                 }
51
52                 public int height;
53
54                 /* this needs to be a property so that the Autosize
55                  * example from the Windows.Forms FAQ will work */
56                 public int Height {
57                         get { return height; }
58                         set {
59                                 if (height != value) {
60                                         height = value;
61                                         owner.UpdateRowsFrom (this);
62                                 }
63                         }
64                 }
65
66                 public bool IsSelected;
67                 public bool IsExpanded;
68                 public int VerticalOffset;
69                 public int RelationHeight;
70                 public Rectangle relation_area; /* the Y coordinate of this rectangle is updated as needed */
71         }
72
73         internal class DataGridDataSource
74         {
75                 public DataGrid owner;
76                 public CurrencyManager list_manager;
77                 public object view;
78                 public string data_member;
79                 public object data_source;
80                 public DataGridCell current;
81
82                 public DataGridDataSource (DataGrid owner, CurrencyManager list_manager, object data_source, string data_member, object view_data, DataGridCell current)
83                 {
84                         this.owner = owner;
85                         this.list_manager = list_manager;
86                         this.view = view_data;
87                         this.data_source = data_source;
88                         this.data_member = data_member;
89                         this.current = current;
90                 }
91
92                 DataGridRelationshipRow[] rows;
93                 public DataGridRelationshipRow[] Rows {
94                         get { return rows; }
95                         set { rows = value; }
96                 }
97
98                 Hashtable selected_rows;
99                 public Hashtable SelectedRows {
100                         get { return selected_rows; }
101                         set { selected_rows = value; }
102                 }
103
104                 int selection_start;
105                 public int SelectionStart {
106                         get { return selection_start; }
107                         set { selection_start = value; }
108                 }
109         }
110
111         [DefaultEvent("Navigate")]
112         [DefaultProperty("DataSource")]
113         [Designer("System.Windows.Forms.Design.DataGridDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
114 #if NET_2_0
115         [ComplexBindingProperties ("DataSource", "DataMember")]
116         [ClassInterface (ClassInterfaceType.AutoDispatch)]
117         [ComVisible (true)]
118 #endif
119         public class DataGrid : Control, ISupportInitialize, IDataGridEditingService
120         {
121                 [Flags]
122 #if !NET_2_0
123                 [Serializable]
124 #endif
125                 public enum HitTestType
126                 {
127                         None            = 0,
128                         Cell            = 1,
129                         ColumnHeader    = 2,
130                         RowHeader       = 4,
131                         ColumnResize    = 8,
132                         RowResize       = 16,
133                         Caption         = 32,
134                         ParentRows      = 64
135                 }
136
137                 public sealed class HitTestInfo
138                 {
139                         public static readonly HitTestInfo Nowhere = null;
140
141                         int row;
142                         int column;
143                         DataGrid.HitTestType type;
144
145                         #region Private Constructors
146                         internal HitTestInfo () : this (-1, -1, HitTestType.None)
147                         {
148                         }
149
150                         internal HitTestInfo (int row, int column, DataGrid.HitTestType type)
151                         {
152                                 this.row = row;
153                                 this.column = column;
154                                 this.type = type;
155                         }
156                         #endregion
157
158
159                         #region Public Instance Properties
160                         public int Column {
161                                 get { return column; }
162                         }
163
164                         public int Row {
165                                 get { return row; }
166                         }
167                         public DataGrid.HitTestType Type {
168                                 get { return type; }
169                         }
170                         #endregion //Public Instance Properties
171
172                         public override bool Equals (object o)
173                         {
174                                 if (!(o is HitTestInfo))
175                                         return false;
176
177                                 HitTestInfo obj = (HitTestInfo) o;
178                                 return (obj.Column == column && obj.Row == row && obj.Type ==type);
179                         }
180
181                         public override int GetHashCode ()
182                         {
183                                 return row ^ column;
184                         }
185
186                         public override string ToString ()
187                         {
188                                 return "{ " + type + "," + row + "," + column + "}";
189                         }
190
191                 }
192
193                 #region Local Variables
194                 /* cached theme defaults */
195                 static readonly Color   def_background_color = ThemeEngine.Current.DataGridBackgroundColor;
196                 static readonly Color   def_caption_backcolor = ThemeEngine.Current.DataGridCaptionBackColor;
197                 static readonly Color   def_caption_forecolor = ThemeEngine.Current.DataGridCaptionForeColor;
198                 static readonly Color   def_parent_rows_backcolor = ThemeEngine.Current.DataGridParentRowsBackColor;
199                 static readonly Color   def_parent_rows_forecolor = ThemeEngine.Current.DataGridParentRowsForeColor;
200
201                 /* colors */
202                 // XXX this needs addressing. Control.background_color should not be internal.
203                 new Color background_color;
204                 Color caption_backcolor;
205                 Color caption_forecolor;
206                 Color parent_rows_backcolor;
207                 Color parent_rows_forecolor;
208
209                 /* flags to determine which areas of the datagrid are shown */
210                 bool caption_visible;
211                 bool parent_rows_visible;
212
213                 GridTableStylesCollection styles_collection;
214                 DataGridParentRowsLabelStyle parent_rows_label_style;
215                 DataGridTableStyle default_style;
216                 DataGridTableStyle grid_style;
217                 DataGridTableStyle current_style;
218
219                 /* selection */
220                 DataGridCell current_cell;
221                 Hashtable selected_rows;
222                 int selection_start; // used for range selection
223
224                 /* layout/rendering */
225                 bool allow_navigation;
226                 int first_visible_row;
227                 int first_visible_column;
228                 int visible_row_count;
229                 int visible_column_count;
230                 Font caption_font;
231                 string caption_text;
232                 bool flatmode;
233                 HScrollBar horiz_scrollbar;
234                 VScrollBar vert_scrollbar;
235                 int horiz_pixeloffset;
236
237                 internal Bitmap back_button_image;
238                 internal Rectangle back_button_rect;
239                 internal bool back_button_mouseover;
240                 internal bool back_button_active;
241                 internal Bitmap parent_rows_button_image;
242                 internal Rectangle parent_rows_button_rect;
243                 internal bool parent_rows_button_mouseover;
244                 internal bool parent_rows_button_active;
245
246                 /* databinding */
247                 object datasource;
248                 string datamember;
249                 CurrencyManager list_manager;
250                 bool refetch_list_manager = true;
251                 bool _readonly;
252                 DataGridRelationshipRow[] rows;
253
254                 /* column resize fields */
255                 bool column_resize_active;
256                 int resize_column_x;
257                 int resize_column_width_delta;
258                 int resize_column;
259                 
260                 /* row resize fields */
261                 bool row_resize_active;
262                 int resize_row_y;
263                 int resize_row_height_delta;
264                 int resize_row;
265
266                 /* used to make sure we don't endlessly recurse calling set_CurrentCell and OnListManagerPositionChanged */
267                 bool from_positionchanged_handler;
268
269                 /* editing state */
270                 bool cursor_in_add_row;
271                 bool add_row_changed;
272                 bool is_editing;                // Current cell is edit mode
273                 bool is_changing;
274
275                 internal Stack data_source_stack;
276
277                 #endregion // Local Variables
278
279                 #region Public Constructors
280                 public DataGrid ()
281                 {
282                         allow_navigation = true;
283                         background_color = def_background_color;
284                         border_style = BorderStyle.Fixed3D;
285                         caption_backcolor = def_caption_backcolor;
286                         caption_forecolor = def_caption_forecolor;
287                         caption_text = string.Empty;
288                         caption_visible = true;
289                         datamember = string.Empty;
290                         parent_rows_backcolor = def_parent_rows_backcolor;
291                         parent_rows_forecolor = def_parent_rows_forecolor;
292                         parent_rows_visible = true;
293                         current_cell = new DataGridCell ();
294                         parent_rows_label_style = DataGridParentRowsLabelStyle.Both;
295                         selected_rows = new Hashtable ();
296                         selection_start = -1;
297                         rows = new DataGridRelationshipRow [0];
298
299                         default_style = new DataGridTableStyle (true);
300                         grid_style = new DataGridTableStyle ();
301
302                         styles_collection = new GridTableStylesCollection (this);
303                         styles_collection.CollectionChanged += new CollectionChangeEventHandler (OnTableStylesCollectionChanged);
304
305                         CurrentTableStyle = grid_style;
306
307                         horiz_scrollbar = new ImplicitHScrollBar ();
308                         horiz_scrollbar.Scroll += new ScrollEventHandler (GridHScrolled);
309                         vert_scrollbar = new ImplicitVScrollBar ();
310                         vert_scrollbar.Scroll += new ScrollEventHandler (GridVScrolled);
311
312                         SetStyle (ControlStyles.UserMouse, true);
313
314                         data_source_stack = new Stack ();
315
316                         back_button_image = ResourceImageLoader.Get ("go-previous.png");
317                         //back_button_image.MakeTransparent (Color.Transparent);
318                         parent_rows_button_image = ResourceImageLoader.Get ("go-top.png");
319                         //parent_rows_button_image.MakeTransparent (Color.Transparent);
320                 }
321
322                 #endregion      // Public Constructor
323
324                 #region Public Instance Properties
325
326                 [DefaultValue(true)]
327                 public bool AllowNavigation {
328                         get { return allow_navigation; }
329                         set {
330                                 if (allow_navigation != value) {
331                                         allow_navigation = value;
332                                         OnAllowNavigationChanged (EventArgs.Empty);
333                                 }
334                         }
335                 }
336
337                 [DefaultValue(true)]
338                 public bool AllowSorting {
339                         get { return grid_style.AllowSorting; }
340                         set { grid_style.AllowSorting = value; }
341                 }
342
343                 public Color AlternatingBackColor  {
344                         get { return grid_style.AlternatingBackColor; }
345                         set { grid_style.AlternatingBackColor = value; }
346                 }
347
348                 public override Color BackColor {
349                         get { return grid_style.BackColor; }
350                         set { grid_style.BackColor = value; }
351                 }
352
353                 public Color BackgroundColor {
354                         get { return background_color; }
355                         set {
356                                  if (background_color != value) {
357                                         background_color = value;
358                                         OnBackgroundColorChanged (EventArgs.Empty);
359                                         Invalidate ();
360                                 }
361                         }
362                 }
363
364                 [Browsable(false)]
365                 [EditorBrowsable(EditorBrowsableState.Never)]
366                 public override Image BackgroundImage {
367                         get { return base.BackgroundImage; }
368                         set {
369                                 if (base.BackgroundImage == value)
370                                         return;
371
372                                 base.BackgroundImage = value;
373                                 Invalidate ();
374                         }
375                 }
376
377                 [DispId(-504)]
378                 [DefaultValue(BorderStyle.Fixed3D)]
379                 public BorderStyle BorderStyle {
380                         get { return InternalBorderStyle; }
381                         set { 
382                                 InternalBorderStyle = value; 
383                                 CalcAreasAndInvalidate ();
384                                 OnBorderStyleChanged (EventArgs.Empty);
385                         }
386                 }
387
388                 public Color CaptionBackColor {
389                         get { return caption_backcolor; }
390                         set {
391                                 if (caption_backcolor != value) {
392                                         caption_backcolor = value;
393                                         InvalidateCaption ();
394                                 }
395                         }
396                 }
397
398                 [Localizable(true)]
399                 [AmbientValue(null)]
400                 public Font CaptionFont {
401                         get {
402                                 if (caption_font == null)
403                                         return new Font (Font, FontStyle.Bold);
404
405                                 return caption_font;
406                         }
407                         set {
408                                 if (caption_font != null && caption_font.Equals (value))
409                                         return;
410
411                                 caption_font = value;
412                                 CalcAreasAndInvalidate ();
413                         }
414                 }
415
416                 public Color CaptionForeColor {
417                         get { return caption_forecolor; }
418                         set {
419                                 if (caption_forecolor != value) {
420                                         caption_forecolor = value;
421                                         InvalidateCaption ();
422                                 }
423                         }
424                 }
425
426                 [Localizable(true)]
427                 [DefaultValue("")]
428                 public string CaptionText {
429                         get { return caption_text; }
430                         set {
431                                 if (caption_text != value) {
432                                         caption_text = value;
433                                         InvalidateCaption ();
434                                 }
435                         }
436                 }
437
438                 [DefaultValue(true)]
439                 public bool CaptionVisible {
440                         get { return caption_visible; }
441                         set {
442                                 if (caption_visible != value) {
443                                         EndEdit ();
444                                         caption_visible = value;
445                                         CalcAreasAndInvalidate ();
446                                         OnCaptionVisibleChanged (EventArgs.Empty);
447                                 }
448                         }
449                 }
450
451                 [DefaultValue(true)]
452                 public bool ColumnHeadersVisible {
453                         get { return grid_style.ColumnHeadersVisible; }
454                         set { grid_style.ColumnHeadersVisible = value; }
455                 }
456
457                 bool setting_current_cell;
458
459                 [Browsable(false)]
460                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
461                 public DataGridCell CurrentCell {
462                         get { return current_cell; }
463                         set {
464                                 if (setting_current_cell)
465                                         return;
466                                 setting_current_cell = true;
467
468                                 if (!IsHandleCreated) {
469                                         setting_current_cell = false;
470                                         throw new Exception ("CurrentCell cannot be set at this time.");
471                                 }
472
473                                 if (current_cell.Equals (value)) {
474                                         setting_current_cell = false;
475                                         return;
476                                 }
477
478                                 /* make sure the new cell fits in the correct bounds for [row,column] */
479                                 if (ReadOnly && value.RowNumber > RowsCount - 1)
480                                         value.RowNumber = RowsCount - 1;
481                                 else if (value.RowNumber > RowsCount)
482                                         value.RowNumber = RowsCount;
483                                 if (value.ColumnNumber >= CurrentTableStyle.GridColumnStyles.Count)
484                                         value.ColumnNumber = CurrentTableStyle.GridColumnStyles.Count == 0 ? 0 : CurrentTableStyle.GridColumnStyles.Count - 1;
485
486                                 bool was_changing = is_changing;
487
488                                 add_row_changed = add_row_changed || was_changing;
489
490                                 EndEdit ();
491                                 if (value.RowNumber != current_cell.RowNumber) {
492                                         if (!from_positionchanged_handler) {
493                                                 try {
494                                                         ListManager.EndCurrentEdit ();
495                                                 }
496                                                 catch (Exception e) {
497                                                         DialogResult r = MessageBox.Show (String.Format ("{0} Do you wish to correct the value?", e.Message),
498                                                                                           "Error when committing the row to the original data source",
499                                                                                           MessageBoxButtons.YesNo);
500                                                         if (r == DialogResult.Yes) {
501                                                                 Edit ();
502                                                                 return;
503                                                         }
504                                                         else
505                                                                 ListManager.CancelCurrentEdit ();
506                                                 }
507                                         }
508
509                                         if (value.RowNumber == RowsCount && !ListManager.CanAddRows)
510                                                 value.RowNumber --;
511                                 }
512
513                                 int old_row = current_cell.RowNumber;
514
515                                 current_cell = value;
516
517                                 EnsureCellVisibility (value);
518
519                                 if (CurrentRow == RowsCount && ListManager.CanAddRows) {
520                                         cursor_in_add_row = true;
521                                         add_row_changed = false;
522                                         AddNewRow ();
523                                 }
524                                 else {
525                                         cursor_in_add_row = false;
526                                 }
527
528                                 InvalidateRowHeader (old_row);
529                                 InvalidateRowHeader (current_cell.RowNumber);
530
531                                 list_manager.Position = current_cell.RowNumber;
532
533                                 OnCurrentCellChanged (EventArgs.Empty);
534
535                                 if (!from_positionchanged_handler)
536                                         Edit ();
537
538                                 setting_current_cell = false;
539                         }
540                 }
541
542                 int CurrentRow {
543                         get { return current_cell.RowNumber; }
544                         set { CurrentCell = new DataGridCell (value, current_cell.ColumnNumber); }
545                 }
546
547                 int CurrentColumn {
548                         get { return current_cell.ColumnNumber; }
549                         set { CurrentCell = new DataGridCell (current_cell.RowNumber, value); }
550                 }
551
552                 [Browsable(false)]
553                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
554                 public int CurrentRowIndex {
555                         get {
556                                 if (ListManager == null)
557                                         return -1;
558                                 
559                                 return CurrentRow;
560                         }
561                         set { CurrentRow = value; }
562                 }
563
564                 [Browsable(false)]
565                 [EditorBrowsable(EditorBrowsableState.Never)]
566                 public override Cursor Cursor {
567                         get { return base.Cursor; }
568                         set { base.Cursor = value; }
569                 }
570
571                 [DefaultValue(null)]
572                 [Editor ("System.Windows.Forms.Design.DataMemberListEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
573                 public string DataMember {
574                         get { return datamember; }
575                         set {
576                                 if (BindingContext != null) {
577                                         SetDataSource (datasource, value);
578                                 }
579                                 else {
580                                         if (list_manager != null)
581                                                 list_manager = null;
582                                         datamember = value;
583                                         refetch_list_manager = true;
584                                 }
585                         }
586                 }
587
588                 [DefaultValue(null)]
589                 [RefreshProperties(RefreshProperties.Repaint)]
590 #if NET_2_0
591                 [AttributeProvider (typeof (IListSource))]
592 #else
593                 [TypeConverter("System.Windows.Forms.Design.DataSourceConverter, " + Consts.AssemblySystem_Design)]
594 #endif
595                 public object DataSource {
596                         get { return datasource; }
597                         set {
598                                 if (BindingContext != null) {
599                                         SetDataSource (value, ListManager == null ? datamember : string.Empty);
600                                 }
601                                 else {
602                                         datasource = value;
603                                         if (list_manager != null)
604                                                 datamember = string.Empty;
605
606                                         if (list_manager != null)
607                                                 list_manager = null;
608                                         refetch_list_manager = true;
609                                 }
610                         }
611                 }
612
613                 protected override Size DefaultSize {
614                         get { return new Size (130, 80); }
615                 }
616
617                 [Browsable(false)]
618                 public int FirstVisibleColumn {
619                         get { return first_visible_column; }
620                 }
621
622                 [DefaultValue(false)]
623                 public bool FlatMode {
624                         get { return flatmode; }
625                         set {
626                                 if (flatmode != value) {
627                                         flatmode = value;
628                                         OnFlatModeChanged (EventArgs.Empty);
629                                         Refresh ();
630                                 }
631                         }
632                 }
633
634                 public override Color ForeColor {
635                         get { return grid_style.ForeColor; }
636                         set { grid_style.ForeColor = value; }
637                 }
638
639                 public Color GridLineColor {
640                         get { return grid_style.GridLineColor; }
641                         set {
642                                 if (value == Color.Empty)
643                                         throw new ArgumentException ("Color.Empty value is invalid.");
644
645                                 grid_style.GridLineColor = value;
646                         }
647                 }
648
649                 [DefaultValue(DataGridLineStyle.Solid)]
650                 public DataGridLineStyle GridLineStyle {
651                         get { return grid_style.GridLineStyle; }
652                         set { grid_style.GridLineStyle = value; }
653                 }
654
655                 public Color HeaderBackColor {
656                         get { return grid_style.HeaderBackColor; }
657                         set {
658                                 if (value == Color.Empty)
659                                         throw new ArgumentException ("Color.Empty value is invalid.");
660
661                                 grid_style.HeaderBackColor = value;
662                         }
663                 }
664
665                 public Font HeaderFont {
666                         get { return grid_style.HeaderFont; }
667                         set { grid_style.HeaderFont = value; }
668                 }
669
670                 public Color HeaderForeColor {
671                         get { return grid_style.HeaderForeColor; }
672                         set { grid_style.HeaderForeColor = value; }
673                 }
674
675                 protected ScrollBar HorizScrollBar {
676                         get { return horiz_scrollbar; }
677                 }
678                 internal ScrollBar HScrollBar {
679                         get { return horiz_scrollbar; }
680                 }
681
682                 internal int HorizPixelOffset {
683                         get { return horiz_pixeloffset; }
684                 }
685
686                 internal bool IsChanging {
687                         get { return is_changing; }
688                 }
689
690                 public object this [DataGridCell cell] {
691                         get { return this [cell.RowNumber, cell.ColumnNumber]; }
692                         set { this [cell.RowNumber, cell.ColumnNumber] = value; }
693                 }
694
695                 public object this [int rowIndex, int columnIndex] {
696                         get { return CurrentTableStyle.GridColumnStyles[columnIndex].GetColumnValueAtRow (ListManager,
697                                                                                                           rowIndex); }
698                         set { CurrentTableStyle.GridColumnStyles[columnIndex].SetColumnValueAtRow (ListManager,
699                                                                                                    rowIndex, value); }
700                 }
701
702                 public Color LinkColor {
703                         get { return grid_style.LinkColor; }
704                         set { grid_style.LinkColor = value; }
705                 }
706
707                 internal Font LinkFont {
708                         get { return new Font (Font, FontStyle.Underline); }
709                 }
710
711 #if !NET_2_0
712                 [ComVisible(false)]
713 #endif
714                 [Browsable(false)]
715                 [EditorBrowsable(EditorBrowsableState.Never)]
716                 public Color LinkHoverColor {
717                         get { return grid_style.LinkHoverColor; }
718                         set { grid_style.LinkHoverColor = value; }
719                 }
720
721                 [Browsable(false)]
722                 [EditorBrowsable(EditorBrowsableState.Advanced)]
723                 protected internal CurrencyManager ListManager {
724                         get {
725                                 if (list_manager == null && refetch_list_manager) {
726                                         SetDataSource (datasource, datamember);
727                                         refetch_list_manager = false;
728                                 }
729
730                                 return list_manager;
731                         }
732                         set { throw new NotSupportedException ("Operation is not supported."); }
733                 }
734
735                 public Color ParentRowsBackColor {
736                         get { return parent_rows_backcolor; }
737                         set {
738                                 if (parent_rows_backcolor != value) {
739                                         parent_rows_backcolor = value;
740                                         if (parent_rows_visible) {
741                                                 Refresh ();
742                                         }
743                                 }
744                         }
745                 }
746
747                 public Color ParentRowsForeColor {
748                         get { return parent_rows_forecolor; }
749                         set {
750                                 if (parent_rows_forecolor != value) {
751                                         parent_rows_forecolor = value;
752                                         if (parent_rows_visible) {
753                                                 Refresh ();
754                                         }
755                                 }
756                         }
757                 }
758
759                 [DefaultValue(DataGridParentRowsLabelStyle.Both)]
760                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
761                 public DataGridParentRowsLabelStyle ParentRowsLabelStyle {
762                         get { return parent_rows_label_style; }
763                         set {
764                                 if (parent_rows_label_style != value) {
765                                         parent_rows_label_style = value;
766                                         if (parent_rows_visible) {
767                                                 Refresh ();
768                                         }
769
770                                         OnParentRowsLabelStyleChanged (EventArgs.Empty);
771                                 }
772                         }
773                 }
774
775                 [DefaultValue(true)]
776                 public bool ParentRowsVisible {
777                         get { return parent_rows_visible; }
778                         set {
779                                 if (parent_rows_visible != value) {
780                                         parent_rows_visible = value;
781                                         CalcAreasAndInvalidate ();
782                                         OnParentRowsVisibleChanged (EventArgs.Empty);
783                                 }
784                         }
785                 }
786
787                 // Settting this property seems to have no effect.
788                 [DefaultValue(75)]
789                 [TypeConverter(typeof(DataGridPreferredColumnWidthTypeConverter))]
790                 public int PreferredColumnWidth {
791                         get { return grid_style.PreferredColumnWidth; }
792                         set { grid_style.PreferredColumnWidth = value; }
793                 }
794
795                 public int PreferredRowHeight {
796                         get { return grid_style.PreferredRowHeight; }
797                         set { grid_style.PreferredRowHeight = value; }
798                 }
799
800                 [DefaultValue(false)]
801                 public bool ReadOnly {
802                         get { return _readonly; }
803                         set {
804                                 if (_readonly != value) {
805                                         _readonly = value;
806                                         OnReadOnlyChanged (EventArgs.Empty);
807                                         CalcAreasAndInvalidate ();
808                                 }
809                         }
810                 }
811
812                 [DefaultValue(true)]
813                 public bool RowHeadersVisible {
814                         get { return grid_style.RowHeadersVisible; }
815                         set { grid_style.RowHeadersVisible = value; }
816                 }
817
818                 [DefaultValue(35)]
819                 public int RowHeaderWidth {
820                         get { return grid_style.RowHeaderWidth; }
821                         set { grid_style.RowHeaderWidth = value; }
822                 }
823
824                 internal DataGridRelationshipRow[] DataGridRows {
825                         get { return rows; }
826                 }
827
828
829                 public Color SelectionBackColor {
830                         get { return grid_style.SelectionBackColor; }
831                         set { grid_style.SelectionBackColor = value; }
832                 }
833
834                 public Color SelectionForeColor  {
835                         get { return grid_style.SelectionForeColor; }
836                         set { grid_style.SelectionForeColor = value; }
837                 }
838
839                 public override ISite Site {
840                         get { return base.Site; }
841                         set { base.Site = value; }
842                 }
843
844                 [Localizable(true)]
845                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
846                 public GridTableStylesCollection TableStyles {
847                         get { return styles_collection; }
848                 }
849
850                 [Bindable(false)]
851                 [Browsable(false)]
852                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
853                 [EditorBrowsable(EditorBrowsableState.Never)]
854                 public override string Text {
855                         get { return base.Text; }
856                         set { base.Text = value; }
857                 }
858
859                 [Browsable(false)]
860                 [EditorBrowsable(EditorBrowsableState.Advanced)]
861                 protected ScrollBar VertScrollBar {
862                         get { return vert_scrollbar; }
863                 }
864                 internal ScrollBar VScrollBar {
865                         get { return vert_scrollbar; }
866                 }
867
868                 [Browsable(false)]
869                 public int VisibleColumnCount {
870                         get { return visible_column_count; }
871                 }
872
873                 [Browsable(false)]
874                 public int VisibleRowCount {
875                         get { return visible_row_count; }
876                 }
877
878                 #endregion      // Public Instance Properties
879
880                 #region Private Instance Properties
881                 internal DataGridTableStyle CurrentTableStyle {
882                         get { return current_style; }
883                         set {
884                                 if (current_style != value) {
885                                         if (current_style != null)
886                                                 DisconnectTableStyleEvents ();
887
888                                         current_style = value;
889
890                                         if (current_style != null) {
891                                                 current_style.DataGrid = this;
892                                                 ConnectTableStyleEvents ();
893                                         }
894                                         CalcAreasAndInvalidate ();
895                                 }
896                         }
897                 }
898
899                 internal int FirstVisibleRow {
900                         get { return first_visible_row; }
901                 }
902                 
903                 internal int RowsCount {
904                         get { return ListManager != null ? ListManager.Count : 0; }
905                 }
906
907                 internal int RowHeight {
908                         get {
909                                 if (CurrentTableStyle.CurrentPreferredRowHeight > Font.Height + 3 + 1 /* line */)
910                                         return CurrentTableStyle.CurrentPreferredRowHeight;
911                                 else
912                                         return Font.Height + 3 + 1 /* line */;
913                         }
914                 }
915                 
916                 internal bool ShowEditRow {
917                         get {
918                                 if (ListManager != null && !ListManager.CanAddRows)
919                                         return false;
920
921                                 return !_readonly;
922                         }
923                 }
924                 
925                 internal bool ShowParentRows {
926                         get { return ParentRowsVisible && data_source_stack.Count > 0; }
927                 }
928                 
929                 #endregion Private Instance Properties
930
931                 #region Public Instance Methods
932
933                 void AbortEditing ()
934                 {
935                         if (is_changing) {
936                                 CurrentTableStyle.GridColumnStyles[current_cell.ColumnNumber].Abort (current_cell.RowNumber);
937                                 is_changing = false;
938                                 InvalidateRowHeader (current_cell.RowNumber);
939                         }
940                 }
941
942                 [MonoTODO]
943                 public bool BeginEdit (DataGridColumnStyle gridColumn, int rowNumber)
944                 {
945                         if (is_changing)
946                                 return false;
947
948                         int column = CurrentTableStyle.GridColumnStyles.IndexOf (gridColumn);
949                         if (column < 0)
950                                 return false;
951
952                         CurrentCell = new DataGridCell (rowNumber, column);
953
954                         /* force editing of CurrentCell if we aren't already editing */
955                         Edit ();
956
957                         return true;
958                 }
959
960                 public void BeginInit ()
961                 {
962                 }
963
964                 protected virtual void CancelEditing ()
965                 {
966                         if (CurrentTableStyle.GridColumnStyles.Count == 0)
967                                 return;
968
969                         CurrentTableStyle.GridColumnStyles[current_cell.ColumnNumber].ConcedeFocus ();
970
971                         if (is_changing) {
972                                 if (current_cell.ColumnNumber < CurrentTableStyle.GridColumnStyles.Count)
973                                         CurrentTableStyle.GridColumnStyles[current_cell.ColumnNumber].Abort (current_cell.RowNumber);
974                                 InvalidateRowHeader (current_cell.RowNumber);
975                         }
976
977                         if (cursor_in_add_row && !is_changing) {
978                                 ListManager.CancelCurrentEdit ();
979                         }
980
981                         is_changing = false;
982                         is_editing = false;
983                 }
984
985                 [MonoTODO]
986                 public void Collapse (int row)
987                 {
988                         if (!rows[row].IsExpanded)
989                                 return;
990
991                         SuspendLayout ();
992                         rows[row].IsExpanded = false;
993                         for (int i = 1; i < rows.Length - row; i ++)
994                                 rows[row + i].VerticalOffset -= rows[row].RelationHeight;
995
996                         rows[row].height -= rows[row].RelationHeight;
997                         rows[row].RelationHeight = 0;
998                         ResumeLayout (false);
999
1000                         /* XX need to redraw from @row down */
1001                         CalcAreasAndInvalidate ();                      
1002                 }
1003
1004                 protected internal virtual void ColumnStartedEditing (Control editingControl)
1005                 {
1006                         ColumnStartedEditing (editingControl.Bounds);
1007                 }
1008
1009                 protected internal virtual void ColumnStartedEditing (Rectangle bounds)
1010                 {
1011                         bool need_invalidate = is_changing == false;
1012                         // XXX calculate the row header to invalidate
1013                         // instead of using CurrentRow
1014                         is_changing = true;
1015
1016                         if (cursor_in_add_row && need_invalidate)
1017                                 RecreateDataGridRows (true);
1018
1019                         if (need_invalidate)
1020                                 InvalidateRowHeader (CurrentRow);
1021                 }
1022
1023                 protected override AccessibleObject CreateAccessibilityInstance ()
1024                 {
1025                         return base.CreateAccessibilityInstance ();
1026                 }
1027
1028                 protected virtual DataGridColumnStyle CreateGridColumn (PropertyDescriptor prop)
1029                 {
1030                         return CreateGridColumn (prop, false);
1031                 }
1032
1033                 protected virtual DataGridColumnStyle CreateGridColumn (PropertyDescriptor prop, bool isDefault)
1034                 {
1035                         throw new NotImplementedException();
1036                 }
1037
1038                 protected override void Dispose (bool disposing)
1039                 {
1040                         base.Dispose (disposing);
1041                 }
1042
1043                 public bool EndEdit (DataGridColumnStyle gridColumn, int rowNumber, bool shouldAbort)
1044                 {
1045                         if (shouldAbort || (_readonly || gridColumn.TableStyleReadOnly || gridColumn.ReadOnly))
1046                                 gridColumn.Abort (rowNumber);
1047                         else {
1048                                 gridColumn.Commit (ListManager, rowNumber);
1049                                 gridColumn.ConcedeFocus ();
1050                         }
1051
1052                         if (is_editing || is_changing) {
1053                                 is_editing = false;
1054                                 is_changing = false;
1055                                 InvalidateRowHeader (rowNumber);
1056                         }
1057                         return true;
1058                 }
1059
1060                 public void EndInit ()
1061                 {
1062                 }
1063
1064                 public void Expand (int row)
1065                 {
1066                         if (rows[row].IsExpanded)
1067                                 return;
1068
1069                         rows[row].IsExpanded = true;
1070
1071                         int i;
1072
1073                         string[] relations = CurrentTableStyle.Relations;
1074                         StringBuilder relation_builder = new StringBuilder ("");
1075
1076                         for (i = 0; i < relations.Length; i ++) {
1077                                 if (i > 0)
1078                                         relation_builder.Append ("\n");
1079
1080                                 relation_builder.Append (relations[i]);
1081                         }
1082                         string relation_text = relation_builder.ToString ();
1083
1084                         SizeF measured_area = DeviceContext.MeasureString (relation_text, LinkFont);
1085
1086                         rows[row].relation_area = new Rectangle (cells_area.X + 1,
1087                                                                  0, /* updated as needed at the usage sites for relation_area */
1088                                                                  (int)measured_area.Width + 4,
1089                                                                  Font.Height * relations.Length);
1090
1091                         for (i = 1; i < rows.Length - row; i ++)
1092                                 rows[row + i].VerticalOffset += rows[row].relation_area.Height;
1093                         rows[row].height += rows[row].relation_area.Height;
1094                         rows[row].RelationHeight = rows[row].relation_area.Height;
1095
1096                         /* XX need to redraw from @row down */
1097                         CalcAreasAndInvalidate ();
1098                 }
1099
1100                 public Rectangle GetCellBounds (DataGridCell cell)
1101                 {
1102                         return GetCellBounds (cell.RowNumber, cell.ColumnNumber);
1103                 }
1104
1105                 public Rectangle GetCellBounds (int row, int col)
1106                 {
1107                         Rectangle bounds = new Rectangle ();
1108                         int col_pixel;
1109
1110                         bounds.Width = CurrentTableStyle.GridColumnStyles[col].Width;
1111                         bounds.Height = rows[row].Height - rows[row].RelationHeight;
1112                         bounds.Y = cells_area.Y + rows[row].VerticalOffset - rows[FirstVisibleRow].VerticalOffset;
1113                         col_pixel = GetColumnStartingPixel (col);
1114                         bounds.X = cells_area.X + col_pixel - horiz_pixeloffset;
1115                         return bounds;
1116                 }
1117
1118                 public Rectangle GetCurrentCellBounds ()
1119                 {
1120                         return GetCellBounds (current_cell.RowNumber, current_cell.ColumnNumber);
1121                 }
1122
1123                 protected virtual string GetOutputTextDelimiter ()
1124                 {
1125                         return string.Empty;
1126                 }
1127
1128                 protected virtual void GridHScrolled (object sender, ScrollEventArgs se)
1129                 {
1130                         if (se.NewValue == horiz_pixeloffset ||
1131                             se.Type == ScrollEventType.EndScroll) {
1132                                 return;
1133                         }
1134
1135                         ScrollToColumnInPixels (se.NewValue);
1136                 }
1137
1138                 protected virtual void GridVScrolled (object sender, ScrollEventArgs se)
1139                 {
1140                         int old_first_visible_row = first_visible_row;
1141                         first_visible_row = se.NewValue;
1142
1143                         if (first_visible_row == old_first_visible_row)
1144                                 return;
1145
1146                         UpdateVisibleRowCount ();
1147
1148                         if (first_visible_row == old_first_visible_row)
1149                                 return;
1150                         
1151                         ScrollToRow (old_first_visible_row, first_visible_row);
1152                 }
1153
1154                 public HitTestInfo HitTest (Point position)
1155                 {
1156                         return HitTest (position.X, position.Y);
1157                 }
1158
1159                 const int RESIZE_HANDLE_HORIZ_SIZE = 5;
1160                 const int RESIZE_HANDLE_VERT_SIZE = 3;
1161
1162                 // From Point to Cell
1163                 public HitTestInfo HitTest (int x, int y)
1164                 {
1165                         if (column_headers_area.Contains (x, y)) {
1166                                 int offset_x = x + horiz_pixeloffset;
1167                                 int column_x;
1168                                 int column_under_mouse = FromPixelToColumn (offset_x, out column_x);
1169                                 
1170                                 if ((column_x + CurrentTableStyle.GridColumnStyles[column_under_mouse].Width - offset_x < RESIZE_HANDLE_HORIZ_SIZE)
1171                                     && column_under_mouse < CurrentTableStyle.GridColumnStyles.Count) {
1172
1173                                         return new HitTestInfo (-1, column_under_mouse, HitTestType.ColumnResize);
1174                                 }
1175                                 else {
1176                                         return new HitTestInfo (-1, column_under_mouse, HitTestType.ColumnHeader);
1177                                 }
1178                         }
1179
1180                         if (row_headers_area.Contains (x, y)) {
1181                                 int posy;
1182                                 int rcnt = FirstVisibleRow + VisibleRowCount;
1183                                 for (int r = FirstVisibleRow; r < rcnt; r++) {
1184                                         posy = cells_area.Y + rows[r].VerticalOffset - rows[FirstVisibleRow].VerticalOffset;
1185                                         if (y <= posy + rows[r].Height) {
1186                                                 if ((posy + rows[r].Height) - y < RESIZE_HANDLE_VERT_SIZE) {
1187                                                         return new HitTestInfo (r, -1, HitTestType.RowResize);
1188                                                 }
1189                                                 else {
1190                                                         return new HitTestInfo (r, -1, HitTestType.RowHeader);
1191                                                 }
1192                                         }
1193                                 }
1194                         }
1195
1196                         if (caption_area.Contains (x, y)) {
1197                                 return new HitTestInfo (-1, -1, HitTestType.Caption);
1198                         }
1199
1200                         if (parent_rows.Contains (x, y)) {
1201                                 return new HitTestInfo (-1, -1, HitTestType.ParentRows);
1202                         }
1203
1204                         int pos_y, pos_x, width;
1205                         int rowcnt = FirstVisibleRow + VisibleRowCount;
1206                         for (int row = FirstVisibleRow; row < rowcnt; row++) {
1207
1208                                 pos_y = cells_area.Y + rows[row].VerticalOffset - rows[FirstVisibleRow].VerticalOffset;
1209                                 if (y <= pos_y + rows[row].Height) {
1210                                         int col_pixel;
1211                                         int column_cnt = first_visible_column + visible_column_count;
1212                                         if (column_cnt > 0) {
1213                                                 for (int column = first_visible_column; column < column_cnt; column++) {
1214                                                         if (CurrentTableStyle.GridColumnStyles[column].bound == false)
1215                                                                 continue;
1216                                                         col_pixel = GetColumnStartingPixel (column);
1217                                                         pos_x = cells_area.X + col_pixel - horiz_pixeloffset;
1218                                                         width = CurrentTableStyle.GridColumnStyles[column].Width;
1219
1220                                                         if (x <= pos_x + width) { // Column found
1221                                                                 return new HitTestInfo (row, column, HitTestType.Cell);
1222                                                         }
1223                                                 }
1224                                         }
1225                                         else if (CurrentTableStyle.HasRelations) {
1226                                                 /* XXX this needs checking against MS somehow... */
1227                                                 if (x < rows[row].relation_area.X + rows[row].relation_area.Width)
1228                                                         return new HitTestInfo (row, 0/*XXX?*/, HitTestType.Cell);
1229                                         }
1230
1231                                         break;
1232                                 }
1233                         }
1234
1235                         return new HitTestInfo ();
1236                 }
1237
1238                 public bool IsExpanded (int rowNumber)
1239                 {
1240                         return (rows[rowNumber].IsExpanded);
1241                 }
1242
1243                 public bool IsSelected (int row)
1244                 {
1245                         return rows[row].IsSelected;
1246                 }
1247
1248                 [MonoTODO]
1249                 public void NavigateBack ()
1250                 {
1251                         if (data_source_stack.Count == 0)
1252                                 return;
1253
1254                         DataGridDataSource source = (DataGridDataSource)data_source_stack.Pop ();
1255                         list_manager = source.list_manager;
1256                         rows = source.Rows;
1257                         selected_rows = source.SelectedRows;
1258                         selection_start = source.SelectionStart;
1259                         SetDataSource (source.data_source, source.data_member);
1260
1261                         CurrentCell = source.current;
1262                 }
1263
1264                 [MonoTODO]
1265                 public void NavigateTo (int rowNumber, string relationName)
1266                 {
1267                         if (allow_navigation == false)
1268                                 return;
1269
1270                         DataGridDataSource previous_source = new DataGridDataSource (this, list_manager, datasource, datamember, list_manager.Current, CurrentCell);
1271                         previous_source.Rows = rows;
1272                         previous_source.SelectedRows = selected_rows;
1273                         previous_source.SelectionStart = selection_start;
1274
1275                         data_source_stack.Push (previous_source);
1276
1277                         rows = null;
1278                         selected_rows = new Hashtable ();
1279                         selection_start = -1;
1280
1281                         DataMember = String.Format ("{0}.{1}", DataMember, relationName);
1282                         OnDataSourceChanged (EventArgs.Empty);
1283                 }
1284
1285                 protected virtual void OnAllowNavigationChanged (EventArgs e)
1286                 {
1287                         EventHandler eh = (EventHandler)(Events [AllowNavigationChangedEvent]);
1288                         if (eh != null)
1289                                 eh (this, e);
1290                 }
1291
1292                 protected void OnBackButtonClicked (object sender, EventArgs e)
1293                 {
1294                         EventHandler eh = (EventHandler)(Events [BackButtonClickEvent]);
1295                         if (eh != null)
1296                                 eh (this, e);
1297                 }
1298
1299                 protected override void OnBackColorChanged (EventArgs e)
1300                 {
1301                         base.OnBackColorChanged (e);
1302                 }
1303
1304                 protected virtual void OnBackgroundColorChanged (EventArgs e)
1305                 {
1306                         EventHandler eh = (EventHandler)(Events [BackgroundColorChangedEvent]);
1307                         if (eh != null)
1308                                 eh (this, e);
1309                 }
1310
1311                 protected override void OnBindingContextChanged (EventArgs e)
1312                 {
1313                         base.OnBindingContextChanged (e);
1314
1315                         SetDataSource (datasource, datamember);
1316                 }
1317
1318                 protected virtual void OnBorderStyleChanged (EventArgs e)
1319                 {
1320                         EventHandler eh = (EventHandler)(Events [BorderStyleChangedEvent]);
1321                         if (eh != null)
1322                                 eh (this, e);
1323                 }
1324
1325                 protected virtual void OnCaptionVisibleChanged (EventArgs e)
1326                 {
1327                         EventHandler eh = (EventHandler)(Events [CaptionVisibleChangedEvent]);
1328                         if (eh != null)
1329                                 eh (this, e);
1330                 }
1331
1332                 protected virtual void OnCurrentCellChanged (EventArgs e)
1333                 {
1334                         EventHandler eh = (EventHandler)(Events [CurrentCellChangedEvent]);
1335                         if (eh != null)
1336                                 eh (this, e);
1337                 }
1338
1339                 protected virtual void OnDataSourceChanged (EventArgs e)
1340                 {
1341                         EventHandler eh = (EventHandler)(Events [DataSourceChangedEvent]);
1342                         if (eh != null)
1343                                 eh (this, e);
1344                 }
1345
1346                 protected override void OnEnter (EventArgs e)
1347                 {
1348                         base.OnEnter (e);
1349                         Edit ();
1350                 }
1351
1352                 protected virtual void OnFlatModeChanged (EventArgs e)
1353                 {
1354                         EventHandler eh = (EventHandler)(Events [FlatModeChangedEvent]);
1355                         if (eh != null)
1356                                 eh (this, e);
1357                 }
1358
1359                 protected override void OnFontChanged (EventArgs e)
1360                 {
1361                         CalcGridAreas ();
1362                         base.OnFontChanged (e);
1363                 }
1364
1365                 protected override void OnForeColorChanged (EventArgs e)
1366                 {
1367                         base.OnForeColorChanged (e);
1368                 }
1369
1370                 protected override void OnHandleCreated (EventArgs e)
1371                 {
1372                         base.OnHandleCreated (e);
1373                         SetDataSource (datasource, datamember);
1374                 }
1375
1376                 protected override void OnHandleDestroyed (EventArgs e)
1377                 {
1378                         base.OnHandleDestroyed (e);
1379                 }
1380
1381                 protected override void OnKeyDown (KeyEventArgs ke)
1382                 {
1383                         base.OnKeyDown (ke);
1384                         
1385                         if (ProcessGridKey (ke) == true)
1386                                 ke.Handled = true;
1387
1388                         /* TODO: we probably don't need this check,
1389                          * since current_cell wouldn't have been set
1390                          * to something invalid */
1391                         if (CurrentTableStyle.GridColumnStyles.Count > 0) {
1392                                 CurrentTableStyle.GridColumnStyles[current_cell.ColumnNumber].OnKeyDown
1393                                         (ke, current_cell.RowNumber, current_cell.ColumnNumber);
1394                         }
1395                 }
1396
1397                 protected override void OnKeyPress (KeyPressEventArgs kpe)
1398                 {
1399                         base.OnKeyPress (kpe);
1400                 }
1401
1402                 protected override void OnLayout (LayoutEventArgs levent)
1403                 {
1404                         base.OnLayout (levent);
1405                         CalcAreasAndInvalidate ();                      
1406                 }
1407
1408                 protected override void OnLeave (EventArgs e)
1409                 {
1410                         base.OnLeave (e);
1411
1412                         if (cursor_in_add_row) {
1413                                 ListManager.CancelCurrentEdit ();
1414                         }
1415                 }
1416
1417                 protected override void OnMouseDown (MouseEventArgs e)
1418                 {
1419                         base.OnMouseDown (e);
1420
1421                         bool ctrl_pressed = ((Control.ModifierKeys & Keys.Control) != 0);
1422                         bool shift_pressed = ((Control.ModifierKeys & Keys.Shift) != 0);
1423
1424                         HitTestInfo testinfo;
1425                         testinfo = HitTest (e.X, e.Y);
1426
1427                         switch (testinfo.Type) {
1428                         case HitTestType.Cell:
1429                                 if (testinfo.Row < 0 || testinfo.Column < 0)
1430                                         break;
1431
1432                                 if (rows[testinfo.Row].IsExpanded) {
1433                                         Rectangle relation_area = rows[testinfo.Row].relation_area;
1434                                         relation_area.Y = rows[testinfo.Row].VerticalOffset + cells_area.Y + rows[testinfo.Row].Height - rows[testinfo.Row].RelationHeight;
1435                                         if (relation_area.Contains (e.X, e.Y)) {
1436                                                 /* the click happened in the relation area, navigate to the new table */
1437                                                 int relative = e.Y - relation_area.Y;
1438                                                 NavigateTo (testinfo.Row, CurrentTableStyle.Relations[relative / LinkFont.Height]);
1439                                                 return;
1440                                         }
1441                                 }
1442
1443                                 DataGridCell new_cell = new DataGridCell (testinfo.Row, testinfo.Column);
1444
1445                                 if ((new_cell.Equals (current_cell) == false) || (!is_editing)) {
1446                                         CurrentCell = new_cell;
1447                                         Edit ();
1448                                 } else {
1449                                         CurrentTableStyle.GridColumnStyles[testinfo.Column].OnMouseDown (e, testinfo.Row, testinfo.Column);
1450                                 }
1451
1452                                 break;
1453
1454                         case HitTestType.RowHeader:
1455                                 bool expansion_click = false;
1456                                 if (CurrentTableStyle.HasRelations) {
1457                                         if (e.X > row_headers_area.X + row_headers_area.Width / 2) {
1458                                                 /* it's in the +/- space */
1459                                                 if (IsExpanded (testinfo.Row))
1460                                                         Collapse (testinfo.Row);
1461                                                 else
1462                                                         Expand (testinfo.Row);
1463
1464                                                 expansion_click = true;
1465                                         }
1466                                 }
1467
1468                                 if (!ctrl_pressed &&
1469                                     !shift_pressed &&
1470                                     !expansion_click) {
1471                                         ResetSelection (); // Invalidates selected rows
1472                                 }
1473
1474                                 if ((shift_pressed ||
1475                                      expansion_click)
1476                                     && selection_start != -1) {
1477                                         ShiftSelection (testinfo.Row);
1478                                 } else { // ctrl_pressed or single item
1479                                         selection_start = testinfo.Row;
1480                                         Select (testinfo.Row);
1481                                 }
1482
1483                                 CancelEditing ();
1484                                 CurrentRow = testinfo.Row;
1485                                 OnRowHeaderClick (EventArgs.Empty);
1486
1487                                 break;
1488
1489                         case HitTestType.ColumnHeader:
1490                                 if (CurrentTableStyle.GridColumnStyles.Count == 0)
1491                                         break;
1492
1493                                 if (AllowSorting == false)
1494                                         break;
1495
1496                                 if (ListManager.List is IBindingList == false)
1497                                         break;
1498                         
1499                                 ListSortDirection direction = ListSortDirection.Ascending;
1500                                 PropertyDescriptor prop = CurrentTableStyle.GridColumnStyles[testinfo.Column].PropertyDescriptor;
1501                                 IBindingList list = (IBindingList) ListManager.List;
1502
1503                                 if (list.SortProperty != null) {
1504                                         CurrentTableStyle.GridColumnStyles[list.SortProperty].ArrowDrawingMode 
1505                                                 = DataGridColumnStyle.ArrowDrawing.No;
1506                                 }
1507
1508                                 if (prop == list.SortProperty && list.SortDirection == ListSortDirection.Ascending) {
1509                                         direction = ListSortDirection.Descending;
1510                                 }
1511                                 
1512                                 CurrentTableStyle.GridColumnStyles[testinfo.Column].ArrowDrawingMode =
1513                                         direction == ListSortDirection.Ascending ? 
1514                                         DataGridColumnStyle.ArrowDrawing.Ascending : DataGridColumnStyle.ArrowDrawing.Descending;
1515                                 
1516                                 list.ApplySort (prop, direction);
1517                                 Refresh ();
1518                                 break;
1519
1520                         case HitTestType.ColumnResize:
1521                                 if (e.Clicks == 2) {
1522                                         // double click column resize goes here
1523                                 }
1524                                 else {
1525                                         resize_column = testinfo.Column;
1526                                         column_resize_active = true;
1527                                         resize_column_x = e.X;
1528                                         resize_column_width_delta = 0;
1529                                         EndEdit ();
1530                                         DrawResizeLineVert (resize_column_x);
1531                                 }
1532                                 break;
1533
1534                         case HitTestType.RowResize:
1535                                 if (e.Clicks == 2) {
1536                                         // double click row resize goes here
1537                                 }
1538                                 else {
1539                                         resize_row = testinfo.Row;
1540                                         row_resize_active = true;
1541                                         resize_row_y = e.Y;
1542                                         resize_row_height_delta = 0;
1543                                         EndEdit ();
1544                                         DrawResizeLineHoriz (resize_row_y);
1545                                 }
1546                                 break;
1547
1548                         case HitTestType.Caption:
1549                                 if (back_button_rect.Contains (e.X, e.Y)) {
1550                                         back_button_active = true;
1551                                         Invalidate (back_button_rect);
1552                                 }
1553                                 if (parent_rows_button_rect.Contains (e.X, e.Y)) {
1554                                         parent_rows_button_active = true;
1555                                         Invalidate (parent_rows_button_rect);
1556                                 }
1557                                 break;
1558
1559                         default:
1560                                 break;
1561                         }
1562                 }
1563
1564                 protected override void OnMouseLeave (EventArgs e)
1565                 {
1566                         base.OnMouseLeave (e);
1567                 }
1568
1569                 protected override void OnMouseMove (MouseEventArgs e)
1570                 {
1571                         base.OnMouseMove (e);
1572
1573                         if (column_resize_active) {
1574                                 /* erase the old line */
1575                                 DrawResizeLineVert (resize_column_x + resize_column_width_delta);
1576
1577                                 resize_column_width_delta = e.X - resize_column_x;
1578
1579                                 /* draw the new line */
1580                                 DrawResizeLineVert (resize_column_x + resize_column_width_delta);
1581                                 return;
1582                         }
1583                         else if (row_resize_active) {
1584                                 /* erase the old line */
1585                                 DrawResizeLineHoriz (resize_row_y + resize_row_height_delta);
1586
1587                                 resize_row_height_delta = e.Y - resize_row_y;
1588
1589                                 /* draw the new line */
1590                                 DrawResizeLineHoriz (resize_row_y + resize_row_height_delta);
1591                                 return;
1592                         }
1593                         else {
1594                                 /* determine the cursor to use */
1595                                 HitTestInfo testinfo;
1596                                 testinfo = HitTest (e.X, e.Y);
1597
1598                                 switch (testinfo.Type) {
1599                                 case HitTestType.ColumnResize:
1600                                         Cursor = Cursors.VSplit;
1601                                         break;
1602                                 case HitTestType.RowResize:
1603                                         Cursor = Cursors.HSplit;
1604                                         break;
1605                                 case HitTestType.Caption:
1606                                         Cursor = Cursors.Default;
1607                                         if (back_button_rect.Contains (e.X, e.Y)) {
1608                                                 if (!back_button_mouseover)
1609                                                         Invalidate (back_button_rect);
1610                                                 back_button_mouseover = true;
1611                                         }
1612                                         else if (back_button_mouseover) {
1613                                                 Invalidate (back_button_rect);
1614                                                 back_button_mouseover = false;
1615                                         }
1616
1617                                         if (parent_rows_button_rect.Contains (e.X, e.Y)) {
1618                                                 if (parent_rows_button_mouseover)
1619                                                         Invalidate (parent_rows_button_rect);
1620                                                 parent_rows_button_mouseover = true;
1621                                         }
1622                                         else if (parent_rows_button_mouseover) {
1623                                                 Invalidate (parent_rows_button_rect);
1624                                                 parent_rows_button_mouseover = false;
1625                                         }
1626                                         break;
1627                                 case HitTestType.Cell:
1628                                         if (rows[testinfo.Row].IsExpanded) {
1629                                                 Rectangle relation_area = rows[testinfo.Row].relation_area;
1630                                                 relation_area.Y = rows[testinfo.Row].VerticalOffset + cells_area.Y + rows[testinfo.Row].Height - rows[testinfo.Row].RelationHeight;
1631                                                 if (relation_area.Contains (e.X, e.Y)) {
1632                                                         Cursor = Cursors.Hand;
1633                                                         break;
1634                                                 }
1635                                         }
1636
1637                                         Cursor = Cursors.Default;
1638                                         break;
1639                                 default:
1640                                         Cursor = Cursors.Default;
1641                                         break;
1642                                 }
1643                         }
1644                 }
1645
1646                 protected override void OnMouseUp (MouseEventArgs e)
1647                 {
1648                         base.OnMouseUp (e);
1649
1650                         if (column_resize_active) {
1651                                 column_resize_active = false;
1652                                 if (resize_column_width_delta + CurrentTableStyle.GridColumnStyles[resize_column].Width < 0)
1653                                         resize_column_width_delta = -CurrentTableStyle.GridColumnStyles[resize_column].Width;
1654                                 CurrentTableStyle.GridColumnStyles[resize_column].Width += resize_column_width_delta;
1655                                 width_of_all_columns += resize_column_width_delta;
1656                                 Edit ();
1657                                 Invalidate ();
1658                         }
1659                         else if (row_resize_active) {
1660                                 row_resize_active = false;
1661
1662                                 if (resize_row_height_delta + rows[resize_row].Height < 0)
1663                                         resize_row_height_delta = -rows[resize_row].Height;
1664
1665                                 rows[resize_row].height = rows[resize_row].Height + resize_row_height_delta;
1666                                 for (int i = resize_row + 1; i < rows.Length; i ++)
1667                                         rows[i].VerticalOffset += resize_row_height_delta;
1668
1669                                 Edit ();
1670                                 CalcAreasAndInvalidate ();
1671                         }
1672                         else if (back_button_active) {
1673                                 if (back_button_rect.Contains (e.X, e.Y)) {
1674                                         Invalidate (back_button_rect);
1675                                         NavigateBack ();
1676                                         OnBackButtonClicked (this, EventArgs.Empty);
1677                                 }
1678                                 back_button_active = false;
1679                         }
1680                         else if (parent_rows_button_active) {
1681                                 if (parent_rows_button_rect.Contains (e.X, e.Y)) {
1682                                         Invalidate (parent_rows_button_rect);
1683                                         ParentRowsVisible = !ParentRowsVisible;
1684                                         OnShowParentDetailsButtonClicked (this, EventArgs.Empty);
1685                                 }
1686                                 parent_rows_button_active = false;
1687                         }
1688                 }
1689
1690                 protected override void OnMouseWheel (MouseEventArgs e)
1691                 {
1692                         base.OnMouseWheel (e);
1693
1694                         bool ctrl_pressed = ((Control.ModifierKeys & Keys.Control) != 0);
1695                         int pixels;
1696
1697                         if (ctrl_pressed) { // scroll horizontally
1698                                 if (!horiz_scrollbar.Visible)
1699                                         return;
1700
1701                                 if (e.Delta > 0) {
1702                                         /* left */
1703                                         pixels = Math.Max (horiz_scrollbar.Minimum,
1704                                                            horiz_scrollbar.Value - horiz_scrollbar.LargeChange);
1705                                 }
1706                                 else {
1707                                         /* right */
1708                                         pixels = Math.Min (horiz_scrollbar.Maximum - horiz_scrollbar.LargeChange + 1,
1709                                                            horiz_scrollbar.Value + horiz_scrollbar.LargeChange);
1710                                 }
1711
1712                                 GridHScrolled (this, new ScrollEventArgs (ScrollEventType.ThumbPosition, pixels));
1713                                 horiz_scrollbar.Value = pixels;
1714                         } else {
1715                                 if (!vert_scrollbar.Visible)
1716                                         return;
1717
1718                                 if (e.Delta > 0) {
1719                                         /* up */
1720                                         pixels = Math.Max (vert_scrollbar.Minimum,
1721                                                            vert_scrollbar.Value - vert_scrollbar.LargeChange);
1722                                 }
1723                                 else {
1724                                         /* down */
1725                                         pixels = Math.Min (vert_scrollbar.Maximum - vert_scrollbar.LargeChange + 1,
1726                                                            vert_scrollbar.Value + vert_scrollbar.LargeChange);
1727                                 }
1728
1729                                 GridVScrolled (this, new ScrollEventArgs (ScrollEventType.ThumbPosition, pixels));
1730                                 vert_scrollbar.Value = pixels;
1731                         }
1732                 }
1733
1734                 protected void OnNavigate (NavigateEventArgs e)
1735                 {
1736                         EventHandler eh = (EventHandler)(Events [NavigateEvent]);
1737                         if (eh != null)
1738                                 eh (this, e);
1739                 }
1740
1741                 protected override void OnPaint (PaintEventArgs pe)
1742                 {
1743                         ThemeEngine.Current.DataGridPaint (pe, this);
1744                 }
1745
1746                 protected override void OnPaintBackground (PaintEventArgs ebe)
1747                 {
1748                 }
1749
1750                 protected virtual void OnParentRowsLabelStyleChanged (EventArgs e)
1751                 {
1752                         EventHandler eh = (EventHandler)(Events [ParentRowsLabelStyleChangedEvent]);
1753                         if (eh != null)
1754                                 eh (this, e);
1755                 }
1756
1757                 protected virtual void OnParentRowsVisibleChanged (EventArgs e)
1758                 {
1759                         EventHandler eh = (EventHandler)(Events [ParentRowsVisibleChangedEvent]);
1760                         if (eh != null)
1761                                 eh (this, e);
1762                 }
1763
1764                 protected virtual void OnReadOnlyChanged (EventArgs e)
1765                 {
1766                         EventHandler eh = (EventHandler)(Events [ReadOnlyChangedEvent]);
1767                         if (eh != null)
1768                                 eh (this, e);
1769                 }
1770
1771                 protected override void OnResize (EventArgs e)
1772                 {
1773                         base.OnResize (e);
1774                 }
1775
1776                 protected void OnRowHeaderClick (EventArgs e)
1777                 {
1778                         EventHandler eh = (EventHandler)(Events [RowHeaderClickEvent]);
1779                         if (eh != null)
1780                                 eh (this, e);
1781                 }
1782
1783                 protected void OnScroll (EventArgs e)
1784                 {
1785                         EventHandler eh = (EventHandler)(Events [ScrollEvent]);
1786                         if (eh != null)
1787                                 eh (this, e);
1788                 }
1789
1790                 protected void OnShowParentDetailsButtonClicked (object sender, EventArgs e)
1791                 {
1792                         EventHandler eh = (EventHandler)(Events [ShowParentDetailsButtonClickEvent]);
1793                         if (eh != null)
1794                                 eh (this, e);
1795                 }
1796
1797                 protected override bool ProcessDialogKey (Keys keyData)
1798                 {
1799                         return ProcessGridKey (new KeyEventArgs (keyData));
1800                 }
1801
1802                 void UpdateSelectionAfterCursorMove (bool extend_selection)
1803                 {
1804                         if (extend_selection) {
1805                                 CancelEditing ();
1806                                 ShiftSelection (CurrentRow);
1807                         }
1808                         else {
1809                                 ResetSelection ();
1810                         }
1811                 }
1812
1813                 protected bool ProcessGridKey (KeyEventArgs ke)
1814                 {
1815                         /* if we have no rows, exit immediately.
1816                            XXX is this necessary? */
1817                         if (RowsCount == 0)
1818                                 return false;
1819
1820                         bool ctrl_pressed = ((ke.Modifiers & Keys.Control) != 0);
1821                         //bool alt_pressed = ((ke.Modifiers & Keys.Alt) != 0);
1822                         bool shift_pressed = ((ke.Modifiers & Keys.Shift) != 0);
1823
1824                         switch (ke.KeyCode) {
1825                         case Keys.Escape:
1826                                 if (is_changing)
1827                                         AbortEditing ();
1828                                 else
1829                                         CancelEditing ();
1830                                 Edit ();
1831                                 return true;
1832                                 
1833                         case Keys.D0:
1834                                 if (ctrl_pressed) {
1835                                         if (is_editing)
1836                                                 CurrentTableStyle.GridColumnStyles[CurrentColumn].EnterNullValue ();
1837                                         return true;
1838                                 }
1839                                 return false;
1840
1841                         case Keys.Enter:
1842                                 if (is_changing)
1843                                         CurrentRow ++;
1844                                 return true;
1845
1846                         case Keys.Tab:
1847                                 if (shift_pressed) {
1848                                         if (CurrentColumn > 0)
1849                                                 CurrentColumn --;
1850                                         else if ((CurrentRow > 0) && (CurrentColumn == 0))
1851                                                 CurrentCell = new DataGridCell (CurrentRow - 1, CurrentTableStyle.GridColumnStyles.Count - 1);
1852                                 }
1853                                 else {
1854                                         if (CurrentColumn < CurrentTableStyle.GridColumnStyles.Count - 1)
1855                                                 CurrentColumn ++;
1856                                         else if ((CurrentRow <= RowsCount) && (CurrentColumn == CurrentTableStyle.GridColumnStyles.Count - 1))
1857                                                 CurrentCell = new DataGridCell (CurrentRow + 1, 0);
1858                                 }
1859
1860                                 UpdateSelectionAfterCursorMove (false);
1861
1862                                 return true;
1863
1864                         case Keys.Right:
1865                                 if (ctrl_pressed) {
1866                                         CurrentColumn = CurrentTableStyle.GridColumnStyles.Count - 1;
1867                                 }
1868                                 else {
1869                                         if (CurrentColumn < CurrentTableStyle.GridColumnStyles.Count - 1) {
1870                                                 CurrentColumn ++;
1871                                         } else if (CurrentRow < RowsCount - 1
1872                                                    || (CurrentRow == RowsCount - 1
1873                                                        && !cursor_in_add_row)) {
1874                                                 CurrentCell = new DataGridCell (CurrentRow + 1, 0);
1875                                         }
1876                                 }
1877
1878                                 UpdateSelectionAfterCursorMove (false);
1879
1880                                 return true;
1881
1882                         case Keys.Left:
1883                                 if (ctrl_pressed) {
1884                                         CurrentColumn = 0;
1885                                 }
1886                                 else {
1887                                         if (current_cell.ColumnNumber > 0)
1888                                                 CurrentColumn --;
1889                                         else if (CurrentRow > 0)
1890                                                 CurrentCell = new DataGridCell (CurrentRow - 1, CurrentTableStyle.GridColumnStyles.Count - 1);
1891                                 }
1892
1893                                 UpdateSelectionAfterCursorMove (false);
1894
1895                                 return true;
1896
1897                         case Keys.Up:
1898                                 if (ctrl_pressed)
1899                                         CurrentRow = 0;
1900                                 else if (CurrentRow > 0)
1901                                         CurrentRow --;
1902
1903                                 UpdateSelectionAfterCursorMove (shift_pressed);
1904
1905                                 return true;
1906
1907                         case Keys.Down:
1908                                 if (ctrl_pressed)
1909                                         CurrentRow = RowsCount - 1;
1910                                 else if (CurrentRow < RowsCount - 1)
1911                                         CurrentRow ++;
1912                                 else if (CurrentRow == RowsCount - 1 && cursor_in_add_row && (add_row_changed || is_changing))
1913                                         CurrentRow ++;
1914                                 else if (CurrentRow == RowsCount - 1 && !cursor_in_add_row && !shift_pressed)
1915                                         CurrentRow ++;
1916
1917                                 UpdateSelectionAfterCursorMove (shift_pressed);
1918
1919                                 return true;
1920
1921                         case Keys.PageUp:
1922                                 if (CurrentRow > VLargeChange)
1923                                         CurrentRow -= VLargeChange;
1924                                 else
1925                                         CurrentRow = 0;
1926
1927                                 UpdateSelectionAfterCursorMove (shift_pressed);
1928
1929                                 return true;
1930
1931                         case Keys.PageDown:
1932                                 if (CurrentRow < RowsCount - VLargeChange)
1933                                         CurrentRow += VLargeChange;
1934                                 else
1935                                         CurrentRow = RowsCount - 1;
1936
1937                                 UpdateSelectionAfterCursorMove (shift_pressed);
1938
1939                                 return true;
1940
1941                         case Keys.Home:
1942                                 if (ctrl_pressed)
1943                                         CurrentCell = new DataGridCell (0, 0);
1944                                 else
1945                                         CurrentColumn = 0;
1946
1947                                 UpdateSelectionAfterCursorMove (ctrl_pressed && shift_pressed);
1948
1949                                 return true;
1950
1951                         case Keys.End:
1952                                 if (ctrl_pressed)
1953                                         CurrentCell = new DataGridCell (RowsCount - 1, CurrentTableStyle.GridColumnStyles.Count - 1);
1954                                 else
1955                                         CurrentColumn = CurrentTableStyle.GridColumnStyles.Count - 1;
1956
1957                                 UpdateSelectionAfterCursorMove (ctrl_pressed && shift_pressed);
1958
1959                                 return true;
1960
1961                         case Keys.Delete:
1962                                 if (is_editing)
1963                                         return false;
1964                                 else if (selected_rows.Keys.Count > 0) {
1965                                         foreach (int row in selected_rows.Keys) {
1966                                                 ListManager.RemoveAt (row);                                             
1967                                         }
1968                                         selected_rows.Clear ();
1969                                         CalcAreasAndInvalidate ();
1970                                 }
1971
1972                                 return true;
1973                         }
1974
1975                         return false; // message not processed
1976                 }
1977
1978                 protected override bool ProcessKeyPreview (ref Message m)
1979                 {
1980                         if ((Msg)m.Msg == Msg.WM_KEYDOWN) {
1981                                 Keys key = (Keys) m.WParam.ToInt32 ();
1982                                 KeyEventArgs ke = new KeyEventArgs (key);
1983                                 if (ProcessGridKey (ke) == true) {
1984                                         return true;
1985                                 }
1986                         }
1987
1988                         return base.ProcessKeyPreview (ref m);
1989                 }
1990                 
1991                 protected bool ProcessTabKey (Keys keyData)
1992                 {
1993                         return false;
1994                 }
1995
1996                 public void ResetAlternatingBackColor ()
1997                 {
1998                         grid_style.AlternatingBackColor = default_style.AlternatingBackColor;
1999                 }
2000
2001                 public override void ResetBackColor ()
2002                 {
2003                         grid_style.BackColor = default_style.BackColor;
2004                 }
2005
2006                 public override void ResetForeColor ()
2007                 {
2008                         grid_style.ForeColor = default_style.ForeColor;
2009                 }
2010
2011                 public void ResetGridLineColor ()
2012                 {
2013                         grid_style.GridLineColor = default_style.GridLineColor;
2014                 }
2015
2016                 public void ResetHeaderBackColor ()
2017                 {
2018                         grid_style.HeaderBackColor = default_style.HeaderBackColor;
2019                 }
2020
2021                 public void ResetHeaderFont ()
2022                 {
2023                         grid_style.HeaderFont = default_style.HeaderFont;
2024                 }
2025
2026                 public void ResetHeaderForeColor ()
2027                 {
2028                         grid_style.HeaderForeColor = default_style.HeaderForeColor;
2029                 }
2030
2031                 public void ResetLinkColor ()
2032                 {
2033                         grid_style.LinkColor = default_style.LinkColor;
2034                 }
2035
2036                 public void ResetLinkHoverColor ()
2037                 {
2038                         grid_style.LinkHoverColor = default_style.LinkHoverColor;
2039                 }
2040
2041                 protected void ResetSelection ()
2042                 {
2043                         InvalidateSelection ();
2044                         selected_rows.Clear ();
2045                         selection_start = -1;
2046                 }
2047
2048                 void InvalidateSelection ()
2049                 {
2050                         foreach (int row in selected_rows.Keys) {
2051                                 rows[row].IsSelected = false;
2052                                 InvalidateRow (row);
2053                         }
2054                 }
2055
2056                 public void ResetSelectionBackColor ()
2057                 {
2058                         grid_style.SelectionBackColor = default_style.SelectionBackColor;
2059                 }
2060
2061                 public void ResetSelectionForeColor ()
2062                 {
2063                         grid_style.SelectionForeColor = default_style.SelectionForeColor;
2064                 }
2065
2066                 public void Select (int row)
2067                 {
2068                         if (selected_rows.Count == 0)
2069                                 selection_start = row;
2070
2071                         selected_rows[row] = true;
2072                         rows[row].IsSelected = true;
2073
2074                         InvalidateRow (row);
2075                 }
2076
2077                 public void SetDataBinding (object dataSource, string dataMember)
2078                 {
2079                         SetDataSource (dataSource, dataMember);
2080                 }
2081
2082                 protected virtual bool ShouldSerializeAlternatingBackColor ()
2083                 {
2084                         return (grid_style.AlternatingBackColor != default_style.AlternatingBackColor);
2085                 }
2086
2087                 protected virtual bool ShouldSerializeBackgroundColor ()
2088                 {
2089                         return (background_color != def_background_color);
2090                 }
2091
2092                 protected virtual bool ShouldSerializeCaptionBackColor ()
2093                 {
2094                         return (caption_backcolor != def_caption_backcolor);
2095                 }
2096
2097                 protected virtual bool ShouldSerializeCaptionForeColor ()
2098                 {
2099                         return caption_forecolor != def_caption_forecolor;
2100                 }
2101
2102                 protected virtual bool ShouldSerializeGridLineColor ()
2103                 {
2104                         return grid_style.GridLineColor != default_style.GridLineColor;
2105                 }
2106
2107                 protected virtual bool ShouldSerializeHeaderBackColor ()
2108                 {
2109                         return grid_style.HeaderBackColor != default_style.HeaderBackColor;
2110                 }
2111
2112                 protected bool ShouldSerializeHeaderFont ()
2113                 {
2114                         return grid_style.HeaderFont != default_style.HeaderFont;
2115                 }
2116
2117                 protected virtual bool ShouldSerializeHeaderForeColor ()
2118                 {
2119                         return grid_style.HeaderForeColor != default_style.HeaderForeColor;
2120                 }
2121
2122                 protected virtual bool ShouldSerializeLinkHoverColor ()
2123                 {
2124                         return grid_style.LinkHoverColor != grid_style.LinkHoverColor;
2125                 }
2126
2127                 protected virtual bool ShouldSerializeParentRowsBackColor ()
2128                 {
2129                         return parent_rows_backcolor != def_parent_rows_backcolor;
2130                 }
2131
2132                 protected virtual bool ShouldSerializeParentRowsForeColor ()
2133                 {
2134                         return parent_rows_backcolor != def_parent_rows_backcolor;
2135                 }
2136
2137                 protected bool ShouldSerializePreferredRowHeight ()
2138                 {
2139                         return grid_style.PreferredRowHeight != default_style.PreferredRowHeight;
2140                 }
2141
2142                 protected bool ShouldSerializeSelectionBackColor ()
2143                 {
2144                         return grid_style.SelectionBackColor != default_style.SelectionBackColor;
2145                 }
2146
2147                 protected virtual bool ShouldSerializeSelectionForeColor ()
2148                 {
2149                         return grid_style.SelectionForeColor != default_style.SelectionForeColor;
2150                 }
2151
2152                 public void SubObjectsSiteChange (bool site)
2153                 {
2154                 }
2155
2156                 public void UnSelect (int row)
2157                 {
2158                         rows[row].IsSelected = false;
2159                         selected_rows.Remove (row);
2160                         InvalidateRow (row);
2161                 }
2162                 #endregion      // Public Instance Methods
2163
2164                 #region Private Instance Methods
2165
2166                 internal void CalcAreasAndInvalidate ()
2167                 {
2168                         CalcGridAreas ();
2169                         Invalidate ();
2170                 }
2171                 
2172                 private void ConnectListManagerEvents ()
2173                 {
2174                         list_manager.MetaDataChanged += new EventHandler (OnListManagerMetaDataChanged);
2175                         list_manager.PositionChanged += new EventHandler (OnListManagerPositionChanged);
2176                         list_manager.ItemChanged += new ItemChangedEventHandler (OnListManagerItemChanged);
2177                 }
2178                 
2179                 private void DisconnectListManagerEvents ()
2180                 {
2181                         list_manager.MetaDataChanged -= new EventHandler (OnListManagerMetaDataChanged);
2182                         list_manager.PositionChanged -= new EventHandler (OnListManagerPositionChanged);
2183                         list_manager.ItemChanged -= new ItemChangedEventHandler (OnListManagerItemChanged);
2184                 }
2185
2186                 void DisconnectTableStyleEvents ()
2187                 {
2188                         current_style.AllowSortingChanged -= new EventHandler (TableStyleChanged);
2189                         current_style.AlternatingBackColorChanged -= new EventHandler (TableStyleChanged);
2190                         current_style.BackColorChanged -= new EventHandler (TableStyleChanged);
2191                         current_style.ColumnHeadersVisibleChanged -= new EventHandler (TableStyleChanged);
2192                         current_style.ForeColorChanged -= new EventHandler (TableStyleChanged);
2193                         current_style.GridLineColorChanged -= new EventHandler (TableStyleChanged);
2194                         current_style.GridLineStyleChanged -= new EventHandler (TableStyleChanged);
2195                         current_style.HeaderBackColorChanged -= new EventHandler (TableStyleChanged);
2196                         current_style.HeaderFontChanged -= new EventHandler (TableStyleChanged);
2197                         current_style.HeaderForeColorChanged -= new EventHandler (TableStyleChanged);
2198                         current_style.LinkColorChanged -= new EventHandler (TableStyleChanged);
2199                         current_style.LinkHoverColorChanged -= new EventHandler (TableStyleChanged);
2200                         current_style.MappingNameChanged -= new EventHandler (TableStyleChanged);
2201                         current_style.PreferredColumnWidthChanged -= new EventHandler (TableStyleChanged);
2202                         current_style.PreferredRowHeightChanged -= new EventHandler (TableStyleChanged);
2203                         current_style.ReadOnlyChanged -= new EventHandler (TableStyleChanged);
2204                         current_style.RowHeadersVisibleChanged -= new EventHandler (TableStyleChanged);
2205                         current_style.RowHeaderWidthChanged -= new EventHandler (TableStyleChanged);
2206                         current_style.SelectionBackColorChanged -= new EventHandler (TableStyleChanged);
2207                         current_style.SelectionForeColorChanged -= new EventHandler (TableStyleChanged);
2208                 }
2209
2210                 void ConnectTableStyleEvents ()
2211                 {
2212                         current_style.AllowSortingChanged += new EventHandler (TableStyleChanged);
2213                         current_style.AlternatingBackColorChanged += new EventHandler (TableStyleChanged);
2214                         current_style.BackColorChanged += new EventHandler (TableStyleChanged);
2215                         current_style.ColumnHeadersVisibleChanged += new EventHandler (TableStyleChanged);
2216                         current_style.ForeColorChanged += new EventHandler (TableStyleChanged);
2217                         current_style.GridLineColorChanged += new EventHandler (TableStyleChanged);
2218                         current_style.GridLineStyleChanged += new EventHandler (TableStyleChanged);
2219                         current_style.HeaderBackColorChanged += new EventHandler (TableStyleChanged);
2220                         current_style.HeaderFontChanged += new EventHandler (TableStyleChanged);
2221                         current_style.HeaderForeColorChanged += new EventHandler (TableStyleChanged);
2222                         current_style.LinkColorChanged += new EventHandler (TableStyleChanged);
2223                         current_style.LinkHoverColorChanged += new EventHandler (TableStyleChanged);
2224                         current_style.MappingNameChanged += new EventHandler (TableStyleChanged);
2225                         current_style.PreferredColumnWidthChanged += new EventHandler (TableStyleChanged);
2226                         current_style.PreferredRowHeightChanged += new EventHandler (TableStyleChanged);
2227                         current_style.ReadOnlyChanged += new EventHandler (TableStyleChanged);
2228                         current_style.RowHeadersVisibleChanged += new EventHandler (TableStyleChanged);
2229                         current_style.RowHeaderWidthChanged += new EventHandler (TableStyleChanged);
2230                         current_style.SelectionBackColorChanged += new EventHandler (TableStyleChanged);
2231                         current_style.SelectionForeColorChanged += new EventHandler (TableStyleChanged);
2232                 }
2233
2234                 void TableStyleChanged (object sender, EventArgs args)
2235                 {
2236                         EndEdit ();
2237                         CalcAreasAndInvalidate ();
2238                 }
2239
2240
2241                 private void EnsureCellVisibility (DataGridCell cell)
2242                 {
2243                         if (cell.ColumnNumber <= first_visible_column ||
2244                                 cell.ColumnNumber + 1 >= first_visible_column + visible_column_count) {                 
2245
2246                                 first_visible_column = GetFirstColumnForColumnVisibility (first_visible_column, cell.ColumnNumber);
2247                                 int pixel = GetColumnStartingPixel (first_visible_column);
2248                                 ScrollToColumnInPixels (pixel);
2249                                 horiz_scrollbar.Value = pixel;
2250                                 Update();
2251                         }
2252
2253                         if (cell.RowNumber < first_visible_row ||
2254                             cell.RowNumber + 1 >= first_visible_row + visible_row_count) {
2255
2256                                 if (cell.RowNumber + 1 >= first_visible_row + visible_row_count) {
2257                                         int old_first_visible_row = first_visible_row;
2258                                         first_visible_row = 1 + cell.RowNumber - visible_row_count;
2259                                         UpdateVisibleRowCount ();
2260                                         ScrollToRow (old_first_visible_row, first_visible_row);
2261                                 } else {
2262                                         int old_first_visible_row = first_visible_row;
2263                                         first_visible_row = cell.RowNumber;
2264                                         UpdateVisibleRowCount ();
2265                                         ScrollToRow (old_first_visible_row, first_visible_row);
2266                                 }
2267
2268                                 vert_scrollbar.Value = first_visible_row;
2269                         }
2270                 }
2271
2272                 private void SetDataSource (object source, string member)
2273                 {
2274                         SetDataSource (source, member, true);
2275                 }
2276
2277                 bool in_setdatasource;
2278                 private void SetDataSource (object source, string member, bool recreate_rows)
2279                 {
2280                         CurrencyManager old_lm = list_manager;
2281
2282                         /* we need this bool flag to work around a
2283                          * problem with OnBindingContextChanged.  once
2284                          * that stuff works properly, remove this
2285                          * hack */
2286                         if (in_setdatasource)
2287                                 return;
2288                         in_setdatasource = true;
2289
2290 #if false
2291                         if (datasource == source && member == datamember)
2292                                 return;
2293 #endif
2294
2295                         if (source != null && source as IListSource != null && source as IList != null)
2296                                 throw new Exception ("Wrong complex data binding source");
2297
2298                         datasource = source;
2299                         datamember = member;
2300
2301                         if (is_editing)
2302                                 CancelEditing ();
2303
2304                         current_cell = new DataGridCell ();
2305
2306                         if (list_manager != null)
2307                                 DisconnectListManagerEvents ();
2308
2309                         list_manager = null;
2310
2311                         /* create the new list manager */
2312                         if (BindingContext != null && datasource != null)
2313                                 list_manager = (CurrencyManager) BindingContext [datasource, datamember];
2314
2315                         if (list_manager != null)
2316                                 ConnectListManagerEvents ();
2317
2318                         if (old_lm != list_manager) {
2319                                 BindColumns ();
2320
2321                                 /* reset first_visible_row to 0 here before
2322                                  * doing anything that'll requires us to
2323                                  * figure out if we need a scrollbar. */
2324                                 vert_scrollbar.Value = 0;
2325                                 horiz_scrollbar.Value = 0;
2326                                 first_visible_row = 0;
2327
2328                                 if (recreate_rows)
2329                                         RecreateDataGridRows (false);
2330                         }
2331
2332                         CalcAreasAndInvalidate ();
2333
2334                         in_setdatasource = false;
2335
2336                         OnDataSourceChanged (EventArgs.Empty);
2337                 }
2338
2339                 void RecreateDataGridRows (bool recalc)
2340                 {
2341                         DataGridRelationshipRow[] new_rows = new DataGridRelationshipRow[RowsCount + (ShowEditRow ? 1 : 0)];
2342                         int start_index = 0;
2343                         if (rows != null) {
2344                                 start_index = rows.Length;
2345                                 Array.Copy (rows, 0, new_rows, 0, rows.Length < new_rows.Length ? rows.Length : new_rows.Length);
2346                         }
2347
2348                         for (int i = start_index; i < new_rows.Length; i ++) {
2349                                 new_rows[i] = new DataGridRelationshipRow (this);
2350                                 new_rows[i].height = RowHeight;
2351                                 if (i > 0)
2352                                         new_rows[i].VerticalOffset = new_rows[i-1].VerticalOffset + new_rows[i-1].Height;
2353                         }
2354
2355                         rows = new_rows;
2356
2357                         if (recalc)
2358                                 CalcAreasAndInvalidate ();
2359                 }
2360
2361                 internal void UpdateRowsFrom (DataGridRelationshipRow row)
2362                 {
2363                         int start_index = Array.IndexOf (rows, row);
2364                         if (start_index == -1)
2365                                 return;
2366
2367                         for (int i = start_index + 1; i < rows.Length; i ++) {
2368                                 rows[i].VerticalOffset = rows[i-1].VerticalOffset + rows[i-1].Height;
2369                         }
2370
2371                         CalcAreasAndInvalidate ();
2372                 }
2373
2374                 void BindColumns ()
2375                 {
2376                         if (list_manager != null) {
2377                                 string list_name = list_manager.GetListName (null);
2378                                 if (TableStyles[list_name] == null) {
2379                                         // no style exists by the supplied name
2380                                         current_style.GridColumnStyles.Clear ();                        
2381                                         current_style.CreateColumnsForTable (false);
2382                                 }
2383                                 else if (CurrentTableStyle == grid_style ||
2384                                          CurrentTableStyle.MappingName != list_name) {
2385                                         // If the style has been defined by the user, use it
2386                                         CurrentTableStyle = styles_collection[list_name];
2387                                         current_style.CreateColumnsForTable (true);
2388                                 }
2389                                 else {
2390                                         current_style.CreateColumnsForTable (true);
2391                                 }
2392                         }
2393                         else
2394                                 current_style.CreateColumnsForTable (false);
2395                 }
2396
2397                 private void OnListManagerMetaDataChanged (object sender, EventArgs e)
2398                 {
2399                         // XXX
2400
2401                         //we need to rethink this, as in 2.0 we get this event when a column is added to a table.
2402                         // forcing a rebind of columns means that we fail bug #80422.  disable this for now.
2403                         //
2404                         // BindColumns ();
2405                 }
2406
2407                 private void OnListManagerPositionChanged (object sender, EventArgs e)
2408                 {
2409                         from_positionchanged_handler = true;
2410                         CurrentRow = list_manager.Position;
2411                         from_positionchanged_handler = false;
2412                 }
2413
2414                 private void OnListManagerItemChanged (object sender, ItemChangedEventArgs e)
2415                 {
2416                         if (e.Index == -1) {
2417                                 ResetSelection ();
2418                                 if (rows == null || RowsCount != rows.Length - (ShowEditRow ? 1 : 0))
2419                                         RecreateDataGridRows (true);
2420                         }
2421                         else {
2422                                 InvalidateRow (e.Index);
2423                         }
2424                 }
2425
2426                 private void OnTableStylesCollectionChanged (object sender, CollectionChangeEventArgs e)
2427                 {
2428                         if (ListManager == null)
2429                                 return;
2430                         
2431                         string list_name = ListManager.GetListName (null);
2432                         switch (e.Action){
2433                                 case CollectionChangeAction.Add: {
2434                                         if (e.Element != null && String.Compare (list_name, ((DataGridTableStyle)e.Element).MappingName, true) == 0) {
2435                                                 CurrentTableStyle = (DataGridTableStyle)e.Element;
2436                                                 ((DataGridTableStyle) e.Element).CreateColumnsForTable (false);
2437                                         }
2438                                         break;
2439                                 }
2440
2441                                 case CollectionChangeAction.Remove: {
2442                                         if (e.Element != null && String.Compare (list_name, ((DataGridTableStyle)e.Element).MappingName, true) == 0) {
2443                                                 CurrentTableStyle = default_style;                                              
2444                                                 current_style.GridColumnStyles.Clear ();
2445                                                 current_style.CreateColumnsForTable (false);
2446                                         }
2447                                         break;
2448                                 }       
2449
2450                                 
2451                                 case CollectionChangeAction.Refresh: {
2452                                         if (CurrentTableStyle == default_style
2453                                             || String.Compare (list_name, CurrentTableStyle.MappingName, true) != 0) {
2454
2455                                                 DataGridTableStyle style = styles_collection [list_name];
2456                                                 if (style != null) {
2457                                                         CurrentTableStyle = style;
2458                                                         current_style.CreateColumnsForTable (false);
2459                                                 }
2460                                                 else {
2461                                                         CurrentTableStyle = default_style;
2462                                                         current_style.GridColumnStyles.Clear ();
2463                                                         current_style.CreateColumnsForTable (false);
2464                                                 }
2465                                         }
2466
2467                                         break;
2468                                 }
2469                         }                                               
2470                         CalcAreasAndInvalidate ();
2471                 }
2472
2473                 private void AddNewRow ()
2474                 {
2475                         ListManager.EndCurrentEdit ();
2476                         ListManager.AddNew ();
2477                 }
2478
2479                 private void Edit ()
2480                 {
2481                         if (CurrentTableStyle.GridColumnStyles.Count == 0)
2482                                 return;
2483
2484                         if (CurrentTableStyle.GridColumnStyles[CurrentColumn].bound == false)
2485                                 return;
2486
2487                         is_editing = true;
2488                         is_changing = false;
2489
2490                         CurrentTableStyle.GridColumnStyles[CurrentColumn].Edit (ListManager,
2491                                 CurrentRow, GetCellBounds (CurrentRow, CurrentColumn),
2492                                 _readonly, null, true);
2493                 }
2494
2495                 private void EndEdit ()
2496                 {
2497                         if (CurrentTableStyle.GridColumnStyles.Count == 0)
2498                                 return;
2499
2500                         if (CurrentTableStyle.GridColumnStyles[current_cell.ColumnNumber].bound == false)
2501                                 return;
2502
2503                         EndEdit (CurrentTableStyle.GridColumnStyles[current_cell.ColumnNumber],
2504                                  current_cell.RowNumber,
2505                                  false);
2506                 }
2507
2508                 private void ShiftSelection (int index)
2509                 {
2510                         // we have to save off selection_start
2511                         // because ResetSelection clobbers it
2512                         int saved_selection_start = selection_start;
2513                         int start, end;
2514
2515                         ResetSelection ();
2516                         selection_start = saved_selection_start;
2517
2518                         if (index >= selection_start) {
2519                                 start = selection_start;
2520                                 end = index;
2521                         }
2522                         else {
2523                                 start = index;
2524                                 end = selection_start;
2525                         }
2526
2527                         if (start == -1) start = 0;
2528
2529                         for (int idx = start; idx <= end; idx ++) {
2530                                 Select (idx);
2531                         }
2532                 }
2533
2534                 private void ScrollToColumnInPixels (int pixel)
2535                 {
2536                         int pixels;
2537
2538                         if (pixel > horiz_pixeloffset) // ScrollRight
2539                                 pixels = -1 * (pixel - horiz_pixeloffset);
2540                         else
2541                                 pixels = horiz_pixeloffset - pixel;
2542
2543                         Rectangle area = cells_area;
2544
2545                         if (ColumnHeadersVisible == true) {
2546                                 area.Y -= ColumnHeadersArea.Height;
2547                                 area.Height += ColumnHeadersArea.Height;
2548                         }
2549                                 
2550                         horiz_pixeloffset = pixel;
2551                         UpdateVisibleColumn ();
2552
2553                         EndEdit ();
2554
2555                         XplatUI.ScrollWindow (Handle, area, pixels, 0, false);
2556
2557                         int pixel_offset = GetColumnStartingPixel (CurrentColumn);
2558                         int next_pixel_offset = pixel_offset + CurrentTableStyle.GridColumnStyles[CurrentColumn].Width;
2559
2560                         if (pixel_offset >= horiz_pixeloffset
2561                             && next_pixel_offset < horiz_pixeloffset + cells_area.Width)
2562                                 Edit ();
2563                 }
2564
2565                 private void ScrollToRow (int old_row, int new_row)
2566                 {
2567                         int pixels = 0;
2568                         int i;
2569
2570                         if (new_row > old_row) { // Scrolldown
2571                                 for (i = old_row; i < new_row; i ++)
2572                                         pixels -= rows[i].Height;
2573                         }
2574                         else {
2575                                 for (i = new_row; i < old_row; i ++)
2576                                         pixels += rows[i].Height;
2577                         }
2578
2579                         if (pixels == 0)
2580                                 return;
2581
2582                         EndEdit ();
2583
2584                         Rectangle rows_area = cells_area; // Cells area - partial rows space
2585
2586                         if (RowHeadersVisible) {
2587                                 rows_area.X -= RowHeaderWidth;
2588                                 rows_area.Width += RowHeaderWidth;
2589                         }
2590
2591                         /* scroll the window */
2592                         XplatUI.ScrollWindow (Handle, rows_area, 0, pixels, false);
2593
2594                         /* if the row is still */
2595                         if (CurrentRow >= first_visible_row && CurrentRow < first_visible_row + visible_row_count)
2596                                 Edit ();
2597                 }
2598
2599                 #endregion Private Instance Methods
2600
2601
2602                 #region Events
2603                 static object AllowNavigationChangedEvent = new object ();
2604                 static object BackButtonClickEvent = new object ();
2605                 static object BackgroundColorChangedEvent = new object ();
2606                 static object BorderStyleChangedEvent = new object ();
2607                 static object CaptionVisibleChangedEvent = new object ();
2608                 static object CurrentCellChangedEvent = new object ();
2609                 static object DataSourceChangedEvent = new object ();
2610                 static object FlatModeChangedEvent = new object ();
2611                 static object NavigateEvent = new object ();
2612                 static object ParentRowsLabelStyleChangedEvent = new object ();
2613                 static object ParentRowsVisibleChangedEvent = new object ();
2614                 static object ReadOnlyChangedEvent = new object ();
2615                 static object RowHeaderClickEvent = new object ();
2616                 static object ScrollEvent = new object ();
2617                 static object ShowParentDetailsButtonClickEvent = new object ();
2618
2619                 public event EventHandler AllowNavigationChanged {
2620                         add { Events.AddHandler (AllowNavigationChangedEvent, value); }
2621                         remove { Events.RemoveHandler (AllowNavigationChangedEvent, value); }
2622                 }
2623
2624                 public event EventHandler BackButtonClick {
2625                         add { Events.AddHandler (BackButtonClickEvent, value); }
2626                         remove { Events.RemoveHandler (BackButtonClickEvent, value); }
2627                 }
2628
2629                 public event EventHandler BackgroundColorChanged {
2630                         add { Events.AddHandler (BackgroundColorChangedEvent, value); }
2631                         remove { Events.RemoveHandler (BackgroundColorChangedEvent, value); }
2632                 }
2633
2634                 [Browsable(false)]
2635                 [EditorBrowsable(EditorBrowsableState.Never)]
2636                 public new event EventHandler BackgroundImageChanged {
2637                         add { base.BackgroundImageChanged += value; }
2638                         remove { base.BackgroundImageChanged -= value; }
2639                 }
2640
2641                 [Browsable(false)]
2642                 [EditorBrowsable(EditorBrowsableState.Never)]
2643                 public new event EventHandler TextChanged {
2644                         add { base.TextChanged += value; }
2645                         remove { base.TextChanged -= value; }
2646                 }
2647
2648                 [Browsable(false)]
2649                 [EditorBrowsable(EditorBrowsableState.Never)]
2650                 public new event EventHandler CursorChanged {
2651                         add { base.CursorChanged += value; }
2652                         remove { base.CursorChanged -= value; }
2653                 }
2654
2655                 public event EventHandler BorderStyleChanged {
2656                         add { Events.AddHandler (BorderStyleChangedEvent, value); }
2657                         remove { Events.RemoveHandler (BorderStyleChangedEvent, value); }
2658                 }
2659
2660                 public event EventHandler CaptionVisibleChanged {
2661                         add { Events.AddHandler (CaptionVisibleChangedEvent, value); }
2662                         remove { Events.RemoveHandler (CaptionVisibleChangedEvent, value); }
2663                 }
2664
2665                 public event EventHandler CurrentCellChanged {
2666                         add { Events.AddHandler (CurrentCellChangedEvent, value); }
2667                         remove { Events.RemoveHandler (CurrentCellChangedEvent, value); }
2668                 }
2669
2670                 public event EventHandler DataSourceChanged {
2671                         add { Events.AddHandler (DataSourceChangedEvent, value); }
2672                         remove { Events.RemoveHandler (DataSourceChangedEvent, value); }
2673                 }
2674
2675                 public event EventHandler FlatModeChanged {
2676                         add { Events.AddHandler (FlatModeChangedEvent, value); }
2677                         remove { Events.RemoveHandler (FlatModeChangedEvent, value); }
2678                 }
2679
2680                 public event NavigateEventHandler Navigate {
2681                         add { Events.AddHandler (NavigateEvent, value); }
2682                         remove { Events.RemoveHandler (NavigateEvent, value); }
2683                 }
2684
2685                 public event EventHandler ParentRowsLabelStyleChanged {
2686                         add { Events.AddHandler (ParentRowsLabelStyleChangedEvent, value); }
2687                         remove { Events.RemoveHandler (ParentRowsLabelStyleChangedEvent, value); }
2688                 }
2689
2690                 public event EventHandler ParentRowsVisibleChanged {
2691                         add { Events.AddHandler (ParentRowsVisibleChangedEvent, value); }
2692                         remove { Events.RemoveHandler (ParentRowsVisibleChangedEvent, value); }
2693                 }
2694
2695                 public event EventHandler ReadOnlyChanged {
2696                         add { Events.AddHandler (ReadOnlyChangedEvent, value); }
2697                         remove { Events.RemoveHandler (ReadOnlyChangedEvent, value); }
2698                 }
2699
2700                 protected event EventHandler RowHeaderClick {
2701                         add { Events.AddHandler (RowHeaderClickEvent, value); }
2702                         remove { Events.RemoveHandler (RowHeaderClickEvent, value); }
2703                 }
2704
2705                 public event EventHandler Scroll {
2706                         add { Events.AddHandler (ScrollEvent, value); }
2707                         remove { Events.RemoveHandler (ScrollEvent, value); }
2708                 }
2709
2710                 public event EventHandler ShowParentDetailsButtonClick {
2711                         add { Events.AddHandler (ShowParentDetailsButtonClickEvent, value); }
2712                         remove { Events.RemoveHandler (ShowParentDetailsButtonClickEvent, value); }
2713                 }
2714                 #endregion      // Events
2715
2716
2717
2718
2719                 #region Code originally in DataGridDrawingLogic.cs
2720
2721                 #region Local Variables
2722
2723                 // Areas
2724                 Rectangle parent_rows;
2725                 int width_of_all_columns;
2726
2727                 internal Rectangle caption_area;
2728                 internal Rectangle column_headers_area; // Used columns header area
2729                 internal int column_headers_max_width;  // Total width (max width) for columns headrs
2730                 internal Rectangle row_headers_area;    // Used Headers rows area
2731                 internal Rectangle cells_area;
2732                 #endregion // Local Variables
2733
2734
2735                 #region Public Instance Methods
2736
2737                 // Calc the max with of all columns
2738                 int CalcAllColumnsWidth ()
2739                 {
2740                         int width = 0;
2741                         int cnt = CurrentTableStyle.GridColumnStyles.Count;
2742
2743                         for (int col = 0; col < cnt; col++) {
2744                                 if (CurrentTableStyle.GridColumnStyles[col].bound == false) {
2745                                         continue;
2746                                 }
2747                                 width += CurrentTableStyle.GridColumnStyles[col].Width;
2748                         }
2749                         return width;
2750                 }
2751
2752                 // Gets a column from a pixel
2753                 int FromPixelToColumn (int pixel, out int column_x)
2754                 {
2755                         int width = 0;
2756                         int cnt = CurrentTableStyle.GridColumnStyles.Count;
2757                         column_x = 0;
2758
2759                         if (cnt == 0)
2760                                 return 0;
2761                                 
2762                         if (CurrentTableStyle.CurrentRowHeadersVisible) {
2763                                 width += row_headers_area.X + row_headers_area.Width;
2764                                 column_x += row_headers_area.X + row_headers_area.Width;
2765                         }
2766
2767                         for (int col = 0; col < cnt; col++) {
2768                                 if (CurrentTableStyle.GridColumnStyles[col].bound == false)
2769                                         continue;
2770
2771                                 width += CurrentTableStyle.GridColumnStyles[col].Width;
2772
2773                                 if (pixel < width)
2774                                         return col;
2775
2776                                 column_x += CurrentTableStyle.GridColumnStyles[col].Width;
2777                         }
2778
2779                         return cnt - 1;
2780                 }
2781
2782                 internal int GetColumnStartingPixel (int my_col)
2783                 {
2784                         int width = 0;
2785                         int cnt = CurrentTableStyle.GridColumnStyles.Count;
2786
2787                         for (int col = 0; col < cnt; col++) {
2788                                 if (CurrentTableStyle.GridColumnStyles[col].bound == false) {
2789                                         continue;
2790                                 }
2791
2792                                 if (my_col == col)
2793                                         return width;
2794
2795                                 width += CurrentTableStyle.GridColumnStyles[col].Width;
2796                         }
2797
2798                         return 0;
2799                 }
2800                 
2801                 // Which column has to be the first visible column to ensure a column visibility
2802                 int GetFirstColumnForColumnVisibility (int current_first_visible_column, int column)
2803                 {
2804                         int new_col = column;
2805                         int width = 0;
2806                         
2807                         if (column > current_first_visible_column) { // Going forward
2808                                 for (new_col = column; new_col >= 0; new_col--){
2809                                         if (CurrentTableStyle.GridColumnStyles[new_col].bound == false)
2810                                                 continue;
2811                                         width += CurrentTableStyle.GridColumnStyles[new_col].Width;
2812                                         
2813                                         if (width >= cells_area.Width)
2814                                                 return new_col + 1;
2815                                                 //return new_col < CurrentTableStyle.GridColumnStyles.Count ? new_col + 1 : CurrentTableStyle.GridColumnStyles.Count;
2816                                 }
2817                                 return 0;
2818                         } else {
2819                                 return  column;
2820                         }
2821                 }
2822
2823                 bool in_calc_grid_areas;
2824                 void CalcGridAreas ()
2825                 {
2826                         if (IsHandleCreated == false) // Delay calculations until the handle is created
2827                                 return;
2828
2829                         /* make sure we don't happen to end up in this method again */
2830                         if (in_calc_grid_areas)
2831                                 return;
2832
2833                         in_calc_grid_areas = true;
2834
2835                         /* Order is important. E.g. row headers max. height depends on caption */
2836                         horiz_pixeloffset = 0;
2837                         CalcCaption ();
2838                         CalcParentRows ();
2839                         CalcParentButtons ();
2840                         UpdateVisibleRowCount ();
2841                         CalcRowHeaders ();
2842                         width_of_all_columns = CalcAllColumnsWidth ();
2843                         CalcColumnHeaders ();
2844                         CalcCellsArea ();
2845
2846                         bool needHoriz = false;
2847                         bool needVert = false;
2848
2849                         /* figure out which scrollbars we need, and what the visible areas are */
2850                         int visible_cells_width = cells_area.Width;
2851                         int visible_cells_height = cells_area.Height;
2852                         int allrows = RowsCount;
2853
2854                         if (ShowEditRow && RowsCount > 0)
2855                                 allrows++;
2856
2857                         /* use a loop to iteratively calculate whether
2858                          * we need horiz/vert scrollbars. */
2859                         for (int i = 0; i < 3; i ++) {
2860                                 if (needVert)
2861                                         visible_cells_width = cells_area.Width - vert_scrollbar.Width;
2862                                 if (needHoriz)
2863                                         visible_cells_height = cells_area.Height - horiz_scrollbar.Height;
2864
2865                                 UpdateVisibleRowCount ();
2866
2867                                 needHoriz = (width_of_all_columns > visible_cells_width);
2868                                 needVert = (allrows > visible_row_count);
2869                         }
2870
2871                         int horiz_scrollbar_width = ClientRectangle.Width;
2872                         int horiz_scrollbar_maximum = 0;
2873                         int vert_scrollbar_height = 0;
2874                         int vert_scrollbar_maximum = 0;
2875
2876                         if (needVert)
2877                                 SetUpVerticalScrollBar (out vert_scrollbar_height, out vert_scrollbar_maximum);
2878
2879                         if (needHoriz)
2880                                 SetUpHorizontalScrollBar (out horiz_scrollbar_maximum);
2881
2882                         cells_area.Width = visible_cells_width;
2883                         cells_area.Height = visible_cells_height;
2884
2885                         if (needVert && needHoriz) {
2886                                 if (ShowParentRows)
2887                                         parent_rows.Width -= vert_scrollbar.Width;
2888
2889                                 if (!ShowingColumnHeaders) {
2890                                         if (column_headers_area.X + column_headers_area.Width > vert_scrollbar.Location.X) {
2891                                                 column_headers_area.Width -= vert_scrollbar.Width;
2892                                         }
2893                                 }
2894
2895                                 horiz_scrollbar_width -= vert_scrollbar.Width;
2896                                 vert_scrollbar_height -= horiz_scrollbar.Height;
2897                         }
2898
2899                         if (needVert) {
2900                                 if (row_headers_area.Y + row_headers_area.Height > ClientRectangle.Y + ClientRectangle.Height) {
2901                                         row_headers_area.Height -= horiz_scrollbar.Height;
2902                                 }
2903
2904                                 vert_scrollbar.Size = new Size (vert_scrollbar.Width,
2905                                                                 vert_scrollbar_height);
2906
2907                                 vert_scrollbar.Maximum = vert_scrollbar_maximum;
2908                                 Controls.Add (vert_scrollbar);
2909                                 vert_scrollbar.Visible = true;
2910                         }
2911                         else {
2912                                 Controls.Remove (vert_scrollbar);
2913                                 vert_scrollbar.Visible = false;
2914                         }
2915
2916                         if (needHoriz) {
2917                                 horiz_scrollbar.Size = new Size (horiz_scrollbar_width,
2918                                                                  horiz_scrollbar.Height);
2919
2920                                 horiz_scrollbar.Maximum = horiz_scrollbar_maximum;
2921                                 Controls.Add (horiz_scrollbar);
2922                                 horiz_scrollbar.Visible = true;
2923                         }
2924                         else {
2925                                 Controls.Remove (horiz_scrollbar);
2926                                 horiz_scrollbar.Visible = false;
2927                         }
2928
2929                         UpdateVisibleColumn ();
2930                         UpdateVisibleRowCount ();
2931
2932                         in_calc_grid_areas = false;
2933                 }
2934
2935                 void CalcCaption ()
2936                 {
2937                         caption_area.X = ClientRectangle.X;
2938                         caption_area.Y = ClientRectangle.Y;
2939                         caption_area.Width = ClientRectangle.Width;
2940                         if (caption_visible) {
2941                                 caption_area.Height = CaptionFont.Height;
2942                                 if (caption_area.Height < back_button_image.Height)
2943                                         caption_area.Height = back_button_image.Height;
2944                                 caption_area.Height += 2;
2945                         }
2946                         else
2947                                 caption_area.Height = 0;
2948                 }
2949
2950                 void CalcCellsArea ()
2951                 {
2952                         cells_area.X = ClientRectangle.X + row_headers_area.Width;
2953                         cells_area.Y = column_headers_area.Y + column_headers_area.Height;
2954                         cells_area.Width = ClientRectangle.X + ClientRectangle.Width - cells_area.X;
2955                         if (cells_area.Width < 0)
2956                                 cells_area.Width = 0;
2957                         cells_area.Height = ClientRectangle.Y + ClientRectangle.Height - cells_area.Y;
2958                         if (cells_area.Height < 0)
2959                                 cells_area.Height = 0;
2960                 }
2961
2962                 void CalcColumnHeaders ()
2963                 {
2964                         int max_width_cols;
2965
2966                         column_headers_area.X = ClientRectangle.X;
2967                         column_headers_area.Y = parent_rows.Y + parent_rows.Height;
2968
2969                         // TODO: take into account Scrollbars
2970                         column_headers_max_width = ClientRectangle.X + ClientRectangle.Width - column_headers_area.X;
2971                         max_width_cols = column_headers_max_width;
2972
2973                         if (CurrentTableStyle.CurrentRowHeadersVisible)
2974                                 max_width_cols -= RowHeaderWidth;
2975
2976                         if (width_of_all_columns > max_width_cols) {
2977                                 column_headers_area.Width = column_headers_max_width;
2978                         } else {
2979                                 column_headers_area.Width = width_of_all_columns;
2980
2981                                 if (CurrentTableStyle.CurrentRowHeadersVisible)
2982                                         column_headers_area.Width += RowHeaderWidth;
2983                         }
2984
2985                         if (ShowingColumnHeaders)
2986                                 column_headers_area.Height = CurrentTableStyle.HeaderFont.Height + 6;
2987                         else
2988                                 column_headers_area.Height = 0;
2989                 }
2990
2991                 void CalcParentRows ()
2992                 {
2993                         parent_rows.X = ClientRectangle.X;
2994                         parent_rows.Y = caption_area.Y + caption_area.Height;
2995                         parent_rows.Width = ClientRectangle.Width;
2996                         if (ShowParentRows)
2997                                 parent_rows.Height = (CaptionFont.Height + 3) * data_source_stack.Count;
2998                         else
2999                                 parent_rows.Height = 0;
3000                 }
3001
3002                 void CalcParentButtons ()
3003                 {
3004                         if (data_source_stack.Count > 0 && CaptionVisible) {
3005                                 back_button_rect = new Rectangle (ClientRectangle.X + ClientRectangle.Width - 2 * (caption_area.Height - 2) - 8,
3006                                                                   caption_area.Height / 2 - back_button_image.Height / 2,
3007                                                                   back_button_image.Width, back_button_image.Height);
3008                                 parent_rows_button_rect = new Rectangle (ClientRectangle.X + ClientRectangle.Width - (caption_area.Height - 2) - 4,
3009                                                                          caption_area.Height / 2 - parent_rows_button_image.Height / 2,
3010                                                                          parent_rows_button_image.Width, parent_rows_button_image.Height);
3011                         }
3012                         else {
3013                                 back_button_rect = parent_rows_button_rect = Rectangle.Empty;
3014                         }
3015                 }
3016
3017                 void CalcRowHeaders ()
3018                 {
3019                         row_headers_area.X = ClientRectangle.X;
3020                         row_headers_area.Y = column_headers_area.Y + column_headers_area.Height;
3021                         row_headers_area.Height = ClientRectangle.Height + ClientRectangle.Y - row_headers_area.Y;
3022
3023                         if (CurrentTableStyle.CurrentRowHeadersVisible)
3024                                 row_headers_area.Width = RowHeaderWidth;
3025                         else
3026                                 row_headers_area.Width = 0;
3027                 }
3028
3029                 int GetVisibleRowCount (int visibleHeight)
3030                 {
3031                         int rows_height = 0;
3032                         int r;
3033                         for (r = FirstVisibleRow; r < rows.Length; r ++) {
3034                                 if (rows_height + rows[r].Height >= visibleHeight)
3035                                         break;
3036                                 rows_height += rows[r].Height;
3037                         }
3038
3039                         if (r < rows.Length - 1)
3040                                 r ++;
3041
3042                         return r - FirstVisibleRow;
3043                 }
3044
3045                 void UpdateVisibleColumn ()
3046                 {
3047                         if (CurrentTableStyle.GridColumnStyles.Count == 0) {
3048                                 visible_column_count = 0;
3049                                 return; 
3050                         }
3051                         
3052                         int col;
3053                         int max_pixel = horiz_pixeloffset + cells_area.Width;
3054                         int unused;
3055
3056                         first_visible_column = FromPixelToColumn (horiz_pixeloffset, out unused);
3057
3058                         col = FromPixelToColumn (max_pixel, out unused);
3059                         
3060                         visible_column_count = 1 + col - first_visible_column;
3061
3062                         visible_column_count = 0;
3063                         for (int i = first_visible_column; i <= col; i ++) {
3064                                 if (CurrentTableStyle.GridColumnStyles[i].bound)
3065                                         visible_column_count++;
3066                         }
3067
3068                         if (first_visible_column + visible_column_count < CurrentTableStyle.GridColumnStyles.Count) { 
3069                                 visible_column_count++; // Partially visible column
3070                         }
3071                 }
3072
3073                 void UpdateVisibleRowCount ()
3074                 {
3075                         visible_row_count = GetVisibleRowCount (cells_area.Height);
3076
3077                         CalcRowHeaders (); // Height depends on num of visible rows
3078                 }
3079
3080
3081                 void InvalidateCaption ()
3082                 {
3083                         if (caption_area.IsEmpty)
3084                                 return;
3085
3086                         Invalidate (caption_area);
3087                 }
3088
3089                 void InvalidateRow (int row)
3090                 {
3091                         if (row < FirstVisibleRow || row > FirstVisibleRow + VisibleRowCount)
3092                                 return;
3093
3094                         Rectangle rect_row = new Rectangle ();
3095
3096                         rect_row.X = cells_area.X;
3097                         rect_row.Width = width_of_all_columns;
3098                         if (rect_row.Width > cells_area.Width)
3099                                 rect_row.Width = cells_area.Width;
3100                         rect_row.Height = rows[row].Height;
3101                         rect_row.Y = cells_area.Y + rows[row].VerticalOffset - rows[FirstVisibleRow].VerticalOffset;
3102                         Invalidate (rect_row);
3103                 }
3104
3105                 void InvalidateRowHeader (int row)
3106                 {
3107                         Rectangle rect_rowhdr = new Rectangle ();
3108                         rect_rowhdr.X = row_headers_area.X;
3109                         rect_rowhdr.Width = row_headers_area.Width;
3110                         rect_rowhdr.Height = rows[row].Height;
3111                         rect_rowhdr.Y = row_headers_area.Y + rows[row].VerticalOffset - rows[FirstVisibleRow].VerticalOffset;
3112                         Invalidate (rect_rowhdr);
3113                 }
3114
3115                 internal void InvalidateColumn (DataGridColumnStyle column)
3116                 {
3117                         Rectangle rect_col = new Rectangle ();
3118                         int col_pixel;
3119                         int col = -1;
3120
3121                         col = CurrentTableStyle.GridColumnStyles.IndexOf (column);
3122
3123                         if (col == -1)
3124                                 return;
3125
3126                         rect_col.Width = column.Width;
3127                         col_pixel = GetColumnStartingPixel (col);
3128                         rect_col.X = cells_area.X + col_pixel - horiz_pixeloffset;
3129                         rect_col.Y = cells_area.Y;
3130                         rect_col.Height = cells_area.Height;
3131                         Invalidate (rect_col);
3132                 }
3133
3134                 void DrawResizeLineVert (int x)
3135                 {
3136                         XplatUI.DrawReversibleRectangle (Handle,
3137                                                          new Rectangle (x, cells_area.Y, 1, cells_area.Height - 3),
3138                                                          2);
3139                 }
3140
3141                 void DrawResizeLineHoriz (int y)
3142                 {
3143                         XplatUI.DrawReversibleRectangle (Handle,
3144                                                          new Rectangle (cells_area.X, y, cells_area.Width - 3, 1),
3145                                                          2);
3146                 }
3147
3148                 void SetUpHorizontalScrollBar (out int maximum)
3149                 {
3150                         maximum = width_of_all_columns;
3151
3152                         horiz_scrollbar.Location = new Point (ClientRectangle.X, ClientRectangle.Y +
3153                                 ClientRectangle.Height - horiz_scrollbar.Height);
3154
3155                         horiz_scrollbar.LargeChange = cells_area.Width;
3156                 }
3157
3158
3159                 void SetUpVerticalScrollBar (out int height, out int maximum)
3160                 {
3161                         int y;
3162                         
3163                         y = ClientRectangle.Y + parent_rows.Y + parent_rows.Height;
3164                         height = ClientRectangle.Height - parent_rows.Y - parent_rows.Height;
3165
3166                         vert_scrollbar.Location = new Point (ClientRectangle.X +
3167                                                              ClientRectangle.Width - vert_scrollbar.Width, y);
3168
3169                         maximum = RowsCount;
3170                         
3171                         if (ShowEditRow && RowsCount > 0) {
3172                                 maximum++;      
3173                         }
3174                         
3175                         vert_scrollbar.LargeChange = VLargeChange;
3176                 }
3177
3178                 #endregion // Public Instance Methods
3179
3180                 #region Instance Properties
3181                 // Returns the ColumnHeaders area excluding the rectangle shared with RowHeaders
3182                 internal Rectangle ColumnHeadersArea {
3183                         get {
3184                                 Rectangle columns_area = column_headers_area;
3185
3186                                 if (CurrentTableStyle.CurrentRowHeadersVisible) {
3187                                         columns_area.X += RowHeaderWidth;
3188                                         columns_area.Width -= RowHeaderWidth;
3189                                 }
3190                                 return columns_area;
3191                         }
3192                 }
3193
3194                 bool ShowingColumnHeaders {
3195                         get { return ColumnHeadersVisible && CurrentTableStyle.GridColumnStyles.Count > 0; }
3196                 }
3197
3198                 internal Rectangle RowHeadersArea {
3199                         get { return row_headers_area; }
3200                 }
3201
3202                 internal Rectangle ParentRowsArea {
3203                         get { return parent_rows; }
3204                 }
3205
3206                 int VLargeChange {
3207                         get { return VisibleRowCount; }
3208                 }
3209
3210                 #endregion Instance Properties
3211
3212                 #endregion // Code originally in DataGridDrawingLogic.cs
3213         }
3214 }