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