* DataGrid.cs (set_CurrentCell): because EnsureCellVisibility
[mono-project.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / DataGrid.cs
blob40f918c76d06dc72dfda672b0c8dfad2f5f2e325
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.
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.
20 // Copyright (c) 2005,2006 Novell, Inc. (http://www.novell.com)
22 // Authors:
23 // Jordi Mas i Hernandez <jordi@ximian.com>
24 // Chris Toshok <toshok@ximian.com>
28 // NOT COMPLETE
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;
39 namespace System.Windows.Forms
41 internal class DataGridRelationshipRow {
42 DataGrid owner;
44 public DataGridRelationshipRow (DataGrid owner)
46 this.owner = owner;
47 IsSelected = false;
48 IsExpanded = false;
49 height = 0;
50 VerticalOffset = 0;
51 RelationHeight = 0;
52 relation_area = Rectangle.Empty;
55 public int height;
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);
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 */
76 internal class DataGridDataSource
78 public DataGrid owner;
79 public CurrencyManager list_manager;
80 public object view;
81 public string data_member;
82 public object data_source;
83 public DataGridCell current;
85 public DataGridDataSource (DataGrid owner, CurrencyManager list_manager, object data_source, string data_member, object view_data, DataGridCell current)
87 this.owner = owner;
88 this.list_manager = list_manager;
89 this.view = view_data;
90 this.data_source = data_source;
91 this.data_member = data_member;
92 this.current = current;
95 DataGridRelationshipRow[] rows;
96 public DataGridRelationshipRow[] Rows {
97 get { return rows; }
98 set { rows = value; }
101 Hashtable selected_rows;
102 public Hashtable SelectedRows {
103 get { return selected_rows; }
104 set { selected_rows = value; }
107 int selection_start;
108 public int SelectionStart {
109 get { return selection_start; }
110 set { selection_start = value; }
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
119 [Flags]
120 [Serializable]
121 public enum HitTestType
123 None = 0,
124 Cell = 1,
125 ColumnHeader = 2,
126 RowHeader = 4,
127 ColumnResize = 8,
128 RowResize = 16,
129 Caption = 32,
130 ParentRows = 64
133 public sealed class HitTestInfo
135 public static readonly HitTestInfo Nowhere = null;
137 int row;
138 int column;
139 DataGrid.HitTestType type;
141 #region Private Constructors
142 internal HitTestInfo () : this (-1, -1, HitTestType.None)
146 internal HitTestInfo (int row, int column, DataGrid.HitTestType type)
148 this.row = row;
149 this.column = column;
150 this.type = type;
152 #endregion
155 #region Public Instance Properties
156 public int Column {
157 get { return column; }
160 public int Row {
161 get { return row; }
163 public DataGrid.HitTestType Type {
164 get { return type; }
166 #endregion //Public Instance Properties
168 public override bool Equals (object o)
170 if (!(o is HitTestInfo))
171 return false;
173 HitTestInfo obj = (HitTestInfo) o;
174 return (obj.Column == column && obj.Row == row && obj.Type ==type);
177 public override int GetHashCode ()
179 return row ^ column;
182 public override string ToString ()
184 return "{ " + type + "," + row + "," + column + "}";
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;
197 /* colors */
198 // XXX this needs addressing. Control.background_color should not be internal.
199 new Color background_color;
200 Color caption_backcolor;
201 Color caption_forecolor;
202 Color parentrowsback_color;
203 Color parentrowsfore_color;
205 /* flags to determine which areas of the datagrid are shown */
206 bool caption_visible;
207 bool parentrows_visible;
209 GridTableStylesCollection styles_collection;
210 DataGridParentRowsLabelStyle parentrowslabel_style;
211 DataGridTableStyle default_style;
212 DataGridTableStyle grid_style;
213 DataGridTableStyle current_style;
215 /* selection */
216 DataGridCell current_cell;
217 Hashtable selected_rows;
218 int selection_start; // used for range selection
220 /* layout/rendering */
221 bool allow_navigation;
222 int first_visiblerow;
223 int first_visiblecolumn;
224 int visiblerow_count;
225 int visiblecolumn_count;
226 Font caption_font;
227 string caption_text;
228 bool flatmode;
229 HScrollBar horiz_scrollbar;
230 VScrollBar vert_scrollbar;
231 int horiz_pixeloffset;
233 internal Bitmap back_button_image;
234 internal Rectangle back_button_rect;
235 internal bool back_button_mouseover;
236 internal bool back_button_active;
237 internal Bitmap parent_rows_button_image;
238 internal Rectangle parent_rows_button_rect;
239 internal bool parent_rows_button_mouseover;
240 internal bool parent_rows_button_active;
242 /* databinding */
243 object datasource;
244 string datamember;
245 CurrencyManager list_manager;
246 bool refetch_list_manager = true;
247 bool _readonly;
248 DataGridRelationshipRow[] rows;
250 /* column resize fields */
251 bool column_resize_active;
252 int resize_column_x;
253 int resize_column_width_delta;
254 int resize_column;
256 /* row resize fields */
257 bool row_resize_active;
258 int resize_row_y;
259 int resize_row_height_delta;
260 int resize_row;
262 /* used to make sure we don't endlessly recurse calling set_CurrentCell and OnListManagerPositionChanged */
263 bool from_positionchanged_handler;
265 /* editing state */
266 bool cursor_in_add_row;
267 bool add_row_changed;
268 bool is_editing; // Current cell is edit mode
269 bool is_changing;
271 internal Stack dataSourceStack;
273 #endregion // Local Variables
275 #region Public Constructors
276 public DataGrid ()
278 allow_navigation = true;
279 background_color = def_background_color;
280 border_style = BorderStyle.Fixed3D;
281 caption_backcolor = def_caption_backcolor;
282 caption_forecolor = def_caption_forecolor;
283 caption_text = string.Empty;
284 caption_visible = true;
285 datamember = string.Empty;
286 parentrowsback_color = def_parentrowsback_color;
287 parentrowsfore_color = def_parentrowsfore_color;
288 parentrows_visible = true;
289 current_cell = new DataGridCell ();
290 parentrowslabel_style = DataGridParentRowsLabelStyle.Both;
291 selected_rows = new Hashtable ();
292 selection_start = -1;
293 rows = new DataGridRelationshipRow [0];
295 default_style = new DataGridTableStyle (true);
296 grid_style = new DataGridTableStyle ();
298 styles_collection = new GridTableStylesCollection (this);
299 styles_collection.CollectionChanged += new CollectionChangeEventHandler (OnTableStylesCollectionChanged);
301 CurrentTableStyle = grid_style;
303 horiz_scrollbar = new ImplicitHScrollBar ();
304 horiz_scrollbar.Scroll += new ScrollEventHandler (GridHScrolled);
305 vert_scrollbar = new ImplicitVScrollBar ();
306 vert_scrollbar.Scroll += new ScrollEventHandler (GridVScrolled);
308 SetStyle (ControlStyles.UserMouse, true);
310 dataSourceStack = new Stack ();
312 back_button_image = ResourceImageLoader.Get ("go-previous.png");
313 //back_button_image.MakeTransparent (Color.Transparent);
314 parent_rows_button_image = ResourceImageLoader.Get ("go-top.png");
315 //parent_rows_button_image.MakeTransparent (Color.Transparent);
318 #endregion // Public Constructor
320 #region Public Instance Properties
322 [DefaultValue(true)]
323 public bool AllowNavigation {
324 get { return allow_navigation; }
325 set {
326 if (allow_navigation != value) {
327 allow_navigation = value;
328 OnAllowNavigationChanged (EventArgs.Empty);
333 [DefaultValue(true)]
334 public bool AllowSorting {
335 get { return grid_style.AllowSorting; }
336 set { grid_style.AllowSorting = value; }
339 public Color AlternatingBackColor {
340 get { return grid_style.AlternatingBackColor; }
341 set { grid_style.AlternatingBackColor = value; }
344 public override Color BackColor {
345 get { return grid_style.BackColor; }
346 set { grid_style.BackColor = value; }
349 public Color BackgroundColor {
350 get { return background_color; }
351 set {
352 if (background_color != value) {
353 background_color = value;
354 OnBackgroundColorChanged (EventArgs.Empty);
355 Invalidate ();
360 [Browsable(false)]
361 [EditorBrowsable(EditorBrowsableState.Never)]
362 public override Image BackgroundImage {
363 get { return base.BackgroundImage; }
364 set {
365 if (base.BackgroundImage == value)
366 return;
368 base.BackgroundImage = value;
369 Invalidate ();
373 [DispId(-504)]
374 [DefaultValue(BorderStyle.Fixed3D)]
375 public BorderStyle BorderStyle {
376 get { return InternalBorderStyle; }
377 set {
378 InternalBorderStyle = value;
379 CalcAreasAndInvalidate ();
380 OnBorderStyleChanged (EventArgs.Empty);
384 public Color CaptionBackColor {
385 get { return caption_backcolor; }
386 set {
387 if (caption_backcolor != value) {
388 caption_backcolor = value;
389 InvalidateCaption ();
394 [Localizable(true)]
395 [AmbientValue(null)]
396 public Font CaptionFont {
397 get {
398 if (caption_font == null)
399 return new Font (Font, FontStyle.Bold);
401 return caption_font;
403 set {
404 if (caption_font != null && caption_font.Equals (value))
405 return;
407 caption_font = value;
408 CalcAreasAndInvalidate ();
412 public Color CaptionForeColor {
413 get { return caption_forecolor; }
414 set {
415 if (caption_forecolor != value) {
416 caption_forecolor = value;
417 InvalidateCaption ();
422 [Localizable(true)]
423 [DefaultValue("")]
424 public string CaptionText {
425 get { return caption_text; }
426 set {
427 if (caption_text != value) {
428 caption_text = value;
429 InvalidateCaption ();
434 [DefaultValue(true)]
435 public bool CaptionVisible {
436 get { return caption_visible; }
437 set {
438 if (caption_visible != value) {
439 EndEdit ();
440 caption_visible = value;
441 CalcAreasAndInvalidate ();
442 OnCaptionVisibleChanged (EventArgs.Empty);
447 [DefaultValue(true)]
448 public bool ColumnHeadersVisible {
449 get { return grid_style.ColumnHeadersVisible; }
450 set { grid_style.ColumnHeadersVisible = value; }
453 bool setting_current_cell;
455 [Browsable(false)]
456 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
457 public DataGridCell CurrentCell {
458 get { return current_cell; }
459 set {
460 if (setting_current_cell)
461 return;
462 setting_current_cell = true;
464 if (!IsHandleCreated) {
465 setting_current_cell = false;
466 throw new Exception ("CurrentCell cannot be set at this time.");
469 if (current_cell.Equals (value)) {
470 setting_current_cell = false;
471 return;
474 /* make sure the new cell fits in the correct bounds for [row,column] */
475 if (ReadOnly && value.RowNumber > RowsCount - 1)
476 value.RowNumber = RowsCount - 1;
477 else if (value.RowNumber > RowsCount)
478 value.RowNumber = RowsCount;
479 if (value.ColumnNumber >= CurrentTableStyle.GridColumnStyles.Count)
480 value.ColumnNumber = CurrentTableStyle.GridColumnStyles.Count == 0 ? 0 : CurrentTableStyle.GridColumnStyles.Count - 1;
482 bool was_changing = is_changing;
484 add_row_changed = add_row_changed || was_changing;
486 EndEdit ();
487 if (value.RowNumber != current_cell.RowNumber) {
488 if (!from_positionchanged_handler) {
489 try {
490 ListManager.EndCurrentEdit ();
492 catch (Exception e) {
493 DialogResult r = MessageBox.Show (String.Format ("{0} Do you wish to correct the value?", e.Message),
494 "Error when committing the row to the original data source",
495 MessageBoxButtons.YesNo);
496 if (r == DialogResult.Yes) {
497 Edit ();
498 return;
500 else
501 ListManager.CancelCurrentEdit ();
505 if (value.RowNumber == RowsCount && !ListManager.CanAddRows)
506 value.RowNumber --;
508 if (value.RowNumber == RowsCount) {
509 cursor_in_add_row = true;
510 add_row_changed = false;
511 AddNewRow ();
513 else {
514 cursor_in_add_row = false;
518 int old_row = current_cell.RowNumber;
520 EnsureCellVisibility (value);
522 current_cell = value;
524 InvalidateRowHeader (old_row);
525 InvalidateRowHeader (current_cell.RowNumber);
527 list_manager.Position = current_cell.RowNumber;
529 OnCurrentCellChanged (EventArgs.Empty);
531 if (!from_positionchanged_handler)
532 Edit ();
534 setting_current_cell = false;
538 int CurrentRow {
539 get { return current_cell.RowNumber; }
540 set { CurrentCell = new DataGridCell (value, current_cell.ColumnNumber); }
543 int CurrentColumn {
544 get { return current_cell.ColumnNumber; }
545 set { CurrentCell = new DataGridCell (current_cell.RowNumber, value); }
548 [Browsable(false)]
549 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
550 public int CurrentRowIndex {
551 get {
552 if (ListManager == null)
553 return -1;
555 return CurrentRow;
557 set { CurrentRow = value; }
560 [Browsable(false)]
561 [EditorBrowsable(EditorBrowsableState.Never)]
562 public override Cursor Cursor {
563 get { return base.Cursor; }
564 set { base.Cursor = value; }
567 [DefaultValue(null)]
568 [Editor ("System.Windows.Forms.Design.DataMemberListEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
569 public string DataMember {
570 get { return datamember; }
571 set {
572 if (BindingContext != null) {
573 SetDataSource (datasource, value);
575 else {
576 if (list_manager != null)
577 list_manager = null;
578 datamember = value;
579 refetch_list_manager = true;
584 [DefaultValue(null)]
585 [RefreshProperties(RefreshProperties.Repaint)]
586 [TypeConverter("System.Windows.Forms.Design.DataSourceConverter, " + Consts.AssemblySystem_Design)]
587 public object DataSource {
588 get { return datasource; }
589 set {
590 if (BindingContext != null) {
591 SetDataSource (value, ListManager == null ? datamember : string.Empty);
593 else {
594 datasource = value;
595 if (list_manager != null)
596 datamember = string.Empty;
598 if (list_manager != null)
599 list_manager = null;
600 refetch_list_manager = true;
605 protected override Size DefaultSize {
606 get { return new Size (130, 80); }
609 [Browsable(false)]
610 public int FirstVisibleColumn {
611 get { return first_visiblecolumn; }
614 [DefaultValue(false)]
615 public bool FlatMode {
616 get { return flatmode; }
617 set {
618 if (flatmode != value) {
619 flatmode = value;
620 OnFlatModeChanged (EventArgs.Empty);
621 Refresh ();
626 public override Color ForeColor {
627 get { return grid_style.ForeColor; }
628 set { grid_style.ForeColor = value; }
631 public Color GridLineColor {
632 get { return grid_style.GridLineColor; }
633 set {
634 if (value == Color.Empty)
635 throw new ArgumentException ("Color.Empty value is invalid.");
637 grid_style.GridLineColor = value;
641 [DefaultValue(DataGridLineStyle.Solid)]
642 public DataGridLineStyle GridLineStyle {
643 get { return grid_style.GridLineStyle; }
644 set { grid_style.GridLineStyle = value; }
647 public Color HeaderBackColor {
648 get { return grid_style.HeaderBackColor; }
649 set {
650 if (value == Color.Empty)
651 throw new ArgumentException ("Color.Empty value is invalid.");
653 grid_style.HeaderBackColor = value;
657 public Font HeaderFont {
658 get { return grid_style.HeaderFont; }
659 set { grid_style.HeaderFont = value; }
662 public Color HeaderForeColor {
663 get { return grid_style.HeaderForeColor; }
664 set { grid_style.HeaderForeColor = value; }
667 protected ScrollBar HorizScrollBar {
668 get { return horiz_scrollbar; }
670 internal ScrollBar HScrollBar {
671 get { return horiz_scrollbar; }
674 internal int HorizPixelOffset {
675 get { return horiz_pixeloffset; }
678 internal bool IsChanging {
679 get { return is_changing; }
682 public object this [DataGridCell cell] {
683 get { return this [cell.RowNumber, cell.ColumnNumber]; }
684 set { this [cell.RowNumber, cell.ColumnNumber] = value; }
687 public object this [int rowIndex, int columnIndex] {
688 get { return CurrentTableStyle.GridColumnStyles[columnIndex].GetColumnValueAtRow (ListManager,
689 rowIndex); }
690 set { CurrentTableStyle.GridColumnStyles[columnIndex].SetColumnValueAtRow (ListManager,
691 rowIndex, value); }
694 public Color LinkColor {
695 get { return grid_style.LinkColor; }
696 set { grid_style.LinkColor = value; }
699 internal Font LinkFont {
700 get { return new Font (Font, FontStyle.Underline); }
703 [ComVisible(false)]
704 [Browsable(false)]
705 [EditorBrowsable(EditorBrowsableState.Never)]
706 public Color LinkHoverColor {
707 get { return grid_style.LinkHoverColor; }
708 set { grid_style.LinkHoverColor = value; }
711 [Browsable(false)]
712 [EditorBrowsable(EditorBrowsableState.Advanced)]
713 protected internal CurrencyManager ListManager {
714 get {
715 if (list_manager == null && refetch_list_manager) {
716 SetDataSource (datasource, datamember);
717 refetch_list_manager = false;
720 return list_manager;
722 set { throw new NotSupportedException ("Operation is not supported."); }
725 public Color ParentRowsBackColor {
726 get { return parentrowsback_color; }
727 set {
728 if (parentrowsback_color != value) {
729 parentrowsback_color = value;
730 if (parentrows_visible) {
731 Refresh ();
737 public Color ParentRowsForeColor {
738 get { return parentrowsfore_color; }
739 set {
740 if (parentrowsfore_color != value) {
741 parentrowsfore_color = value;
742 if (parentrows_visible) {
743 Refresh ();
749 [DefaultValue(DataGridParentRowsLabelStyle.Both)]
750 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
751 public DataGridParentRowsLabelStyle ParentRowsLabelStyle {
752 get { return parentrowslabel_style; }
753 set {
754 if (parentrowslabel_style != value) {
755 parentrowslabel_style = value;
756 if (parentrows_visible) {
757 Refresh ();
760 OnParentRowsLabelStyleChanged (EventArgs.Empty);
765 [DefaultValue(true)]
766 public bool ParentRowsVisible {
767 get { return parentrows_visible; }
768 set {
769 if (parentrows_visible != value) {
770 parentrows_visible = value;
771 CalcAreasAndInvalidate ();
772 OnParentRowsVisibleChanged (EventArgs.Empty);
777 // Settting this property seems to have no effect.
778 [DefaultValue(75)]
779 [TypeConverter(typeof(DataGridPreferredColumnWidthTypeConverter))]
780 public int PreferredColumnWidth {
781 get { return grid_style.PreferredColumnWidth; }
782 set { grid_style.PreferredColumnWidth = value; }
785 public int PreferredRowHeight {
786 get { return grid_style.PreferredRowHeight; }
787 set { grid_style.PreferredRowHeight = value; }
790 [DefaultValue(false)]
791 public bool ReadOnly {
792 get { return _readonly; }
793 set {
794 if (_readonly != value) {
795 _readonly = value;
796 OnReadOnlyChanged (EventArgs.Empty);
797 CalcAreasAndInvalidate ();
802 [DefaultValue(true)]
803 public bool RowHeadersVisible {
804 get { return grid_style.RowHeadersVisible; }
805 set { grid_style.RowHeadersVisible = value; }
808 [DefaultValue(35)]
809 public int RowHeaderWidth {
810 get { return grid_style.RowHeaderWidth; }
811 set { grid_style.RowHeaderWidth = value; }
814 internal DataGridRelationshipRow[] DataGridRows {
815 get { return rows; }
819 public Color SelectionBackColor {
820 get { return grid_style.SelectionBackColor; }
821 set { grid_style.SelectionBackColor = value; }
824 public Color SelectionForeColor {
825 get { return grid_style.SelectionForeColor; }
826 set { grid_style.SelectionForeColor = value; }
829 public override ISite Site {
830 get { return base.Site; }
831 set { base.Site = value; }
834 [Localizable(true)]
835 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
836 public GridTableStylesCollection TableStyles {
837 get { return styles_collection; }
840 [Bindable(false)]
841 [Browsable(false)]
842 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
843 [EditorBrowsable(EditorBrowsableState.Never)]
844 public override string Text {
845 get { return base.Text; }
846 set { base.Text = value; }
849 [Browsable(false)]
850 [EditorBrowsable(EditorBrowsableState.Advanced)]
851 protected ScrollBar VertScrollBar {
852 get { return vert_scrollbar; }
854 internal ScrollBar VScrollBar {
855 get { return vert_scrollbar; }
858 [Browsable(false)]
859 public int VisibleColumnCount {
860 get { return visiblecolumn_count; }
863 [Browsable(false)]
864 public int VisibleRowCount {
865 get { return visiblerow_count; }
868 #endregion // Public Instance Properties
870 #region Private Instance Properties
871 internal DataGridTableStyle CurrentTableStyle {
872 get { return current_style; }
873 set {
874 if (current_style != value) {
875 if (current_style != null)
876 DisconnectTableStyleEvents ();
878 current_style = value;
880 if (current_style != null) {
881 current_style.DataGrid = this;
882 ConnectTableStyleEvents ();
884 CalcAreasAndInvalidate ();
889 internal int FirstVisibleRow {
890 get { return first_visiblerow; }
893 internal int RowsCount {
894 get { return ListManager != null ? ListManager.Count : 0; }
897 internal int RowHeight {
898 get {
899 if (CurrentTableStyle.CurrentPreferredRowHeight > Font.Height + 3 + 1 /* line */)
900 return CurrentTableStyle.CurrentPreferredRowHeight;
901 else
902 return Font.Height + 3 + 1 /* line */;
906 internal bool ShowEditRow {
907 get {
908 if (ListManager != null && !ListManager.CanAddRows)
909 return false;
911 return !_readonly;
915 internal bool ShowParentRows {
916 get { return ParentRowsVisible && dataSourceStack.Count > 0; }
919 #endregion Private Instance Properties
921 #region Public Instance Methods
923 void AbortEditing ()
925 if (is_changing) {
926 CurrentTableStyle.GridColumnStyles[current_cell.ColumnNumber].Abort (current_cell.RowNumber);
927 is_changing = false;
928 InvalidateRowHeader (current_cell.RowNumber);
932 [MonoTODO]
933 public bool BeginEdit (DataGridColumnStyle gridColumn, int rowNumber)
935 if (is_changing)
936 return false;
938 int column = CurrentTableStyle.GridColumnStyles.IndexOf (gridColumn);
939 if (column < 0)
940 return false;
942 CurrentCell = new DataGridCell (rowNumber, column);
944 /* force editing of CurrentCell if we aren't already editing */
945 Edit ();
947 return true;
950 public void BeginInit ()
954 protected virtual void CancelEditing ()
956 if (CurrentTableStyle.GridColumnStyles.Count == 0)
957 return;
959 CurrentTableStyle.GridColumnStyles[current_cell.ColumnNumber].ConcedeFocus ();
961 if (is_changing) {
962 if (current_cell.ColumnNumber < CurrentTableStyle.GridColumnStyles.Count)
963 CurrentTableStyle.GridColumnStyles[current_cell.ColumnNumber].Abort (current_cell.RowNumber);
964 InvalidateRowHeader (current_cell.RowNumber);
967 if (cursor_in_add_row && !is_changing) {
968 ListManager.CancelCurrentEdit ();
971 is_changing = false;
972 is_editing = false;
975 [MonoTODO]
976 public void Collapse (int row)
978 if (!rows[row].IsExpanded)
979 return;
981 SuspendLayout ();
982 rows[row].IsExpanded = false;
983 for (int i = 1; i < rows.Length - row; i ++)
984 rows[row + i].VerticalOffset -= rows[row].RelationHeight;
986 rows[row].height -= rows[row].RelationHeight;
987 rows[row].RelationHeight = 0;
988 ResumeLayout (false);
990 /* XX need to redraw from @row down */
991 CalcAreasAndInvalidate ();
994 protected internal virtual void ColumnStartedEditing (Control editingControl)
996 ColumnStartedEditing (editingControl.Bounds);
999 protected internal virtual void ColumnStartedEditing (Rectangle bounds)
1001 bool need_invalidate = is_changing == false;
1002 // XXX calculate the row header to invalidate
1003 // instead of using CurrentRow
1004 is_changing = true;
1006 if (cursor_in_add_row && need_invalidate)
1007 RecreateDataGridRows (true);
1009 if (need_invalidate)
1010 InvalidateRowHeader (CurrentRow);
1013 protected override AccessibleObject CreateAccessibilityInstance ()
1015 return base.CreateAccessibilityInstance ();
1018 protected virtual DataGridColumnStyle CreateGridColumn (PropertyDescriptor prop)
1020 return CreateGridColumn (prop, false);
1023 protected virtual DataGridColumnStyle CreateGridColumn (PropertyDescriptor prop, bool isDefault)
1025 throw new NotImplementedException();
1028 protected override void Dispose (bool disposing)
1030 base.Dispose (disposing);
1033 public bool EndEdit (DataGridColumnStyle gridColumn, int rowNumber, bool shouldAbort)
1035 if (shouldAbort || gridColumn.ParentReadOnly)
1036 gridColumn.Abort (rowNumber);
1037 else {
1038 gridColumn.Commit (ListManager, rowNumber);
1039 gridColumn.ConcedeFocus ();
1042 if (is_editing || is_changing) {
1043 is_editing = false;
1044 is_changing = false;
1045 InvalidateRowHeader (rowNumber);
1047 return true;
1050 public void EndInit ()
1054 public void Expand (int row)
1056 if (rows[row].IsExpanded)
1057 return;
1059 rows[row].IsExpanded = true;
1061 int i;
1063 string[] relations = CurrentTableStyle.Relations;
1064 StringBuilder relation_builder = new StringBuilder ("");
1066 for (i = 0; i < relations.Length; i ++) {
1067 if (i > 0)
1068 relation_builder.Append ("\n");
1070 relation_builder.Append (relations[i]);
1072 string relation_text = relation_builder.ToString ();
1074 SizeF measured_area = DeviceContext.MeasureString (relation_text, LinkFont);
1076 rows[row].relation_area = new Rectangle (cells_area.X + 1,
1077 0, /* updated as needed at the usage sites for relation_area */
1078 (int)measured_area.Width + 4,
1079 Font.Height * relations.Length);
1081 for (i = 1; i < rows.Length - row; i ++)
1082 rows[row + i].VerticalOffset += rows[row].relation_area.Height;
1083 rows[row].height += rows[row].relation_area.Height;
1084 rows[row].RelationHeight = rows[row].relation_area.Height;
1086 /* XX need to redraw from @row down */
1087 CalcAreasAndInvalidate ();
1090 public Rectangle GetCellBounds (DataGridCell cell)
1092 return GetCellBounds (cell.RowNumber, cell.ColumnNumber);
1095 public Rectangle GetCellBounds (int row, int col)
1097 Rectangle bounds = new Rectangle ();
1098 int col_pixel;
1100 bounds.Width = CurrentTableStyle.GridColumnStyles[col].Width;
1101 bounds.Height = rows[row].Height - rows[row].RelationHeight;
1102 bounds.Y = cells_area.Y + rows[row].VerticalOffset - rows[FirstVisibleRow].VerticalOffset;
1103 col_pixel = GetColumnStartingPixel (col);
1104 bounds.X = cells_area.X + col_pixel - horiz_pixeloffset;
1105 return bounds;
1108 public Rectangle GetCurrentCellBounds ()
1110 return GetCellBounds (current_cell.RowNumber, current_cell.ColumnNumber);
1113 protected virtual string GetOutputTextDelimiter ()
1115 return string.Empty;
1118 protected virtual void GridHScrolled (object sender, ScrollEventArgs se)
1120 if (se.NewValue == horiz_pixeloffset ||
1121 se.Type == ScrollEventType.EndScroll) {
1122 return;
1125 ScrollToColumnInPixels (se.NewValue);
1128 protected virtual void GridVScrolled (object sender, ScrollEventArgs se)
1130 int old_first_visiblerow = first_visiblerow;
1131 first_visiblerow = se.NewValue;
1133 if (first_visiblerow == old_first_visiblerow)
1134 return;
1136 UpdateVisibleRowCount ();
1138 if (first_visiblerow == old_first_visiblerow)
1139 return;
1141 ScrollToRow (old_first_visiblerow, first_visiblerow);
1144 public HitTestInfo HitTest (Point position)
1146 return HitTest (position.X, position.Y);
1149 const int RESIZE_HANDLE_HORIZ_SIZE = 5;
1150 const int RESIZE_HANDLE_VERT_SIZE = 3;
1152 // From Point to Cell
1153 public HitTestInfo HitTest (int x, int y)
1155 if (columnhdrs_area.Contains (x, y)) {
1156 int offset_x = x + horiz_pixeloffset;
1157 int column_x;
1158 int column_under_mouse = FromPixelToColumn (offset_x, out column_x);
1160 if ((column_x + CurrentTableStyle.GridColumnStyles[column_under_mouse].Width - offset_x < RESIZE_HANDLE_HORIZ_SIZE)
1161 && column_under_mouse < CurrentTableStyle.GridColumnStyles.Count) {
1163 return new HitTestInfo (-1, column_under_mouse, HitTestType.ColumnResize);
1165 else {
1166 return new HitTestInfo (-1, column_under_mouse, HitTestType.ColumnHeader);
1170 if (rowhdrs_area.Contains (x, y)) {
1171 int posy;
1172 int rcnt = FirstVisibleRow + VisibleRowCount;
1173 for (int r = FirstVisibleRow; r < rcnt; r++) {
1174 posy = cells_area.Y + rows[r].VerticalOffset - rows[FirstVisibleRow].VerticalOffset;
1175 if (y <= posy + rows[r].Height) {
1176 if ((posy + rows[r].Height) - y < RESIZE_HANDLE_VERT_SIZE) {
1177 return new HitTestInfo (r, -1, HitTestType.RowResize);
1179 else {
1180 return new HitTestInfo (r, -1, HitTestType.RowHeader);
1186 if (caption_area.Contains (x, y)) {
1187 return new HitTestInfo (-1, -1, HitTestType.Caption);
1190 if (parent_rows.Contains (x, y)) {
1191 return new HitTestInfo (-1, -1, HitTestType.ParentRows);
1194 int pos_y, pos_x, width;
1195 int rowcnt = FirstVisibleRow + VisibleRowCount;
1196 for (int row = FirstVisibleRow; row < rowcnt; row++) {
1198 pos_y = cells_area.Y + rows[row].VerticalOffset - rows[FirstVisibleRow].VerticalOffset;
1199 if (y <= pos_y + rows[row].Height) {
1200 int col_pixel;
1201 int column_cnt = first_visiblecolumn + visiblecolumn_count;
1202 if (column_cnt > 0) {
1203 for (int column = first_visiblecolumn; column < column_cnt; column++) {
1204 if (CurrentTableStyle.GridColumnStyles[column].bound == false)
1205 continue;
1206 col_pixel = GetColumnStartingPixel (column);
1207 pos_x = cells_area.X + col_pixel - horiz_pixeloffset;
1208 width = CurrentTableStyle.GridColumnStyles[column].Width;
1210 if (x <= pos_x + width) { // Column found
1211 return new HitTestInfo (row, column, HitTestType.Cell);
1215 else if (CurrentTableStyle.HasRelations) {
1216 /* XXX this needs checking against MS somehow... */
1217 if (x < rows[row].relation_area.X + rows[row].relation_area.Width)
1218 return new HitTestInfo (row, 0/*XXX?*/, HitTestType.Cell);
1221 break;
1225 return new HitTestInfo ();
1228 public bool IsExpanded (int rowNumber)
1230 return (rows[rowNumber].IsExpanded);
1233 public bool IsSelected (int row)
1235 return rows[row].IsSelected;
1238 [MonoTODO]
1239 public void NavigateBack ()
1241 if (dataSourceStack.Count == 0)
1242 return;
1244 DataGridDataSource source = (DataGridDataSource)dataSourceStack.Pop ();
1245 list_manager = source.list_manager;
1246 rows = source.Rows;
1247 selected_rows = source.SelectedRows;
1248 selection_start = source.SelectionStart;
1249 SetDataSource (source.data_source, source.data_member);
1251 CurrentCell = source.current;
1254 [MonoTODO]
1255 public void NavigateTo (int rowNumber, string relationName)
1257 if (allow_navigation == false)
1258 return;
1260 DataGridDataSource previous_source = new DataGridDataSource (this, list_manager, datasource, datamember, list_manager.Current, CurrentCell);
1261 previous_source.Rows = rows;
1262 previous_source.SelectedRows = selected_rows;
1263 previous_source.SelectionStart = selection_start;
1265 dataSourceStack.Push (previous_source);
1267 rows = null;
1268 selected_rows = new Hashtable ();
1269 selection_start = -1;
1271 DataMember = String.Format ("{0}.{1}", DataMember, relationName);
1272 OnDataSourceChanged (EventArgs.Empty);
1275 protected virtual void OnAllowNavigationChanged (EventArgs e)
1277 EventHandler eh = (EventHandler)(Events [AllowNavigationChangedEvent]);
1278 if (eh != null)
1279 eh (this, e);
1282 protected void OnBackButtonClicked (object sender, EventArgs e)
1284 EventHandler eh = (EventHandler)(Events [BackButtonClickEvent]);
1285 if (eh != null)
1286 eh (this, e);
1289 protected override void OnBackColorChanged (EventArgs e)
1291 base.OnBackColorChanged (e);
1294 protected virtual void OnBackgroundColorChanged (EventArgs e)
1296 EventHandler eh = (EventHandler)(Events [BackgroundColorChangedEvent]);
1297 if (eh != null)
1298 eh (this, e);
1301 protected override void OnBindingContextChanged (EventArgs e)
1303 base.OnBindingContextChanged (e);
1305 SetDataSource (datasource, datamember);
1308 protected virtual void OnBorderStyleChanged (EventArgs e)
1310 EventHandler eh = (EventHandler)(Events [BorderStyleChangedEvent]);
1311 if (eh != null)
1312 eh (this, e);
1315 protected virtual void OnCaptionVisibleChanged (EventArgs e)
1317 EventHandler eh = (EventHandler)(Events [CaptionVisibleChangedEvent]);
1318 if (eh != null)
1319 eh (this, e);
1322 protected virtual void OnCurrentCellChanged (EventArgs e)
1324 EventHandler eh = (EventHandler)(Events [CurrentCellChangedEvent]);
1325 if (eh != null)
1326 eh (this, e);
1329 protected virtual void OnDataSourceChanged (EventArgs e)
1331 EventHandler eh = (EventHandler)(Events [DataSourceChangedEvent]);
1332 if (eh != null)
1333 eh (this, e);
1336 protected override void OnEnter (EventArgs e)
1338 base.OnEnter (e);
1341 protected virtual void OnFlatModeChanged (EventArgs e)
1343 EventHandler eh = (EventHandler)(Events [FlatModeChangedEvent]);
1344 if (eh != null)
1345 eh (this, e);
1348 protected override void OnFontChanged (EventArgs e)
1350 CalcGridAreas ();
1351 base.OnFontChanged (e);
1354 protected override void OnForeColorChanged (EventArgs e)
1356 base.OnForeColorChanged (e);
1359 protected override void OnHandleCreated (EventArgs e)
1361 base.OnHandleCreated (e);
1362 SetDataSource (datasource, datamember);
1365 protected override void OnHandleDestroyed (EventArgs e)
1367 base.OnHandleDestroyed (e);
1370 protected override void OnKeyDown (KeyEventArgs ke)
1372 base.OnKeyDown (ke);
1374 if (ProcessGridKey (ke) == true)
1375 ke.Handled = true;
1377 /* TODO: we probably don't need this check,
1378 * since current_cell wouldn't have been set
1379 * to something invalid */
1380 if (CurrentTableStyle.GridColumnStyles.Count > 0) {
1381 CurrentTableStyle.GridColumnStyles[current_cell.ColumnNumber].OnKeyDown
1382 (ke, current_cell.RowNumber, current_cell.ColumnNumber);
1386 protected override void OnKeyPress (KeyPressEventArgs kpe)
1388 base.OnKeyPress (kpe);
1391 protected override void OnLayout (LayoutEventArgs levent)
1393 base.OnLayout (levent);
1394 CalcAreasAndInvalidate ();
1397 protected override void OnLeave (EventArgs e)
1399 base.OnLeave (e);
1401 #if false
1402 /* we get an OnLeave call when the
1403 * DataGridTextBox control is focused, so we
1404 * need to ignore that. If we get an OnLeave
1405 * call when a child control is not receiving
1406 * focus, we need to cancel the current
1407 * edit. */
1408 if (cursor_in_add_row) {
1409 ListManager.CancelCurrentEdit ();
1411 #endif
1414 protected override void OnMouseDown (MouseEventArgs e)
1416 base.OnMouseDown (e);
1418 bool ctrl_pressed = ((Control.ModifierKeys & Keys.Control) != 0);
1419 bool shift_pressed = ((Control.ModifierKeys & Keys.Shift) != 0);
1421 HitTestInfo testinfo;
1422 testinfo = HitTest (e.X, e.Y);
1424 switch (testinfo.Type) {
1425 case HitTestType.Cell:
1426 if (testinfo.Row < 0 || testinfo.Column < 0)
1427 break;
1429 if (rows[testinfo.Row].IsExpanded) {
1430 Rectangle relation_area = rows[testinfo.Row].relation_area;
1431 relation_area.Y = rows[testinfo.Row].VerticalOffset + cells_area.Y + rows[testinfo.Row].Height - rows[testinfo.Row].RelationHeight;
1432 if (relation_area.Contains (e.X, e.Y)) {
1433 /* the click happened in the relation area, navigate to the new table */
1434 int relative = e.Y - relation_area.Y;
1435 NavigateTo (testinfo.Row, CurrentTableStyle.Relations[relative / LinkFont.Height]);
1436 return;
1440 DataGridCell new_cell = new DataGridCell (testinfo.Row, testinfo.Column);
1442 if ((new_cell.Equals (current_cell) == false) || (!is_editing)) {
1443 EnsureCellVisibility (new_cell);
1444 CurrentCell = new_cell;
1445 Edit ();
1446 } else {
1447 CurrentTableStyle.GridColumnStyles[testinfo.Column].OnMouseDown (e, testinfo.Row, testinfo.Column);
1450 break;
1452 case HitTestType.RowHeader:
1453 bool expansion_click = false;
1454 if (CurrentTableStyle.HasRelations) {
1455 if (e.X > rowhdrs_area.X + rowhdrs_area.Width / 2) {
1456 /* it's in the +/- space */
1457 if (IsExpanded (testinfo.Row))
1458 Collapse (testinfo.Row);
1459 else
1460 Expand (testinfo.Row);
1462 expansion_click = true;
1466 if (!ctrl_pressed &&
1467 !shift_pressed &&
1468 !expansion_click) {
1469 ResetSelection (); // Invalidates selected rows
1472 if ((shift_pressed ||
1473 expansion_click)
1474 && selection_start != -1) {
1475 ShiftSelection (testinfo.Row);
1476 } else { // ctrl_pressed or single item
1477 selection_start = testinfo.Row;
1478 Select (testinfo.Row);
1481 CancelEditing ();
1482 CurrentRow = testinfo.Row;
1483 OnRowHeaderClick (EventArgs.Empty);
1485 break;
1487 case HitTestType.ColumnHeader:
1488 if (CurrentTableStyle.GridColumnStyles.Count == 0)
1489 break;
1491 if (AllowSorting == false)
1492 break;
1494 if (ListManager.List is IBindingList == false)
1495 break;
1497 ListSortDirection direction = ListSortDirection.Ascending;
1498 PropertyDescriptor prop = CurrentTableStyle.GridColumnStyles[testinfo.Column].PropertyDescriptor;
1499 IBindingList list = (IBindingList) ListManager.List;
1501 if (list.SortProperty != null) {
1502 CurrentTableStyle.GridColumnStyles[list.SortProperty].ArrowDrawingMode
1503 = DataGridColumnStyle.ArrowDrawing.No;
1506 if (prop == list.SortProperty && list.SortDirection == ListSortDirection.Ascending) {
1507 direction = ListSortDirection.Descending;
1510 CurrentTableStyle.GridColumnStyles[testinfo.Column].ArrowDrawingMode =
1511 direction == ListSortDirection.Ascending ?
1512 DataGridColumnStyle.ArrowDrawing.Ascending : DataGridColumnStyle.ArrowDrawing.Descending;
1514 list.ApplySort (prop, direction);
1515 Refresh ();
1516 break;
1518 case HitTestType.ColumnResize:
1519 if (e.Clicks == 2) {
1520 // double click column resize goes here
1522 else {
1523 resize_column = testinfo.Column;
1524 column_resize_active = true;
1525 resize_column_x = e.X;
1526 resize_column_width_delta = 0;
1527 EndEdit ();
1528 DrawResizeLineVert (resize_column_x);
1530 break;
1532 case HitTestType.RowResize:
1533 if (e.Clicks == 2) {
1534 // double click row resize goes here
1536 else {
1537 resize_row = testinfo.Row;
1538 row_resize_active = true;
1539 resize_row_y = e.Y;
1540 resize_row_height_delta = 0;
1541 EndEdit ();
1542 DrawResizeLineHoriz (resize_row_y);
1544 break;
1546 case HitTestType.Caption:
1547 if (back_button_rect.Contains (e.X, e.Y)) {
1548 back_button_active = true;
1549 Invalidate (back_button_rect);
1551 if (parent_rows_button_rect.Contains (e.X, e.Y)) {
1552 parent_rows_button_active = true;
1553 Invalidate (parent_rows_button_rect);
1555 break;
1557 default:
1558 break;
1562 protected override void OnMouseLeave (EventArgs e)
1564 base.OnMouseLeave (e);
1567 protected override void OnMouseMove (MouseEventArgs e)
1569 base.OnMouseMove (e);
1571 if (column_resize_active) {
1572 /* erase the old line */
1573 DrawResizeLineVert (resize_column_x + resize_column_width_delta);
1575 resize_column_width_delta = e.X - resize_column_x;
1577 /* draw the new line */
1578 DrawResizeLineVert (resize_column_x + resize_column_width_delta);
1579 return;
1581 else if (row_resize_active) {
1582 /* erase the old line */
1583 DrawResizeLineHoriz (resize_row_y + resize_row_height_delta);
1585 resize_row_height_delta = e.Y - resize_row_y;
1587 /* draw the new line */
1588 DrawResizeLineHoriz (resize_row_y + resize_row_height_delta);
1589 return;
1591 else {
1592 /* determine the cursor to use */
1593 HitTestInfo testinfo;
1594 testinfo = HitTest (e.X, e.Y);
1596 switch (testinfo.Type) {
1597 case HitTestType.ColumnResize:
1598 Cursor = Cursors.VSplit;
1599 break;
1600 case HitTestType.RowResize:
1601 Cursor = Cursors.HSplit;
1602 break;
1603 case HitTestType.Caption:
1604 Cursor = Cursors.Default;
1605 if (back_button_rect.Contains (e.X, e.Y)) {
1606 if (!back_button_mouseover)
1607 Invalidate (back_button_rect);
1608 back_button_mouseover = true;
1610 else if (back_button_mouseover) {
1611 Invalidate (back_button_rect);
1612 back_button_mouseover = false;
1615 if (parent_rows_button_rect.Contains (e.X, e.Y)) {
1616 if (parent_rows_button_mouseover)
1617 Invalidate (parent_rows_button_rect);
1618 parent_rows_button_mouseover = true;
1620 else if (parent_rows_button_mouseover) {
1621 Invalidate (parent_rows_button_rect);
1622 parent_rows_button_mouseover = false;
1624 break;
1625 case HitTestType.Cell:
1626 if (rows[testinfo.Row].IsExpanded) {
1627 Rectangle relation_area = rows[testinfo.Row].relation_area;
1628 relation_area.Y = rows[testinfo.Row].VerticalOffset + cells_area.Y + rows[testinfo.Row].Height - rows[testinfo.Row].RelationHeight;
1629 if (relation_area.Contains (e.X, e.Y)) {
1630 Cursor = Cursors.Hand;
1631 break;
1635 Cursor = Cursors.Default;
1636 break;
1637 default:
1638 Cursor = Cursors.Default;
1639 break;
1644 protected override void OnMouseUp (MouseEventArgs e)
1646 base.OnMouseUp (e);
1648 if (column_resize_active) {
1649 column_resize_active = false;
1650 if (resize_column_width_delta + CurrentTableStyle.GridColumnStyles[resize_column].Width < 0)
1651 resize_column_width_delta = -CurrentTableStyle.GridColumnStyles[resize_column].Width;
1652 CurrentTableStyle.GridColumnStyles[resize_column].Width += resize_column_width_delta;
1653 width_of_all_columns += resize_column_width_delta;
1654 Edit ();
1655 Invalidate ();
1657 else if (row_resize_active) {
1658 row_resize_active = false;
1660 if (resize_row_height_delta + rows[resize_row].Height < 0)
1661 resize_row_height_delta = -rows[resize_row].Height;
1663 rows[resize_row].height = rows[resize_row].Height + resize_row_height_delta;
1664 for (int i = resize_row + 1; i < rows.Length; i ++)
1665 rows[i].VerticalOffset += resize_row_height_delta;
1667 Edit ();
1668 CalcAreasAndInvalidate ();
1670 else if (back_button_active) {
1671 if (back_button_rect.Contains (e.X, e.Y)) {
1672 Invalidate (back_button_rect);
1673 NavigateBack ();
1674 OnBackButtonClicked (this, EventArgs.Empty);
1676 back_button_active = false;
1678 else if (parent_rows_button_active) {
1679 if (parent_rows_button_rect.Contains (e.X, e.Y)) {
1680 Invalidate (parent_rows_button_rect);
1681 ParentRowsVisible = !ParentRowsVisible;
1682 OnShowParentDetailsButtonClicked (this, EventArgs.Empty);
1684 parent_rows_button_active = false;
1688 protected override void OnMouseWheel (MouseEventArgs e)
1690 base.OnMouseWheel (e);
1692 bool ctrl_pressed = ((Control.ModifierKeys & Keys.Control) != 0);
1693 int pixels;
1695 if (ctrl_pressed) { // scroll horizontally
1696 if (!horiz_scrollbar.Visible)
1697 return;
1699 if (e.Delta > 0) {
1700 /* left */
1701 pixels = Math.Max (horiz_scrollbar.Minimum,
1702 horiz_scrollbar.Value - horiz_scrollbar.LargeChange);
1704 else {
1705 /* right */
1706 pixels = Math.Min (horiz_scrollbar.Maximum - horiz_scrollbar.LargeChange + 1,
1707 horiz_scrollbar.Value + horiz_scrollbar.LargeChange);
1710 GridHScrolled (this, new ScrollEventArgs (ScrollEventType.ThumbPosition, pixels));
1711 horiz_scrollbar.Value = pixels;
1712 } else {
1713 if (!vert_scrollbar.Visible)
1714 return;
1716 if (e.Delta > 0) {
1717 /* up */
1718 pixels = Math.Max (vert_scrollbar.Minimum,
1719 vert_scrollbar.Value - vert_scrollbar.LargeChange);
1721 else {
1722 /* down */
1723 pixels = Math.Min (vert_scrollbar.Maximum - vert_scrollbar.LargeChange + 1,
1724 vert_scrollbar.Value + vert_scrollbar.LargeChange);
1727 GridVScrolled (this, new ScrollEventArgs (ScrollEventType.ThumbPosition, pixels));
1728 vert_scrollbar.Value = pixels;
1732 protected void OnNavigate (NavigateEventArgs e)
1734 EventHandler eh = (EventHandler)(Events [NavigateEvent]);
1735 if (eh != null)
1736 eh (this, e);
1739 protected override void OnPaint (PaintEventArgs pe)
1741 ThemeEngine.Current.DataGridPaint (pe, this);
1744 protected override void OnPaintBackground (PaintEventArgs ebe)
1748 protected virtual void OnParentRowsLabelStyleChanged (EventArgs e)
1750 EventHandler eh = (EventHandler)(Events [ParentRowsLabelStyleChangedEvent]);
1751 if (eh != null)
1752 eh (this, e);
1755 protected virtual void OnParentRowsVisibleChanged (EventArgs e)
1757 EventHandler eh = (EventHandler)(Events [ParentRowsVisibleChangedEvent]);
1758 if (eh != null)
1759 eh (this, e);
1762 protected virtual void OnReadOnlyChanged (EventArgs e)
1764 EventHandler eh = (EventHandler)(Events [ReadOnlyChangedEvent]);
1765 if (eh != null)
1766 eh (this, e);
1769 protected override void OnResize (EventArgs e)
1771 base.OnResize (e);
1774 protected void OnRowHeaderClick (EventArgs e)
1776 EventHandler eh = (EventHandler)(Events [RowHeaderClickEvent]);
1777 if (eh != null)
1778 eh (this, e);
1781 protected void OnScroll (EventArgs e)
1783 EventHandler eh = (EventHandler)(Events [ScrollEvent]);
1784 if (eh != null)
1785 eh (this, e);
1788 protected void OnShowParentDetailsButtonClicked (object sender, EventArgs e)
1790 EventHandler eh = (EventHandler)(Events [ShowParentDetailsButtonClickEvent]);
1791 if (eh != null)
1792 eh (this, e);
1795 protected override bool ProcessDialogKey (Keys keyData)
1797 return ProcessGridKey (new KeyEventArgs (keyData));
1800 void UpdateSelectionAfterCursorMove (bool extend_selection)
1802 if (extend_selection) {
1803 CancelEditing ();
1804 ShiftSelection (CurrentRow);
1806 else {
1807 ResetSelection ();
1811 protected bool ProcessGridKey (KeyEventArgs ke)
1813 /* if we have no rows, exit immediately.
1814 XXX is this necessary? */
1815 if (RowsCount == 0)
1816 return false;
1818 bool ctrl_pressed = ((ke.Modifiers & Keys.Control) != 0);
1819 bool alt_pressed = ((ke.Modifiers & Keys.Alt) != 0);
1820 bool shift_pressed = ((ke.Modifiers & Keys.Shift) != 0);
1822 switch (ke.KeyCode) {
1823 case Keys.Escape:
1824 if (is_changing)
1825 AbortEditing ();
1826 else
1827 CancelEditing ();
1828 Edit ();
1829 return true;
1831 case Keys.D0:
1832 if (alt_pressed) {
1833 if (is_editing)
1834 CurrentTableStyle.GridColumnStyles[CurrentColumn].EnterNullValue ();
1835 return true;
1837 return false;
1839 case Keys.Enter:
1840 if (is_changing)
1841 CurrentRow ++;
1842 return true;
1844 case Keys.Tab:
1845 if (shift_pressed) {
1846 if (CurrentColumn > 0)
1847 CurrentColumn --;
1848 else if ((CurrentRow > 0) && (CurrentColumn == 0))
1849 CurrentCell = new DataGridCell (CurrentRow - 1, CurrentTableStyle.GridColumnStyles.Count - 1);
1851 else {
1852 if (CurrentColumn < CurrentTableStyle.GridColumnStyles.Count - 1)
1853 CurrentColumn ++;
1854 else if ((CurrentRow <= RowsCount) && (CurrentColumn == CurrentTableStyle.GridColumnStyles.Count - 1))
1855 CurrentCell = new DataGridCell (CurrentRow + 1, 0);
1858 UpdateSelectionAfterCursorMove (false);
1860 return true;
1862 case Keys.Right:
1863 if (ctrl_pressed) {
1864 CurrentColumn = CurrentTableStyle.GridColumnStyles.Count - 1;
1866 else {
1867 if (CurrentColumn < CurrentTableStyle.GridColumnStyles.Count - 1) {
1868 CurrentColumn ++;
1869 } else if (CurrentRow < RowsCount - 1
1870 || (CurrentRow == RowsCount - 1
1871 && !cursor_in_add_row)) {
1872 CurrentCell = new DataGridCell (CurrentRow + 1, 0);
1876 UpdateSelectionAfterCursorMove (false);
1878 return true;
1880 case Keys.Left:
1881 if (ctrl_pressed) {
1882 CurrentColumn = 0;
1884 else {
1885 if (current_cell.ColumnNumber > 0)
1886 CurrentColumn --;
1887 else if (CurrentRow > 0)
1888 CurrentCell = new DataGridCell (CurrentRow - 1, CurrentTableStyle.GridColumnStyles.Count - 1);
1891 UpdateSelectionAfterCursorMove (false);
1893 return true;
1895 case Keys.Up:
1896 if (ctrl_pressed)
1897 CurrentRow = 0;
1898 else if (CurrentRow > 0)
1899 CurrentRow --;
1901 UpdateSelectionAfterCursorMove (shift_pressed);
1903 return true;
1905 case Keys.Down:
1906 if (ctrl_pressed)
1907 CurrentRow = RowsCount - 1;
1908 else if (CurrentRow < RowsCount - 1)
1909 CurrentRow ++;
1910 else if (CurrentRow == RowsCount - 1 && cursor_in_add_row && (add_row_changed || is_changing))
1911 CurrentRow ++;
1912 else if (CurrentRow == RowsCount - 1 && !cursor_in_add_row && !shift_pressed)
1913 CurrentRow ++;
1915 UpdateSelectionAfterCursorMove (shift_pressed);
1917 return true;
1919 case Keys.PageUp:
1920 if (CurrentRow > VLargeChange)
1921 CurrentRow -= VLargeChange;
1922 else
1923 CurrentRow = 0;
1925 UpdateSelectionAfterCursorMove (shift_pressed);
1927 return true;
1929 case Keys.PageDown:
1930 if (CurrentRow < RowsCount - VLargeChange)
1931 CurrentRow += VLargeChange;
1932 else
1933 CurrentRow = RowsCount - 1;
1935 UpdateSelectionAfterCursorMove (shift_pressed);
1937 return true;
1939 case Keys.Home:
1940 if (ctrl_pressed)
1941 CurrentCell = new DataGridCell (0, 0);
1942 else
1943 CurrentColumn = 0;
1945 UpdateSelectionAfterCursorMove (ctrl_pressed && shift_pressed);
1947 return true;
1949 case Keys.End:
1950 if (ctrl_pressed)
1951 CurrentCell = new DataGridCell (RowsCount - 1, CurrentTableStyle.GridColumnStyles.Count - 1);
1952 else
1953 CurrentColumn = CurrentTableStyle.GridColumnStyles.Count - 1;
1955 UpdateSelectionAfterCursorMove (ctrl_pressed && shift_pressed);
1957 return true;
1959 case Keys.Delete:
1960 foreach (int row in selected_rows.Keys) {
1961 ListManager.RemoveAt (row);
1963 selected_rows.Clear ();
1964 CalcAreasAndInvalidate ();
1966 return true;
1969 return false; // message not processed
1972 protected override bool ProcessKeyPreview (ref Message m)
1974 if ((Msg)m.Msg == Msg.WM_KEYDOWN) {
1975 Keys key = (Keys) m.WParam.ToInt32 ();
1976 KeyEventArgs ke = new KeyEventArgs (key);
1977 if (ProcessGridKey (ke) == true) {
1978 return true;
1982 return base.ProcessKeyPreview (ref m);
1985 protected bool ProcessTabKey (Keys keyData)
1987 return false;
1990 public void ResetAlternatingBackColor ()
1992 grid_style.AlternatingBackColor = default_style.AlternatingBackColor;
1995 public override void ResetBackColor ()
1997 grid_style.BackColor = default_style.BackColor;
2000 public override void ResetForeColor ()
2002 grid_style.ForeColor = default_style.ForeColor;
2005 public void ResetGridLineColor ()
2007 grid_style.GridLineColor = default_style.GridLineColor;
2010 public void ResetHeaderBackColor ()
2012 grid_style.HeaderBackColor = default_style.HeaderBackColor;
2015 public void ResetHeaderFont ()
2017 grid_style.HeaderFont = default_style.HeaderFont;
2020 public void ResetHeaderForeColor ()
2022 grid_style.HeaderForeColor = default_style.HeaderForeColor;
2025 public void ResetLinkColor ()
2027 grid_style.LinkColor = default_style.LinkColor;
2030 public void ResetLinkHoverColor ()
2032 grid_style.LinkHoverColor = default_style.LinkHoverColor;
2035 protected void ResetSelection ()
2037 InvalidateSelection ();
2038 selected_rows.Clear ();
2039 selection_start = -1;
2042 void InvalidateSelection ()
2044 foreach (int row in selected_rows.Keys) {
2045 rows[row].IsSelected = false;
2046 InvalidateRow (row);
2050 public void ResetSelectionBackColor ()
2052 grid_style.SelectionBackColor = default_style.SelectionBackColor;
2055 public void ResetSelectionForeColor ()
2057 grid_style.SelectionForeColor = default_style.SelectionForeColor;
2060 public void Select (int row)
2062 if (selected_rows.Count == 0)
2063 selection_start = row;
2065 selected_rows[row] = true;
2066 rows[row].IsSelected = true;
2068 InvalidateRow (row);
2071 public void SetDataBinding (object dataSource, string dataMember)
2073 SetDataSource (dataSource, dataMember);
2076 protected virtual bool ShouldSerializeAlternatingBackColor ()
2078 return (grid_style.AlternatingBackColor != default_style.AlternatingBackColor);
2081 protected virtual bool ShouldSerializeBackgroundColor ()
2083 return (background_color != def_background_color);
2086 protected virtual bool ShouldSerializeCaptionBackColor ()
2088 return (caption_backcolor != def_caption_backcolor);
2091 protected virtual bool ShouldSerializeCaptionForeColor ()
2093 return caption_forecolor != def_caption_forecolor;
2096 protected virtual bool ShouldSerializeGridLineColor ()
2098 return grid_style.GridLineColor != default_style.GridLineColor;
2101 protected virtual bool ShouldSerializeHeaderBackColor ()
2103 return grid_style.HeaderBackColor != default_style.HeaderBackColor;
2106 protected bool ShouldSerializeHeaderFont ()
2108 return grid_style.HeaderFont != default_style.HeaderFont;
2111 protected virtual bool ShouldSerializeHeaderForeColor ()
2113 return grid_style.HeaderForeColor != default_style.HeaderForeColor;
2116 protected virtual bool ShouldSerializeLinkHoverColor ()
2118 return grid_style.LinkHoverColor != grid_style.LinkHoverColor;
2121 protected virtual bool ShouldSerializeParentRowsBackColor ()
2123 return parentrowsback_color != def_parentrowsback_color;
2126 protected virtual bool ShouldSerializeParentRowsForeColor ()
2128 return parentrowsback_color != def_parentrowsback_color;
2131 protected bool ShouldSerializePreferredRowHeight ()
2133 return grid_style.PreferredRowHeight != default_style.PreferredRowHeight;
2136 protected bool ShouldSerializeSelectionBackColor ()
2138 return grid_style.SelectionBackColor != default_style.SelectionBackColor;
2141 protected virtual bool ShouldSerializeSelectionForeColor ()
2143 return grid_style.SelectionForeColor != default_style.SelectionForeColor;
2146 public void SubObjectsSiteChange (bool site)
2150 public void UnSelect (int row)
2152 rows[row].IsSelected = false;
2153 selected_rows.Remove (row);
2154 InvalidateRow (row);
2156 #endregion // Public Instance Methods
2158 #region Private Instance Methods
2160 internal void CalcAreasAndInvalidate ()
2162 CalcGridAreas ();
2163 Invalidate ();
2166 private void ConnectListManagerEvents ()
2168 list_manager.PositionChanged += new EventHandler (OnListManagerPositionChanged);
2169 list_manager.ItemChanged += new ItemChangedEventHandler (OnListManagerItemChanged);
2172 private void DisconnectListManagerEvents ()
2174 list_manager.PositionChanged -= new EventHandler (OnListManagerPositionChanged);
2175 list_manager.ItemChanged -= new ItemChangedEventHandler (OnListManagerItemChanged);
2178 void DisconnectTableStyleEvents ()
2180 current_style.AllowSortingChanged -= new EventHandler (TableStyleChanged);
2181 current_style.AlternatingBackColorChanged -= new EventHandler (TableStyleChanged);
2182 current_style.BackColorChanged -= new EventHandler (TableStyleChanged);
2183 current_style.ColumnHeadersVisibleChanged -= new EventHandler (TableStyleChanged);
2184 current_style.ForeColorChanged -= new EventHandler (TableStyleChanged);
2185 current_style.GridLineColorChanged -= new EventHandler (TableStyleChanged);
2186 current_style.GridLineStyleChanged -= new EventHandler (TableStyleChanged);
2187 current_style.HeaderBackColorChanged -= new EventHandler (TableStyleChanged);
2188 current_style.HeaderFontChanged -= new EventHandler (TableStyleChanged);
2189 current_style.HeaderForeColorChanged -= new EventHandler (TableStyleChanged);
2190 current_style.LinkColorChanged -= new EventHandler (TableStyleChanged);
2191 current_style.LinkHoverColorChanged -= new EventHandler (TableStyleChanged);
2192 current_style.MappingNameChanged -= new EventHandler (TableStyleChanged);
2193 current_style.PreferredColumnWidthChanged -= new EventHandler (TableStyleChanged);
2194 current_style.PreferredRowHeightChanged -= new EventHandler (TableStyleChanged);
2195 current_style.ReadOnlyChanged -= new EventHandler (TableStyleChanged);
2196 current_style.RowHeadersVisibleChanged -= new EventHandler (TableStyleChanged);
2197 current_style.RowHeaderWidthChanged -= new EventHandler (TableStyleChanged);
2198 current_style.SelectionBackColorChanged -= new EventHandler (TableStyleChanged);
2199 current_style.SelectionForeColorChanged -= new EventHandler (TableStyleChanged);
2202 void ConnectTableStyleEvents ()
2204 current_style.AllowSortingChanged += new EventHandler (TableStyleChanged);
2205 current_style.AlternatingBackColorChanged += new EventHandler (TableStyleChanged);
2206 current_style.BackColorChanged += new EventHandler (TableStyleChanged);
2207 current_style.ColumnHeadersVisibleChanged += new EventHandler (TableStyleChanged);
2208 current_style.ForeColorChanged += new EventHandler (TableStyleChanged);
2209 current_style.GridLineColorChanged += new EventHandler (TableStyleChanged);
2210 current_style.GridLineStyleChanged += new EventHandler (TableStyleChanged);
2211 current_style.HeaderBackColorChanged += new EventHandler (TableStyleChanged);
2212 current_style.HeaderFontChanged += new EventHandler (TableStyleChanged);
2213 current_style.HeaderForeColorChanged += new EventHandler (TableStyleChanged);
2214 current_style.LinkColorChanged += new EventHandler (TableStyleChanged);
2215 current_style.LinkHoverColorChanged += new EventHandler (TableStyleChanged);
2216 current_style.MappingNameChanged += new EventHandler (TableStyleChanged);
2217 current_style.PreferredColumnWidthChanged += new EventHandler (TableStyleChanged);
2218 current_style.PreferredRowHeightChanged += new EventHandler (TableStyleChanged);
2219 current_style.ReadOnlyChanged += new EventHandler (TableStyleChanged);
2220 current_style.RowHeadersVisibleChanged += new EventHandler (TableStyleChanged);
2221 current_style.RowHeaderWidthChanged += new EventHandler (TableStyleChanged);
2222 current_style.SelectionBackColorChanged += new EventHandler (TableStyleChanged);
2223 current_style.SelectionForeColorChanged += new EventHandler (TableStyleChanged);
2226 void TableStyleChanged (object sender, EventArgs args)
2228 EndEdit ();
2229 CalcAreasAndInvalidate ();
2233 private void EnsureCellVisibility (DataGridCell cell)
2235 if (cell.ColumnNumber <= first_visiblecolumn ||
2236 cell.ColumnNumber + 1 >= first_visiblecolumn + visiblecolumn_count) {
2238 first_visiblecolumn = GetFirstColumnForColumnVisibility (first_visiblecolumn, cell.ColumnNumber);
2239 int pixel = GetColumnStartingPixel (first_visiblecolumn);
2240 ScrollToColumnInPixels (pixel);
2241 horiz_scrollbar.Value = pixel;
2242 Update();
2245 if (cell.RowNumber < first_visiblerow ||
2246 cell.RowNumber + 1 >= first_visiblerow + visiblerow_count) {
2248 if (cell.RowNumber + 1 >= first_visiblerow + visiblerow_count) {
2249 int old_first_visiblerow = first_visiblerow;
2250 first_visiblerow = 1 + cell.RowNumber - visiblerow_count;
2251 UpdateVisibleRowCount ();
2252 ScrollToRow (old_first_visiblerow, first_visiblerow);
2253 } else {
2254 int old_first_visiblerow = first_visiblerow;
2255 first_visiblerow = cell.RowNumber;
2256 UpdateVisibleRowCount ();
2257 ScrollToRow (old_first_visiblerow, first_visiblerow);
2260 vert_scrollbar.Value = first_visiblerow;
2264 private void SetDataSource (object source, string member)
2266 SetDataSource (source, member, true);
2269 bool in_setdatasource;
2270 private void SetDataSource (object source, string member, bool recreate_rows)
2272 CurrencyManager old_lm = list_manager;
2274 /* we need this bool flag to work around a
2275 * problem with OnBindingContextChanged. once
2276 * that stuff works properly, remove this
2277 * hack */
2278 if (in_setdatasource)
2279 return;
2280 in_setdatasource = true;
2282 #if false
2283 if (datasource == source && member == datamember)
2284 return;
2285 #endif
2287 if (source != null && source as IListSource != null && source as IList != null)
2288 throw new Exception ("Wrong complex data binding source");
2290 datasource = source;
2291 datamember = member;
2293 if (is_editing)
2294 CancelEditing ();
2296 current_cell = new DataGridCell ();
2298 if (list_manager != null)
2299 DisconnectListManagerEvents ();
2301 list_manager = null;
2303 /* create the new list manager */
2304 if (BindingContext != null && datasource != null)
2305 list_manager = (CurrencyManager) BindingContext [datasource, datamember];
2307 if (list_manager != null)
2308 ConnectListManagerEvents ();
2310 if (list_manager != null) {
2311 string list_name = list_manager.GetListName (null);
2312 if (TableStyles[list_name] == null) {
2313 current_style.GridColumnStyles.Clear ();
2314 current_style.CreateColumnsForTable (false);
2316 else if (CurrentTableStyle.MappingName != list_name) {
2317 // If the style has been defined by the user, use it
2318 CurrentTableStyle = styles_collection[list_name];
2319 current_style.CreateColumnsForTable (true);
2321 else {
2322 current_style.CreateColumnsForTable (true);
2325 else
2326 current_style.CreateColumnsForTable (false);
2328 if (old_lm != list_manager) {
2329 /* reset first_visiblerow to 0 here before
2330 * doing anything that'll requires us to
2331 * figure out if we need a scrollbar. */
2332 vert_scrollbar.Value = 0;
2333 horiz_scrollbar.Value = 0;
2334 first_visiblerow = 0;
2336 if (recreate_rows)
2337 RecreateDataGridRows (false);
2340 CalcAreasAndInvalidate ();
2342 in_setdatasource = false;
2344 OnDataSourceChanged (EventArgs.Empty);
2347 private void OnListManagerPositionChanged (object sender, EventArgs e)
2349 from_positionchanged_handler = true;
2350 CurrentRow = list_manager.Position;
2351 from_positionchanged_handler = false;
2354 void RecreateDataGridRows (bool recalc)
2356 DataGridRelationshipRow[] new_rows = new DataGridRelationshipRow[RowsCount + (ShowEditRow ? 1 : 0)];
2357 int start_index = 0;
2358 if (rows != null) {
2359 start_index = rows.Length;
2360 Array.Copy (rows, 0, new_rows, 0, rows.Length < new_rows.Length ? rows.Length : new_rows.Length);
2363 for (int i = start_index; i < new_rows.Length; i ++) {
2364 new_rows[i] = new DataGridRelationshipRow (this);
2365 new_rows[i].height = RowHeight;
2366 if (i > 0)
2367 new_rows[i].VerticalOffset = new_rows[i-1].VerticalOffset + new_rows[i-1].Height;
2370 rows = new_rows;
2372 if (recalc)
2373 CalcAreasAndInvalidate ();
2376 internal void UpdateRowsFrom (DataGridRelationshipRow row)
2378 int start_index = Array.IndexOf (rows, row);
2379 if (start_index == -1)
2380 return;
2382 for (int i = start_index + 1; i < rows.Length; i ++) {
2383 rows[i].VerticalOffset = rows[i-1].VerticalOffset + rows[i-1].Height;
2386 CalcAreasAndInvalidate ();
2389 private void OnListManagerItemChanged (object sender, ItemChangedEventArgs e)
2391 if (e.Index == -1) {
2392 ResetSelection ();
2393 if (rows == null || RowsCount != rows.Length - (ShowEditRow ? 1 : 0))
2394 RecreateDataGridRows (true);
2396 else {
2397 InvalidateRow (e.Index);
2401 private void OnTableStylesCollectionChanged (object sender, CollectionChangeEventArgs e)
2403 if (ListManager == null)
2404 return;
2406 string list_name = ListManager.GetListName (null);
2407 switch (e.Action){
2408 case CollectionChangeAction.Add: {
2409 if (e.Element != null && String.Compare (list_name, ((DataGridTableStyle)e.Element).MappingName, true) == 0) {
2410 CurrentTableStyle = (DataGridTableStyle)e.Element;
2411 ((DataGridTableStyle) e.Element).CreateColumnsForTable (false);
2413 break;
2416 case CollectionChangeAction.Remove: {
2417 if (e.Element != null && String.Compare (list_name, ((DataGridTableStyle)e.Element).MappingName, true) == 0) {
2418 CurrentTableStyle = default_style;
2419 current_style.GridColumnStyles.Clear ();
2420 current_style.CreateColumnsForTable (false);
2422 break;
2426 case CollectionChangeAction.Refresh: {
2427 if (CurrentTableStyle == default_style
2428 || String.Compare (list_name, CurrentTableStyle.MappingName, true) != 0) {
2430 DataGridTableStyle style = styles_collection [list_name];
2431 if (style != null) {
2432 CurrentTableStyle = style;
2433 current_style.CreateColumnsForTable (false);
2435 else {
2436 CurrentTableStyle = default_style;
2437 current_style.GridColumnStyles.Clear ();
2438 current_style.CreateColumnsForTable (false);
2442 break;
2445 CalcAreasAndInvalidate ();
2448 private void AddNewRow ()
2450 ListManager.EndCurrentEdit ();
2451 ListManager.AddNew ();
2454 private void Edit ()
2456 if (CurrentTableStyle.GridColumnStyles[current_cell.ColumnNumber].bound == false)
2457 return;
2459 is_editing = true;
2460 is_changing = false;
2462 CurrentTableStyle.GridColumnStyles[current_cell.ColumnNumber].Edit (ListManager,
2463 current_cell.RowNumber, GetCellBounds (current_cell.RowNumber, current_cell.ColumnNumber),
2464 _readonly, "", true);
2467 private void EndEdit ()
2469 if (CurrentTableStyle.GridColumnStyles.Count == 0)
2470 return;
2472 if (CurrentTableStyle.GridColumnStyles[current_cell.ColumnNumber].bound == false)
2473 return;
2475 EndEdit (CurrentTableStyle.GridColumnStyles[current_cell.ColumnNumber],
2476 current_cell.RowNumber,
2477 false);
2480 private void ShiftSelection (int index)
2482 // we have to save off selection_start
2483 // because ResetSelection clobbers it
2484 int saved_selection_start = selection_start;
2485 int start, end;
2487 ResetSelection ();
2488 selection_start = saved_selection_start;
2490 if (index >= selection_start) {
2491 start = selection_start;
2492 end = index;
2494 else {
2495 start = index;
2496 end = selection_start;
2499 for (int idx = start; idx <= end; idx ++) {
2500 Select (idx);
2504 private void ScrollToColumnInPixels (int pixel)
2506 int pixels;
2508 if (pixel > horiz_pixeloffset) // ScrollRight
2509 pixels = -1 * (pixel - horiz_pixeloffset);
2510 else
2511 pixels = horiz_pixeloffset - pixel;
2513 Rectangle area = cells_area;
2515 if (ColumnHeadersVisible == true) {
2516 area.Y -= ColumnHeadersArea.Height;
2517 area.Height += ColumnHeadersArea.Height;
2520 horiz_pixeloffset = pixel;
2521 UpdateVisibleColumn ();
2523 EndEdit ();
2525 XplatUI.ScrollWindow (Handle, area, pixels, 0, false);
2527 int pixel_offset = GetColumnStartingPixel (CurrentColumn);
2528 int next_pixel_offset = pixel_offset + CurrentTableStyle.GridColumnStyles[CurrentColumn].Width;
2530 if (pixel_offset >= horiz_pixeloffset
2531 && next_pixel_offset < horiz_pixeloffset + cells_area.Width)
2532 Edit ();
2535 private void ScrollToRow (int old_row, int new_row)
2537 int pixels = 0;
2538 int i;
2540 if (new_row > old_row) { // Scrolldown
2541 for (i = old_row; i < new_row; i ++)
2542 pixels -= rows[i].Height;
2544 else {
2545 for (i = new_row; i < old_row; i ++)
2546 pixels += rows[i].Height;
2549 if (pixels == 0)
2550 return;
2552 EndEdit ();
2554 Rectangle rows_area = cells_area; // Cells area - partial rows space
2556 if (RowHeadersVisible) {
2557 rows_area.X -= RowHeaderWidth;
2558 rows_area.Width += RowHeaderWidth;
2561 /* scroll the window */
2562 XplatUI.ScrollWindow (Handle, rows_area, 0, pixels, false);
2564 /* if the row is still */
2565 if (CurrentRow >= first_visiblerow && CurrentRow < first_visiblerow + visiblerow_count)
2566 Edit ();
2569 #endregion Private Instance Methods
2572 #region Events
2573 static object AllowNavigationChangedEvent = new object ();
2574 static object BackButtonClickEvent = new object ();
2575 static object BackgroundColorChangedEvent = new object ();
2576 static object BorderStyleChangedEvent = new object ();
2577 static object CaptionVisibleChangedEvent = new object ();
2578 static object CurrentCellChangedEvent = new object ();
2579 static object DataSourceChangedEvent = new object ();
2580 static object FlatModeChangedEvent = new object ();
2581 static object NavigateEvent = new object ();
2582 static object ParentRowsLabelStyleChangedEvent = new object ();
2583 static object ParentRowsVisibleChangedEvent = new object ();
2584 static object ReadOnlyChangedEvent = new object ();
2585 static object RowHeaderClickEvent = new object ();
2586 static object ScrollEvent = new object ();
2587 static object ShowParentDetailsButtonClickEvent = new object ();
2589 public event EventHandler AllowNavigationChanged {
2590 add { Events.AddHandler (AllowNavigationChangedEvent, value); }
2591 remove { Events.RemoveHandler (AllowNavigationChangedEvent, value); }
2594 public event EventHandler BackButtonClick {
2595 add { Events.AddHandler (BackButtonClickEvent, value); }
2596 remove { Events.RemoveHandler (BackButtonClickEvent, value); }
2599 public event EventHandler BackgroundColorChanged {
2600 add { Events.AddHandler (BackgroundColorChangedEvent, value); }
2601 remove { Events.RemoveHandler (BackgroundColorChangedEvent, value); }
2604 [Browsable(false)]
2605 [EditorBrowsable(EditorBrowsableState.Never)]
2606 public new event EventHandler BackgroundImageChanged {
2607 add { base.BackgroundImageChanged += value; }
2608 remove { base.BackgroundImageChanged -= value; }
2611 [Browsable(false)]
2612 [EditorBrowsable(EditorBrowsableState.Never)]
2613 public new event EventHandler TextChanged {
2614 add { base.TextChanged += value; }
2615 remove { base.TextChanged -= value; }
2618 [Browsable(false)]
2619 [EditorBrowsable(EditorBrowsableState.Never)]
2620 public new event EventHandler CursorChanged {
2621 add { base.CursorChanged += value; }
2622 remove { base.CursorChanged -= value; }
2625 public event EventHandler BorderStyleChanged {
2626 add { Events.AddHandler (BorderStyleChangedEvent, value); }
2627 remove { Events.RemoveHandler (BorderStyleChangedEvent, value); }
2630 public event EventHandler CaptionVisibleChanged {
2631 add { Events.AddHandler (CaptionVisibleChangedEvent, value); }
2632 remove { Events.RemoveHandler (CaptionVisibleChangedEvent, value); }
2635 public event EventHandler CurrentCellChanged {
2636 add { Events.AddHandler (CurrentCellChangedEvent, value); }
2637 remove { Events.RemoveHandler (CurrentCellChangedEvent, value); }
2640 public event EventHandler DataSourceChanged {
2641 add { Events.AddHandler (DataSourceChangedEvent, value); }
2642 remove { Events.RemoveHandler (DataSourceChangedEvent, value); }
2645 public event EventHandler FlatModeChanged {
2646 add { Events.AddHandler (FlatModeChangedEvent, value); }
2647 remove { Events.RemoveHandler (FlatModeChangedEvent, value); }
2650 public event NavigateEventHandler Navigate {
2651 add { Events.AddHandler (NavigateEvent, value); }
2652 remove { Events.RemoveHandler (NavigateEvent, value); }
2655 public event EventHandler ParentRowsLabelStyleChanged {
2656 add { Events.AddHandler (ParentRowsLabelStyleChangedEvent, value); }
2657 remove { Events.RemoveHandler (ParentRowsLabelStyleChangedEvent, value); }
2660 public event EventHandler ParentRowsVisibleChanged {
2661 add { Events.AddHandler (ParentRowsVisibleChangedEvent, value); }
2662 remove { Events.RemoveHandler (ParentRowsVisibleChangedEvent, value); }
2665 public event EventHandler ReadOnlyChanged {
2666 add { Events.AddHandler (ReadOnlyChangedEvent, value); }
2667 remove { Events.RemoveHandler (ReadOnlyChangedEvent, value); }
2670 protected event EventHandler RowHeaderClick {
2671 add { Events.AddHandler (RowHeaderClickEvent, value); }
2672 remove { Events.RemoveHandler (RowHeaderClickEvent, value); }
2675 public event EventHandler Scroll {
2676 add { Events.AddHandler (ScrollEvent, value); }
2677 remove { Events.RemoveHandler (ScrollEvent, value); }
2680 public event EventHandler ShowParentDetailsButtonClick {
2681 add { Events.AddHandler (ShowParentDetailsButtonClickEvent, value); }
2682 remove { Events.RemoveHandler (ShowParentDetailsButtonClickEvent, value); }
2684 #endregion // Events
2689 #region Code originally in DataGridDrawingLogic.cs
2691 #region Local Variables
2693 // Areas
2694 Rectangle parent_rows;
2695 int width_of_all_columns;
2697 internal Rectangle caption_area;
2698 internal Rectangle columnhdrs_area; // Used columns header area
2699 internal int columnhdrs_maxwidth; // Total width (max width) for columns headrs
2700 internal Rectangle rowhdrs_area; // Used Headers rows area
2701 internal Rectangle cells_area;
2702 #endregion // Local Variables
2705 #region Public Instance Methods
2707 // Calc the max with of all columns
2708 int CalcAllColumnsWidth ()
2710 int width = 0;
2711 int cnt = CurrentTableStyle.GridColumnStyles.Count;
2713 for (int col = 0; col < cnt; col++) {
2714 if (CurrentTableStyle.GridColumnStyles[col].bound == false) {
2715 continue;
2717 width += CurrentTableStyle.GridColumnStyles[col].Width;
2719 return width;
2722 // Gets a column from a pixel
2723 int FromPixelToColumn (int pixel, out int column_x)
2725 int width = 0;
2726 int cnt = CurrentTableStyle.GridColumnStyles.Count;
2727 column_x = 0;
2729 if (cnt == 0)
2730 return 0;
2732 if (CurrentTableStyle.CurrentRowHeadersVisible) {
2733 width += rowhdrs_area.X + rowhdrs_area.Width;
2734 column_x += rowhdrs_area.X + rowhdrs_area.Width;
2737 for (int col = 0; col < cnt; col++) {
2738 if (CurrentTableStyle.GridColumnStyles[col].bound == false)
2739 continue;
2741 width += CurrentTableStyle.GridColumnStyles[col].Width;
2743 if (pixel < width)
2744 return col;
2746 column_x += CurrentTableStyle.GridColumnStyles[col].Width;
2749 return cnt - 1;
2752 internal int GetColumnStartingPixel (int my_col)
2754 int width = 0;
2755 int cnt = CurrentTableStyle.GridColumnStyles.Count;
2757 for (int col = 0; col < cnt; col++) {
2758 if (CurrentTableStyle.GridColumnStyles[col].bound == false) {
2759 continue;
2762 if (my_col == col)
2763 return width;
2765 width += CurrentTableStyle.GridColumnStyles[col].Width;
2768 return 0;
2771 // Which column has to be the first visible column to ensure a column visibility
2772 int GetFirstColumnForColumnVisibility (int current_first_visiblecolumn, int column)
2774 int new_col = column;
2775 int width = 0;
2777 if (column > current_first_visiblecolumn) { // Going forward
2778 for (new_col = column; new_col >= 0; new_col--){
2779 if (CurrentTableStyle.GridColumnStyles[new_col].bound == false)
2780 continue;
2781 width += CurrentTableStyle.GridColumnStyles[new_col].Width;
2783 if (width >= cells_area.Width)
2784 return new_col + 1;
2785 //return new_col < CurrentTableStyle.GridColumnStyles.Count ? new_col + 1 : CurrentTableStyle.GridColumnStyles.Count;
2787 return 0;
2788 } else {
2789 return column;
2793 bool in_calc_grid_areas;
2794 void CalcGridAreas ()
2796 if (IsHandleCreated == false) // Delay calculations until the handle is created
2797 return;
2799 /* make sure we don't happen to end up in this method again */
2800 if (in_calc_grid_areas)
2801 return;
2803 in_calc_grid_areas = true;
2805 /* Order is important. E.g. row headers max. height depends on caption */
2806 horiz_pixeloffset = 0;
2807 CalcCaption ();
2808 CalcParentRows ();
2809 CalcParentButtons ();
2810 UpdateVisibleRowCount ();
2811 CalcRowHeaders ();
2812 width_of_all_columns = CalcAllColumnsWidth ();
2813 CalcColumnHeaders ();
2814 CalcCellsArea ();
2816 bool needHoriz = false;
2817 bool needVert = false;
2819 /* figure out which scrollbars we need, and what the visible areas are */
2820 int visible_cells_width = cells_area.Width;
2821 int visible_cells_height = cells_area.Height;
2822 int allrows = RowsCount;
2824 if (ShowEditRow && RowsCount > 0)
2825 allrows++;
2827 /* use a loop to iteratively calculate whether
2828 * we need horiz/vert scrollbars. */
2829 for (int i = 0; i < 3; i ++) {
2830 if (needVert)
2831 visible_cells_width = cells_area.Width - vert_scrollbar.Width;
2832 if (needHoriz)
2833 visible_cells_height = cells_area.Height - horiz_scrollbar.Height;
2835 UpdateVisibleRowCount ();
2837 needHoriz = (width_of_all_columns > visible_cells_width);
2838 needVert = (allrows > visiblerow_count);
2841 int horiz_scrollbar_width = ClientRectangle.Width;
2842 int horiz_scrollbar_maximum = 0;
2843 int vert_scrollbar_height = 0;
2844 int vert_scrollbar_maximum = 0;
2846 if (needVert)
2847 SetUpVerticalScrollBar (out vert_scrollbar_height, out vert_scrollbar_maximum);
2849 if (needHoriz)
2850 SetUpHorizontalScrollBar (out horiz_scrollbar_maximum);
2852 cells_area.Width = visible_cells_width;
2853 cells_area.Height = visible_cells_height;
2855 if (needVert && needHoriz) {
2856 if (ShowParentRows)
2857 parent_rows.Width -= vert_scrollbar.Width;
2859 if (!ShowingColumnHeaders) {
2860 if (columnhdrs_area.X + columnhdrs_area.Width > vert_scrollbar.Location.X) {
2861 columnhdrs_area.Width -= vert_scrollbar.Width;
2865 horiz_scrollbar_width -= vert_scrollbar.Width;
2866 vert_scrollbar_height -= horiz_scrollbar.Height;
2869 if (needVert) {
2870 if (rowhdrs_area.Y + rowhdrs_area.Height > ClientRectangle.Y + ClientRectangle.Height) {
2871 rowhdrs_area.Height -= horiz_scrollbar.Height;
2874 vert_scrollbar.Size = new Size (vert_scrollbar.Width,
2875 vert_scrollbar_height);
2877 vert_scrollbar.Maximum = vert_scrollbar_maximum;
2878 Controls.Add (vert_scrollbar);
2879 vert_scrollbar.Visible = true;
2881 else {
2882 Controls.Remove (vert_scrollbar);
2883 vert_scrollbar.Visible = false;
2886 if (needHoriz) {
2887 horiz_scrollbar.Size = new Size (horiz_scrollbar_width,
2888 horiz_scrollbar.Height);
2890 horiz_scrollbar.Maximum = horiz_scrollbar_maximum;
2891 Controls.Add (horiz_scrollbar);
2892 horiz_scrollbar.Visible = true;
2894 else {
2895 Controls.Remove (horiz_scrollbar);
2896 horiz_scrollbar.Visible = false;
2899 UpdateVisibleColumn ();
2900 UpdateVisibleRowCount ();
2902 in_calc_grid_areas = false;
2905 void CalcCaption ()
2907 caption_area.X = ClientRectangle.X;
2908 caption_area.Y = ClientRectangle.Y;
2909 caption_area.Width = ClientRectangle.Width;
2910 if (caption_visible) {
2911 caption_area.Height = CaptionFont.Height;
2912 if (caption_area.Height < back_button_image.Height)
2913 caption_area.Height = back_button_image.Height;
2914 caption_area.Height += 2;
2916 else
2917 caption_area.Height = 0;
2920 void CalcCellsArea ()
2922 cells_area.X = ClientRectangle.X + rowhdrs_area.Width;
2923 cells_area.Y = columnhdrs_area.Y + columnhdrs_area.Height;
2924 cells_area.Width = ClientRectangle.X + ClientRectangle.Width - cells_area.X;
2925 if (cells_area.Width < 0)
2926 cells_area.Width = 0;
2927 cells_area.Height = ClientRectangle.Y + ClientRectangle.Height - cells_area.Y;
2928 if (cells_area.Height < 0)
2929 cells_area.Height = 0;
2932 void CalcColumnHeaders ()
2934 int max_width_cols;
2936 columnhdrs_area.X = ClientRectangle.X;
2937 columnhdrs_area.Y = parent_rows.Y + parent_rows.Height;
2939 // TODO: take into account Scrollbars
2940 columnhdrs_maxwidth = ClientRectangle.X + ClientRectangle.Width - columnhdrs_area.X;
2941 max_width_cols = columnhdrs_maxwidth;
2943 if (CurrentTableStyle.CurrentRowHeadersVisible)
2944 max_width_cols -= RowHeaderWidth;
2946 if (width_of_all_columns > max_width_cols) {
2947 columnhdrs_area.Width = columnhdrs_maxwidth;
2948 } else {
2949 columnhdrs_area.Width = width_of_all_columns;
2951 if (CurrentTableStyle.CurrentRowHeadersVisible)
2952 columnhdrs_area.Width += RowHeaderWidth;
2955 if (ShowingColumnHeaders)
2956 columnhdrs_area.Height = CurrentTableStyle.HeaderFont.Height + 6;
2957 else
2958 columnhdrs_area.Height = 0;
2961 void CalcParentRows ()
2963 parent_rows.X = ClientRectangle.X;
2964 parent_rows.Y = caption_area.Y + caption_area.Height;
2965 parent_rows.Width = ClientRectangle.Width;
2966 if (ShowParentRows)
2967 parent_rows.Height = (CaptionFont.Height + 3) * dataSourceStack.Count;
2968 else
2969 parent_rows.Height = 0;
2972 void CalcParentButtons ()
2974 if (dataSourceStack.Count > 0 && CaptionVisible) {
2975 back_button_rect = new Rectangle (ClientRectangle.X + ClientRectangle.Width - 2 * (caption_area.Height - 2) - 8,
2976 caption_area.Height / 2 - back_button_image.Height / 2,
2977 back_button_image.Width, back_button_image.Height);
2978 parent_rows_button_rect = new Rectangle (ClientRectangle.X + ClientRectangle.Width - (caption_area.Height - 2) - 4,
2979 caption_area.Height / 2 - parent_rows_button_image.Height / 2,
2980 parent_rows_button_image.Width, parent_rows_button_image.Height);
2982 else {
2983 back_button_rect = parent_rows_button_rect = Rectangle.Empty;
2987 void CalcRowHeaders ()
2989 rowhdrs_area.X = ClientRectangle.X;
2990 rowhdrs_area.Y = columnhdrs_area.Y + columnhdrs_area.Height;
2991 rowhdrs_area.Height = ClientRectangle.Height + ClientRectangle.Y - rowhdrs_area.Y;
2993 if (CurrentTableStyle.CurrentRowHeadersVisible)
2994 rowhdrs_area.Width = RowHeaderWidth;
2995 else
2996 rowhdrs_area.Width = 0;
2999 int GetVisibleRowCount (int visibleHeight)
3001 int rows_height = 0;
3002 int r;
3003 for (r = FirstVisibleRow; r < rows.Length; r ++) {
3004 if (rows_height + rows[r].Height >= visibleHeight)
3005 break;
3006 rows_height += rows[r].Height;
3009 if (r < rows.Length - 1)
3010 r ++;
3012 return r - FirstVisibleRow;
3015 void UpdateVisibleColumn ()
3017 if (CurrentTableStyle.GridColumnStyles.Count == 0) {
3018 visiblecolumn_count = 0;
3019 return;
3022 int col;
3023 int max_pixel = horiz_pixeloffset + cells_area.Width;
3024 int unused;
3026 first_visiblecolumn = FromPixelToColumn (horiz_pixeloffset, out unused);
3028 col = FromPixelToColumn (max_pixel, out unused);
3030 visiblecolumn_count = 1 + col - first_visiblecolumn;
3032 visiblecolumn_count = 0;
3033 for (int i = first_visiblecolumn; i <= col; i ++) {
3034 if (CurrentTableStyle.GridColumnStyles[i].bound)
3035 visiblecolumn_count++;
3038 if (first_visiblecolumn + visiblecolumn_count < CurrentTableStyle.GridColumnStyles.Count) {
3039 visiblecolumn_count++; // Partially visible column
3043 void UpdateVisibleRowCount ()
3045 visiblerow_count = GetVisibleRowCount (cells_area.Height);
3047 CalcRowHeaders (); // Height depends on num of visible rows
3051 void InvalidateCaption ()
3053 if (caption_area.IsEmpty)
3054 return;
3056 Invalidate (caption_area);
3059 void InvalidateRow (int row)
3061 if (row < FirstVisibleRow || row > FirstVisibleRow + VisibleRowCount)
3062 return;
3064 Rectangle rect_row = new Rectangle ();
3066 rect_row.X = cells_area.X;
3067 rect_row.Width = width_of_all_columns;
3068 if (rect_row.Width > cells_area.Width)
3069 rect_row.Width = cells_area.Width;
3070 rect_row.Height = rows[row].Height;
3071 rect_row.Y = cells_area.Y + rows[row].VerticalOffset - rows[FirstVisibleRow].VerticalOffset;
3072 Invalidate (rect_row);
3075 void InvalidateRowHeader (int row)
3077 Rectangle rect_rowhdr = new Rectangle ();
3078 rect_rowhdr.X = rowhdrs_area.X;
3079 rect_rowhdr.Width = rowhdrs_area.Width;
3080 rect_rowhdr.Height = rows[row].Height;
3081 rect_rowhdr.Y = rowhdrs_area.Y + rows[row].VerticalOffset - rows[FirstVisibleRow].VerticalOffset;
3082 Invalidate (rect_rowhdr);
3085 internal void InvalidateColumn (DataGridColumnStyle column)
3087 Rectangle rect_col = new Rectangle ();
3088 int col_pixel;
3089 int col = -1;
3091 col = CurrentTableStyle.GridColumnStyles.IndexOf (column);
3093 if (col == -1)
3094 return;
3096 rect_col.Width = column.Width;
3097 col_pixel = GetColumnStartingPixel (col);
3098 rect_col.X = cells_area.X + col_pixel - horiz_pixeloffset;
3099 rect_col.Y = cells_area.Y;
3100 rect_col.Height = cells_area.Height;
3101 Invalidate (rect_col);
3104 void DrawResizeLineVert (int x)
3106 XplatUI.DrawReversibleRectangle (Handle,
3107 new Rectangle (x, cells_area.Y, 1, cells_area.Height - 3),
3111 void DrawResizeLineHoriz (int y)
3113 XplatUI.DrawReversibleRectangle (Handle,
3114 new Rectangle (cells_area.X, y, cells_area.Width - 3, 1),
3118 void SetUpHorizontalScrollBar (out int maximum)
3120 maximum = width_of_all_columns;
3122 horiz_scrollbar.Location = new Point (ClientRectangle.X, ClientRectangle.Y +
3123 ClientRectangle.Height - horiz_scrollbar.Height);
3125 horiz_scrollbar.LargeChange = cells_area.Width;
3129 void SetUpVerticalScrollBar (out int height, out int maximum)
3131 int y;
3133 y = ClientRectangle.Y + parent_rows.Y + parent_rows.Height;
3134 height = ClientRectangle.Height - parent_rows.Y - parent_rows.Height;
3136 vert_scrollbar.Location = new Point (ClientRectangle.X +
3137 ClientRectangle.Width - vert_scrollbar.Width, y);
3139 maximum = RowsCount;
3141 if (ShowEditRow && RowsCount > 0) {
3142 maximum++;
3145 vert_scrollbar.LargeChange = VLargeChange;
3148 #endregion // Public Instance Methods
3150 #region Instance Properties
3151 // Returns the ColumnHeaders area excluding the rectangle shared with RowHeaders
3152 internal Rectangle ColumnHeadersArea {
3153 get {
3154 Rectangle columns_area = columnhdrs_area;
3156 if (CurrentTableStyle.CurrentRowHeadersVisible) {
3157 columns_area.X += RowHeaderWidth;
3158 columns_area.Width -= RowHeaderWidth;
3160 return columns_area;
3164 bool ShowingColumnHeaders {
3165 get { return ColumnHeadersVisible && CurrentTableStyle.GridColumnStyles.Count > 0; }
3168 internal Rectangle RowHeadersArea {
3169 get { return rowhdrs_area; }
3172 internal Rectangle ParentRowsArea {
3173 get { return parent_rows; }
3176 int VLargeChange {
3177 get { return VisibleRowCount; }
3180 #endregion Instance Properties
3182 #endregion // Code originally in DataGridDrawingLogic.cs