* Monodoc/man-provider.cs: NEVER return a non-null string from
[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 #if NET_2_0
29
30 using System;
31 using System.Drawing;
32 using System.ComponentModel;
33 using System.Runtime.InteropServices;
34
35 namespace System.Windows.Forms
36 {
37         [ClassInterface (ClassInterfaceType.AutoDispatch)]
38         [ComVisible (true)]
39         public class MenuStrip : ToolStrip
40         {
41                 private ToolStripMenuItem mdi_window_list_item;
42
43                 public MenuStrip () : base ()
44                 {
45                         base.CanOverflow = false;
46                         this.GripStyle = ToolStripGripStyle.Hidden;
47                         this.Stretch = true;
48                         this.Dock = DockStyle.Top;
49                 }
50
51                 #region Public Properties
52                 [DefaultValue (false)]
53                 [Browsable (false)]
54                 public new bool CanOverflow {
55                         get { return base.CanOverflow; }
56                         set { base.CanOverflow = value; }
57                 }
58
59                 [DefaultValue (ToolStripGripStyle.Hidden)]
60                 public new ToolStripGripStyle GripStyle {
61                         get { return base.GripStyle; }
62                         set { base.GripStyle = value; }
63                 }
64
65                 [DefaultValue (null)]
66                 [MergableProperty (false)]
67                 [TypeConverter (typeof (MdiWindowListItemConverter))]
68                 public ToolStripMenuItem MdiWindowListItem {
69                         get { return this.mdi_window_list_item; }
70                         set { 
71                                 if (this.mdi_window_list_item != value) {
72                                         this.mdi_window_list_item = value;
73                                         this.RefreshMdiItems ();
74                                 }
75                         }
76                 }
77                 
78                 [DefaultValue (false)]
79                 public new bool ShowItemToolTips {
80                         get { return base.ShowItemToolTips; }
81                         set { base.ShowItemToolTips = value; }
82                 }
83
84                 [DefaultValue (true)]
85                 public new bool Stretch {
86                         get { return base.Stretch; }
87                         set { base.Stretch = value; }
88                 }
89                 #endregion
90
91                 #region Protected Properties
92                 protected override Padding DefaultGripMargin { get { return new Padding (2, 2, 0, 2); } }
93                 protected override Padding DefaultPadding { get { return new Padding (6, 2, 0, 2); } }
94                 protected override bool DefaultShowItemToolTips { get { return false; } }
95                 protected override Size DefaultSize { get { return new Size (200, 24); } }
96                 #endregion
97
98                 #region Protected Methods
99                 protected override AccessibleObject CreateAccessibilityInstance ()
100                 {
101                         return new MenuStripAccessibleObject ();
102                 }
103                 
104                 protected internal override ToolStripItem CreateDefaultItem (string text, Image image, EventHandler onClick)
105                 {
106                         return new ToolStripMenuItem (text, image, onClick);
107                 }
108
109                 protected virtual void OnMenuActivate (EventArgs e)
110                 {
111                         EventHandler eh = (EventHandler)(Events [MenuActivateEvent]);
112                         if (eh != null)
113                                 eh (this, e);
114                 }
115
116                 protected virtual void OnMenuDeactivate (EventArgs e)
117                 {
118                         EventHandler eh = (EventHandler)(Events [MenuDeactivateEvent]);
119                         if (eh != null)
120                                 eh (this, e);
121                 }
122
123                 protected override bool ProcessCmdKey (ref Message m, Keys keyData)
124                 {
125                         return base.ProcessCmdKey (ref m, keyData);
126                 }
127
128                 protected override void WndProc (ref Message m)
129                 {
130                         base.WndProc (ref m);
131                 }
132                 #endregion
133
134                 #region Public Events
135                 static object MenuActivateEvent = new object ();
136                 static object MenuDeactivateEvent = new object ();
137
138                 public event EventHandler MenuActivate {
139                         add { Events.AddHandler (MenuActivateEvent, value); }
140                         remove { Events.RemoveHandler (MenuActivateEvent, value); }
141                 }
142
143                 public event EventHandler MenuDeactivate {
144                         add { Events.AddHandler (MenuDeactivateEvent, value); }
145                         remove { Events.RemoveHandler (MenuDeactivateEvent, value); }
146                 }
147                 #endregion
148
149                 #region Internal Properties
150                 internal override bool KeyboardActive {
151                         get { return base.KeyboardActive; }
152                         set {
153                                 if (base.KeyboardActive != value) {
154                                         base.KeyboardActive = value;
155                                         
156                                         if (value)
157                                                 this.OnMenuActivate (EventArgs.Empty);
158                                         else
159                                                 this.OnMenuDeactivate (EventArgs.Empty);
160                                 }
161                         }
162                 }
163                 
164                 internal bool MenuDroppedDown {
165                         get { return this.menu_selected; }
166                         set { this.menu_selected = value; }
167                 }
168                 #endregion
169                 
170                 #region Internal Methods
171                 internal override void Dismiss (ToolStripDropDownCloseReason reason)
172                 {
173                         // Make sure we don't auto-dropdown next time we're activated
174                         this.MenuDroppedDown = false;
175                         
176                         base.Dismiss (reason);
177                 }
178                 
179                 internal void FireMenuActivate ()
180                 {
181                         // The tracker lets us know when the form is clicked or loses focus
182                         ToolStripManager.AppClicked += new EventHandler (ToolStripMenuTracker_AppClicked);
183                         ToolStripManager.AppFocusChange += new EventHandler (ToolStripMenuTracker_AppFocusChange);
184                         
185                         this.OnMenuActivate (EventArgs.Empty);
186                 }
187
188                 internal void FireMenuDeactivate ()
189                 {
190                         // Detach from the tracker
191                         ToolStripManager.AppClicked -= new EventHandler (ToolStripMenuTracker_AppClicked); ;
192                         ToolStripManager.AppFocusChange -= new EventHandler (ToolStripMenuTracker_AppFocusChange);
193                 
194                         this.OnMenuDeactivate (EventArgs.Empty);
195                 }
196
197                 internal override bool OnMenuKey ()
198                 {
199                         // Set ourselves active and select our first item
200                         ToolStripManager.SetActiveToolStrip (this, true);
201                         ToolStripItem tsi = this.SelectNextToolStripItem (null, true);
202                         
203                         if (tsi == null)
204                                 return false;
205                                 
206                         if (tsi is MdiControlStrip.SystemMenuItem)
207                                 this.SelectNextToolStripItem (tsi, true);
208                                 
209                         return true;
210                 }
211                 
212                 private void ToolStripMenuTracker_AppFocusChange (object sender, EventArgs e)
213                 {
214                         this.GetTopLevelToolStrip ().Dismiss (ToolStripDropDownCloseReason.AppFocusChange);
215                 }
216
217                 private void ToolStripMenuTracker_AppClicked (object sender, EventArgs e)
218                 {
219                         this.GetTopLevelToolStrip ().Dismiss (ToolStripDropDownCloseReason.AppClicked);
220                 }
221                 
222                 internal void RefreshMdiItems ()
223                 {
224                         if (this.mdi_window_list_item == null)
225                                 return;
226                         
227                         Form parent_form = this.FindForm ();
228                         
229                         if (parent_form == null || parent_form.MainMenuStrip != this)
230                                 return;
231                                 
232                         MdiClient mdi = parent_form.MdiContainer;
233                         
234                         // If there isn't a MdiContainer, we don't need to worry about MdiItems  :)
235                         if (mdi == null)
236                                 return;
237                                 
238                         // Make a copy so we can delete from the real one
239                         ToolStripItem[] loopitems = new ToolStripItem[this.mdi_window_list_item.DropDownItems.Count];
240                         this.mdi_window_list_item.DropDownItems.CopyTo (loopitems, 0);
241
242                         // If the mdi child has been removed, remove our menu item
243                         foreach (ToolStripItem tsi in loopitems)
244                                 if (tsi is ToolStripMenuItem && (tsi as ToolStripMenuItem).IsMdiWindowListEntry)
245                                         if (!mdi.mdi_child_list.Contains ((tsi as ToolStripMenuItem).MdiClientForm) || !(tsi as ToolStripMenuItem).MdiClientForm.Visible)
246                                                 this.mdi_window_list_item.DropDownItems.Remove (tsi);
247
248                         // Add the new forms and update state
249                         for (int i = 0; i < mdi.mdi_child_list.Count; i++) {
250                                 Form mdichild = (Form)mdi.mdi_child_list[i];
251                                 ToolStripMenuItem tsi;
252                                 
253                                 if (!mdichild.Visible)
254                                         continue;
255                                         
256                                 if ((tsi = FindMdiMenuItemOfForm (mdichild)) == null) {
257                                         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))
258                                                 this.mdi_window_list_item.DropDownItems.Add (new ToolStripSeparator ());
259                                                 
260                                         tsi = new ToolStripMenuItem ();
261                                         tsi.MdiClientForm = mdichild;
262                                         this.mdi_window_list_item.DropDownItems.Add (tsi);
263                                 }
264                                 
265                                 tsi.Text = string.Format ("&{0} {1}", i + 1, mdichild.Text);
266                                 tsi.Checked = parent_form.ActiveMdiChild == mdichild;
267                         }
268                         
269                         // Check that everything is in the correct order
270                         if (NeedToReorderMdi ())
271                                 ReorderMdiMenu ();
272                 }
273                 
274                 private ToolStripMenuItem FindMdiMenuItemOfForm (Form f)
275                 {
276                         // Not terribly efficient, but Mdi window lists shouldn't get too big
277                         foreach (ToolStripItem tsi in this.mdi_window_list_item.DropDownItems)
278                                 if (tsi is ToolStripMenuItem && (tsi as ToolStripMenuItem).MdiClientForm == f)
279                                         return (ToolStripMenuItem)tsi;
280                                         
281                         return null;
282                 }
283
284                 private int CountMdiMenuItems ()
285                 {
286                         int count = 0;
287                         
288                         foreach (ToolStripItem tsi in this.mdi_window_list_item.DropDownItems)
289                                 if (tsi is ToolStripMenuItem && (tsi as ToolStripMenuItem).IsMdiWindowListEntry)
290                                         count++;
291                                         
292                         return count;
293                 }
294                 
295                 private bool NeedToReorderMdi ()
296                 {
297                         // Mdi menus must be: User Items, Separator, Mdi Items
298                         bool seenMdi = false;
299                         
300                         foreach (ToolStripItem tsi in this.mdi_window_list_item.DropDownItems) {
301                                 if (tsi is ToolStripMenuItem) {
302                                         if (!(tsi as ToolStripMenuItem).IsMdiWindowListEntry) {
303                                                 if (seenMdi)
304                                                         return true;
305                                         } else 
306                                                 seenMdi = true;
307                                 }
308                         }
309                         
310                         return false;
311                 }
312
313                 internal bool ProcessImplicitMnemonic (char charCode)
314                 {
315                         string code = Char.ToUpper (charCode).ToString ();
316                         
317                         // If any item's text starts with our letter, it gets the message
318                         foreach (ToolStripItem tsi in this.Items)
319                                 if (tsi.Enabled && tsi.Visible && !string.IsNullOrEmpty (tsi.Text) && tsi.Text.ToUpper ().StartsWith (code))
320                                         return tsi.ProcessMnemonic (charCode);
321                                         
322                         return false;
323                 }
324                 
325                 private void ReorderMdiMenu ()
326                 {
327                         ToolStripItem[] loopitems = new ToolStripItem[this.mdi_window_list_item.DropDownItems.Count];
328                         this.mdi_window_list_item.DropDownItems.CopyTo (loopitems, 0);
329
330                         this.mdi_window_list_item.DropDownItems.Clear ();
331
332                         foreach (ToolStripItem tsi in loopitems)
333                                 if (tsi is ToolStripSeparator || !(tsi as ToolStripMenuItem).IsMdiWindowListEntry)
334                                         this.mdi_window_list_item.DropDownItems.Add (tsi);
335         
336                         int count = this.mdi_window_list_item.DropDownItems.Count;
337                         
338                         if (count > 0 && !(this.mdi_window_list_item.DropDownItems[count - 1] is ToolStripSeparator))
339                                 this.mdi_window_list_item.DropDownItems.Add (new ToolStripSeparator ());
340
341                         foreach (ToolStripItem tsi in loopitems)
342                                 if (tsi is ToolStripMenuItem && (tsi as ToolStripMenuItem).IsMdiWindowListEntry)
343                                         this.mdi_window_list_item.DropDownItems.Add (tsi);
344                 }
345                 #endregion
346
347                 #region MenuStripAccessibleObject
348                 private class MenuStripAccessibleObject : AccessibleObject
349                 {
350                 }
351                 #endregion
352
353         }
354         
355         #region MdiWindowListItemConverter
356         internal class MdiWindowListItemConverter : TypeConverter
357         {
358         }
359         #endregion
360 }
361 #endif