Merge pull request #2311 from mlancione/master
[mono.git] / mcs / class / System.Windows.Forms / System.Windows.Forms / MenuStrip.cs
1 //
2 // MenuStrip.cs
3 //
4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the
6 // "Software"), to deal in the Software without restriction, including
7 // without limitation the rights to use, copy, modify, merge, publish,
8 // distribute, sublicense, and/or sell copies of the Software, and to
9 // permit persons to whom the Software is furnished to do so, subject to
10 // the following conditions:
11 // 
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
14 // 
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 //
23 // Copyright (c) 2006 Jonathan Pobst
24 //
25 // Authors:
26 //      Jonathan Pobst (monkey@jpobst.com)
27 //
28
29 using System;
30 using System.Drawing;
31 using System.ComponentModel;
32 using System.Runtime.InteropServices;
33
34 namespace System.Windows.Forms
35 {
36         [ClassInterface (ClassInterfaceType.AutoDispatch)]
37         [ComVisible (true)]
38         public class MenuStrip : ToolStrip
39         {
40                 private ToolStripMenuItem mdi_window_list_item;
41
42                 public MenuStrip () : base ()
43                 {
44                         base.CanOverflow = false;
45                         this.GripStyle = ToolStripGripStyle.Hidden;
46                         this.Stretch = true;
47                         this.Dock = DockStyle.Top;
48                 }
49
50                 #region Public Properties
51                 [DefaultValue (false)]
52                 [Browsable (false)]
53                 public new bool CanOverflow {
54                         get { return base.CanOverflow; }
55                         set { base.CanOverflow = value; }
56                 }
57
58                 [DefaultValue (ToolStripGripStyle.Hidden)]
59                 public new ToolStripGripStyle GripStyle {
60                         get { return base.GripStyle; }
61                         set { base.GripStyle = value; }
62                 }
63
64                 [DefaultValue (null)]
65                 [MergableProperty (false)]
66                 [TypeConverter (typeof (MdiWindowListItemConverter))]
67                 public ToolStripMenuItem MdiWindowListItem {
68                         get { return this.mdi_window_list_item; }
69                         set { 
70                                 if (this.mdi_window_list_item != value) {
71                                         this.mdi_window_list_item = value;
72                                         this.RefreshMdiItems ();
73                                 }
74                         }
75                 }
76                 
77                 [DefaultValue (false)]
78                 public new bool ShowItemToolTips {
79                         get { return base.ShowItemToolTips; }
80                         set { base.ShowItemToolTips = value; }
81                 }
82
83                 [DefaultValue (true)]
84                 public new bool Stretch {
85                         get { return base.Stretch; }
86                         set { base.Stretch = value; }
87                 }
88                 #endregion
89
90                 #region Protected Properties
91                 protected override Padding DefaultGripMargin { get { return new Padding (2, 2, 0, 2); } }
92                 protected override Padding DefaultPadding { get { return new Padding (6, 2, 0, 2); } }
93                 protected override bool DefaultShowItemToolTips { get { return false; } }
94                 protected override Size DefaultSize { get { return new Size (200, 24); } }
95                 #endregion
96
97                 #region Protected Methods
98                 protected override AccessibleObject CreateAccessibilityInstance ()
99                 {
100                         return new MenuStripAccessibleObject ();
101                 }
102                 
103                 protected internal override ToolStripItem CreateDefaultItem (string text, Image image, EventHandler onClick)
104                 {
105                         return new ToolStripMenuItem (text, image, onClick);
106                 }
107
108                 protected virtual void OnMenuActivate (EventArgs e)
109                 {
110                         EventHandler eh = (EventHandler)(Events [MenuActivateEvent]);
111                         if (eh != null)
112                                 eh (this, e);
113                 }
114
115                 protected virtual void OnMenuDeactivate (EventArgs e)
116                 {
117                         EventHandler eh = (EventHandler)(Events [MenuDeactivateEvent]);
118                         if (eh != null)
119                                 eh (this, e);
120                 }
121
122                 protected override bool ProcessCmdKey (ref Message m, Keys keyData)
123                 {
124                         return base.ProcessCmdKey (ref m, keyData);
125                 }
126
127                 protected override void WndProc (ref Message m)
128                 {
129                         base.WndProc (ref m);
130                 }
131                 #endregion
132
133                 #region Public Events
134                 static object MenuActivateEvent = new object ();
135                 static object MenuDeactivateEvent = new object ();
136
137                 public event EventHandler MenuActivate {
138                         add { Events.AddHandler (MenuActivateEvent, value); }
139                         remove { Events.RemoveHandler (MenuActivateEvent, value); }
140                 }
141
142                 public event EventHandler MenuDeactivate {
143                         add { Events.AddHandler (MenuDeactivateEvent, value); }
144                         remove { Events.RemoveHandler (MenuDeactivateEvent, value); }
145                 }
146                 #endregion
147
148                 #region Internal Properties
149                 internal override bool KeyboardActive {
150                         get { return base.KeyboardActive; }
151                         set {
152                                 if (base.KeyboardActive != value) {
153                                         base.KeyboardActive = value;
154                                         
155                                         if (value)
156                                                 this.OnMenuActivate (EventArgs.Empty);
157                                         else
158                                                 this.OnMenuDeactivate (EventArgs.Empty);
159                                 }
160                         }
161                 }
162                 
163                 internal bool MenuDroppedDown {
164                         get { return this.menu_selected; }
165                         set { this.menu_selected = value; }
166                 }
167                 #endregion
168                 
169                 #region Internal Methods
170                 internal override void Dismiss (ToolStripDropDownCloseReason reason)
171                 {
172                         // Make sure we don't auto-dropdown next time we're activated
173                         this.MenuDroppedDown = false;
174                         
175                         base.Dismiss (reason);
176
177                         this.FireMenuDeactivate ();
178                 }
179                 
180                 internal void FireMenuActivate ()
181                 {
182                         // The tracker lets us know when the form is clicked or loses focus
183                         ToolStripManager.AppClicked += new EventHandler (ToolStripMenuTracker_AppClicked);
184                         ToolStripManager.AppFocusChange += new EventHandler (ToolStripMenuTracker_AppFocusChange);
185                         
186                         this.OnMenuActivate (EventArgs.Empty);
187                 }
188
189                 internal void FireMenuDeactivate ()
190                 {
191                         // Detach from the tracker
192                         ToolStripManager.AppClicked -= new EventHandler (ToolStripMenuTracker_AppClicked); ;
193                         ToolStripManager.AppFocusChange -= new EventHandler (ToolStripMenuTracker_AppFocusChange);
194                 
195                         this.OnMenuDeactivate (EventArgs.Empty);
196                 }
197
198                 internal override bool OnMenuKey ()
199                 {
200                         // Set ourselves active and select our first item
201                         ToolStripManager.SetActiveToolStrip (this, true);
202                         ToolStripItem tsi = this.SelectNextToolStripItem (null, true);
203                         
204                         if (tsi == null)
205                                 return false;
206                                 
207                         if (tsi is MdiControlStrip.SystemMenuItem)
208                                 this.SelectNextToolStripItem (tsi, true);
209                                 
210                         return true;
211                 }
212                 
213                 private void ToolStripMenuTracker_AppFocusChange (object sender, EventArgs e)
214                 {
215                         this.GetTopLevelToolStrip ().Dismiss (ToolStripDropDownCloseReason.AppFocusChange);
216                 }
217
218                 private void ToolStripMenuTracker_AppClicked (object sender, EventArgs e)
219                 {
220                         this.GetTopLevelToolStrip ().Dismiss (ToolStripDropDownCloseReason.AppClicked);
221                 }
222                 
223                 internal void RefreshMdiItems ()
224                 {
225                         if (this.mdi_window_list_item == null)
226                                 return;
227                         
228                         Form parent_form = this.FindForm ();
229                         
230                         if (parent_form == null || parent_form.MainMenuStrip != this)
231                                 return;
232                                 
233                         MdiClient mdi = parent_form.MdiContainer;
234                         
235                         // If there isn't a MdiContainer, we don't need to worry about MdiItems  :)
236                         if (mdi == null)
237                                 return;
238                                 
239                         // Make a copy so we can delete from the real one
240                         ToolStripItem[] loopitems = new ToolStripItem[this.mdi_window_list_item.DropDownItems.Count];
241                         this.mdi_window_list_item.DropDownItems.CopyTo (loopitems, 0);
242
243                         // If the mdi child has been removed, remove our menu item
244                         foreach (ToolStripItem tsi in loopitems)
245                                 if (tsi is ToolStripMenuItem && (tsi as ToolStripMenuItem).IsMdiWindowListEntry)
246                                         if (!mdi.mdi_child_list.Contains ((tsi as ToolStripMenuItem).MdiClientForm) || !(tsi as ToolStripMenuItem).MdiClientForm.Visible)
247                                                 this.mdi_window_list_item.DropDownItems.Remove (tsi);
248
249                         // Add the new forms and update state
250                         for (int i = 0; i < mdi.mdi_child_list.Count; i++) {
251                                 Form mdichild = (Form)mdi.mdi_child_list[i];
252                                 ToolStripMenuItem tsi;
253                                 
254                                 if (!mdichild.Visible)
255                                         continue;
256                                         
257                                 if ((tsi = FindMdiMenuItemOfForm (mdichild)) == null) {
258                                         if (CountMdiMenuItems () == 0 && this.mdi_window_list_item.DropDownItems.Count > 0 && !(this.mdi_window_list_item.DropDownItems[this.mdi_window_list_item.DropDownItems.Count - 1] is ToolStripSeparator))
259                                                 this.mdi_window_list_item.DropDownItems.Add (new ToolStripSeparator ());
260                                                 
261                                         tsi = new ToolStripMenuItem ();
262                                         tsi.MdiClientForm = mdichild;
263                                         this.mdi_window_list_item.DropDownItems.Add (tsi);
264                                 }
265                                 
266                                 tsi.Text = string.Format ("&{0} {1}", i + 1, mdichild.Text);
267                                 tsi.Checked = parent_form.ActiveMdiChild == mdichild;
268                         }
269                         
270                         // Check that everything is in the correct order
271                         if (NeedToReorderMdi ())
272                                 ReorderMdiMenu ();
273                 }
274                 
275                 private ToolStripMenuItem FindMdiMenuItemOfForm (Form f)
276                 {
277                         // Not terribly efficient, but Mdi window lists shouldn't get too big
278                         foreach (ToolStripItem tsi in this.mdi_window_list_item.DropDownItems)
279                                 if (tsi is ToolStripMenuItem && (tsi as ToolStripMenuItem).MdiClientForm == f)
280                                         return (ToolStripMenuItem)tsi;
281                                         
282                         return null;
283                 }
284
285                 private int CountMdiMenuItems ()
286                 {
287                         int count = 0;
288                         
289                         foreach (ToolStripItem tsi in this.mdi_window_list_item.DropDownItems)
290                                 if (tsi is ToolStripMenuItem && (tsi as ToolStripMenuItem).IsMdiWindowListEntry)
291                                         count++;
292                                         
293                         return count;
294                 }
295                 
296                 private bool NeedToReorderMdi ()
297                 {
298                         // Mdi menus must be: User Items, Separator, Mdi Items
299                         bool seenMdi = false;
300                         
301                         foreach (ToolStripItem tsi in this.mdi_window_list_item.DropDownItems) {
302                                 if (tsi is ToolStripMenuItem) {
303                                         if (!(tsi as ToolStripMenuItem).IsMdiWindowListEntry) {
304                                                 if (seenMdi)
305                                                         return true;
306                                         } else 
307                                                 seenMdi = true;
308                                 }
309                         }
310                         
311                         return false;
312                 }
313
314                 private void ReorderMdiMenu ()
315                 {
316                         ToolStripItem[] loopitems = new ToolStripItem[this.mdi_window_list_item.DropDownItems.Count];
317                         this.mdi_window_list_item.DropDownItems.CopyTo (loopitems, 0);
318
319                         this.mdi_window_list_item.DropDownItems.Clear ();
320
321                         foreach (ToolStripItem tsi in loopitems)
322                                 if (tsi is ToolStripSeparator || !(tsi as ToolStripMenuItem).IsMdiWindowListEntry)
323                                         this.mdi_window_list_item.DropDownItems.Add (tsi);
324         
325                         int count = this.mdi_window_list_item.DropDownItems.Count;
326                         
327                         if (count > 0 && !(this.mdi_window_list_item.DropDownItems[count - 1] is ToolStripSeparator))
328                                 this.mdi_window_list_item.DropDownItems.Add (new ToolStripSeparator ());
329
330                         foreach (ToolStripItem tsi in loopitems)
331                                 if (tsi is ToolStripMenuItem && (tsi as ToolStripMenuItem).IsMdiWindowListEntry)
332                                         this.mdi_window_list_item.DropDownItems.Add (tsi);
333                 }
334                 #endregion
335
336                 #region MenuStripAccessibleObject
337                 private class MenuStripAccessibleObject : AccessibleObject
338                 {
339                 }
340                 #endregion
341
342         }
343         
344         #region MdiWindowListItemConverter
345         internal class MdiWindowListItemConverter : TypeConverter
346         {
347         }
348         #endregion
349 }