8cad840c4eef4f16614d9aad46d2f59a2cf8512d
[mono.git] / mcs / class / Managed.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                 
178                 internal void FireMenuActivate ()
179                 {
180                         // The tracker lets us know when the form is clicked or loses focus
181                         ToolStripManager.AppClicked += new EventHandler (ToolStripMenuTracker_AppClicked);
182                         ToolStripManager.AppFocusChange += new EventHandler (ToolStripMenuTracker_AppFocusChange);
183                         
184                         this.OnMenuActivate (EventArgs.Empty);
185                 }
186
187                 internal void FireMenuDeactivate ()
188                 {
189                         // Detach from the tracker
190                         ToolStripManager.AppClicked -= new EventHandler (ToolStripMenuTracker_AppClicked); ;
191                         ToolStripManager.AppFocusChange -= new EventHandler (ToolStripMenuTracker_AppFocusChange);
192                 
193                         this.OnMenuDeactivate (EventArgs.Empty);
194                 }
195
196                 internal override bool OnMenuKey ()
197                 {
198                         // Set ourselves active and select our first item
199                         ToolStripManager.SetActiveToolStrip (this, true);
200                         ToolStripItem tsi = this.SelectNextToolStripItem (null, true);
201                         
202                         if (tsi == null)
203                                 return false;
204                                 
205                         if (tsi is MdiControlStrip.SystemMenuItem)
206                                 this.SelectNextToolStripItem (tsi, true);
207                                 
208                         return true;
209                 }
210                 
211                 private void ToolStripMenuTracker_AppFocusChange (object sender, EventArgs e)
212                 {
213                         this.GetTopLevelToolStrip ().Dismiss (ToolStripDropDownCloseReason.AppFocusChange);
214                 }
215
216                 private void ToolStripMenuTracker_AppClicked (object sender, EventArgs e)
217                 {
218                         this.GetTopLevelToolStrip ().Dismiss (ToolStripDropDownCloseReason.AppClicked);
219                 }
220                 
221                 internal void RefreshMdiItems ()
222                 {
223                         if (this.mdi_window_list_item == null)
224                                 return;
225                         
226                         Form parent_form = this.FindForm ();
227                         
228                         if (parent_form == null || parent_form.MainMenuStrip != this)
229                                 return;
230                                 
231                         MdiClient mdi = parent_form.MdiContainer;
232                         
233                         // If there isn't a MdiContainer, we don't need to worry about MdiItems  :)
234                         if (mdi == null)
235                                 return;
236                                 
237                         // Make a copy so we can delete from the real one
238                         ToolStripItem[] loopitems = new ToolStripItem[this.mdi_window_list_item.DropDownItems.Count];
239                         this.mdi_window_list_item.DropDownItems.CopyTo (loopitems, 0);
240
241                         // If the mdi child has been removed, remove our menu item
242                         foreach (ToolStripItem tsi in loopitems)
243                                 if (tsi is ToolStripMenuItem && (tsi as ToolStripMenuItem).IsMdiWindowListEntry)
244                                         if (!mdi.mdi_child_list.Contains ((tsi as ToolStripMenuItem).MdiClientForm) || !(tsi as ToolStripMenuItem).MdiClientForm.Visible)
245                                                 this.mdi_window_list_item.DropDownItems.Remove (tsi);
246
247                         // Add the new forms and update state
248                         for (int i = 0; i < mdi.mdi_child_list.Count; i++) {
249                                 Form mdichild = (Form)mdi.mdi_child_list[i];
250                                 ToolStripMenuItem tsi;
251                                 
252                                 if (!mdichild.Visible)
253                                         continue;
254                                         
255                                 if ((tsi = FindMdiMenuItemOfForm (mdichild)) == null) {
256                                         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))
257                                                 this.mdi_window_list_item.DropDownItems.Add (new ToolStripSeparator ());
258                                                 
259                                         tsi = new ToolStripMenuItem ();
260                                         tsi.MdiClientForm = mdichild;
261                                         this.mdi_window_list_item.DropDownItems.Add (tsi);
262                                 }
263                                 
264                                 tsi.Text = string.Format ("&{0} {1}", i + 1, mdichild.Text);
265                                 tsi.Checked = parent_form.ActiveMdiChild == mdichild;
266                         }
267                         
268                         // Check that everything is in the correct order
269                         if (NeedToReorderMdi ())
270                                 ReorderMdiMenu ();
271                 }
272                 
273                 private ToolStripMenuItem FindMdiMenuItemOfForm (Form f)
274                 {
275                         // Not terribly efficient, but Mdi window lists shouldn't get too big
276                         foreach (ToolStripItem tsi in this.mdi_window_list_item.DropDownItems)
277                                 if (tsi is ToolStripMenuItem && (tsi as ToolStripMenuItem).MdiClientForm == f)
278                                         return (ToolStripMenuItem)tsi;
279                                         
280                         return null;
281                 }
282
283                 private int CountMdiMenuItems ()
284                 {
285                         int count = 0;
286                         
287                         foreach (ToolStripItem tsi in this.mdi_window_list_item.DropDownItems)
288                                 if (tsi is ToolStripMenuItem && (tsi as ToolStripMenuItem).IsMdiWindowListEntry)
289                                         count++;
290                                         
291                         return count;
292                 }
293                 
294                 private bool NeedToReorderMdi ()
295                 {
296                         // Mdi menus must be: User Items, Separator, Mdi Items
297                         bool seenMdi = false;
298                         
299                         foreach (ToolStripItem tsi in this.mdi_window_list_item.DropDownItems) {
300                                 if (tsi is ToolStripMenuItem) {
301                                         if (!(tsi as ToolStripMenuItem).IsMdiWindowListEntry) {
302                                                 if (seenMdi)
303                                                         return true;
304                                         } else 
305                                                 seenMdi = true;
306                                 }
307                         }
308                         
309                         return false;
310                 }
311
312                 private void ReorderMdiMenu ()
313                 {
314                         ToolStripItem[] loopitems = new ToolStripItem[this.mdi_window_list_item.DropDownItems.Count];
315                         this.mdi_window_list_item.DropDownItems.CopyTo (loopitems, 0);
316
317                         this.mdi_window_list_item.DropDownItems.Clear ();
318
319                         foreach (ToolStripItem tsi in loopitems)
320                                 if (tsi is ToolStripSeparator || !(tsi as ToolStripMenuItem).IsMdiWindowListEntry)
321                                         this.mdi_window_list_item.DropDownItems.Add (tsi);
322         
323                         int count = this.mdi_window_list_item.DropDownItems.Count;
324                         
325                         if (count > 0 && !(this.mdi_window_list_item.DropDownItems[count - 1] is ToolStripSeparator))
326                                 this.mdi_window_list_item.DropDownItems.Add (new ToolStripSeparator ());
327
328                         foreach (ToolStripItem tsi in loopitems)
329                                 if (tsi is ToolStripMenuItem && (tsi as ToolStripMenuItem).IsMdiWindowListEntry)
330                                         this.mdi_window_list_item.DropDownItems.Add (tsi);
331                 }
332                 #endregion
333
334                 #region MenuStripAccessibleObject
335                 private class MenuStripAccessibleObject : AccessibleObject
336                 {
337                 }
338                 #endregion
339
340         }
341         
342         #region MdiWindowListItemConverter
343         internal class MdiWindowListItemConverter : TypeConverter
344         {
345         }
346         #endregion
347 }