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:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
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.
20 // Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
23 // Peter Bartok (pbartok@novell.com)
28 using System.Collections;
29 using System.ComponentModel;
32 namespace System.Windows.Forms {
33 [ToolboxItemFilter("System.Windows.Forms")]
34 [ProvideProperty("IconAlignment", "System.Windows.Forms.Control, " + Consts.AssemblySystem_Windows_Forms)]
35 [ProvideProperty("IconPadding", "System.Windows.Forms.Control, " + Consts.AssemblySystem_Windows_Forms)]
36 [ProvideProperty("Error", "System.Windows.Forms.Control, " + Consts.AssemblySystem_Windows_Forms)]
37 [ComplexBindingProperties ("DataSource", "DataMember")]
38 public class ErrorProvider : Component, IExtenderProvider, ISupportInitialize
40 private class ErrorWindow : UserControl
44 SetStyle (ControlStyles.Selectable, false);
48 #region Private Classes
49 private class ErrorProperty {
50 public ErrorIconAlignment alignment;
53 public Control control;
54 public ErrorProvider ep;
55 private ErrorWindow window;
57 private int blink_count;
58 private EventHandler tick;
59 private System.Windows.Forms.Timer timer;
61 public ErrorProperty(ErrorProvider ep, Control control) {
63 this.control = control;
65 alignment = ErrorIconAlignment.MiddleRight;
70 tick = new EventHandler(window_Tick);
72 window = new ErrorWindow ();
73 window.Visible = false;
74 window.Width = ep.icon.Width;
75 window.Height = ep.icon.Height;
77 // UIA Framework: Associate ErrorProvider with Control
78 ErrorProvider.OnUIAErrorProviderHookUp (ep, new ControlEventArgs (control));
80 // UIA Framework: Generate event to associate UserControl with ErrorProvider
81 window.VisibleChanged += delegate (object sender, EventArgs args) {
82 if (window.Visible == true)
83 ErrorProvider.OnUIAControlHookUp (control, new ControlEventArgs (window));
85 ErrorProvider.OnUIAControlUnhookUp (control, new ControlEventArgs (window));
88 if (control.Parent != null) {
89 // UIA Framework: Generate event to associate UserControl with ErrorProvider
90 ErrorProvider.OnUIAControlHookUp (control, new ControlEventArgs (window));
91 control.Parent.Controls.Add(window);
92 control.Parent.Controls.SetChildIndex(window, control.Parent.Controls.IndexOf (control) + 1);
95 window.Paint += new PaintEventHandler(window_Paint);
96 window.MouseEnter += new EventHandler(window_MouseEnter);
97 window.MouseLeave += new EventHandler(window_MouseLeave);
98 control.SizeChanged += new EventHandler(control_SizeLocationChanged);
99 control.LocationChanged += new EventHandler(control_SizeLocationChanged);
100 control.ParentChanged += new EventHandler (control_ParentChanged);
101 // Do we want to block mouse clicks? if so we need a few more events handled
103 CalculateAlignment();
113 value = string.Empty;
115 bool differentError = text != value;
118 if (text != String.Empty) {
119 window.Visible = true;
121 window.Visible = false;
125 // even if blink style is NeverBlink we need it to allow
126 // the timer to elapse at least once to get the icon to
128 if (differentError || ep.blinkstyle == ErrorBlinkStyle.AlwaysBlink) {
130 timer = new System.Windows.Forms.Timer();
133 timer.Interval = ep.blinkrate;
135 timer.Enabled = true;
140 public ErrorIconAlignment Alignment {
146 if (alignment != value) {
148 CalculateAlignment();
159 if (padding != value) {
161 CalculateAlignment();
166 private void CalculateAlignment() {
169 ep.tooltip.Visible = false;
173 case ErrorIconAlignment.TopLeft: {
174 window.Left = control.Left - ep.icon.Width - padding;
175 window.Top = control.Top;
179 case ErrorIconAlignment.TopRight: {
180 window.Left = control.Left + control.Width + padding;
181 window.Top = control.Top;
185 case ErrorIconAlignment.MiddleLeft: {
186 window.Left = control.Left - ep.icon.Width - padding;
187 window.Top = control.Top + (control.Height - ep.icon.Height) / 2;
191 case ErrorIconAlignment.MiddleRight: {
192 window.Left = control.Left + control.Width + padding;
193 window.Top = control.Top + (control.Height - ep.icon.Height) / 2;
197 case ErrorIconAlignment.BottomLeft: {
198 window.Left = control.Left - ep.icon.Width - padding;
199 window.Top = control.Top + control.Height - ep.icon.Height;
203 case ErrorIconAlignment.BottomRight: {
204 window.Left = control.Left + control.Width + padding;
205 window.Top = control.Top + control.Height - ep.icon.Height;
211 private void window_Paint(object sender, PaintEventArgs e) {
212 if (text != string.Empty) {
213 e.Graphics.DrawIcon(this.ep.icon, 0, 0);
217 private void window_MouseEnter(object sender, EventArgs e) {
224 pt = Control.MousePosition;
226 size = ThemeEngine.Current.ToolTipSize(ep.tooltip, text);
227 ep.tooltip.Width = size.Width;
228 ep.tooltip.Height = size.Height;
229 ep.tooltip.Text = text;
231 if ((pt.X + size.Width) < SystemInformation.WorkingArea.Width) {
232 ep.tooltip.Left = pt.X;
234 ep.tooltip.Left = pt.X - size.Width;
237 if ((pt.Y + size.Height) < (SystemInformation.WorkingArea.Height - 16)) {
238 ep.tooltip.Top = pt.Y + 16;
240 ep.tooltip.Top = pt.Y - size.Height;
243 // UIA Framework: Associate Control with ToolTip, used on Popup events
244 ep.UIAControl = control;
246 ep.tooltip.Visible = true;
250 private void window_MouseLeave(object sender, EventArgs e) {
253 ep.tooltip.Visible = false;
257 private void control_SizeLocationChanged(object sender, EventArgs e) {
260 ep.tooltip.Visible = false;
262 CalculateAlignment();
265 private void control_ParentChanged (object sender, EventArgs e)
267 if (control.Parent != null) {
269 // UIA Framework: Generate event to disassociate UserControl with ErrorProvider
270 ErrorProvider.OnUIAControlUnhookUp (control, new ControlEventArgs (window));
271 control.Parent.Controls.Add (window);
272 control.Parent.Controls.SetChildIndex (window, control.Parent.Controls.IndexOf (control) + 1);
274 // UIA Framework: Generate event to associate UserControl with ErrorProvider
275 ErrorProvider.OnUIAControlHookUp (control, new ControlEventArgs (window));
279 private void window_Tick(object sender, EventArgs e) {
280 if (timer.Enabled && control.IsHandleCreated && control.Visible) {
285 g = window.CreateGraphics();
286 if ((blink_count % 2) == 0) {
287 g.FillRectangle(ThemeEngine.Current.ResPool.GetSolidBrush(window.Parent.BackColor), window.ClientRectangle);
289 g.DrawIcon(this.ep.icon, 0, 0);
293 switch (ep.blinkstyle) {
294 case ErrorBlinkStyle.AlwaysBlink:
296 case ErrorBlinkStyle.BlinkIfDifferentError:
297 if (blink_count > 10)
300 case ErrorBlinkStyle.NeverBlink:
305 if (blink_count == 11)
312 #region Local Variables
313 private int blinkrate;
314 private ErrorBlinkStyle blinkstyle;
315 private string datamember;
316 private object datasource;
317 private ContainerControl container;
319 private Hashtable controls;
320 private ToolTip.ToolTipWindow tooltip;
322 private bool right_to_left;
324 #endregion // Local Variables
326 #region Public Constructors
327 public ErrorProvider()
329 controls = new Hashtable();
332 blinkstyle = ErrorBlinkStyle.BlinkIfDifferentError;
334 icon = ResourceImageLoader.GetIcon ("errorProvider.ico");
335 tooltip = new ToolTip.ToolTipWindow();
337 //UIA Framework: Event used to indicate the ToolTip is shown/hidden.
338 tooltip.VisibleChanged += delegate (object sender, EventArgs args) {
339 if (tooltip.Visible == true)
340 OnUIAPopup (this, new PopupEventArgs (UIAControl, UIAControl, false, Size.Empty));
341 else if (tooltip.Visible == false)
342 OnUIAUnPopup (this, new PopupEventArgs (UIAControl, UIAControl, false, Size.Empty));
346 public ErrorProvider(ContainerControl parentControl) : this ()
348 container = parentControl;
351 public ErrorProvider (IContainer container) : this ()
353 container.Add (this);
355 #endregion // Public Constructors
357 #region Public Instance Properties
359 [RefreshProperties(RefreshProperties.Repaint)]
360 public int BlinkRate {
370 [DefaultValue(ErrorBlinkStyle.BlinkIfDifferentError)]
371 public ErrorBlinkStyle BlinkStyle {
382 public ContainerControl ContainerControl {
392 [MonoTODO ("Stub, does nothing")]
393 [DefaultValue (null)]
394 [Editor ("System.Windows.Forms.Design.DataMemberListEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
395 public string DataMember {
402 // FIXME - add binding magic and also update BindToDataAndErrors with it
406 [MonoTODO ("Stub, does nothing")]
407 [DefaultValue (null)]
408 [AttributeProvider (typeof (IListSource))]
409 public object DataSource {
416 // FIXME - add binding magic and also update BindToDataAndErrors with it
427 if (value != null && (value.Height != 16 || value.Width != 16))
428 icon = new Icon (value, 16, 16);
434 public override ISite Site {
440 [MonoTODO ("RTL not supported")]
442 [DefaultValue (false)]
443 public virtual bool RightToLeft {
444 get { return right_to_left; }
445 set { right_to_left = value; }
448 [Localizable (false)]
450 [TypeConverter (typeof (StringConverter))]
451 [DefaultValue (null)]
452 [MWFCategory ("Data")]
454 get { return this.tag; }
455 set { this.tag = value; }
457 #endregion // Public Instance Properties
459 #region Public Instance Methods
460 [MonoTODO ("Stub, does nothing")]
461 public void BindToDataAndErrors (object newDataSource, string newDataMember)
463 datasource = newDataSource;
464 datamember = newDataMember;
468 public bool CanExtend(object extendee) {
469 if (!(extendee is Control)) {
473 if ((extendee is Form) || (extendee is ToolBar)) {
482 foreach (ErrorProperty ep in controls.Values)
483 ep.Text = string.Empty;
488 public string GetError(Control control) {
489 return GetErrorProperty(control).Text;
493 [DefaultValue(ErrorIconAlignment.MiddleRight)]
494 public ErrorIconAlignment GetIconAlignment(Control control) {
495 return GetErrorProperty(control).Alignment;
500 public int GetIconPadding(Control control) {
501 return GetErrorProperty(control).padding;
504 public void SetError(Control control, string value) {
505 GetErrorProperty(control).Text = value;
508 public void SetIconAlignment(Control control, ErrorIconAlignment value) {
509 GetErrorProperty(control).Alignment = value;
512 public void SetIconPadding(Control control, int padding) {
513 GetErrorProperty(control).Padding = padding;
516 [MonoTODO ("Stub, does nothing")]
517 public void UpdateBinding ()
520 #endregion // Public Instance Methods
522 #region Protected Instance Methods
523 protected override void Dispose(bool disposing) {
524 base.Dispose (disposing);
527 [EditorBrowsableAttribute (EditorBrowsableState.Advanced)]
528 protected virtual void OnRightToLeftChanged (EventArgs e)
530 EventHandler eh = (EventHandler)(Events[RightToLeftChangedEvent]);
534 #endregion // Protected Instance Methods
536 #region Private Methods
537 private ErrorProperty GetErrorProperty(Control control) {
538 ErrorProperty ep = (ErrorProperty)controls[control];
540 ep = new ErrorProperty(this, control);
541 controls[control] = ep;
545 #endregion // Private Methods
547 void ISupportInitialize.BeginInit ()
551 void ISupportInitialize.EndInit ()
555 #region Public Events
556 static object RightToLeftChangedEvent = new object ();
558 public event EventHandler RightToLeftChanged {
559 add { Events.AddHandler (RightToLeftChangedEvent, value); }
560 remove { Events.RemoveHandler (RightToLeftChangedEvent, value); }
564 #region UIA Framework: Events, Properties and Methods
566 // We are using Reflection to add/remove internal events.
567 // Class ToolTipListener uses the events.
569 // - UIAControlHookUp. Event used to associate UserControl with ErrorProvider
570 // - UIAControlUnhookUp. Event used to disassociate UserControl with ErrorProvider
571 // - UIAErrorProviderHookUp. Event used to associate Control with ErrorProvider
572 // - UIAErrorProviderUnhookUp. Event used to disassociate Control with ErrorProvider
573 // - UIAPopup. Event used show Popup
574 // - UIAUnPopup. Event used to hide popup.
576 private Control uia_control;
578 internal Control UIAControl {
579 get { return uia_control; }
580 set { uia_control = value; }
583 internal Rectangle UIAToolTipRectangle {
584 get { return tooltip.Bounds; }
587 internal static event ControlEventHandler UIAControlHookUp;
588 internal static event ControlEventHandler UIAControlUnhookUp;
589 internal static event ControlEventHandler UIAErrorProviderHookUp;
590 internal static event ControlEventHandler UIAErrorProviderUnhookUp;
591 internal static event PopupEventHandler UIAPopup;
592 internal static event PopupEventHandler UIAUnPopup;
594 internal static void OnUIAPopup (ErrorProvider sender, PopupEventArgs args)
596 if (UIAPopup != null)
597 UIAPopup (sender, args);
600 internal static void OnUIAUnPopup (ErrorProvider sender, PopupEventArgs args)
602 if (UIAUnPopup != null)
603 UIAUnPopup (sender, args);
606 internal static void OnUIAControlHookUp (object sender, ControlEventArgs args)
608 if (UIAControlHookUp != null)
609 UIAControlHookUp (sender, args);
612 internal static void OnUIAControlUnhookUp (object sender, ControlEventArgs args)
614 if (UIAControlUnhookUp != null)
615 UIAControlUnhookUp (sender, args);
618 internal static void OnUIAErrorProviderHookUp (object sender, ControlEventArgs args)
620 if (UIAErrorProviderHookUp != null)
621 UIAErrorProviderHookUp (sender, args);
624 internal static void OnUIAErrorProviderUnhookUp (object sender, ControlEventArgs args)
626 if (UIAErrorProviderUnhookUp != null)
627 UIAErrorProviderUnhookUp (sender, args);