2008-12-08 Ivan N. Zlatev <contact@i-nz.net>
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / DataGridView.cs
index 823f0527094686c702133a3571346e7e25ab249f..3f766d3eb01f01c462da2825d4cb66a9a6656b20 100644 (file)
@@ -2232,7 +2232,7 @@ namespace System.Windows.Forms {
                public virtual bool BeginEdit (bool selectAll) {
                        if (currentCell == null || currentCell.IsInEditMode)
                                return false;
-                       
+
                        if (currentCell.RowIndex >= 0) {
                                if ((currentCell.InheritedState & DataGridViewElementStates.ReadOnly) == DataGridViewElementStates.ReadOnly) {
                                        return false;
@@ -2285,9 +2285,14 @@ namespace System.Windows.Forms {
                                // Show the editing control
                                EditingControlInternal.Visible = true;
 
-                               // Allow editing control to set focus as needed
-                               (EditingControlInternal as IDataGridViewEditingControl).PrepareEditingControlForEdit (selectAll);
-                               
+                               IDataGridViewEditingControl dgvEditingControl = (IDataGridViewEditingControl) EditingControlInternal;
+                               if (dgvEditingControl != null) {
+                                       dgvEditingControl.EditingControlDataGridView = this;
+                                       dgvEditingControl.EditingControlRowIndex = currentCell.OwningRow.Index;
+                                       dgvEditingControl.ApplyCellStyleToEditingControl (style);
+                                       dgvEditingControl.PrepareEditingControlForEdit (selectAll);
+                                       dgvEditingControl.EditingControlFormattedValue = currentCell.EditedFormattedValue;
+                               }
                                return true;
                        }
 
@@ -2332,14 +2337,29 @@ namespace System.Windows.Forms {
 
                public bool CommitEdit (DataGridViewDataErrorContexts context)
                {
-                       if (currentCell != null && currentCell.IsInEditMode) {
-                               IDataGridViewEditingControl ctrl = EditingControl as IDataGridViewEditingControl;
-                               ctrl.GetEditingControlFormattedValue (DataGridViewDataErrorContexts.Commit);
-                               currentCell.Value = ctrl.GetEditingControlFormattedValue (DataGridViewDataErrorContexts.Commit);
-                               return true;
+                       if (currentCell != null && currentCell.OwningRow.DataBoundItem != null) {
+                               Object ob = currentCell.OwningRow.DataBoundItem;
+                               PropertyDescriptor property = TypeDescriptor.GetProperties (ob)[currentCell.OwningColumn.DataPropertyName];
+                               if (property != null && !property.IsReadOnly) {
+                                       try {
+                                               object value = currentCell.Value;
+                                               if (property.Converter != null && 
+                                                   property.Converter.CanConvertFrom (value.GetType()))
+                                                       value = property.Converter.ConvertFrom (value);
+                                               property.SetValue (ob, value);
+                                               return true;
+                                       } catch (Exception exc) {
+                                               DataGridViewDataErrorEventArgs args = new DataGridViewDataErrorEventArgs (exc, currentCell.ColumnIndex, 
+                                                                                                                         currentCell.RowIndex, context);
+                                               InternalOnDataError (args);
+                                               if (args.ThrowException)
+                                                       throw exc;
+                                               return false;
+                                       }
+                               }
                        }
-                       
-                       return false;
+
+                       return true;
                }
 
                [MonoTODO ("Always includes partial columns")]
@@ -2356,46 +2376,59 @@ namespace System.Windows.Forms {
                        return result;
                }
 
-               [MonoTODO ("Always includes partial rows")]
                public int DisplayedRowCount (bool includePartialRow)
                {
                        int result = 0;
-                       
-                       for (int i = first_row_index; i < Rows.Count; i++)
-                               if (Rows[i].Displayed)
+                       int rowTop = 0;
+
+                       if (ColumnHeadersVisible)
+                               rowTop += ColumnHeadersHeight;
+
+                       for (int index = first_row_index; index < Rows.Count; index++) {
+                               DataGridViewRow row = GetRowInternal (index);
+                               if (rowTop + row.Height < ClientSize.Height) {
                                        result++;
-                               else
+                                       rowTop += row.Height;
+                               } else {
+                                       if (includePartialRow)
+                                               result++;
                                        break;
+                               }
+                       }
                                        
                        return result;
                }
 
                public bool EndEdit ()
                {
-                       if (currentCell != null && currentCell.IsInEditMode) {
-                               if (EditingControl != null) {
-                                       IDataGridViewEditingControl ctrl = EditingControl as IDataGridViewEditingControl;
-                                       ctrl.GetEditingControlFormattedValue (DataGridViewDataErrorContexts.Commit);
-                                       currentCell.Value = ctrl.GetEditingControlFormattedValue (DataGridViewDataErrorContexts.Commit);
-                                       
-                                       currentCell.SetIsInEditMode (false);
-                                       currentCell.DetachEditingControl ();    
-                               } else if (currentCell is IDataGridViewEditingCell) {
-                                       currentCell.Value = (currentCell as IDataGridViewEditingCell).EditingCellFormattedValue;
-                                       currentCell.SetIsInEditMode (false);
-                               }
-
-                               new_row_commited = true;
-                               OnCellEndEdit (new DataGridViewCellEventArgs (currentCell.ColumnIndex, currentCell.RowIndex));
-                       }
-                       
-                       return true;
+                       return EndEdit (DataGridViewDataErrorContexts.Commit);
                }
 
                [MonoTODO ("Does not use context parameter")]
                public bool EndEdit (DataGridViewDataErrorContexts context)
                {
-                       return EndEdit ();
+                       if (currentCell == null || !currentCell.IsInEditMode)
+                               return true;
+
+                       if (EditingControl != null) {
+                               IDataGridViewEditingControl ctrl = EditingControl as IDataGridViewEditingControl;
+                               currentCell.Value = ctrl.GetEditingControlFormattedValue (DataGridViewDataErrorContexts.Commit);
+                               if (!CommitEdit (context)) {
+                                       EditingControl.Focus ();
+                                       return false;
+                               }
+                               currentCell.DetachEditingControl ();    
+                       } else if (currentCell is IDataGridViewEditingCell) {
+                               currentCell.Value = (currentCell as IDataGridViewEditingCell).EditingCellFormattedValue;
+                               if (!CommitEdit (context))
+                                       return false;
+                       }
+
+                       currentCell.SetIsInEditMode (false);
+                       new_row_commited = true;
+                       OnCellEndEdit (new DataGridViewCellEventArgs (currentCell.ColumnIndex, currentCell.RowIndex));
+                       Focus ();
+                       return true;
                }
 
                public int GetCellCount (DataGridViewElementStates includeFilter) {
@@ -2833,7 +2866,8 @@ namespace System.Windows.Forms {
                }
 
                public virtual void NotifyCurrentCellDirty (bool dirty) {
-                       throw new NotImplementedException();
+                       if (currentCell != null)
+                               InvalidateCell (currentCell);
                }
 
                public bool RefreshEdit ()
@@ -2906,40 +2940,46 @@ namespace System.Windows.Forms {
                                throw new ArgumentNullException ("dataGridViewColumn");
                        if (dataGridViewColumn.DataGridView != this)
                                throw new ArgumentException ("dataGridViewColumn");
-                       // XXX: This is thrown too much, disable for now..
-                       //if (DataSource != null && !dataGridViewColumn.IsDataBound)
-                       //        throw new ArgumentException ("dataGridViewColumn");
-                       //if (VirtualMode && !dataGridViewColumn.IsDataBound)
-                       //        throw new InvalidOperationException ();
+
+                       if (!EndEdit ())
+                               return;
 
                        if (SortedColumn != null)
                                SortedColumn.HeaderCell.SortGlyphDirection = SortOrder.None;
 
-                       EndEdit ();
-                       
-                       // Figure out if this is a numeric sort or text sort
-                       bool is_numeric = true;
-                       double n;
+                       sortedColumn = dataGridViewColumn;
+                       sortOrder = direction == ListSortDirection.Ascending ? SortOrder.Ascending : SortOrder.Descending;
                        
-                       foreach (DataGridViewRow row in Rows) {
-                               object val = row.Cells[dataGridViewColumn.Index].Value;
+                       if (Rows.Count == 0)
+                               return;
+
+                       IBindingList bindingList = DataSource as IBindingList;
+                       if (dataGridViewColumn.IsDataBound) {
+                               if (bindingList != null && bindingList.SupportsSorting) {
+                                       CurrencyManager currencyManager = (CurrencyManager) this.BindingContext[DataSource];
+                                       bindingList.ApplySort (currencyManager.GetItemProperties()[dataGridViewColumn.DataPropertyName], direction);
+                                       dataGridViewColumn.HeaderCell.SortGlyphDirection = sortOrder;
+                               }
+                       } else {
+                               // Figure out if this is a numeric sort or text sort
+                               bool is_numeric = true;
+                               double n;
                                
-                               if (val != null && !double.TryParse (val.ToString (), out n)) {
-                                       is_numeric = false;
-                                       break;
+                               foreach (DataGridViewRow row in Rows) {
+                                       object val = row.Cells[dataGridViewColumn.Index].Value;
+                                       
+                                       if (val != null && !double.TryParse (val.ToString (), out n)) {
+                                               is_numeric = false;
+                                               break;
+                                       }
                                }
+                               
+                               ColumnSorter sorter = new ColumnSorter (dataGridViewColumn, direction, is_numeric);
+                               Rows.Sort (sorter);
+                               dataGridViewColumn.HeaderCell.SortGlyphDirection = sortOrder;
                        }
-                       
-                       ColumnSorter sorter = new ColumnSorter (dataGridViewColumn, direction, is_numeric);
-                       Rows.Sort (sorter);
-
-                       sortedColumn = dataGridViewColumn;
-                       sortOrder = (SortOrder)direction + 1;
-
-                       dataGridViewColumn.HeaderCell.SortGlyphDirection = (SortOrder)direction + 1;
 
                        Invalidate ();
-
                        OnSorted (EventArgs.Empty);
                }
                
@@ -4156,6 +4196,9 @@ namespace System.Windows.Forms {
                {
                        base.OnMouseDown(e);
                        
+                       if (!EndEdit ())
+                               return;
+
                        HitTestInfo hitTest = HitTest(e.X, e.Y);
                        
                        DataGridViewCell cell = null;
@@ -4164,7 +4207,6 @@ namespace System.Windows.Forms {
 
                        if (hitTest.Type == DataGridViewHitTestType.ColumnHeader && MouseOverColumnResize (hitTest.ColumnIndex, e.X)) {
                                if (e.Clicks == 2) {
-                                       EndEdit ();
                                        AutoResizeColumn (hitTest.ColumnIndex);
                                        return;
                                }
@@ -4173,14 +4215,12 @@ namespace System.Windows.Forms {
                                column_resize_active = true;
                                resize_band_start = e.X;
                                resize_band_delta = 0;
-                               EndEdit ();
                                DrawVerticalResizeLine (resize_band_start);
                                return;
                        }
 
                        if (hitTest.Type == DataGridViewHitTestType.RowHeader && MouseOverRowResize (hitTest.RowIndex, e.Y)) {
                                if (e.Clicks == 2) {
-                                       EndEdit ();
                                        AutoResizeRow (hitTest.RowIndex);
                                        return;
                                }
@@ -4189,7 +4229,6 @@ namespace System.Windows.Forms {
                                row_resize_active = true;
                                resize_band_start = e.Y;
                                resize_band_delta = 0;
-                               EndEdit ();
                                DrawHorizontalResizeLine (resize_band_start);
                                return;
                        }
@@ -4220,9 +4259,11 @@ namespace System.Windows.Forms {
 
                private void UpdateBindingPosition (int position)
                {
-                       BindingSource source = dataSource as BindingSource;
-                       if (source != null && source.CurrencyManager != null)
-                               source.CurrencyManager.Position = position;
+                       if (DataSource != null && BindingContext != null) {
+                               CurrencyManager currencyManager = this.BindingContext[DataSource] as CurrencyManager;
+                               if (currencyManager != null)
+                                       currencyManager.Position = position;
+                       }
                }
 
                protected override void OnMouseEnter (EventArgs e)
@@ -4498,7 +4539,6 @@ namespace System.Windows.Forms {
                        gridWidth = rowHeadersVisible ? rowHeadersWidth : 0;
                        gridHeight = 0;
                        
-                       int rows_displayed = 0;
                        int first_row_height = Rows.Count > 0 ? Rows[Math.Min (Rows.Count - 1, first_row_index)].Height : 0;
 //                     int room_left = this.Height;
                        
@@ -4538,9 +4578,7 @@ namespace System.Windows.Forms {
                                bounds.Y += bounds.Height;
                                bounds.X = BorderWidth;
                                
-                               if (bounds.Y < ClientSize.Height - (horizontalScrollBar.Visible ? horizontalScrollBar.Height : 0))
-                                       rows_displayed++;
-                               else
+                               if (bounds.Y >= ClientSize.Height - (horizontalScrollBar.Visible ? horizontalScrollBar.Height : 0))
                                        break;
                                        
                                gridHeight += row.Height;
@@ -5333,24 +5371,24 @@ namespace System.Windows.Forms {
                        if (cell != null && !cell.Visible)
                                throw new InvalidOperationException ("cell is not visible");
                                
-                       if (setAnchorCellAddress)
-                               anchor_cell = new Point (columnIndex, rowIndex);
-
-                       DataGridViewCell oldCell = CurrentCell;
-                       currentCell = cell;
-                       currentCellAddress = new Point (columnIndex, rowIndex);
-                       if (currentCell != oldCell) {
-                               if (oldCell != null) {
-                                       if (currentCell.IsInEditMode)
-                                               EndEdit ();
-                                       OnCellLeave (new DataGridViewCellEventArgs(oldCell.ColumnIndex, oldCell.RowIndex));
-                                       OnRowLeave (new DataGridViewCellEventArgs (oldCell.ColumnIndex, oldCell.RowIndex));
+                       if (cell != currentCell) {
+                               if (currentCell != null) {
+                                       if (currentCell.IsInEditMode && !EndEdit ())
+                                               return false;
+                                       OnCellLeave (new DataGridViewCellEventArgs(currentCell.ColumnIndex, currentCell.RowIndex));
+                                       OnRowLeave (new DataGridViewCellEventArgs (currentCell.ColumnIndex, currentCell.RowIndex));
                                }
+
+                               currentCell = cell;
+                               if (setAnchorCellAddress)
+                                       anchor_cell = new Point (columnIndex, rowIndex);
+                               currentCellAddress = new Point (columnIndex, rowIndex);
+
                                UpdateBindingPosition (currentCell.RowIndex);
                                OnRowEnter (new DataGridViewCellEventArgs (cell.ColumnIndex, cell.RowIndex));
                                OnCellEnter (new DataGridViewCellEventArgs(cell.ColumnIndex, cell.RowIndex));
                                OnCurrentCellChanged (EventArgs.Empty);
-                               if (throughMouseClick && editMode == DataGridViewEditMode.EditOnEnter)
+                               if (throughMouseClick || editMode == DataGridViewEditMode.EditOnEnter)
                                        BeginEdit (true);
                        } else {
                                if (throughMouseClick)
@@ -5472,12 +5510,14 @@ namespace System.Windows.Forms {
                internal void OnVScrollBarScroll (object sender, ScrollEventArgs e)
                {
                        verticalScrollingOffset = e.NewValue;
+                       if (Rows.Count == 0)
+                               return;
+
                        int top = 0;
                        
                        for (int index = 0; index < Rows.Count; index++) {
                                DataGridViewRow row = Rows[index];
-                               
-                               if (e.NewValue <= top + row.Height) {
+                               if (e.NewValue < top + row.Height) {
                                        if (first_row_index != index) {
                                                first_row_index = index;
                                                Invalidate ();
@@ -5490,9 +5530,6 @@ namespace System.Windows.Forms {
                                top += row.Height;
                        }
                        
-                       if (Rows.Count == 0)
-                               return;
-                               
                        first_row_index = Rows.Count - DisplayedRowCount (false);
                        Invalidate ();
                        OnScroll (e);
@@ -5925,7 +5962,8 @@ namespace System.Windows.Forms {
 
                private void MoveCurrentCell (int x, int y, bool select, bool isControl, bool isShift, bool scroll)
                {
-                       SetCurrentCellAddressCore (x, y, true, false, false);
+                       if (!SetCurrentCellAddressCore (x, y, true, false, false))
+                               return;
 
                        bool full_row_selected = Rows.SharedRow(CurrentCellAddress.Y).Selected;
                        bool full_col_selected = Columns[CurrentCellAddress.X].Selected;
@@ -5963,10 +6001,10 @@ namespace System.Windows.Forms {
                                }
 
                                int disp_y = y;
+                               int displayedRowsCount = DisplayedRowCount (false);
+                               int delta_y = 0;
 
                                if (disp_y < first_row_index) {
-                                       int delta_y = 0;
-
                                        if (disp_y == 0)
                                                delta_y = verticalScrollBar.Value;
                                        else
@@ -5975,13 +6013,11 @@ namespace System.Windows.Forms {
 
                                        verticalScrollBar.SafeValueSet (verticalScrollBar.Value - delta_y);
                                        OnVScrollBarScroll (this, new ScrollEventArgs (ScrollEventType.ThumbPosition, verticalScrollBar.Value));
-                               } else if (disp_y > first_row_index + DisplayedRowCount (false) - 1) {
-                                       int delta_y = 0;
-                                       
+                               } else if (disp_y > first_row_index + displayedRowsCount - 1) {
                                        if (disp_y == Rows.Count - 1)
                                                delta_y = verticalScrollBar.Maximum - verticalScrollBar.Value;
                                        else
-                                               for (int i = first_row_index + DisplayedRowCount (false) - 1; i < disp_y; i++)
+                                               for (int i = first_row_index + displayedRowsCount - 1; i < disp_y; i++)
                                                        delta_y += GetRowInternal (i).Height;
 
                                        verticalScrollBar.SafeValueSet (verticalScrollBar.Value + delta_y);