* TabControl.cs: Show the tooltip depending on the value
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / DataGridViewRowCollection.cs
1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
8 // 
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 // 
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19 //
20 // Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
21 //
22 // Author:
23 //      Pedro Martínez Juliá <pedromj@gmail.com>
24 //
25
26
27 #if NET_2_0
28
29 using System.ComponentModel;
30 using System.Collections;
31 using System.ComponentModel.Design.Serialization;
32
33 namespace System.Windows.Forms
34         {
35         [DesignerSerializerAttribute ("System.Windows.Forms.Design.DataGridViewRowCollectionCodeDomSerializer, " + Consts.AssemblySystem_Design,
36                                       "System.ComponentModel.Design.Serialization.CodeDomSerializer, " + Consts.AssemblySystem_Design)]
37         [ListBindable (false)]
38         public class DataGridViewRowCollection : IList, ICollection, IEnumerable
39         {
40                 private ArrayList list;
41                 private DataGridView dataGridView;
42                 private bool raiseEvent = true;
43
44                 public DataGridViewRowCollection (DataGridView dataGridView)
45                 {
46                         this.dataGridView = dataGridView;
47                         list = new ArrayList ();
48                 }
49
50                 public int Count {
51                         get { return list.Count; }
52                 }
53
54                 int ICollection.Count {
55                         get { return Count; }
56                 }
57
58                 bool IList.IsFixedSize {
59                         get { return list.IsFixedSize; }
60                 }
61
62                 bool IList.IsReadOnly {
63                         get { return list.IsReadOnly; }
64                 }
65
66                 bool ICollection.IsSynchronized {
67                         get { return list.IsSynchronized; }
68                 }
69
70                 object IList.this [int index] {
71                         get {
72                                 return this[index];
73                         }
74                         set { list[index] = value as DataGridViewRow; }
75                 }
76
77                 public DataGridViewRow this [int index] {
78                         get {
79                                 // Accessing a System.Windows.Forms.DataGridViewRow with this indexer causes the row to become unshared. 
80                                 // To keep the row shared, use the System.Windows.Forms.DataGridViewRowCollection.SharedRow method. 
81                                 // For more information, see Best Practices for Scaling the Windows Forms DataGridView Control.
82                                 DataGridViewRow row = (DataGridViewRow) list [index];
83                                 if (row.Index == -1) {
84                                         row = (DataGridViewRow) row.Clone ();
85                                         row.SetIndex (index);
86                                         list [index] = row;
87                                 }
88                                 return row;
89                         }
90                 }
91
92                 object ICollection.SyncRoot {
93                         get { return list.SyncRoot; }
94                 }
95
96                 public event CollectionChangeEventHandler CollectionChanged;
97
98                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
99                 public virtual int Add ()
100                 {
101                         return Add (dataGridView.RowTemplateFull as DataGridViewRow);
102                 }
103
104                 int IList.Add (object value)
105                 {
106                         return Add (value as DataGridViewRow);
107                 }
108
109                 private int AddCore (DataGridViewRow dataGridViewRow, bool sharable)
110                 {
111                         if (dataGridView.Columns.Count == 0)
112                                 throw new InvalidOperationException ("DataGridView has no columns.");
113                         
114                         int result;
115                         
116                         dataGridViewRow.SetDataGridView (dataGridView);
117
118                         // 
119                         // Add the row just before the editing row (if there is an editing row).
120                         // 
121                         int editing_index = -1;
122                         if (DataGridView != null && DataGridView.EditingRow != null && DataGridView.EditingRow != dataGridViewRow) {
123                                 editing_index = list.Count - 1; // always the last row
124                                 DataGridView.EditingRow.SetIndex (list.Count);
125                         }
126                         
127                         if (editing_index >= 0) {
128                                 list.Insert (editing_index, dataGridViewRow);
129                                 result = editing_index;
130                         } else {
131                                 result = list.Add (dataGridViewRow);
132                         }
133                         
134                         if (sharable && CanBeShared (dataGridViewRow)) {
135                                 dataGridViewRow.SetIndex (-1);
136                         } else {
137                                 dataGridViewRow.SetIndex (result);
138                         }
139
140                         CompleteRowCells (dataGridViewRow);
141                         for (int i = 0; i < dataGridViewRow.Cells.Count; i++) {
142                                 dataGridViewRow.Cells [i].SetOwningColumn (dataGridView.Columns [i]);
143                         }
144
145                         if (raiseEvent) {
146                                 OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Add, dataGridViewRow));
147                                 DataGridView.OnRowsAddedInternal (new DataGridViewRowsAddedEventArgs (result, 1));
148                         }
149
150                         return result;
151                 }
152
153                 // Complete the rows if they are incomplete.
154                 private void CompleteRowCells (DataGridViewRow row)
155                 {
156                         if (row == null || DataGridView == null)
157                                 return;
158
159                         if (row.Cells.Count < DataGridView.ColumnCount) {
160                                 for (int i = row.Cells.Count; i < DataGridView.ColumnCount; i++)
161                                         row.Cells.Add ((DataGridViewCell) DataGridView.Columns[i].CellTemplate.Clone ());
162                         }
163                 }
164
165                 public virtual int Add (DataGridViewRow dataGridViewRow)
166                 {
167                         if (dataGridView.DataSource != null)
168                                 throw new InvalidOperationException ("DataSource of DataGridView is not null.");
169                         return AddCore (dataGridViewRow, true);
170                 }
171                 
172                 private bool CanBeShared (DataGridViewRow row)
173                 {
174                         // We don't currently support shared rows
175                         return false;
176                         
177                         //foreach (DataGridViewCell cell in row.Cells) {
178                         //        if (cell.Value != null)
179                         //                return false;
180                         //        if (cell.ToolTipText != string.Empty)
181                         //                return false;
182                         //        if (cell.ContextMenuStrip != null)
183                         //                return false;
184                         //}
185
186                         //return true;
187                 }
188                 
189
190                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
191                 public virtual int Add (int count)
192                 {
193                         if (count <= 0)
194                                 throw new ArgumentOutOfRangeException("Count is less than or equeal to 0.");
195                         if (dataGridView.DataSource != null)
196                                 throw new InvalidOperationException("DataSource of DataGridView is not null.");
197                         if (dataGridView.Columns.Count == 0)
198                                 throw new InvalidOperationException("DataGridView has no columns.");
199
200                         raiseEvent = false;
201                         int result = 0;
202                         for (int i = 0; i < count; i++)
203                                 result = Add (dataGridView.RowTemplateFull as DataGridViewRow);
204                         DataGridView.OnRowsAddedInternal (new DataGridViewRowsAddedEventArgs (result - count + 1, count));
205                         raiseEvent = true;
206                         return result;
207                 }
208
209                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
210                 public virtual int Add (params object[] values)
211                 {
212                         if (values == null)
213                                 throw new ArgumentNullException("values is null.");
214                         if (dataGridView.VirtualMode)
215                                 throw new InvalidOperationException("DataGridView is in virtual mode.");
216
217                         DataGridViewRow row = (DataGridViewRow)dataGridView.RowTemplateFull;
218                         int result = AddCore (row, false);
219                         row.SetValues(values);
220                         return result;
221                 }
222
223                 public virtual int AddCopies (int indexSource, int count)
224                 {
225                         raiseEvent = false;
226                         int lastIndex = 0;
227                         for (int i = 0; i < count; i++)
228                                 lastIndex = AddCopy(indexSource);
229                         DataGridView.OnRowsAddedInternal (new DataGridViewRowsAddedEventArgs (lastIndex - count + 1, count));
230                         raiseEvent = true;
231                         return lastIndex;
232                 }
233
234                 public virtual int AddCopy (int indexSource)
235                 {
236                         return Add ((list [indexSource] as DataGridViewRow).Clone () as DataGridViewRow);
237                 }
238
239                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
240                 public virtual void AddRange (params DataGridViewRow [] dataGridViewRows)
241                 {
242                         if (dataGridView.DataSource != null)
243                                 throw new InvalidOperationException ("DataSource of DataGridView is not null.");
244
245                         int count = 0;
246                         int lastIndex = -1;
247                         raiseEvent = false;
248                         foreach (DataGridViewRow row in dataGridViewRows) {
249                                 lastIndex = Add (row);
250                                 count++;
251                         }
252                         raiseEvent = true;
253
254                         DataGridView.OnRowsAddedInternal (new DataGridViewRowsAddedEventArgs (lastIndex - count + 1, count));
255                         OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Add, dataGridViewRows));
256                 }
257
258                 public virtual void Clear ()
259                 {
260                         int total = list.Count;
261                         
262                         DataGridView.OnRowsPreRemovedInternal (new DataGridViewRowsRemovedEventArgs (0, total));
263
264                         for (int i = 0; i < total; i++) {
265                                 DataGridViewRow row = (DataGridViewRow)list[0];
266                                 
267                                 // We can exit because the NewRow is always last
268                                 if (row.IsNewRow)
269                                         break;
270                                         
271                                 list.Remove (row);
272                                 ReIndex ();
273                         }
274
275                         DataGridView.OnRowsPostRemovedInternal (new DataGridViewRowsRemovedEventArgs (0, total));
276                         OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, null));
277                 }
278
279                 internal void ClearInternal ()
280                 {
281                         list.Clear ();
282                 }
283
284                 bool IList.Contains (object value)
285                 {
286                         return Contains (value as DataGridViewRow);
287                 }
288
289                 public virtual bool Contains (DataGridViewRow dataGridViewRow)
290                 {
291                         return list.Contains (dataGridViewRow);
292                 }
293
294                 void ICollection.CopyTo (Array array, int index)
295                 {
296                         list.CopyTo (array, index);
297                 }
298
299                 public void CopyTo (DataGridViewRow[] array, int index)
300                 {
301                         list.CopyTo (array, index);
302                 }
303
304                 IEnumerator IEnumerable.GetEnumerator ()
305                 {
306                         return list.GetEnumerator ();
307                 }
308
309                 public int GetFirstRow (DataGridViewElementStates includeFilter)
310                 {
311                         for (int i = 0; i < list.Count; i++) {
312                                 DataGridViewRow row = (DataGridViewRow) list [i];
313                                 if ((row.State & includeFilter) != 0)
314                                         return i;
315                         }
316                         return -1;
317                 }
318
319                 public int GetFirstRow (DataGridViewElementStates includeFilter, DataGridViewElementStates excludeFilter)
320                 {
321                         for (int i = 0; i < list.Count; i++) {
322                                 DataGridViewRow row = (DataGridViewRow) list [i];
323                                 if (((row.State & includeFilter) != 0) && ((row.State & excludeFilter) == 0))
324                                         return i;
325                         }
326                         return -1;
327                 }
328
329                 public int GetLastRow (DataGridViewElementStates includeFilter)
330                 {
331                         for (int i = list.Count - 1; i >= 0; i--) {
332                                 DataGridViewRow row = (DataGridViewRow) list [i];
333                                 if ((row.State & includeFilter) != 0)
334                                         return i;
335                         }
336                         return -1;
337                 }
338
339                 public int GetNextRow (int indexStart, DataGridViewElementStates includeFilter)
340                 {
341                         for (int i = indexStart + 1; i < list.Count; i++) {
342                                 DataGridViewRow row = (DataGridViewRow) list [i];
343                                 if ((row.State & includeFilter) != 0)
344                                         return i;
345                         }
346                         return -1;
347                 }
348
349                 public int GetNextRow (int indexStart, DataGridViewElementStates includeFilter, DataGridViewElementStates excludeFilter)
350                 {
351                         for (int i = indexStart + 1; i < list.Count; i++) {
352                                 DataGridViewRow row = (DataGridViewRow) list [i];
353                                 if (((row.State & includeFilter) != 0) && ((row.State & excludeFilter) == 0))
354                                         return i;
355                         }
356                         return -1;
357                 }
358
359                 public int GetPreviousRow (int indexStart, DataGridViewElementStates includeFilter)
360                 {
361                         for (int i = indexStart - 1; i >= 0; i--) {
362                                 DataGridViewRow row = (DataGridViewRow) list [i];
363                                 if ((row.State & includeFilter) != 0)
364                                         return i;
365                         }
366                         return -1;
367                 }
368
369                 public int GetPreviousRow (int indexStart, DataGridViewElementStates includeFilter, DataGridViewElementStates excludeFilter)
370                 {
371                         for (int i = indexStart - 1; i >= 0; i--) {
372                                 DataGridViewRow row = (DataGridViewRow) list [i];
373                                 if (((row.State & includeFilter) != 0) && ((row.State & excludeFilter) == 0))
374                                         return i;
375                         }
376                         return -1;
377                 }
378
379                 public int GetRowCount (DataGridViewElementStates includeFilter)
380                 {
381                         int result = 0;
382                         foreach (DataGridViewRow row in list)
383                                 if ((row.State & includeFilter) != 0)
384                                         result ++;
385                         return result;
386                 }
387
388                 public int GetRowsHeight (DataGridViewElementStates includeFilter)
389                 {
390                         int result = 0;
391                         foreach (DataGridViewRow row in list)
392                                 if ((row.State & includeFilter) != 0)
393                                         result += row.Height;
394                         return result;
395                 }
396
397                 public virtual DataGridViewElementStates GetRowState (int rowIndex)
398                 {
399                         return (list [rowIndex] as DataGridViewRow).State;
400                 }
401
402                 int IList.IndexOf (object value)
403                 {
404                         return IndexOf (value as DataGridViewRow);
405                 }
406
407                 public int IndexOf (DataGridViewRow dataGridViewRow)
408                 {
409                         return list.IndexOf (dataGridViewRow);
410                 }
411
412                 void IList.Insert (int index, object value)
413                 {
414                         Insert (index, value as DataGridViewRow);
415                 }
416
417                 // FIXME: Do *not* allow insertation *after* the editing row!
418                 public virtual void Insert (int rowIndex, DataGridViewRow dataGridViewRow)
419                 {
420                         dataGridViewRow.SetIndex (rowIndex);
421                         dataGridViewRow.SetDataGridView (dataGridView);
422                         CompleteRowCells (dataGridViewRow);
423                         list.Insert (rowIndex, dataGridViewRow);
424                         ReIndex ();
425                         OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Add, dataGridViewRow));
426                         if (raiseEvent)
427                                 DataGridView.OnRowsAddedInternal (new DataGridViewRowsAddedEventArgs (rowIndex, 1));
428                 }
429
430                 public virtual void Insert (int rowIndex, int count)
431                 {
432                         int index = rowIndex;
433                         raiseEvent = false;
434                         for (int i = 0; i < count; i++)
435                                 Insert (index++, dataGridView.RowTemplateFull);
436                         DataGridView.OnRowsAddedInternal (new DataGridViewRowsAddedEventArgs (rowIndex, count));
437                         raiseEvent = true;
438                 }
439
440                 public virtual void Insert (int rowIndex, params object[] values)
441                 {
442                         if (values == null)
443                                 throw new ArgumentNullException ("Values is null.");
444                         if (dataGridView.VirtualMode || dataGridView.DataSource != null)
445                                 throw new InvalidOperationException ();
446                         DataGridViewRow row = new DataGridViewRow ();
447                         row.SetValues (values);
448                         Insert (rowIndex, row);
449                 }
450
451                 public virtual void InsertCopies (int indexSource, int indexDestination, int count)
452                 {
453                         raiseEvent = false;
454                         int index = indexDestination;
455                         for (int i = 0; i < count; i++)
456                                 InsertCopy (indexSource, index++);
457                         DataGridView.OnRowsAddedInternal (new DataGridViewRowsAddedEventArgs (indexDestination, count));
458                         raiseEvent = true;
459                 }
460
461                 public virtual void InsertCopy (int indexSource, int indexDestination)
462                 {
463                         Insert (indexDestination, (list [indexSource] as DataGridViewRow).Clone());
464                 }
465
466                 public virtual void InsertRange (int rowIndex, params DataGridViewRow [] dataGridViewRows)
467                 {
468                         raiseEvent = false;
469                         int index = rowIndex;
470                         int count = 0;
471                         foreach (DataGridViewRow row in dataGridViewRows) {
472                                 Insert (index++, row);
473                                 count++;
474                         }
475                         DataGridView.OnRowsAddedInternal (new DataGridViewRowsAddedEventArgs (rowIndex, count));
476                         raiseEvent = true;
477                 }
478
479                 void IList.Remove (object value)
480                 {
481                         Remove (value as DataGridViewRow);
482                 }
483
484                 public virtual void Remove (DataGridViewRow dataGridViewRow)
485                 {
486                         if (dataGridViewRow.IsNewRow)
487                                 throw new InvalidOperationException ("Cannot delete the new row");
488                                 
489                         DataGridView.OnRowsPreRemovedInternal (new DataGridViewRowsRemovedEventArgs (dataGridViewRow.Index, 1));
490                         list.Remove (dataGridViewRow);
491                         ReIndex ();
492                         OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Remove, dataGridViewRow));
493                         DataGridView.OnRowsPostRemovedInternal (new DataGridViewRowsRemovedEventArgs (dataGridViewRow.Index, 1));
494                 }
495
496                 internal virtual void RemoveInternal (DataGridViewRow dataGridViewRow)
497                 {
498                         DataGridView.OnRowsPreRemovedInternal (new DataGridViewRowsRemovedEventArgs (dataGridViewRow.Index, 1));
499                         list.Remove (dataGridViewRow);
500                         ReIndex ();
501                         OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Remove, dataGridViewRow));
502                         DataGridView.OnRowsPostRemovedInternal (new DataGridViewRowsRemovedEventArgs (dataGridViewRow.Index, 1));
503                 }
504                 
505                 public virtual void RemoveAt (int index)
506                 {
507                         DataGridViewRow row = this [index];
508                         
509                         Remove (row);
510                 }
511
512                 internal void RemoveAtInternal (int index)
513                 {
514                         DataGridViewRow row = this [index];
515                         
516                         RemoveInternal (row);
517                 }
518
519                 public DataGridViewRow SharedRow (int rowIndex)
520                 {
521                         return (DataGridViewRow) list [rowIndex];
522                 }
523
524                 internal int SharedRowIndexOf (DataGridViewRow row)
525                 {
526                         return list.IndexOf (row);
527                 }
528
529                 protected DataGridView DataGridView {
530                         get { return dataGridView; }
531                 }
532
533                 protected ArrayList List {
534                         get { return list; }
535                 }
536
537                 protected virtual void OnCollectionChanged (CollectionChangeEventArgs e)
538                 {
539                         if (CollectionChanged != null)
540                                 CollectionChanged (this, e);
541                 }
542
543                 internal void AddInternal (DataGridViewRow dataGridViewRow, bool sharable)
544                 {
545                         raiseEvent = false;
546                         AddCore (dataGridViewRow, sharable);
547                         raiseEvent = true;
548                 }
549
550                 internal ArrayList RowIndexSortedArrayList {
551                         get {
552                                 ArrayList result = (ArrayList) list.Clone();
553                                 result.Sort(new RowIndexComparator());
554                                 return result;
555                         }
556                 }
557                 
558                 internal void ReIndex ()
559                 {
560                         for (int i = 0; i < Count; i++)
561                                 (list[i] as DataGridViewRow).SetIndex (i);
562                 }
563                 
564                 internal void Sort (IComparer comparer)
565                 {
566                         // Note: you will probably want to call
567                         // invalidate after using this.
568                         if (DataGridView != null && DataGridView.EditingRow != null)
569                                 list.Sort (0, Count - 1, comparer);
570                         else
571                                 list.Sort (comparer);
572                         
573                         for (int i = 0; i < list.Count; i++)
574                                 (list[i] as DataGridViewRow).SetIndex (i);
575                 }
576
577                 private class RowIndexComparator : IComparer 
578                 {
579                         public int Compare (object o1, object o2)
580                         {
581                                 DataGridViewRow row1 = (DataGridViewRow) o1;
582                                 DataGridViewRow row2 = (DataGridViewRow) o2;
583                                 if (row1.Index < row2.Index) {
584                                         return -1;
585                                 } else if (row1.Index > row2.Index) {
586                                         return 1;
587                                 } else {
588                                         return 0;
589                                 }
590                         }
591                 }
592         }
593 }
594
595 #endif