Merge pull request #5714 from alexischr/update_bockbuild
[mono.git] / mcs / class / System.Design / System.Windows.Forms.Design / ControlDesigner.cs
1 //
2 // System.Windows.Forms.Design.ControlDesigner
3 //
4 // Authors:
5 //        Ivan N. Zlatev (contact i-nZ.net)
6 //
7 // (C) 2006-2007 Ivan N. Zlatev
8
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 //
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29
30
31 using System;
32 using System.ComponentModel;
33 using System.ComponentModel.Design;
34 using System.Runtime.InteropServices;
35 using System.Windows.Forms;
36 using System.Drawing;
37 using System.Drawing.Design;
38 using System.Collections;
39 using System.Windows.Forms.Design.Behavior;
40
41 namespace System.Windows.Forms.Design
42 {
43         public class ControlDesigner : ComponentDesigner, IMessageReceiver
44         {
45                 
46
47                 private WndProcRouter _messageRouter;
48                 private bool _locked = false;
49                 private bool _mouseDown = false;
50                 private bool _mouseMoveAfterMouseDown = false;
51                 private bool _mouseDownFirstMove = false;
52                 private bool _firstMouseMoveInClient = true;
53
54                 public ControlDesigner ()
55                 {
56                 }
57
58 #region Initialization
59                 public override void Initialize (IComponent component)
60                 {
61                         base.Initialize (component);
62
63                         if (!(component is Control))
64                                 throw new ArgumentException ("Component is not a Control.");
65
66                         Control.Text = component.Site.Name;
67                         _messageRouter = new WndProcRouter ((Control) component, (IMessageReceiver) this);
68                         Control.WindowTarget = _messageRouter;
69
70                         // DT properties
71                         //
72                         this.Visible = true;
73                         this.Enabled = true;
74                         this.Locked = false;
75                         this.AllowDrop = false;
76                         //
77                         // The control properties
78                         //
79                         Control.Enabled = true;
80                         Control.Visible = true;
81                         Control.AllowDrop = false;
82
83                         this.Control.DragDrop += new DragEventHandler (OnDragDrop);
84                         this.Control.DragEnter += new DragEventHandler (OnDragEnter);
85                         this.Control.DragLeave += new EventHandler (OnDragLeave);
86                         this.Control.DragOver += new DragEventHandler (OnDragOver);
87
88                         // XXX: The control already has a handle?
89                         //
90                         if (Control.IsHandleCreated)
91                                 OnCreateHandle ();
92
93                 }
94
95                 // The default implementation of this method sets the component's Text property to
96                 // its name (Component.Site.Name), if the property field is of type string.
97                 //
98                 public override void OnSetComponentDefaults ()
99                 {
100                         if (this.Component != null && this.Component.Site != null) {
101                                 PropertyDescriptor propertyDescriptor = TypeDescriptor.GetProperties (this.Component)["Text"];
102                                 if (propertyDescriptor != null && !propertyDescriptor.IsReadOnly &&
103                                         propertyDescriptor.PropertyType == typeof (string)) {
104                                         propertyDescriptor.SetValue (Component, Component.Site.Name);
105                                 }
106                         }
107                 }
108 #endregion
109
110
111 #region Properties and Fields - AccessabilityObject Left
112                 protected static readonly Point InvalidPoint = new Point (int.MinValue, int.MinValue);
113
114                 protected internal BehaviorService BehaviorService {
115                         get { throw new NotImplementedException (); }
116                 }
117
118                 public virtual Control Control {
119                         get { return (Control) base.Component; }
120                 }
121
122                 protected virtual bool EnableDragRect {
123                         get { return true; }
124                 }
125
126                 public virtual SelectionRules SelectionRules {
127                         get {
128                                 if (this.Control == null)
129                                         return SelectionRules.None;
130
131                                 // all controls on the surface are visible
132                                 //
133                                 SelectionRules selectionRules = SelectionRules.Visible;
134
135                                 if ((bool)GetValue (this.Component, "Locked") == true) {
136                                         selectionRules |= SelectionRules.Locked;
137                                 }
138                                 else {
139                                         DockStyle dockStyle = (DockStyle) this.GetValue (base.Component, "Dock", typeof (DockStyle));
140
141                                         switch (dockStyle) {
142                                                 case DockStyle.Top:
143                                                         selectionRules |= SelectionRules.BottomSizeable;
144                                                         break;
145                                                 case DockStyle.Left:
146                                                         selectionRules |= SelectionRules.RightSizeable;
147                                                         break;
148                                                 case DockStyle.Right:
149                                                         selectionRules |= SelectionRules.LeftSizeable;
150                                                         break;
151                                                 case DockStyle.Bottom:
152                                                         selectionRules |= SelectionRules.TopSizeable;
153                                                         break;
154                                                 case DockStyle.Fill:
155                                                         break;
156                                                 default:
157                                                         selectionRules |= SelectionRules.Moveable;
158                                                         selectionRules |= SelectionRules.AllSizeable;
159                                                         break;
160                                         }
161                                 }
162
163                                 return selectionRules;
164                         }
165                 }
166
167                 public override ICollection AssociatedComponents {
168                         get {
169                                 ArrayList components = new ArrayList ();
170                                 foreach (Control c in this.Control.Controls)
171                                         if (c.Site != null)
172                                                 components.Add (c);
173                                 return components;
174                         }
175                 }
176
177                 protected override IComponent ParentComponent {
178                         get { return this.GetValue (this.Control,  "Parent") as Control;}
179                 }
180                 // TODO: implement ControlDesigner.ControlAccessabilityObject
181                 //
182                 public virtual AccessibleObject AccessibilityObject {
183                         get {
184                                 if (accessibilityObj == null)
185                                         accessibilityObj = new AccessibleObject ();
186
187                                 return accessibilityObj;
188                         }
189                 }
190                 protected AccessibleObject accessibilityObj;
191
192 #endregion
193
194
195 #region WndProc
196         
197                 protected void DefWndProc (ref Message m)
198                 {
199                         _messageRouter.ToControl (ref m);
200                 }
201                 
202                 protected void BaseWndProc (ref Message m)
203                 {
204                         _messageRouter.ToSystem (ref m);
205                 }
206                 
207                 void IMessageReceiver.WndProc (ref Message m)
208                 {
209                         this.WndProc (ref m);
210                 }
211                 
212                 // Keep in mind that messages are recieved for the child controls if routed
213                 //
214                 protected virtual void WndProc (ref Message m)
215                 {
216                         // Filter out kb input
217                         //
218                         if ((Native.Msg) m.Msg >= Native.Msg.WM_KEYFIRST &&  (Native.Msg) m.Msg <= Native.Msg.WM_KEYLAST)
219                                 return;
220
221                         // Mouse messages should be routed the control, if GetHitTest (virtual) returns true.
222                         //
223                         if (IsMouseMessage ((Native.Msg) m.Msg) &&
224                             this.GetHitTest (new Point (Native.LoWord((int) m.LParam), Native.HiWord (((int) m.LParam))))) {
225                                 
226                                 this.DefWndProc (ref m);
227                                 return;
228                         }
229
230                         switch ((Native.Msg) m.Msg) {
231                                 case Native.Msg.WM_CREATE:
232                                         this.DefWndProc (ref m);
233                                         if (m.HWnd == this.Control.Handle)
234                                                 OnCreateHandle ();
235                                         break;
236
237                                 case Native.Msg.WM_CONTEXTMENU:
238                                         OnContextMenu (Native.LoWord ((int) m.LParam), Native.HiWord ((int) m.LParam));
239                                         break;
240
241                                 case Native.Msg.WM_SETCURSOR:
242                                         if (this.GetHitTest (new Point (Native.LoWord ((int) m.LParam), Native.HiWord ((int) m.LParam))))
243                                                 this.DefWndProc (ref m);
244                                         else
245                                                 OnSetCursor ();
246                                         break;
247
248                                 case Native.Msg.WM_SETFOCUS:
249                                         this.DefWndProc (ref m);
250                                         break;
251                                 
252                                 case Native.Msg.WM_PAINT:
253                                         // Wait for control's WM_PAINT to complete first.
254                                         //
255                                         this.DefWndProc (ref m);
256
257                                         Graphics gfx = Graphics.FromHwnd (m.HWnd);
258                                         PaintEventArgs args = new PaintEventArgs (gfx, this.Control.Bounds);
259                                         OnPaintAdornments (args);
260                                         gfx.Dispose ();
261                                         args.Dispose ();
262                                         break;
263
264                                 case Native.Msg.WM_NCRBUTTONDOWN:
265                                 case Native.Msg.WM_NCLBUTTONDOWN:
266                                 case Native.Msg.WM_NCMBUTTONDOWN:
267                                 case Native.Msg.WM_NCLBUTTONDBLCLK:
268                                 case Native.Msg.WM_NCRBUTTONDBLCLK:
269                                         break;
270
271                                 case Native.Msg.WM_LBUTTONDBLCLK:
272                                 case Native.Msg.WM_RBUTTONDBLCLK:
273                                 case Native.Msg.WM_MBUTTONDBLCLK:
274                                         if ((Native.Msg)m.Msg == Native.Msg.WM_LBUTTONDBLCLK)
275                                                 _mouseButtonDown = MouseButtons.Left;
276                                         else if ((Native.Msg)m.Msg == Native.Msg.WM_RBUTTONDBLCLK)
277                                                 _mouseButtonDown = MouseButtons.Right;
278                                         else if ((Native.Msg)m.Msg == Native.Msg.WM_MBUTTONDBLCLK)
279                                                 _mouseButtonDown = MouseButtons.Middle;
280                                         OnMouseDoubleClick ();
281                                         this.BaseWndProc (ref m);
282                                         break;
283
284                                 case Native.Msg.WM_MOUSEHOVER:
285                                         OnMouseHover ();
286                                         break;
287                                 
288                                 case Native.Msg.WM_LBUTTONDOWN:
289                                 case Native.Msg.WM_RBUTTONDOWN:          
290                                 case Native.Msg.WM_MBUTTONDOWN:
291                                         _mouseMoveAfterMouseDown = true;
292                                         if ((Native.Msg)m.Msg == Native.Msg.WM_LBUTTONDOWN)
293                                                 _mouseButtonDown = MouseButtons.Left;
294                                         else if ((Native.Msg)m.Msg == Native.Msg.WM_RBUTTONDOWN)
295                                                 _mouseButtonDown = MouseButtons.Right;
296                                         else if ((Native.Msg)m.Msg == Native.Msg.WM_MBUTTONDOWN)
297                                                 _mouseButtonDown = MouseButtons.Middle;
298                                 
299                                         if (_firstMouseMoveInClient) {
300                                                 OnMouseEnter ();
301                                                 _firstMouseMoveInClient = false;
302                                         }
303                                         this.OnMouseDown (Native.LoWord ((int)m.LParam), Native.HiWord ((int)m.LParam));
304                                         this.BaseWndProc (ref m);
305                                         break;
306
307                                 case Native.Msg.WM_MOUSELEAVE:
308                                         _firstMouseMoveInClient = false;
309                                         OnMouseLeave ();
310                                         this.BaseWndProc (ref m);
311                                         break;
312
313                                 // The WM_CANCELMODE message is sent to cancel certain modes, such as mouse capture.
314                                 // For example, the system sends this message to the active window when a dialog box
315                                 // or message box is displayed. Certain functions also send this message explicitly to
316                                 // the specified window regardless of whether it is the active window. For example,
317                                 // the EnableWindow function sends this message when disabling the specified window.
318                                 //
319                                 case Native.Msg.WM_CANCELMODE:
320                                         OnMouseDragEnd (true);
321                                         this.DefWndProc (ref m);
322                                         break;
323
324                                 case Native.Msg.WM_LBUTTONUP:
325                                 case Native.Msg.WM_RBUTTONUP:
326                                 case Native.Msg.WM_NCLBUTTONUP:
327                                 case Native.Msg.WM_NCRBUTTONUP:
328                                 case Native.Msg.WM_MBUTTONUP:  
329                                 case Native.Msg.WM_NCMBUTTONUP:
330                                         _mouseMoveAfterMouseDown = false; // just in case
331                                         this.OnMouseUp ();
332                                         this.BaseWndProc (ref m);
333                                         break;
334
335                                 // // MWF Specific msg! - must reach control
336                                 // //
337                                 // case Native.Msg.WM_MOUSE_ENTER:
338                                 //      _firstMouseMoveInClient = false; // just so that nothing will get fired in WM_MOUSEMOVE
339                                 //      OnMouseEnter ();
340                                 //      this.DefWndProc (ref m);
341                                 //      break;
342
343                                 // FIXME: The first MOUSEMOVE after WM_MOUSEDOWN should be ingored
344                                 //
345                                 case Native.Msg.WM_MOUSEMOVE:
346                                         if (_mouseMoveAfterMouseDown) { // mousemove is send after each mousedown so ignore that
347                                                 _mouseMoveAfterMouseDown = false;
348                                                 this.BaseWndProc (ref m);
349                                                 return;
350                                         }
351                                         // If selection is in progress pass the mouse move msg to the primary selection.
352                                         // If resizing is in progress pass to the parent of the primary selection (remmember that the selection
353                                         // frame is not a control and is drawn in the parent of the primary selection).
354                                         //
355                                         // Required in order for those 2 operations to continue when the mouse is moving over a control covering
356                                         // the one where the action takes place.
357                                         // 
358                                         IUISelectionService uiSelectionServ = this.GetService (typeof (IUISelectionService)) as IUISelectionService;
359                                         ISelectionService selectionServ = this.GetService (typeof (ISelectionService)) as ISelectionService;
360                                         IDesignerHost host = this.GetService (typeof (IDesignerHost)) as IDesignerHost;
361                                         
362
363                                         if (uiSelectionServ != null && selectionServ != null && host != null) {
364                                                 Control primarySelection = selectionServ.PrimarySelection as Control;
365                                                 Point location = new Point (Native.LoWord ((int)m.LParam), Native.HiWord ((int)m.LParam));
366
367                                                 if (uiSelectionServ.SelectionInProgress &&
368                                                         this.Component != host.RootComponent && 
369                                                         this.Component != selectionServ.PrimarySelection) {
370
371                                                         location = primarySelection.PointToClient (this.Control.PointToScreen (location));
372                                                         Native.SendMessage (primarySelection.Handle, (Native.Msg)m.Msg, m.WParam, Native.LParam (location.X, location.Y));
373                                                 }
374                                                 else if (uiSelectionServ.ResizeInProgress && 
375                                                    // this.Component != host.RootComponent && 
376                                                         this.Control.Parent == ((Control)selectionServ.PrimarySelection).Parent) {
377
378                                                         location = this.Control.Parent.PointToClient (this.Control.PointToScreen (location));
379                                                         Native.SendMessage (this.Control.Parent.Handle, (Native.Msg)m.Msg, m.WParam, Native.LParam (location.X, location.Y));
380                                                 }
381                                                 else {
382                                                         this.OnMouseMove (location.X, location.Y);
383                                                 }
384                                         }
385                                         else {
386                                                 this.OnMouseMove (Native.LoWord ((int)m.LParam), Native.HiWord ((int)m.LParam));
387                                         }
388                                         this.BaseWndProc (ref m);
389                                         break;
390
391                                 default:
392                                         // Pass everything else to the control and return
393                                         //
394                                         this.DefWndProc (ref m);
395                                         break;
396                         }
397                 }
398                 
399                 // Indicates whether a mouse click at the specified point should be handled by the control.
400                 //
401                 protected virtual bool GetHitTest (Point point)
402                 {
403                         return false;
404                 }
405
406                 private bool IsMouseMessage (Native.Msg msg)
407                 {
408                         if (msg >= Native.Msg.WM_MOUSEFIRST && msg <= Native.Msg.WM_MOUSELAST)
409                                 return true;
410                         else if (msg >= Native.Msg.WM_NCLBUTTONDOWN && msg <= Native.Msg.WM_NCMBUTTONDBLCLK)
411                                 return true;
412                         else if (msg == Native.Msg.WM_MOUSEHOVER || msg == Native.Msg.WM_MOUSELEAVE)
413                                 return true;
414                         else
415                                 return false;
416                 }
417 #endregion
418
419
420 #region WndProc Message Handlers
421
422                 protected virtual void OnSetCursor ()
423                 {
424                 }
425
426                 // Raises the DoDefaultAction.
427                 //
428                 private void OnMouseDoubleClick ()
429                 {
430                         try {
431                                 base.DoDefaultAction ();
432                         }
433                         catch (Exception e) {
434                                 this.DisplayError (e);
435                         }
436                 }
437
438                 internal virtual void OnMouseDown (int x, int y)
439                 {
440                         _mouseDown = true;
441                         _mouseDownFirstMove = true;
442                         IUISelectionService uiSelection = this.GetService (typeof (IUISelectionService)) as IUISelectionService;
443                         if (uiSelection != null && uiSelection.AdornmentsHitTest (this.Control, x, y)) {
444                                 // 1) prevent primary selection from being changed at this point.
445                                 // 2) delegate behaviour in the future to the IUISelectionService
446                         }
447                         else {
448                                 ISelectionService selectionService = this.GetService (typeof (ISelectionService)) as ISelectionService;
449                                 if (selectionService != null) {
450                                         selectionService.SetSelectedComponents (new IComponent[] { this.Component });
451                                 }
452                         }
453                 }
454
455                 // Note that this is a pure WM_MOUSEMOVE acceptor
456                 //
457                 internal virtual void OnMouseMove (int x, int y)
458                 {
459                         if (_mouseDown) {
460                                 if (_mouseDownFirstMove) {
461                                         OnMouseDragBegin (x, y);
462                                         _mouseDownFirstMove = false;
463                                 }
464                                 else {
465                                         OnMouseDragMove (x, y);
466                                 }
467                         }
468
469                 }
470
471                 internal virtual void OnMouseUp ()
472                 {
473                         IUISelectionService uiSelection = this.GetService (typeof (IUISelectionService)) as IUISelectionService;
474
475                         if (_mouseDown) {
476                                 this.OnMouseDragEnd (false);
477                                 if (uiSelection != null && (uiSelection.SelectionInProgress || uiSelection.ResizeInProgress)) {
478                                         uiSelection.MouseDragEnd (false);
479                                 }
480                                 _mouseDown = false;
481                         }
482                         else {                    
483                                 if (uiSelection != null && (uiSelection.SelectionInProgress || uiSelection.ResizeInProgress)) { 
484                                         // If the mouse up happens over the a control which is not defacto participating in 
485                                         // the selection or resizing in progress, then inform the IUISelectionService of that event
486                                         //
487                                         uiSelection.MouseDragEnd (false);
488                                 }
489                         }
490                 }
491
492                 protected virtual void OnContextMenu (int x, int y)
493                 {
494                         IMenuCommandService service = this.GetService (typeof(IMenuCommandService)) as IMenuCommandService;
495                         if (service != null) {
496                                 service.ShowContextMenu (MenuCommands.SelectionMenu, x, y);
497                         }
498                 }
499
500                 protected virtual void OnMouseEnter ()
501                 {
502                 }
503
504                 protected virtual void OnMouseHover ()
505                 {
506                 }
507
508                 protected virtual void OnMouseLeave ()
509                 {
510                 }
511
512                 // Provides an opportunity to perform additional processing immediately
513                 // after the control handle has been created.
514                 //
515                 protected virtual void OnCreateHandle ()
516                 {
517                 }
518
519                 // Called after the control is done with the painting so that the designer host
520                 // can paint stuff over it.
521                 //
522                 protected virtual void OnPaintAdornments (PaintEventArgs pe)
523                 {
524                 }
525 #endregion
526
527
528 #region Mouse Dragging
529
530                 MouseButtons _mouseButtonDown;
531
532                 internal MouseButtons MouseButtonDown {
533                         get { return _mouseButtonDown;  }
534                 }
535
536                 protected virtual void OnMouseDragBegin (int x, int y)
537                 {
538                         IUISelectionService selectionServ = this.GetService (typeof (IUISelectionService)) as IUISelectionService;
539                         if (selectionServ != null && ((this.SelectionRules & SelectionRules.Moveable) == SelectionRules.Moveable)) {
540                                 // once this is fired the parent control (parentcontroldesigner) will start getting dragover events.
541                                 //
542                                 selectionServ.DragBegin ();
543                         }
544                 }
545
546                 protected virtual void OnMouseDragMove (int x, int y)
547                 {
548                 }
549                 
550                 protected virtual void OnMouseDragEnd (bool cancel)
551                 {
552                 }
553 #endregion
554
555                 
556 #region Parenting
557                 protected void HookChildControls (Control firstChild)
558                 {
559                         if (firstChild != null) {
560                                 foreach (Control control in firstChild.Controls) {
561                                         control.WindowTarget = (IWindowTarget) new WndProcRouter (control, (IMessageReceiver) this);
562                                 }
563                         }
564                 }
565
566                 protected void UnhookChildControls (Control firstChild)
567                 {
568                         if (firstChild != null) {
569                                 foreach (Control control in firstChild.Controls) {
570                                         if (control.WindowTarget is WndProcRouter)
571                                                 ((WndProcRouter) control.WindowTarget).Dispose ();
572                                 }
573                         }
574                 }
575
576                 // Someone please tell me why the hell is this method here?
577                 // What about having ParentControlDesigner.CanParent(...) ?
578                 // 
579                 public virtual bool CanBeParentedTo (IDesigner parentDesigner)
580                 {
581                         IDesignerHost host = this.GetService (typeof (IDesignerHost)) as IDesignerHost;
582
583                         if (parentDesigner is ParentControlDesigner &&
584                                 this.Component != host.RootComponent &&
585                                 !this.Control.Controls.Contains (((ParentControlDesigner)parentDesigner).Control)) {
586                                         return true;
587                         } else {
588                                 return false;
589                         }
590                 }
591 #endregion
592
593                 protected void DisplayError (Exception e)
594                 {
595                         if (e != null) {
596                                 IUIService uiService = GetService (typeof (IUIService)) as IUIService;
597                                 if (uiService != null) {
598                                         uiService.ShowError (e);
599                                 }
600                                 else {
601                                         string errorText = e.Message;
602                                         if (errorText == null ||  errorText == String.Empty)
603                                                 errorText = e.ToString ();
604                                         MessageBox.Show (Control, errorText, "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
605                                 }
606                         }
607                 }
608
609 #region Drag and Drop handling
610
611                 // Enables or disables Drag and Drop
612                 //
613                 protected void EnableDragDrop(bool value)
614                 {
615                         if (this.Control != null) {
616                                 if (value) {
617                                         Control.DragDrop += new DragEventHandler (OnDragDrop);
618                                         Control.DragOver += new DragEventHandler (OnDragOver);
619                                         Control.DragEnter += new DragEventHandler (OnDragEnter);
620                                         Control.DragLeave += new EventHandler (OnDragLeave);
621                                         Control.GiveFeedback += new GiveFeedbackEventHandler (OnGiveFeedback);
622                                         Control.AllowDrop = true;
623                                 }
624                                 else {
625                                         Control.DragDrop -= new DragEventHandler (OnDragDrop);
626                                         Control.DragOver -= new DragEventHandler (OnDragOver);
627                                         Control.DragEnter -= new DragEventHandler (OnDragEnter);
628                                         Control.DragLeave -= new EventHandler (OnDragLeave);
629                                         Control.GiveFeedback -= new GiveFeedbackEventHandler (OnGiveFeedback);
630                                         Control.AllowDrop = false;
631                                 }
632                         }
633                 }
634
635                 private void OnGiveFeedback (object sender, GiveFeedbackEventArgs e)
636                 {
637                         OnGiveFeedback (e);
638                 }
639
640                 private void OnDragDrop (object sender, DragEventArgs e)
641                 {
642                         OnDragDrop (e);
643                 }
644
645                 private void OnDragEnter (object sender, DragEventArgs e)
646                 {
647                         OnDragEnter (e);
648                 }
649
650                 private void OnDragLeave (object sender, EventArgs e)
651                 {
652                         OnDragLeave (e);
653                 }
654
655                 private void OnDragOver (object sender, DragEventArgs e)
656                 {
657                         OnDragOver (e);
658                 }
659
660                 protected virtual void OnGiveFeedback (GiveFeedbackEventArgs e)
661                 {
662                         e.UseDefaultCursors = false;
663                 }
664
665                 protected virtual void OnDragDrop (DragEventArgs de)
666                 {
667                 }
668
669                 protected virtual void OnDragEnter (DragEventArgs de)
670                 {
671                 }
672
673                 protected virtual void OnDragLeave (EventArgs e)
674                 {
675                 }
676
677                 protected virtual void OnDragOver (DragEventArgs de)
678                 {
679                 }
680 #endregion
681
682
683 #region Redirected Properties
684
685                 // This IDesignerFilter interface method override adds a set of properties
686                 // to this designer's component at design time. This method adds the following
687                 // browsable properties: "Visible", "Enabled", "ContextMenu", "AllowDrop", "Location",
688                 // "Name", "Controls", and "Locked".
689                 //
690                 // XXX: We aren't redirecting Controls
691                 // 
692                 protected override void PreFilterProperties (IDictionary properties)
693                 {
694                         base.PreFilterProperties (properties);
695
696                         string[] newProperties = {
697                                 "Visible", "Enabled", "ContextMenu", "AllowDrop", "Location", "Name",
698                         };
699
700                         Attribute[][] attributes = { 
701                                 new Attribute[] { new DefaultValueAttribute (true) },
702                                 new Attribute[] { new DefaultValueAttribute (true) },
703                                 new Attribute[] { new DefaultValueAttribute (null) },
704                                 new Attribute[] { new DefaultValueAttribute (false) },
705                                 new Attribute[] { new DefaultValueAttribute (typeof (Point), "0, 0") },
706                                 new Attribute[] {}
707                          };
708                         
709                         PropertyDescriptor propertyDescriptor = null;
710
711                         // If existing redirect each property to the ControlDesigner.
712                         //
713                         for (int i=0; i < newProperties.Length; i++) {
714                                 propertyDescriptor = properties[newProperties[i]] as PropertyDescriptor;
715                                 if (propertyDescriptor != null)
716                                         properties[newProperties[i]] = TypeDescriptor.CreateProperty (typeof (ControlDesigner),
717                                                                                                       propertyDescriptor,
718                                                                                                       attributes[i]);
719                         }
720
721                         // This one is a must to have.
722                         //
723                         properties["Locked"] = TypeDescriptor.CreateProperty (typeof (ControlDesigner), "Locked",
724                                                                                   typeof(bool),
725                                                                                   new Attribute[] {
726                                                                                           DesignOnlyAttribute.Yes,
727                                                                                           BrowsableAttribute.Yes,
728                                                                                           CategoryAttribute.Design,
729                                                                                           new DefaultValueAttribute (false),
730                                                                                           new DescriptionAttribute("The Locked property determines if we can move or resize the control.")
731                                                                                   });
732
733                 }
734
735                 // ShadowProperties returns the real property value if there is no "shadow" one set
736                 // Welcome to the land of shadows... :-)
737                 //
738                 private bool Visible {
739                         get { return (bool) base.ShadowProperties["Visible"]; }
740                         set { base.ShadowProperties["Visible"] = value; }
741                 }
742
743                 private bool Enabled {
744                         get { return (bool) base.ShadowProperties["Enabled"]; }
745                         set { base.ShadowProperties["Enabled"] = value; }
746                 }
747
748                 private bool Locked {
749                         get { return _locked; }
750                         set { _locked = value; }
751                 }
752
753                 private bool AllowDrop {
754                         get { return (bool)base.ShadowProperties["AllowDrop"]; }
755                         set { base.ShadowProperties["AllowDrop"] = value; }
756                 }
757
758                 private string Name {
759                         get { return base.Component.Site.Name; }
760                         set { base.Component.Site.Name = value; }
761                 }
762
763                 private ContextMenu ContextMenu {
764                         get { return (ContextMenu) base.ShadowProperties["ContextMenu"]; }
765                         set { base.ShadowProperties["ContextMenu"] = value; }
766                 }
767
768                 private Point Location {
769                         get { return this.Control.Location; }
770                         set { this.Control.Location = value; }
771                 }
772 #endregion
773
774
775 #region Utility methods
776                 internal object GetValue (object component, string propertyName)
777                 {
778                    return this.GetValue (component, propertyName, null);
779                 }
780                 
781                 internal object GetValue (object component, string propertyName, Type propertyType)
782                 {
783                         PropertyDescriptor prop = TypeDescriptor.GetProperties (component)[propertyName] as PropertyDescriptor;
784                         if (prop == null)
785                                 throw new InvalidOperationException ("Property \"" + propertyName + "\" is missing on " + 
786                                                                                                          component.GetType().AssemblyQualifiedName);
787                         if (propertyType != null && !propertyType.IsAssignableFrom (prop.PropertyType))
788                                         throw new InvalidOperationException ("Types do not match: " + prop.PropertyType.AssemblyQualifiedName +
789                                                                                                                  " : " + propertyType.AssemblyQualifiedName);
790                         return prop.GetValue (component);
791                 }
792
793                 internal void SetValue (object component, string propertyName, object value)
794                 {
795                         PropertyDescriptor prop = TypeDescriptor.GetProperties (component)[propertyName] as PropertyDescriptor;
796
797                         if (prop == null)
798                                         throw new InvalidOperationException ("Property \"" + propertyName + "\" is missing on " + 
799                                                                                                                  component.GetType().AssemblyQualifiedName);
800                         if (!prop.PropertyType.IsAssignableFrom (value.GetType ()))
801                                         throw new InvalidOperationException ("Types do not match: " + value.GetType ().AssemblyQualifiedName +
802                                                                                                                  " : " + prop.PropertyType.AssemblyQualifiedName);
803                         if (!prop.IsReadOnly)
804                                 prop.SetValue (component, value);
805                 }
806 #endregion
807
808                 protected override void Dispose (bool disposing)
809                 {
810                         if (disposing) {
811                                 if (this.Control != null) {
812                                         UnhookChildControls (Control);
813                                         OnMouseDragEnd (true);
814                                         _messageRouter.Dispose ();
815                                         this.Control.DragDrop -= new DragEventHandler (OnDragDrop);
816                                         this.Control.DragEnter -= new DragEventHandler (OnDragEnter);
817                                         this.Control.DragLeave -= new EventHandler (OnDragLeave);
818                                         this.Control.DragOver -= new DragEventHandler (OnDragOver);
819                                 }
820                         }
821                         base.Dispose (true);
822                 }
823
824
825
826                 public virtual ControlDesigner InternalControlDesigner (int internalControlIndex)
827                 {
828                         return null;
829                 }
830
831                 public virtual int NumberOfInternalControlDesigners ()
832                 {
833                         return 0;
834                 }
835
836                 protected bool EnableDesignMode (Control child, string name)
837                 {
838                         if (name == null)
839                                 throw new ArgumentNullException ("name");
840                         if (child == null)
841                                 throw new ArgumentNullException ("child");
842
843                         bool success = false;
844                         INestedContainer nestedContainer = this.GetService (typeof (INestedContainer)) as INestedContainer;
845                         if (nestedContainer != null) {
846                                 nestedContainer.Add (child, name);
847                                 success = true;
848                         }
849                         return success;
850                 }
851
852 #region NET_2_0 Stubs
853
854                 [ComVisible (true)]
855                 public class ControlDesignerAccessibleObject : AccessibleObject
856                 {
857                         [MonoTODO]
858                         public ControlDesignerAccessibleObject (ControlDesigner designer, Control control)
859                         {
860                                 throw new NotImplementedException ();
861                         }
862
863                         [MonoTODO]
864                         public override AccessibleObject GetChild (int index)
865                         {
866                                 throw new NotImplementedException ();
867                         }
868
869                         [MonoTODO]
870                         public override int GetChildCount ()
871                         {
872                                 throw new NotImplementedException ();
873                         }
874
875                         [MonoTODO]
876                         public override AccessibleObject GetFocused ()
877                         {
878                                 throw new NotImplementedException ();
879                         }
880
881                         [MonoTODO]
882                         public override AccessibleObject GetSelected ()
883                         {
884                                 throw new NotImplementedException ();
885                         }
886
887                         [MonoTODO]
888                         public override AccessibleObject HitTest (int x, int y)
889                         {
890                                 throw new NotImplementedException ();
891                         }
892
893                         [MonoTODO]
894                         public override Rectangle Bounds {
895                                 get { throw new NotImplementedException (); }
896                         }
897
898                         [MonoTODO]
899                         public override string DefaultAction {
900                                 get { throw new NotImplementedException (); }
901                         }
902
903                         [MonoTODO]
904                         public override string Description {
905                                 get { throw new NotImplementedException (); }
906                         }
907
908                         [MonoTODO]
909                         public override string Name {
910                                 get { throw new NotImplementedException (); }
911                         }
912
913                         [MonoTODO]
914                         public override AccessibleObject Parent {
915                                 get { throw new NotImplementedException (); }
916                         }
917
918                         [MonoTODO]
919                         public override AccessibleRole Role {
920                                 get { throw new NotImplementedException (); }
921                         }
922
923                         [MonoTODO]
924                         public override AccessibleStates State {
925                                 get { throw new NotImplementedException (); }
926                         }
927
928                         [MonoTODO]
929                         public override string Value {
930                                 get { throw new NotImplementedException (); }
931                         }
932                 }
933
934                 [MonoTODO]
935                 protected virtual ControlBodyGlyph GetControlGlyph (GlyphSelectionType selectionType)
936                 {
937                         throw new NotImplementedException ();
938                 }
939
940                 [MonoTODO]
941                 public virtual GlyphCollection GetGlyphs (GlyphSelectionType selectionType)
942                 {
943                         throw new NotImplementedException ();
944                 }
945
946                 [MonoTODO]
947                 public override void InitializeExistingComponent (IDictionary defaultValues)
948                 {
949                         throw new NotImplementedException ();
950                 }
951
952                 [MonoTODO]
953                 public override void InitializeNewComponent (IDictionary defaultValues)
954                 {
955                         throw new NotImplementedException ();
956                 }
957
958                 [MonoTODO]
959                 protected virtual void OnDragComplete (DragEventArgs de)
960                 {
961                         throw new NotImplementedException ();
962                 }
963
964                 [MonoTODO]
965                 protected override InheritanceAttribute InheritanceAttribute {
966                         get { throw new NotImplementedException (); }
967                 }
968
969                 [MonoTODO]
970                 public virtual IList SnapLines {
971                         get { throw new NotImplementedException (); }
972                 }
973
974                 [MonoTODO]
975                 public virtual bool ParticipatesWithSnapLines {
976                         get { throw new NotImplementedException (); }
977                 }
978
979                 [MonoTODO]
980                 public bool AutoResizeHandles {
981                         get { throw new NotImplementedException (); }
982                         set { throw new NotImplementedException (); }
983                 }
984 #endregion
985
986
987         }
988 }