Merge pull request #3802 from lambdageek/dev-reference-attr-take3
[mono.git] / mcs / class / System.Windows.Forms / System.Windows.Forms / ToolStripDropDownItem.cs
1 //
2 // ToolStripDropDownItem.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.Threading;
33
34 namespace System.Windows.Forms
35 {
36         [DefaultProperty ("DropDownItems")]
37         [Designer ("System.Windows.Forms.Design.ToolStripMenuItemDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
38         public abstract class ToolStripDropDownItem : ToolStripItem
39         {
40                 internal ToolStripDropDown drop_down;
41                 private ToolStripDropDownDirection drop_down_direction;
42
43                 #region Protected Constructors
44                 protected ToolStripDropDownItem () : this (string.Empty, null, null, string.Empty)
45                 {
46                 }
47
48                 protected ToolStripDropDownItem (string text, Image image, EventHandler onClick)
49                         : this (text, image, onClick, string.Empty)
50                 {
51                 }
52
53                 protected ToolStripDropDownItem (string text, Image image, params ToolStripItem[] dropDownItems)
54                         : this (text, image, null, string.Empty)
55                 {
56                 }
57
58                 protected ToolStripDropDownItem (string text, Image image, EventHandler onClick, string name)
59                         : base (text, image, onClick, name)
60                 {
61                 }
62                 #endregion
63
64                 #region Public Properties
65                 [TypeConverter (typeof (ReferenceConverter))]
66                 public ToolStripDropDown DropDown {
67                         get {
68                                 if (this.drop_down == null) {
69                                         this.drop_down = CreateDefaultDropDown ();
70                                         this.drop_down.ItemAdded += new ToolStripItemEventHandler (DropDown_ItemAdded);
71                                 }
72                         
73                                 return this.drop_down;
74                         }
75                         set { 
76                                 this.drop_down = value;
77                                 this.drop_down.OwnerItem = this;
78                         }
79                 }
80
81                 [Browsable (false)]
82                 public ToolStripDropDownDirection DropDownDirection {
83                         get { return this.drop_down_direction; }
84                         set {
85                                 if (!Enum.IsDefined (typeof (ToolStripDropDownDirection), value))
86                                         throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for ToolStripDropDownDirection", value));
87
88                                 this.drop_down_direction = value;
89                         }
90                 }
91
92                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
93                 public ToolStripItemCollection DropDownItems {
94                         get { return this.DropDown.Items; }
95                 }
96
97                 [Browsable (false)]
98                 public virtual bool HasDropDownItems {
99                         get { return this.drop_down != null && this.DropDown.Items.Count != 0; }
100                 }
101
102                 [Browsable (false)]
103                 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
104                 public override bool Pressed {
105                         get { return base.Pressed || (this.drop_down != null && this.DropDown.Visible); }
106                 }
107                 #endregion
108
109                 #region Protected Properties
110                 protected internal virtual Point DropDownLocation {
111                         get {
112                                 Point p;
113
114                                 if (this.IsOnDropDown) {
115                                         p = Parent.PointToScreen (new Point (this.Bounds.Left, this.Bounds.Top - 1));
116                                         p.X += this.Bounds.Width;
117                                         p.Y += this.Bounds.Left;
118                                         return p;
119                                 }
120                                 else
121                                         p = new Point (this.Bounds.Left, this.Bounds.Bottom - 1);
122
123                                 return Parent.PointToScreen (p);
124                         }
125                 }
126                 #endregion
127
128                 #region Public Methods
129                 public void HideDropDown ()
130                 {
131                         if (this.drop_down == null || !this.DropDown.Visible)
132                                 return;
133
134                         // OnDropDownHide is called before actually closing DropDown
135                         this.OnDropDownHide (EventArgs.Empty);
136                         this.DropDown.Close (ToolStripDropDownCloseReason.CloseCalled);
137                         this.is_pressed = false;
138                         this.Invalidate ();
139                 }
140
141                 public void ShowDropDown ()
142                 {
143                         // Don't go through this whole deal if
144                         // the DropDown is already visible
145                         if (this.DropDown.Visible)
146                                 return;
147                                 
148                         // Call this before the HasDropDownItems check to give
149                         // users a chance to handle it and add drop down items
150                         this.OnDropDownShow (EventArgs.Empty);
151                         
152                         if (!this.HasDropDownItems)
153                                 return;
154                         
155                         this.Invalidate ();
156                         this.DropDown.Show (this.DropDownLocation);
157                 }
158                 #endregion
159
160                 #region Protected Methods
161                 protected override AccessibleObject CreateAccessibilityInstance ()
162                 {
163                         return new ToolStripDropDownItemAccessibleObject (this);
164                 }
165                 
166                 protected virtual ToolStripDropDown CreateDefaultDropDown ()
167                 {
168                         ToolStripDropDown tsdd = new ToolStripDropDown ();
169                         tsdd.OwnerItem = this;
170                         return tsdd;
171                 }
172
173                 protected override void Dispose (bool disposing)
174                 {
175                         if (!IsDisposed) {
176                                 if(disposing) {
177                                         if (this.HasDropDownItems)
178                                                 foreach (ToolStripItem tsi in this.DropDownItems)
179                                                         if (tsi is ToolStripMenuItem)
180                                                                 ToolStripManager.RemoveToolStripMenuItem ((ToolStripMenuItem)tsi);
181
182                                         if (drop_down != null)
183                                                 ToolStripManager.RemoveToolStrip (drop_down);
184                                 }
185                                 base.Dispose (disposing);
186                         }
187                 }
188
189                 protected override void OnBoundsChanged ()
190                 {
191                         base.OnBoundsChanged ();
192                 }
193
194                 protected internal virtual void OnDropDownClosed (EventArgs e)
195                 {
196                         EventHandler eh = (EventHandler)(Events [DropDownClosedEvent]);
197                         if (eh != null)
198                                 eh (this, e);
199                 }
200
201                 protected virtual void OnDropDownHide (EventArgs e)
202                 {
203                 }
204
205                 protected internal virtual void OnDropDownItemClicked (ToolStripItemClickedEventArgs e)
206                 {
207                         ToolStripItemClickedEventHandler eh = (ToolStripItemClickedEventHandler)(Events [DropDownItemClickedEvent]);
208                         if (eh != null)
209                                 eh (this, e);
210                 }
211
212                 protected internal virtual void OnDropDownOpened (EventArgs e)
213                 {
214                         EventHandler eh = (EventHandler)(Events [DropDownOpenedEvent]);
215                         if (eh != null)
216                                 eh (this, e);
217                 }
218
219                 protected virtual void OnDropDownShow (EventArgs e)
220                 {
221                         EventHandler eh = (EventHandler)(Events[DropDownOpeningEvent]);
222                         if (eh != null)
223                                 eh (this, e);
224                 }
225
226                 protected override void OnFontChanged (EventArgs e)
227                 {
228                         base.OnFontChanged (e);
229
230                         // don't use DropDown directly, since doing that
231                         // would created the DropDown control
232                         if (drop_down != null)
233                                 drop_down.Font = Font;
234                 }
235
236                 protected override void OnRightToLeftChanged (EventArgs e)
237                 {
238                         base.OnRightToLeftChanged (e);
239                 }
240                 
241                 protected internal override bool ProcessCmdKey (ref Message m, Keys keyData)
242                 {
243                         if (this.HasDropDownItems)
244                                 foreach (ToolStripItem tsi in this.DropDownItems)
245                                         if (tsi.ProcessCmdKey (ref m, keyData) == true)
246                                                 return true;
247
248                         return base.ProcessCmdKey (ref m, keyData);
249                 }
250
251                 protected internal override bool ProcessDialogKey (Keys keyData)
252                 {
253                         if (!this.Selected || !this.HasDropDownItems)
254                                 return base.ProcessDialogKey (keyData);
255                                 
256                         if (!this.IsOnDropDown) {
257                                 if (this.Parent.Orientation == Orientation.Horizontal) {
258                                         if (keyData == Keys.Down || keyData == Keys.Enter) {
259                                                 if (this.Parent is MenuStrip)
260                                                         (this.Parent as MenuStrip).MenuDroppedDown = true;
261                                                 this.ShowDropDown ();
262                                                 this.DropDown.SelectNextToolStripItem (null, true);
263                                                 return true;
264                                         }
265                                 } else {
266                                         if (keyData == Keys.Right || keyData == Keys.Enter) {
267                                                 if (this.Parent is MenuStrip)
268                                                         (this.Parent as MenuStrip).MenuDroppedDown = true;
269                                                 this.ShowDropDown ();
270                                                 this.DropDown.SelectNextToolStripItem (null, true);
271                                                 return true;
272                                         }
273                                 }
274                         } else {
275                                 if (keyData == Keys.Right || keyData == Keys.Enter) {
276                                         if (this.HasDropDownItems) {
277                                                 this.ShowDropDown ();
278                                                 this.DropDown.SelectNextToolStripItem (null, true);
279                                                 return true;
280                                         }
281                                 }
282                         }
283                         
284                         
285                         return base.ProcessDialogKey (keyData);
286                 }
287                 #endregion
288
289                 #region Public Events
290                 static object DropDownClosedEvent = new object ();
291                 static object DropDownItemClickedEvent = new object ();
292                 static object DropDownOpenedEvent = new object ();
293                 static object DropDownOpeningEvent = new object ();
294
295                 public event EventHandler DropDownClosed {
296                         add { Events.AddHandler (DropDownClosedEvent, value); }
297                         remove { Events.RemoveHandler (DropDownClosedEvent, value); }
298                 }
299
300                 public event ToolStripItemClickedEventHandler DropDownItemClicked {
301                         add { Events.AddHandler (DropDownItemClickedEvent, value); }
302                         remove { Events.RemoveHandler (DropDownItemClickedEvent, value); }
303                 }
304
305                 public event EventHandler DropDownOpened {
306                         add { Events.AddHandler (DropDownOpenedEvent, value); }
307                         remove { Events.RemoveHandler (DropDownOpenedEvent, value); }
308                 }
309
310                 public event EventHandler DropDownOpening {
311                         add { Events.AddHandler (DropDownOpeningEvent, value); }
312                         remove { Events.RemoveHandler (DropDownOpeningEvent, value); }
313                 }
314                 #endregion
315
316                 #region Internal Methods
317                 internal override void Dismiss (ToolStripDropDownCloseReason reason)
318                 {
319                         if (this.HasDropDownItems && this.DropDown.Visible)
320                                 this.DropDown.Dismiss (reason);
321                                 
322                         base.Dismiss (reason);
323                 }
324
325                 internal override void HandleClick (int mouse_clicks, EventArgs e)
326                 {
327                         OnClick (e);
328                 }
329                 
330                 internal void HideDropDown (ToolStripDropDownCloseReason reason)
331                 {
332                         if (this.drop_down == null || !this.DropDown.Visible)
333                                 return;
334
335                         // OnDropDownHide is called before actually closing DropDown
336                         this.OnDropDownHide (EventArgs.Empty);
337                         this.DropDown.Close (reason);
338                         this.is_pressed = false;
339                         this.Invalidate ();
340                 }
341                 
342                 private void DropDown_ItemAdded (object sender, ToolStripItemEventArgs e)
343                 {
344                         e.Item.owner_item = this;
345                 }
346                 #endregion
347         }
348 }