New test.
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / MenuItem.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-2005 Novell, Inc.
21 //
22 // Authors:
23 //      Jordi Mas i Hernandez, jordi@ximian.com
24 //
25 //
26
27 // NOT COMPLETE
28
29 using System.Collections;
30 using System.ComponentModel;
31 using System.ComponentModel.Design;
32 using System.Drawing;
33 using System.Drawing.Text;
34
35 namespace System.Windows.Forms
36 {
37         [DefaultProperty("Text")]
38         [DefaultEvent("Click")]
39         [DesignTimeVisible(false)]
40         [ToolboxItem(false)]
41         public class MenuItem : Menu
42         {
43                 internal bool separator;
44                 internal bool break_;
45                 internal bool bar_break;
46                 private Shortcut shortcut;
47                 private string text;
48                 private bool checked_;
49                 private bool radiocheck;
50                 private bool enabled;
51                 private char mnemonic;
52                 private bool showshortcut;
53                 private int index;
54                 private bool mdilist;
55                 private Hashtable mdilist_items;
56                 private MdiClient mdicontainer;
57                 private bool defaut_item;
58                 private bool visible;
59                 private bool ownerdraw;
60                 private int menuid;
61                 private int mergeorder;
62                 private int xtab;
63                 private int menuheight;
64                 private bool menubar;
65                 private MenuMerge mergetype;
66                 internal Rectangle bounds;
67                 
68                 public MenuItem (): base (null)
69                 {       
70                         CommonConstructor (string.Empty);
71                         shortcut = Shortcut.None;
72                 }
73
74                 public MenuItem (string text) : base (null)
75                 {
76                         CommonConstructor (text);
77                         shortcut = Shortcut.None;
78                 }
79
80                 public MenuItem (string text, EventHandler onClick) : base (null)
81                 {
82                         CommonConstructor (text);
83                         shortcut = Shortcut.None;
84                         Click += onClick;
85                 }
86
87                 public MenuItem (string text, MenuItem[] items) : base (items)
88                 {
89                         CommonConstructor (text);
90                         shortcut = Shortcut.None;
91                 }
92
93                 public MenuItem (string text, EventHandler onClick, Shortcut shortcut) : base (null)
94                 {
95                         CommonConstructor (text);
96                         Click += onClick;
97                         this.shortcut = shortcut;
98                 }
99
100                 public MenuItem (MenuMerge mergeType, int mergeOrder, Shortcut shortcut, string text,
101                         EventHandler onClick, EventHandler onPopup,  EventHandler onSelect,  MenuItem[] items)
102                         : base (items)
103                 {
104                         CommonConstructor (text);
105                         this.shortcut = shortcut;
106                         mergeorder = mergeOrder;
107                         mergetype = mergeType;
108
109                         Click += onClick;
110                         Popup += onPopup;
111                         Select += onSelect;
112                 }
113
114                 private void CommonConstructor (string text)
115                 {
116                         defaut_item = false;
117                         separator = false;
118                         break_ = false;
119                         bar_break = false;
120                         checked_ = false;
121                         radiocheck = false;
122                         enabled = true;
123                         showshortcut = true;
124                         visible = true;
125                         ownerdraw = false;
126                         menubar = false;
127                         menuheight = 0;
128                         xtab = 0;
129                         index = -1;
130                         mnemonic = '\0';
131                         menuid = -1;
132                         mergeorder = 0;
133                         mergetype = MenuMerge.Add;
134                         Text = text;    // Text can change separator status
135                 }
136
137                 #region Events
138                 public event EventHandler Click;
139                 public event DrawItemEventHandler DrawItem;
140                 public event MeasureItemEventHandler MeasureItem;
141                 public event EventHandler Popup;
142                 public event EventHandler Select;
143                 #endregion // Events
144
145                 #region Public Properties
146
147                 [Browsable(false)]
148                 [DefaultValue(false)]
149                 public bool BarBreak {
150                         get { return break_; }
151                         set { break_ = value; }
152                 }
153
154                 [Browsable(false)]
155                 [DefaultValue(false)]
156                 public bool Break {
157                         get { return bar_break; }
158                         set { bar_break = value; }
159                 }
160
161                 [DefaultValue(false)]
162                 public bool Checked {
163                         get { return checked_; }
164                         set { checked_ = value; }
165                 }
166
167                 [DefaultValue(false)]
168                 public bool DefaultItem {
169                         get { return defaut_item; }
170                         set { defaut_item = value; }
171                 }
172
173                 [DefaultValue(true)]
174                 [Localizable(true)]
175                 public bool Enabled {
176                         get { return enabled; }
177                         set { enabled = value; }
178                 }
179
180                 [Browsable(false)]
181                 public int Index {
182                         get { return index; }
183                         set { 
184                                 if (Parent != null && Parent.MenuItems != null && (value < 0 || value >= Parent.MenuItems.Count))
185                                         throw new ArgumentException ("'" + value + "' is not a valid value for 'value'");
186                                 index = value; 
187                         }
188                 }
189
190                 [Browsable(false)]
191                 public override bool IsParent {
192                         get { return IsPopup; }
193                 }
194
195                 [DefaultValue(false)]
196                 public bool MdiList {
197                         get { return mdilist; }
198                         set {
199                                 if (mdilist == value)
200                                         return;
201                                 mdilist = value;
202
203                                 if (mdilist || mdilist_items == null)
204                                         return;
205
206                                 foreach (MenuItem item in mdilist_items.Keys)
207                                         MenuItems.Remove (item);
208                                 mdilist_items.Clear ();
209                                 mdilist_items = null;
210                                 
211                         }
212                 }
213
214                 protected int MenuID {
215                         get { return menuid; }
216                 }
217
218                 [DefaultValue(0)]
219                 public int MergeOrder {
220                         get { return mergeorder; }
221                         set { mergeorder = value; }
222                 }
223
224                 [DefaultValue(MenuMerge.Add)]
225                 public MenuMerge MergeType {
226                         get { return mergetype; }
227                         set {
228                                 if (!Enum.IsDefined (typeof (MenuMerge), value))
229                                         throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for MenuMerge", value));
230
231                                 mergetype = value;
232                         }
233                 }
234
235                 [Browsable(false)]
236                 public char Mnemonic {
237                         get { return mnemonic; }
238                 }
239
240                 [DefaultValue(false)]
241                 public bool OwnerDraw {
242                         get { return ownerdraw; }
243                         set { ownerdraw = value; }
244                 }
245
246                 [Browsable(false)]
247                 public Menu Parent {
248                         get { return parent_menu;}
249                 }
250
251                 [DefaultValue(false)]
252                 public bool RadioCheck {
253                         get { return radiocheck; }
254                         set { radiocheck = value; }
255                 }
256
257                 [DefaultValue(Shortcut.None)]
258                 [Localizable(true)]
259                 public Shortcut Shortcut {
260                         get { return shortcut;}
261                         set {
262                                 if (!Enum.IsDefined (typeof (Shortcut), value))
263                                         throw new InvalidEnumArgumentException (string.Format("Enum argument value '{0}' is not valid for Shortcut", value));
264
265                                 shortcut = value;
266                         }
267                 }
268
269                 [DefaultValue(true)]
270                 [Localizable(true)]
271                 public bool ShowShortcut {
272                         get { return showshortcut;}
273                         set { showshortcut = value; }
274                 }
275
276                 [Localizable(true)]
277                 public string Text {
278                         get { return text; }
279                         set {
280                                 text = value;
281
282                                 if (text == "-")
283                                         separator = true;
284                                 else
285                                         separator = false;
286
287                                 ProcessMnemonic ();
288                         }
289                 }
290
291                 [DefaultValue(true)]
292                 [Localizable(true)]
293                 public bool Visible {
294                         get { return visible;}
295                         set { 
296                                 if (value == visible)
297                                         return;
298
299                                 visible = value;
300
301                                 if (menu_items != null) {
302                                         foreach (MenuItem mi in menu_items)
303                                                 mi.Visible = value;
304                                 }
305
306                                 if (parent_menu != null)
307                                         parent_menu.OnMenuChanged (EventArgs.Empty);
308                         }
309                 }
310
311                 #endregion Public Properties
312
313                 #region Private Properties
314
315                 internal new int Height {
316                         get { return bounds.Height; }
317                         set { bounds.Height = value; }
318                 }
319
320                 internal bool IsPopup {
321                         get {
322                                 if (menu_items.Count > 0)
323                                         return true;
324                                 else
325                                         return false;
326                         }
327                 }
328                 
329                 internal bool MeasureEventDefined {
330                         get { 
331                                 if (ownerdraw == true && MeasureItem != null) {
332                                         return true;
333                                 } else {
334                                         return false;
335                                 }
336                         }
337                 }
338                 
339                 internal bool MenuBar {
340                         get { return menubar; }
341                         set { menubar = value; }
342                 }
343                 
344                 internal int MenuHeight {
345                         get { return menuheight; }
346                         set { menuheight = value; }
347                 }       
348
349                 bool selected;
350                 internal bool Selected {
351                         get { return selected; }
352                         set { selected = value; }
353                 }
354
355                 internal bool Separator {
356                         get { return separator; }
357                         set { separator = value; }
358                 }
359                 
360                 internal DrawItemState Status {
361                         get {
362                                 DrawItemState status = DrawItemState.None;
363                                 MenuTracker tracker = Parent.Tracker;
364                                 if (Selected)
365                                         status |= (tracker.active ? DrawItemState.Selected : DrawItemState.HotLight);
366                                 if (!Enabled)
367                                         status |= DrawItemState.Grayed | DrawItemState.Disabled;
368                                 if (Checked)
369                                         status |= DrawItemState.Checked;
370                                 if (!tracker.Navigating)
371                                         status |= DrawItemState.NoAccelerator;
372                                 return status;
373                         }
374                 }
375                 
376                 internal new int Width {
377                         get { return bounds.Width; }
378                         set { bounds.Width = value; }
379                 }
380
381                 internal new int X {
382                         get { return bounds.X; }
383                         set { bounds.X = value; }
384                 }
385
386                 internal int XTab {
387                         get { return xtab; }
388                         set { xtab = value; }
389                 }
390
391                 internal new int Y {
392                         get { return bounds.Y; }
393                         set { bounds.Y = value; }
394                 }
395
396                 #endregion Private Properties
397
398                 #region Public Methods
399
400                 public virtual MenuItem CloneMenu ()
401                 {
402                         MenuItem item = new MenuItem ();
403                         item.CloneMenu (this);
404                         return item;
405                 }
406
407                 protected void CloneMenu (MenuItem menuitem)
408                 {
409                         base.CloneMenu (menuitem); // Copy subitems
410
411                         // Properties
412                         BarBreak = menuitem.BarBreak;
413                         Break = menuitem.Break;
414                         Checked = menuitem.Checked;
415                         DefaultItem = menuitem.DefaultItem;
416                         Enabled = menuitem.Enabled;                     
417                         MergeOrder = menuitem.MergeOrder;
418                         MergeType = menuitem.MergeType;
419                         OwnerDraw = menuitem.OwnerDraw;
420                         //Parent = menuitem.Parent;
421                         RadioCheck = menuitem.RadioCheck;
422                         Shortcut = menuitem.Shortcut;
423                         ShowShortcut = menuitem.ShowShortcut;
424                         Text = menuitem.Text;
425                         Visible = menuitem.Visible;
426
427                         // Events
428                         Click = menuitem.Click;
429                         DrawItem = menuitem.DrawItem;
430                         MeasureItem = menuitem.MeasureItem;
431                         Popup = menuitem.Popup;
432                         Select = menuitem.Select;
433                 }
434
435                 protected override void Dispose (bool disposing)
436                 {
437                         base.Dispose (disposing);                       
438                 }
439
440                 // This really clones the item
441                 public virtual MenuItem MergeMenu ()
442                 {
443                         MenuItem item = new MenuItem ();
444                         item.CloneMenu (this);
445                         return item;
446                 }
447
448                 public void MergeMenu (MenuItem menuitem)
449                 {
450                         base.MergeMenu (menuitem);
451                 }
452
453                 protected virtual void OnClick (EventArgs e)
454                 {
455                         if (Click != null)
456                                 Click (this, e);
457                 }
458
459                 protected virtual void OnDrawItem (DrawItemEventArgs e)
460                 {
461                         if (OwnerDraw) {
462                                 if (DrawItem != null)
463                                         DrawItem (this, e);
464                                 return;
465                         }
466
467                         ThemeEngine.Current.DrawMenuItem (this, e);     
468                 }
469
470
471                 protected virtual void OnInitMenuPopup (EventArgs e)
472                 {
473                         OnPopup (e);
474                 }
475
476                 protected virtual void OnMeasureItem (MeasureItemEventArgs e)
477                 {
478                         if (OwnerDraw && MeasureItem != null)
479                                 MeasureItem (this, e);
480                 }
481
482                 protected virtual void OnPopup (EventArgs e)
483                 {
484                         if (Popup != null)
485                                 Popup (this, e);
486                 }
487
488                 protected virtual void OnSelect (EventArgs e)
489                 {
490                         if (Select != null)
491                                 Select (this, e);
492                 }
493
494                 public void PerformClick ()
495                 {
496                         OnClick (EventArgs.Empty);
497                 }
498
499                 public virtual void PerformSelect ()
500                 {
501                         OnSelect (EventArgs.Empty);
502                 }
503
504                 public override string ToString ()
505                 {
506                         return base.ToString () + ", Items.Count: " + MenuItems.Count + ", Text: " + text;
507                 }
508
509                 #endregion Public Methods
510
511                 #region Private Methods
512
513                 internal void PerformPopup ()
514                 {
515                         OnPopup (EventArgs.Empty);
516                 }
517
518                 internal void PerformDrawItem (DrawItemEventArgs e)
519                 {
520                         if (mdilist && mdilist_items == null) {
521                                 do {
522                                         // Add the mdilist for the first time
523                                         mdilist_items = new Hashtable ();
524
525                                         MainMenu main = GetMainMenu ();
526                                         if (main == null || main.GetForm () == null)
527                                                 break;
528
529                                         Form form = main.GetForm ();
530                                         mdicontainer = form.MdiContainer;
531                                         if (mdicontainer == null)
532                                                 break;
533
534                                         foreach (Form mdichild in mdicontainer.Controls) {
535                                                 MenuItem item = new MenuItem (mdichild.Text);
536                                                 item.Click += new EventHandler (MdiWindowClickHandler);
537                                                 MenuItems.AddNoEvents (item);
538                                                 mdilist_items.Add (item, form);
539                                         }
540
541                                 } while (false);
542                         }
543
544                         OnDrawItem (e);
545                 }
546                 
547                 internal void PerformMeasureItem (MeasureItemEventArgs e)
548                 {
549                         OnMeasureItem (e);
550                 }
551
552                 private void ProcessMnemonic ()
553                 {
554                         if (text == null || text.Length < 2) {
555                                 mnemonic = '\0';
556                                 return;
557                         }
558
559                         bool bPrevAmp = false;
560                         for (int i = 0; i < text.Length -1 ; i++) {
561                                 if (text[i] == '&') {
562                                         if (bPrevAmp == false &&  (text[i+1] != '&')) {
563                                                 mnemonic = Char.ToUpper (text[i+1]);
564                                                 return;
565                                         }
566
567                                         bPrevAmp = true;
568                                 }
569                                 else
570                                         bPrevAmp = false;
571                         }
572
573                         mnemonic = '\0';
574                 }
575
576                 private string GetShortCutTextCtrl () { return "Ctrl"; }
577                 private string GetShortCutTextAlt () { return "Alt"; }
578                 private string GetShortCutTextShift () { return "Shift"; }              
579
580                 internal string GetShortCutText ()
581                 {
582                         /* Ctrl+A - Ctrl+Z */
583                         if (Shortcut >= Shortcut.CtrlA && Shortcut <= Shortcut.CtrlZ)
584                                 return GetShortCutTextCtrl () + "+" + (char)((int) 'A' + (int)(Shortcut - Shortcut.CtrlA));
585
586                         /* Alt+0 - Alt+9 */
587                         if (Shortcut >= Shortcut.Alt0 && Shortcut <= Shortcut.Alt9)
588                                 return GetShortCutTextAlt () + "+" + (char)((int) '0' + (int)(Shortcut - Shortcut.Alt0));
589
590                         /* Alt+F1 - Alt+F2 */
591                         if (Shortcut >= Shortcut.AltF1 && Shortcut <= Shortcut.AltF9)
592                                 return GetShortCutTextAlt () + "+F" + (char)((int) '1' + (int)(Shortcut - Shortcut.AltF1));
593
594                         /* Ctrl+0 - Ctrl+9 */
595                         if (Shortcut >= Shortcut.Ctrl0 && Shortcut <= Shortcut.Ctrl9)
596                                 return GetShortCutTextCtrl () + "+" + (char)((int) '0' + (int)(Shortcut - Shortcut.Ctrl0));
597                                                         
598                         /* Ctrl+F0 - Ctrl+F9 */
599                         if (Shortcut >= Shortcut.CtrlF1 && Shortcut <= Shortcut.CtrlF9)
600                                 return GetShortCutTextCtrl () + "+F" + (char)((int) '1' + (int)(Shortcut - Shortcut.CtrlF1));
601                                 
602                         /* Ctrl+Shift+0 - Ctrl+Shift+9 */
603                         if (Shortcut >= Shortcut.CtrlShift0 && Shortcut <= Shortcut.CtrlShift9)
604                                 return GetShortCutTextCtrl () + "+" + GetShortCutTextShift () + "+" + (char)((int) '0' + (int)(Shortcut - Shortcut.CtrlShift0));
605                                 
606                         /* Ctrl+Shift+A - Ctrl+Shift+Z */
607                         if (Shortcut >= Shortcut.CtrlShiftA && Shortcut <= Shortcut.CtrlShiftZ)
608                                 return GetShortCutTextCtrl () + "+" + GetShortCutTextShift () + "+" + (char)((int) 'A' + (int)(Shortcut - Shortcut.CtrlShiftA));
609
610                         /* Ctrl+Shift+F1 - Ctrl+Shift+F9 */
611                         if (Shortcut >= Shortcut.CtrlShiftF1 && Shortcut <= Shortcut.CtrlShiftF9)
612                                 return GetShortCutTextCtrl () + "+" + GetShortCutTextShift () + "+F" + (char)((int) '1' + (int)(Shortcut - Shortcut.CtrlShiftF1));
613                                 
614                         /* F1 - F9 */
615                         if (Shortcut >= Shortcut.F1 && Shortcut <= Shortcut.F9)
616                                 return "F" + (char)((int) '1' + (int)(Shortcut - Shortcut.F1));
617                                 
618                         /* Shift+F1 - Shift+F9 */
619                         if (Shortcut >= Shortcut.ShiftF1 && Shortcut <= Shortcut.ShiftF9)
620                                 return GetShortCutTextShift () + "+F" + (char)((int) '1' + (int)(Shortcut - Shortcut.ShiftF1));
621                         
622                         /* Special cases */
623                         switch (Shortcut) {
624                                 case Shortcut.AltBksp:
625                                         return "AltBksp";
626                                 case Shortcut.AltF10:
627                                         return GetShortCutTextAlt () + "+F10";
628                                 case Shortcut.AltF11:
629                                         return GetShortCutTextAlt () + "+F11";
630                                 case Shortcut.AltF12:
631                                         return GetShortCutTextAlt () + "+F12";
632                                 case Shortcut.CtrlDel:          
633                                         return GetShortCutTextCtrl () + "+Del";
634                                 case Shortcut.CtrlF10:
635                                         return GetShortCutTextCtrl () + "+F10";
636                                 case Shortcut.CtrlF11:
637                                         return GetShortCutTextCtrl () + "+F11";
638                                 case Shortcut.CtrlF12:
639                                         return GetShortCutTextCtrl () + "+F12";
640                                 case Shortcut.CtrlIns:
641                                         return GetShortCutTextCtrl () + "+Ins";
642                                 case Shortcut.CtrlShiftF10:
643                                         return GetShortCutTextCtrl () + "+" + GetShortCutTextShift () + "+F10";
644                                 case Shortcut.CtrlShiftF11:
645                                         return GetShortCutTextCtrl () + "+" + GetShortCutTextShift () + "+F11";
646                                 case Shortcut.CtrlShiftF12:
647                                         return GetShortCutTextCtrl () + "+" + GetShortCutTextShift () + "+F12";
648                                 case Shortcut.Del:
649                                         return "Del";
650                                 case Shortcut.F10:
651                                         return "F10";   
652                                 case Shortcut.F11:
653                                         return "F11";   
654                                 case Shortcut.F12:
655                                         return "F12";   
656                                 case Shortcut.Ins:
657                                         return "Ins";   
658                                 case Shortcut.None:
659                                         return "None";  
660                                 case Shortcut.ShiftDel:
661                                         return GetShortCutTextShift () + "+Del";
662                                 case Shortcut.ShiftF10:
663                                         return GetShortCutTextShift () + "+F10";
664                                 case Shortcut.ShiftF11:
665                                         return GetShortCutTextShift () + "+F11";
666                                 case Shortcut.ShiftF12:
667                                         return GetShortCutTextShift () + "+F12";                                
668                                 case Shortcut.ShiftIns:
669                                         return GetShortCutTextShift () + "+Ins";
670                                 default:
671                                         break;
672                                 }
673                                 
674                         return "";
675                 }
676
677                 private void MdiWindowClickHandler (object sender, EventArgs e)
678                 {
679                         Form mdichild = (Form) mdilist_items [SelectedItem];
680
681                         // people could add weird items to the Window menu
682                         // so we can't assume its just us
683                         if (mdichild == null)
684                                 return;
685
686                         mdicontainer.ActivateChild (mdichild);
687                 }
688
689                 #endregion Private Methods
690
691         }
692 }
693
694