* X11Keyboard.cs: Detect and use the num lock mask.
[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 Novell, Inc.
21 //
22 // Authors:
23 //      Jordi Mas i Hernandez, jordi@ximian.com
24 //
25 //      TODO:
26 //              - Merge menus
27 //              - MDI integration
28 //              - ShortCut navigation
29 //
30 // NOT COMPLETE
31
32 using System.Collections;
33 using System.ComponentModel;
34
35 namespace System.Windows.Forms
36 {
37         public abstract class Menu : Component
38         {
39                 internal MenuItemCollection menu_items;
40                 internal IntPtr menu_handle = IntPtr.Zero;
41                 internal bool is_dirty = true;
42                 internal bool creating = false;
43
44                 public const int FindHandle = 0;
45                 public const int FindShortcut = 1;
46
47                 protected Menu (MenuItem[] items)
48                 {
49                         menu_items = new MenuItemCollection (this);
50
51                         if (items != null)
52                                 menu_items.AddRange (items);
53                 }
54
55
56                 #region Public Properties
57                 public IntPtr Handle {
58                         get {
59                                 if (IsDirty && creating == false) {                                     
60                                         Dispose (true);
61                                 }
62
63                                 if (menu_handle == IntPtr.Zero) {                                       
64                                         menu_handle = CreateMenuHandle ();
65                                         CreateItems ();
66                                         IsDirty = false;
67                                 }
68
69                                 return menu_handle;
70                         }
71                 }
72
73                 public virtual bool IsParent {
74                         get {
75                                 if (menu_items != null && menu_items.Count > 0)
76                                         return true;
77                                 else
78                                         return false;
79                         }
80                 }
81
82                 public MenuItem MdiListItem {
83                         get {
84                                 throw new NotImplementedException ();
85                         }
86                 }
87
88                 public MenuItemCollection MenuItems {
89                         get { return menu_items; }
90                 }
91
92                 #endregion Public Properties
93
94                 #region Private Properties
95
96                 internal bool IsDirty {
97                         get { return is_dirty; }
98                         set { is_dirty = value; }
99                 }
100
101                 #endregion Private Properties
102
103                 #region Public Methods
104
105                 protected void CloneMenu (Menu menuSrc)
106                 {
107                         Dispose (true);
108
109                         menu_items = new MenuItemCollection (this);
110
111                         for (int i = 0; i < menuSrc.MenuItems.Count ; i++)
112                                 menu_items.Add (menuSrc.MenuItems [i]);
113                 }
114
115                 protected virtual IntPtr CreateMenuHandle ()
116                 {
117                         IntPtr menu;
118
119                         menu = MenuAPI.CreatePopupMenu (this);
120                         return menu;
121                 }
122
123                 protected override void Dispose (bool disposing)
124                 {               
125                         if (disposing) {
126                                 if (menu_handle != IntPtr.Zero)
127                                         MenuAPI.DestroyMenu (menu_handle);
128                                         menu_handle = IntPtr.Zero;
129                         }
130                 }
131
132                 public MenuItem FindMenuItem (int type, IntPtr value)
133                 {
134                         throw new NotImplementedException ();
135                 }
136
137                 protected int FindMergePosition (int mergeOrder)
138                 {
139                         throw new NotImplementedException ();
140                 }
141
142                 public ContextMenu GetContextMenu ()
143                 {
144                         if (this is ContextMenu)
145                                 return (ContextMenu) this;
146                         else
147                                 return null;
148                 }
149
150                 public MainMenu GetMainMenu ()
151                 {
152                         if (this is MainMenu)
153                                 return (MainMenu) this;
154                         else
155                                 return null;
156                 }
157
158                 public virtual void MergeMenu (Menu menuSrc)
159                 {
160                         if (menuSrc == this)
161                                 throw new ArgumentException ("The menu cannot be merged with itself");
162
163                 }
164
165                 protected internal virtual bool ProcessCmdKey (ref Message msg, Keys keyData)
166                 {
167                         return false;
168                 }
169
170                 public override string ToString ()
171                 {
172                         return base.ToString ();
173                 }
174
175                 #endregion Public Methods
176
177                 #region Private Methods
178
179                 internal void CreateItems ()
180                 {
181                         creating = true;
182
183                         for (int i = 0; i < menu_items.Count; i++)
184                                 menu_items[i].Create ();
185
186                         creating = false;
187                 }
188
189                 #endregion Private Methods
190
191                 public class MenuItemCollection : IList, ICollection, IEnumerable
192                 {
193                         private Menu owner;
194                         private ArrayList items = new ArrayList ();
195
196                         public MenuItemCollection (Menu owner)
197                         {
198                                 this.owner = owner;
199                         }
200
201                         #region Public Properties
202
203                         public virtual int Count {
204                                 get { return items.Count;}
205                         }
206
207                         public virtual bool IsReadOnly {
208                                 get { return false;}
209                         }
210
211                         bool ICollection.IsSynchronized {
212                                 get { return false;}
213                         }
214
215                         object ICollection.SyncRoot {
216                                 get { return this;}
217                         }
218
219                         bool IList.IsFixedSize {
220                                 get { return false;}
221                         }
222
223                         public MenuItem this [int index] {
224                                 get {
225                                         if (index < 0 || index >= Count)
226                                                 throw new ArgumentOutOfRangeException ("Index of out range");
227
228                                         return (MenuItem) items[index];
229                                 }
230                         }
231
232                         object IList.this[int index] {
233                                 get { return items[index]; }
234                                 set { throw new NotSupportedException (); }
235                         }
236
237                         #endregion Public Properties
238
239                         #region Public Methods
240
241                         public virtual int Add (MenuItem mi)
242                         {
243                                 mi.parent_menu = owner;
244                                 mi.Index = items.Count;
245                                 items.Add (mi);
246
247                                 owner.IsDirty = true;
248                                 return items.Count - 1;
249                         }
250
251                         public virtual MenuItem Add (string s)
252                         {
253                                 MenuItem item = new MenuItem (s);
254                                 Add (item);
255                                 return item;
256                         }
257
258                         public virtual int Add (int index, MenuItem mi)
259                         {
260                                 if (index < 0 || index >= Count)
261                                         throw new ArgumentOutOfRangeException ("Index of out range");
262
263                                 ArrayList new_items = new ArrayList (Count + 1);
264
265                                 for (int i = 0; i < index; i++)
266                                         new_items.Add (items[i]);
267
268                                 new_items.Add (mi);
269
270                                 for (int i = index; i < Count; i++)
271                                         new_items.Add (items[i]);
272
273                                 items = new_items;
274                                 UpdateItemsIndices ();
275                                 owner.IsDirty = true;
276
277                                 return index;
278                         }
279
280                         public virtual MenuItem Add (string s, EventHandler e)
281                         {
282                                 MenuItem item = new MenuItem (s, e);
283                                 Add (item);
284
285                                 return item;
286                         }
287
288                         public virtual MenuItem Add (string s, MenuItem[] items)
289                         {
290                                 MenuItem item = new MenuItem (s, items);
291                                 Add (item);
292
293                                 return item;
294                         }
295
296                         public virtual void AddRange (MenuItem[] items)
297                         {
298                                 if (items == null)
299                                         throw new ArgumentNullException ("items");
300
301                                 foreach (MenuItem mi in items)
302                                         Add (mi);
303                         }
304
305                         public virtual void Clear ()
306                         {
307                                 items.Clear ();
308                                 owner.IsDirty = true;
309                         }
310
311                         public bool Contains (MenuItem value)
312                         {
313                                 return items.Contains (value);
314                         }
315
316                         public virtual void CopyTo (Array dest, int index)
317                         {
318                                 items.CopyTo (dest, index);
319                         }
320
321                         public virtual IEnumerator GetEnumerator ()
322                         {
323                                 return items.GetEnumerator ();
324                         }
325
326                         int IList.Add (object value)
327                         {
328                                 return Add ((MenuItem)value);
329                         }
330
331                         bool IList.Contains (object value)
332                         {
333                                 return Contains ((MenuItem)value);
334                         }
335
336                         int IList.IndexOf (object value)
337                         {
338                                 return IndexOf ((MenuItem)value);
339                         }
340
341                         void IList.Insert (int index, object value)
342                         {
343                                 Add (index, (MenuItem) value);
344                         }
345
346                         void IList.Remove (object value)
347                         {
348                                 Remove ((MenuItem) value);
349                         }
350
351                         public int IndexOf (MenuItem value)
352                         {
353                                 return items.IndexOf (value);
354                         }
355
356                         public virtual void Remove (MenuItem item)
357                         {
358                                 RemoveAt (item.Index);
359                         }
360
361                         public virtual void RemoveAt (int index)
362                         {
363                                 if (index < 0 || index >= Count)
364                                         throw new ArgumentOutOfRangeException ("Index of out range");
365
366                                 items.RemoveAt (index);
367
368                                 UpdateItemsIndices ();
369                                 owner.IsDirty = true;
370                         }
371
372                         #endregion Public Methods
373
374                         #region Private Methods
375
376                         private void UpdateItemsIndices ()
377                         {
378                                 for (int i = 0; i < Count; i++) // Recalculate indeces
379                                         ((MenuItem)items[i]).Index = i;
380                         }
381
382                         #endregion Private Methods
383                 }
384         }
385 }
386
387