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