* ImageList.cs: When the image stream is set pull all the images
[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 //              - MDI integration
27 //              - ShortCut navigation
28 //
29 // NOT COMPLETE
30
31 using System.Collections;
32 using System.ComponentModel;
33 using System.ComponentModel.Design;
34 using System.Reflection;
35 using System.Runtime.InteropServices;
36
37 namespace System.Windows.Forms
38 {
39         [Designer ("Microsoft.VisualStudio.Windows.Forms.MenuDesigner, Microsoft.VisualStudio, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", (string)null)]
40         [ToolboxItemFilter("System.Windows.Forms", ToolboxItemFilterType.Allow)]
41         [ListBindable(false)]
42         public abstract class Menu : Component
43         {
44                 internal MenuItemCollection menu_items;
45                 internal IntPtr menu_handle = IntPtr.Zero;
46                 internal bool is_dirty = true;
47                 internal bool creating = false;
48                 internal Menu parent_menu = null;
49
50                 public const int FindHandle = 0;
51                 public const int FindShortcut = 1;
52
53                 protected Menu (MenuItem[] items)
54                 {
55                         menu_items = new MenuItemCollection (this);
56
57                         if (items != null)
58                                 menu_items.AddRange (items);
59                 }
60
61
62                 #region Public Properties
63                 [BrowsableAttribute(false)]
64                 [EditorBrowsableAttribute(EditorBrowsableState.Advanced)]
65                 [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
66                 public IntPtr Handle {
67                         get {
68                                 if (IsDirty && creating == false) {                                     
69                                         Dispose (true);
70                                 }
71
72                                 if (menu_handle == IntPtr.Zero) {                                       
73                                         menu_handle = CreateMenuHandle ();
74                                         CreateItems ();
75                                         IsDirty = false;
76                                 }
77
78                                 return menu_handle;
79                         }
80                 }
81
82                 [BrowsableAttribute(false)]
83                 [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
84                 public virtual bool IsParent {
85                         get {
86                                 if (menu_items != null && menu_items.Count > 0)
87                                         return true;
88                                 else
89                                         return false;
90                         }
91                 }
92
93                 [BrowsableAttribute(false)]
94                 [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Hidden)]
95                 public MenuItem MdiListItem {
96                         get {
97                                 throw new NotImplementedException ();
98                         }
99                 }
100
101                 [BrowsableAttribute(false)]
102                 [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Content)]
103                 [MergableProperty(false)]
104                 public MenuItemCollection MenuItems {
105                         get { return menu_items; }
106                 }
107
108                 #endregion Public Properties
109
110                 #region Private Properties
111
112                 internal bool IsDirty {
113                         get { return is_dirty; }
114                         set { is_dirty = value; }
115                 }
116
117                 #endregion Private Properties
118
119                 #region Public Methods
120
121                 protected void CloneMenu (Menu menuSrc)
122                 {
123                         Dispose (true);
124
125                         menu_items = new MenuItemCollection (this);
126
127                         for (int i = 0; i < menuSrc.MenuItems.Count ; i++)
128                                 menu_items.Add (menuSrc.MenuItems [i]);
129                 }
130
131                 protected virtual IntPtr CreateMenuHandle ()
132                 {
133                         IntPtr menu;
134
135                         menu = MenuAPI.CreatePopupMenu (this);
136                         return menu;
137                 }
138
139                 protected override void Dispose (bool disposing)
140                 {               
141                         if (disposing) {
142                                 if (menu_handle != IntPtr.Zero)
143                                         MenuAPI.DestroyMenu (menu_handle);
144                                         menu_handle = IntPtr.Zero;
145                         }
146                 }
147
148                 // From Microsoft documentation is impossible to guess that 
149                 // this method is supossed to do
150                 public MenuItem FindMenuItem (int type, IntPtr value)
151                 {
152                         return null;
153                 }
154
155                 protected int FindMergePosition (int mergeOrder)
156                 {
157                         int cnt = MenuItems.Count, cur, pos;
158                         
159                         for (pos = 0; pos < cnt; ) {
160                                 cur = (pos + cnt) /2;
161                                 if (MenuItems[cur].MergeOrder > mergeOrder) {
162                                         cnt = cur;
163                                 } else  {
164                                         pos = cur +1;
165                                 }
166                         }
167                         
168                         return pos;
169                 }
170
171                 public ContextMenu GetContextMenu ()
172                 {
173                         for (Menu item = this; item != null; item = item.parent_menu) {
174                                 if (item is ContextMenu) {
175                                         return (ContextMenu) item;
176                                 }
177                         }
178                         
179                         return null;
180                 }
181
182                 public MainMenu GetMainMenu ()
183                 {                               
184                         for (Menu item = this; item != null; item = item.parent_menu) {
185                                 if (item is MainMenu) {
186                                         return (MainMenu) item;
187                                 }                               
188                         }
189                         
190                         return null;
191                 }
192
193                 public virtual void MergeMenu (Menu menuSrc)
194                 {
195                         if (menuSrc == this)
196                                 throw new ArgumentException ("The menu cannot be merged with itself");
197                         
198                         for (int i = 0; i < menuSrc.MenuItems.Count; i++){
199                                                                 
200                                 switch (menuSrc.MenuItems[i].MergeType) {
201                                         case MenuMerge.Remove:  // Item not included
202                                                 break;
203                                                 
204                                         case MenuMerge.Add:
205                                         {
206                                                 int pos = FindMergePosition (menuSrc.MenuItems[i].MergeOrder);                                          
207                                                 MenuItems.Add (pos, menuSrc.MenuItems[i].CloneMenu ());
208                                                 break;                                  
209                                         }
210                                         
211                                         case MenuMerge.Replace:
212                                         case MenuMerge.MergeItems:
213                                         {
214                                                 int pos = FindMergePosition (menuSrc.MenuItems[i].MergeOrder - 1);                                              
215                                                 MenuItems.Add (pos, menuSrc.MenuItems[i].CloneMenu ());
216                                                 
217                                                 break;
218                                         }
219                                         
220                                         default:
221                                                 break;
222                                 }                       
223                         }               
224                 }
225
226                 protected internal virtual bool ProcessCmdKey (ref Message msg, Keys keyData)
227                 {
228                         return false;
229                 }
230
231                 public override string ToString ()
232                 {
233                         return base.ToString () + ", Items.Count: " + MenuItems.Count;
234                 }
235
236                 #endregion Public Methods
237
238                 #region Private Methods
239
240                 internal void CreateItems ()
241                 {
242                         creating = true;
243
244                         for (int i = 0; i < menu_items.Count; i++)
245                                 menu_items[i].Create ();
246
247                         creating = false;
248                 }
249
250                 #endregion Private Methods
251
252                 [ListBindable(false)]
253                 public class MenuItemCollection : IList, ICollection, IEnumerable
254                 {
255                         private Menu owner;
256                         private ArrayList items = new ArrayList ();
257
258                         public MenuItemCollection (Menu owner)
259                         {
260                                 this.owner = owner;
261                         }
262
263                         #region Public Properties
264
265                         public virtual int Count {
266                                 get { return items.Count;}
267                         }
268
269                         public virtual bool IsReadOnly {
270                                 get { return false;}
271                         }
272
273                         bool ICollection.IsSynchronized {
274                                 get { return false;}
275                         }
276
277                         object ICollection.SyncRoot {
278                                 get { return this;}
279                         }
280
281                         bool IList.IsFixedSize {
282                                 get { return false;}
283                         }
284
285                         public MenuItem this [int index] {
286                                 get {
287                                         if (index < 0 || index >= Count)
288                                                 throw new ArgumentOutOfRangeException ("Index of out range");
289
290                                         return (MenuItem) items[index];
291                                 }
292                         }
293
294                         object IList.this[int index] {
295                                 get { return items[index]; }
296                                 set { throw new NotSupportedException (); }
297                         }
298
299                         #endregion Public Properties
300
301                         #region Public Methods
302
303                         public virtual int Add (MenuItem mi)
304                         {
305                                 mi.parent_menu = owner;
306                                 mi.Index = items.Count;
307                                 items.Add (mi);
308
309                                 owner.IsDirty = true;
310                                 return items.Count - 1;
311                         }
312
313                         public virtual MenuItem Add (string s)
314                         {
315                                 MenuItem item = new MenuItem (s);
316                                 Add (item);
317                                 return item;
318                         }
319
320                         public virtual int Add (int index, MenuItem mi)
321                         {
322                                 if (index < 0 || index > Count)
323                                         throw new ArgumentOutOfRangeException ("Index of out range");
324
325                                 ArrayList new_items = new ArrayList (Count + 1);
326
327                                 for (int i = 0; i < index; i++)
328                                         new_items.Add (items[i]);
329
330                                 new_items.Add (mi);
331
332                                 for (int i = index; i < Count; i++)
333                                         new_items.Add (items[i]);
334
335                                 items = new_items;
336                                 UpdateItemsIndices ();
337                                 owner.IsDirty = true;
338
339                                 return index;
340                         }
341
342                         public virtual MenuItem Add (string s, EventHandler e)
343                         {
344                                 MenuItem item = new MenuItem (s, e);
345                                 Add (item);
346
347                                 return item;
348                         }
349
350                         public virtual MenuItem Add (string s, MenuItem[] items)
351                         {
352                                 MenuItem item = new MenuItem (s, items);
353                                 Add (item);
354
355                                 return item;
356                         }
357
358                         public virtual void AddRange (MenuItem[] items)
359                         {
360                                 if (items == null)
361                                         throw new ArgumentNullException ("items");
362
363                                 foreach (MenuItem mi in items)
364                                         Add (mi);
365                         }
366
367                         public virtual void Clear ()
368                         {
369                                 items.Clear ();
370                                 owner.IsDirty = true;
371                         }
372
373                         public bool Contains (MenuItem value)
374                         {
375                                 return items.Contains (value);
376                         }
377
378                         public virtual void CopyTo (Array dest, int index)
379                         {
380                                 items.CopyTo (dest, index);
381                         }
382
383                         public virtual IEnumerator GetEnumerator ()
384                         {
385                                 return items.GetEnumerator ();
386                         }
387
388                         int IList.Add (object value)
389                         {
390                                 return Add ((MenuItem)value);
391                         }
392
393                         bool IList.Contains (object value)
394                         {
395                                 return Contains ((MenuItem)value);
396                         }
397
398                         int IList.IndexOf (object value)
399                         {
400                                 return IndexOf ((MenuItem)value);
401                         }
402
403                         void IList.Insert (int index, object value)
404                         {
405                                 Add (index, (MenuItem) value);
406                         }
407
408                         void IList.Remove (object value)
409                         {
410                                 Remove ((MenuItem) value);
411                         }
412
413                         public int IndexOf (MenuItem value)
414                         {
415                                 return items.IndexOf (value);
416                         }
417
418                         public virtual void Remove (MenuItem item)
419                         {
420                                 RemoveAt (item.Index);
421                         }
422
423                         public virtual void RemoveAt (int index)
424                         {
425                                 if (index < 0 || index >= Count)
426                                         throw new ArgumentOutOfRangeException ("Index of out range");
427
428                                 items.RemoveAt (index);
429
430                                 UpdateItemsIndices ();
431                                 owner.IsDirty = true;
432                         }
433
434                         #endregion Public Methods
435
436                         #region Private Methods
437
438                         private void UpdateItemsIndices ()
439                         {
440                                 for (int i = 0; i < Count; i++) // Recalculate indeces
441                                         ((MenuItem)items[i]).Index = i;
442                         }
443
444                         #endregion Private Methods
445                 }
446         }
447 }
448
449