make another pass at corcompare, mostly attributes on classes/properties/events/etc
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / Menu.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) 2004-2005 Novell, Inc.
21 //
22 // Authors:
23 //      Jordi Mas i Hernandez, jordi@ximian.com
24 //
25 //      TODO:
26 //              - FindMenuItem
27 //              - MdiListItem
28 //
29
30 using System.Collections;
31 using System.ComponentModel;
32 using System.ComponentModel.Design;
33 using System.Reflection;
34 using System.Runtime.InteropServices;
35
36 namespace System.Windows.Forms
37 {
38 #if !NET_2_0
39         [Designer ("Microsoft.VisualStudio.Windows.Forms.MenuDesigner, " + Consts.AssemblyMicrosoft_VisualStudio, "System.ComponentModel.Design.IDesigner")]
40 #endif
41         [ToolboxItemFilter("System.Windows.Forms", ToolboxItemFilterType.Allow)]
42         [ListBindable(false)]
43         public abstract class Menu : Component
44         {
45                 internal MenuItemCollection menu_items;
46                 internal IntPtr menu_handle = IntPtr.Zero;
47                 internal Menu parent_menu = null;
48                 System.Drawing.Rectangle rect;
49                 internal Control Wnd;
50                 internal MenuTracker tracker;
51
52 #if NET_2_0
53                 private string control_name;
54                 private object control_tag;
55 #endif
56
57                 public const int FindHandle = 0;
58                 public const int FindShortcut = 1;
59
60                 protected Menu (MenuItem[] items)
61                 {
62                         menu_items = new MenuItemCollection (this);
63
64                         if (items != null)
65                                 menu_items.AddRange (items);
66                 }
67
68                 #region Public Properties
69                 
70                 [BrowsableAttribute(false)]
71                 [EditorBrowsableAttribute(EditorBrowsableState.Advanced)]
72                 [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
73                 public IntPtr Handle {
74                         get { return menu_handle; }
75                 }
76
77                 internal virtual void OnMenuChanged (EventArgs e)
78                 {
79                         EventHandler eh = (EventHandler)(Events [MenuChangedEvent]);
80                         if (eh != null)
81                                 eh (this, e);
82                 }
83
84                 [BrowsableAttribute(false)]
85                 [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
86                 public virtual bool IsParent {
87                         get {
88                                 if (menu_items != null && menu_items.Count > 0)
89                                         return true;
90                                 else
91                                         return false;
92                         }
93                 }
94
95                 [BrowsableAttribute(false)]
96                 [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
97                 public MenuItem MdiListItem {
98                         get {
99                                 throw new NotImplementedException ();
100                         }
101                 }
102
103                 [BrowsableAttribute(false)]
104                 [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Content)]
105                 [MergableProperty(false)]
106                 public MenuItemCollection MenuItems {
107                         get { return menu_items; }
108                 }
109                 
110 #if NET_2_0
111
112                 [BrowsableAttribute(false)]
113                 [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
114                 public string Name { 
115                         get { return control_name; } 
116                         set { control_name = value; }
117                 }
118
119                 [Localizable(false)]
120                 [Bindable(true)]
121                 [TypeConverter(typeof(StringConverter))]
122                 [DefaultValue(null)]
123                 [MWFCategory("Data")]
124                 public object Tag {
125                         get { return control_tag; }
126                         set { control_tag = value; }
127                 }
128 #endif
129
130                 #endregion Public Properties
131
132                 #region Private Properties
133
134                 internal System.Drawing.Rectangle Rect {
135                         get { return rect; }
136                 }
137
138                 internal MenuItem SelectedItem  {
139                         get {
140                                 foreach (MenuItem item in MenuItems)
141                                         if (item.Selected)
142                                                 return item;
143
144                                 return null;
145                         }
146                 }
147
148                 internal int Height {
149                         get { return rect.Height; }
150                         set { rect.Height = value; }
151                 }
152
153                 internal int Width {
154                         get { return rect.Width; }
155                         set { rect.Width = value; }
156                 }
157
158                 internal int X {
159                         get { return rect.X; }
160                         set { rect.X = value; }
161                 }
162
163                 internal int Y {
164                         get { return rect.Y; }
165                         set { rect.Y = value; }
166                 }
167
168                 internal MenuTracker Tracker {
169                         get {
170                                 Menu top = this;
171                                 while (top.parent_menu != null)
172                                         top = top.parent_menu;
173
174                                 return top.tracker;
175                         }
176                 }
177                 #endregion Private Properties
178
179                 #region Public Methods
180
181                 protected void CloneMenu (Menu menuSrc)
182                 {
183                         Dispose (true);
184
185                         menu_items = new MenuItemCollection (this);
186
187                         for (int i = 0; i < menuSrc.MenuItems.Count ; i++)
188                                 menu_items.Add (menuSrc.MenuItems [i].CloneMenu ());
189                 }
190
191                 protected virtual IntPtr CreateMenuHandle ()
192                 {
193                         return IntPtr.Zero;
194                 }
195
196                 protected override void Dispose (bool disposing)
197                 {               
198                         if (disposing) {
199                                 if (menu_handle != IntPtr.Zero) {
200                                         menu_handle = IntPtr.Zero;
201                                 }
202                         }
203                 }
204
205                 // From Microsoft documentation is impossible to guess that 
206                 // this method is supossed to do
207                 //
208                 // update: according to MS documentation, first parameter is on of this
209                 // constant values FindHandle or FindShortcut, value depends from what
210                 // you what to search, by shortcut or handle. FindHandle and FindShortcut
211                 // is a constant fields and was defined for this class.  
212                 public MenuItem FindMenuItem (int type, IntPtr value)
213                 {
214                         return null;
215                 }
216
217                 protected int FindMergePosition (int mergeOrder)
218                 {
219                         int cnt = MenuItems.Count, cur, pos;
220                         
221                         for (pos = 0; pos < cnt; ) {
222                                 cur = (pos + cnt) /2;
223                                 if (MenuItems[cur].MergeOrder > mergeOrder) {
224                                         cnt = cur;
225                                 } else  {
226                                         pos = cur +1;
227                                 }
228                         }
229                         
230                         return pos;
231                 }
232
233                 public ContextMenu GetContextMenu ()
234                 {
235                         for (Menu item = this; item != null; item = item.parent_menu) {
236                                 if (item is ContextMenu) {
237                                         return (ContextMenu) item;
238                                 }
239                         }
240                         
241                         return null;
242                 }
243
244                 public MainMenu GetMainMenu ()
245                 {                               
246                         for (Menu item = this; item != null; item = item.parent_menu) {
247                                 if (item is MainMenu) {
248                                         return (MainMenu) item;
249                                 }                               
250                         }
251                         
252                         return null;
253                 }
254
255                 internal virtual void InvalidateItem (MenuItem item)
256                 {
257                         if (Wnd != null)
258                                 Wnd.Invalidate (item.bounds);
259                 }
260
261                 public virtual void MergeMenu (Menu menuSrc)
262                 {
263                         if (menuSrc == this)
264                                 throw new ArgumentException ("The menu cannot be merged with itself");
265                         
266                         for (int i = 0; i < menuSrc.MenuItems.Count; i++){
267                                                                 
268                                 switch (menuSrc.MenuItems[i].MergeType) {
269                                         case MenuMerge.Remove:  // Item not included
270                                                 break;
271                                                 
272                                         case MenuMerge.Add:
273                                         {
274                                                 int pos = FindMergePosition (menuSrc.MenuItems[i].MergeOrder);                                          
275                                                 MenuItems.Add (pos, menuSrc.MenuItems[i].CloneMenu ());
276                                                 break;                                  
277                                         }
278                                         
279                                         case MenuMerge.Replace:
280                                         case MenuMerge.MergeItems:
281                                         {
282                                                 int pos = FindMergePosition (menuSrc.MenuItems[i].MergeOrder - 1);                                              
283                                                 MenuItems.Insert (pos, menuSrc.MenuItems[i].CloneMenu ());
284                                                 
285                                                 break;
286                                         }
287                                         
288                                         default:
289                                                 break;
290                                 }                       
291                         }               
292                 }
293
294                 protected internal virtual bool ProcessCmdKey (ref Message msg, Keys keyData)
295                 {
296                         if (tracker == null)
297                                 return false;
298                         return tracker.ProcessKeys (ref msg, keyData);
299                 }
300
301                 public override string ToString ()
302                 {
303                         return base.ToString () + ", Items.Count: " + MenuItems.Count;
304                 }
305
306                 #endregion Public Methods
307                 static object MenuChangedEvent = new object ();
308
309                 internal event EventHandler MenuChanged {
310                         add { Events.AddHandler (MenuChangedEvent, value); }
311                         remove { Events.RemoveHandler (MenuChangedEvent, value); }
312                 }
313
314                 [ListBindable(false)]
315                 public class MenuItemCollection : IList, ICollection, IEnumerable
316                 {
317                         private Menu owner;
318                         private ArrayList items = new ArrayList ();
319
320                         public MenuItemCollection (Menu owner)
321                         {
322                                 this.owner = owner;
323                         }
324
325                         #region Public Properties
326
327                         public int Count {
328                                 get { return items.Count;}
329                         }
330
331                         public bool IsReadOnly {
332                                 get { return false; }
333                         }
334
335                         bool ICollection.IsSynchronized {
336                                 get { return false;}
337                         }
338
339                         object ICollection.SyncRoot {
340                                 get { return this;}
341                         }
342
343                         bool IList.IsFixedSize {
344                                 get { return false;}
345                         }
346
347                         public virtual MenuItem this [int index] {
348                                 get {
349                                         if (index < 0 || index >= Count)
350                                                 throw new ArgumentOutOfRangeException ("Index of out range");
351
352                                         return (MenuItem) items[index];
353                                 }
354                         }
355
356                         object IList.this[int index] {
357                                 get { return items[index]; }
358                                 set { throw new NotSupportedException (); }
359                         }
360
361                         #endregion Public Properties
362
363                         #region Public Methods
364
365                         public virtual int Add (MenuItem mi)
366                         {
367                                 if (mi.Parent != null)
368                                         mi.Parent.MenuItems.Remove (mi);
369                                 
370                                 items.Add (mi);
371                                 mi.Index = items.Count - 1;
372                                 UpdateItem (mi);
373                                 
374                                 owner.OnMenuChanged (EventArgs.Empty);
375                                 if (owner.parent_menu != null)
376                                         owner.parent_menu.OnMenuChanged (EventArgs.Empty);
377                                 return items.Count - 1;
378                         }
379
380                         internal void AddNoEvents (MenuItem mi)
381                         {
382                                 if (mi.Parent != null)
383                                         mi.Parent.MenuItems.Remove (mi);
384                                 
385                                 items.Add (mi);
386                                 mi.Index = items.Count - 1;
387                                 mi.parent_menu = owner;
388                         }
389
390                         public virtual MenuItem Add (string s)
391                         {
392                                 MenuItem item = new MenuItem (s);
393                                 Add (item);
394                                 return item;
395                         }
396
397                         public virtual int Add (int index, MenuItem mi)
398                         {
399                                 if (index < 0 || index > Count)
400                                         throw new ArgumentOutOfRangeException ("Index of out range");
401
402                                 ArrayList new_items = new ArrayList (Count + 1);
403
404                                 for (int i = 0; i < index; i++)
405                                         new_items.Add (items[i]);
406
407                                 new_items.Add (mi);
408
409                                 for (int i = index; i < Count; i++)
410                                         new_items.Add (items[i]);
411
412                                 items = new_items;
413                                 UpdateItemsIndices ();                          
414                                 UpdateItem (mi);
415
416                                 return index;
417                         }
418
419                         private void UpdateItem (MenuItem mi)
420                         {
421                                 mi.parent_menu = owner;
422                                 owner.OnMenuChanged (EventArgs.Empty);
423                                 if (owner.parent_menu != null)
424                                         owner.parent_menu.OnMenuChanged (EventArgs.Empty);
425                                 if (owner.Tracker != null)
426                                         owner.Tracker.AddShortcuts (mi);
427                         }
428
429                         internal void Insert (int index, MenuItem mi)
430                         {
431                                 if (index < 0 || index > Count)
432                                         throw new ArgumentOutOfRangeException ("Index of out range");
433                                 UpdateItemsIndices ();
434                                 UpdateItem (mi);
435                         }
436
437                         public virtual MenuItem Add (string s, EventHandler e)
438                         {
439                                 MenuItem item = new MenuItem (s, e);
440                                 Add (item);
441
442                                 return item;
443                         }
444
445                         public virtual MenuItem Add (string s, MenuItem[] items)
446                         {
447                                 MenuItem item = new MenuItem (s, items);
448                                 Add (item);
449
450                                 return item;
451                         }
452
453                         public virtual void AddRange (MenuItem[] items)
454                         {
455                                 if (items == null)
456                                         throw new ArgumentNullException ("items");
457
458                                 foreach (MenuItem mi in items)
459                                         Add (mi);
460                         }
461
462                         public virtual void Clear ()
463                         {
464                                 MenuTracker tracker = owner.Tracker;
465                                 foreach (MenuItem item in items) {
466                                         if (tracker != null)
467                                                 tracker.RemoveShortcuts (item);
468                                         item.parent_menu = null;
469                                 }
470                                 items.Clear ();
471                                 owner.OnMenuChanged (EventArgs.Empty);
472                         }
473
474                         public bool Contains (MenuItem value)
475                         {
476                                 return items.Contains (value);
477                         }
478
479                         public void CopyTo (Array dest, int index)
480                         {
481                                 items.CopyTo (dest, index);
482                         }
483
484                         public IEnumerator GetEnumerator ()
485                         {
486                                 return items.GetEnumerator ();
487                         }
488
489                         int IList.Add (object value)
490                         {
491                                 return Add ((MenuItem)value);
492                         }
493
494                         bool IList.Contains (object value)
495                         {
496                                 return Contains ((MenuItem)value);
497                         }
498
499                         int IList.IndexOf (object value)
500                         {
501                                 return IndexOf ((MenuItem)value);
502                         }
503
504                         void IList.Insert (int index, object value)
505                         {
506                                 Insert (index, (MenuItem) value);
507                         }
508
509                         void IList.Remove (object value)
510                         {
511                                 Remove ((MenuItem) value);
512                         }
513
514                         public int IndexOf (MenuItem value)
515                         {
516                                 return items.IndexOf (value);
517                         }
518
519                         public virtual void Remove (MenuItem item)
520                         {
521                                 RemoveAt (item.Index);
522                         }
523
524                         public virtual void RemoveAt (int index)
525                         {
526                                 if (index < 0 || index >= Count)
527                                         throw new ArgumentOutOfRangeException ("Index of out range");
528
529                                 MenuItem item = (MenuItem) items [index];
530                                 MenuTracker tracker = owner.Tracker;
531                                 if (tracker != null)
532                                         tracker.RemoveShortcuts (item);
533                                 item.parent_menu = null;
534
535                                 items.RemoveAt (index);
536
537                                 UpdateItemsIndices ();
538                                 owner.OnMenuChanged (EventArgs.Empty);
539                         }
540
541                         #endregion Public Methods
542
543                         #region Private Methods
544
545                         private void UpdateItemsIndices ()
546                         {
547                                 for (int i = 0; i < Count; i++) // Recalculate indeces
548                                         ((MenuItem)items[i]).Index = i;
549                         }
550
551                         #endregion Private Methods
552                 }
553         }
554 }
555
556