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)]
38 [ComplexBindingProperties ("DataSource", "DataMember")]
40 public class ErrorProvider : Component, IExtenderProvider
45 private class ErrorWindow : UserControl
49 SetStyle (ControlStyles.Selectable, false);
53 #region Private Classes
54 private class ErrorProperty {
55 public ErrorIconAlignment alignment;
58 public Control control;
59 public ErrorProvider ep;
60 private ErrorWindow window;
62 private int blink_count;
63 private EventHandler tick;
64 private System.Windows.Forms.Timer timer;
66 public ErrorProperty(ErrorProvider ep, Control control) {
68 this.control = control;
70 alignment = ErrorIconAlignment.MiddleRight;
75 tick = new EventHandler(window_Tick);
77 window = new ErrorWindow ();
78 window.Visible = false;
79 window.Width = ep.icon.Width;
80 window.Height = ep.icon.Height;
83 // UIA Framework: Associate ErrorProvider with Control
84 ErrorProvider.OnUIAErrorProviderHookUp (ep, new ControlEventArgs (control));
86 // UIA Framework: Generate event to associate UserControl with ErrorProvider
87 window.VisibleChanged += delegate (object sender, EventArgs args) {
88 if (window.Visible == true)
89 ErrorProvider.OnUIAControlHookUp (control, new ControlEventArgs (window));
91 ErrorProvider.OnUIAControlUnhookUp (control, new ControlEventArgs (window));
95 if (control.Parent != null) {
97 // UIA Framework: Generate event to associate UserControl with ErrorProvider
98 ErrorProvider.OnUIAControlHookUp (control, new ControlEventArgs (window));
100 control.Parent.Controls.Add(window);
101 control.Parent.Controls.SetChildIndex(window, control.Parent.Controls.IndexOf (control) + 1);
104 window.Paint += new PaintEventHandler(window_Paint);
105 window.MouseEnter += new EventHandler(window_MouseEnter);
106 window.MouseLeave += new EventHandler(window_MouseLeave);
107 control.SizeChanged += new EventHandler(control_SizeLocationChanged);
108 control.LocationChanged += new EventHandler(control_SizeLocationChanged);
109 control.ParentChanged += new EventHandler (control_ParentChanged);
110 // Do we want to block mouse clicks? if so we need a few more events handled
112 CalculateAlignment();
122 value = string.Empty;
124 bool differentError = text != value;
127 if (text != String.Empty) {
128 window.Visible = true;
130 window.Visible = false;
134 // even if blink style is NeverBlink we need it to allow
135 // the timer to elapse at least once to get the icon to
137 if (differentError || ep.blinkstyle == ErrorBlinkStyle.AlwaysBlink) {
139 timer = new System.Windows.Forms.Timer();
142 timer.Interval = ep.blinkrate;
144 timer.Enabled = true;
149 public ErrorIconAlignment Alignment {
155 if (alignment != value) {
157 CalculateAlignment();
168 if (padding != value) {
170 CalculateAlignment();
175 private void CalculateAlignment() {
178 ep.tooltip.Visible = false;
182 case ErrorIconAlignment.TopLeft: {
183 window.Left = control.Left - ep.icon.Width - padding;
184 window.Top = control.Top;
188 case ErrorIconAlignment.TopRight: {
189 window.Left = control.Left + control.Width + padding;
190 window.Top = control.Top;
194 case ErrorIconAlignment.MiddleLeft: {
195 window.Left = control.Left - ep.icon.Width - padding;
196 window.Top = control.Top + (control.Height - ep.icon.Height) / 2;
200 case ErrorIconAlignment.MiddleRight: {
201 window.Left = control.Left + control.Width + padding;
202 window.Top = control.Top + (control.Height - ep.icon.Height) / 2;
206 case ErrorIconAlignment.BottomLeft: {
207 window.Left = control.Left - ep.icon.Width - padding;
208 window.Top = control.Top + control.Height - ep.icon.Height;
212 case ErrorIconAlignment.BottomRight: {
213 window.Left = control.Left + control.Width + padding;
214 window.Top = control.Top + control.Height - ep.icon.Height;
220 private void window_Paint(object sender, PaintEventArgs e) {
221 if (text != string.Empty) {
222 e.Graphics.DrawIcon(this.ep.icon, 0, 0);
226 private void window_MouseEnter(object sender, EventArgs e) {
233 pt = Control.MousePosition;
235 size = ThemeEngine.Current.ToolTipSize(ep.tooltip, text);
236 ep.tooltip.Width = size.Width;
237 ep.tooltip.Height = size.Height;
238 ep.tooltip.Text = text;
240 if ((pt.X + size.Width) < SystemInformation.WorkingArea.Width) {
241 ep.tooltip.Left = pt.X;
243 ep.tooltip.Left = pt.X - size.Width;
246 if ((pt.Y + size.Height) < (SystemInformation.WorkingArea.Height - 16)) {
247 ep.tooltip.Top = pt.Y + 16;
249 ep.tooltip.Top = pt.Y - size.Height;
253 // UIA Framework: Associate Control with ToolTip, used on Popup events
254 ep.UIAControl = control;
257 ep.tooltip.Visible = true;
261 private void window_MouseLeave(object sender, EventArgs e) {
264 ep.tooltip.Visible = false;
268 private void control_SizeLocationChanged(object sender, EventArgs e) {
271 ep.tooltip.Visible = false;
273 CalculateAlignment();
276 private void control_ParentChanged (object sender, EventArgs e)
278 if (control.Parent != null) {
281 // UIA Framework: Generate event to disassociate UserControl with ErrorProvider
282 ErrorProvider.OnUIAControlUnhookUp (control, new ControlEventArgs (window));
284 control.Parent.Controls.Add (window);
285 control.Parent.Controls.SetChildIndex (window, control.Parent.Controls.IndexOf (control) + 1);
288 // UIA Framework: Generate event to associate UserControl with ErrorProvider
289 ErrorProvider.OnUIAControlHookUp (control, new ControlEventArgs (window));
294 private void window_Tick(object sender, EventArgs e) {
295 if (timer.Enabled && control.IsHandleCreated && control.Visible) {
300 g = window.CreateGraphics();
301 if ((blink_count % 2) == 0) {
302 g.FillRectangle(ThemeEngine.Current.ResPool.GetSolidBrush(window.Parent.BackColor), window.ClientRectangle);
304 g.DrawIcon(this.ep.icon, 0, 0);
308 switch (ep.blinkstyle) {
309 case ErrorBlinkStyle.AlwaysBlink:
311 case ErrorBlinkStyle.BlinkIfDifferentError:
312 if (blink_count > 10)
315 case ErrorBlinkStyle.NeverBlink:
320 if (blink_count == 11)
327 #region Local Variables
328 private int blinkrate;
329 private ErrorBlinkStyle blinkstyle;
330 private string datamember;
331 private object datasource;
332 private ContainerControl container;
334 private Hashtable controls;
335 private ToolTip.ToolTipWindow tooltip;
338 private bool right_to_left;
341 #endregion // Local Variables
343 #region Public Constructors
344 public ErrorProvider()
346 controls = new Hashtable();
349 blinkstyle = ErrorBlinkStyle.BlinkIfDifferentError;
351 icon = ResourceImageLoader.GetIcon ("errorProvider.ico");
352 tooltip = new ToolTip.ToolTipWindow();
354 //UIA Framework: Event used to indicate the ToolTip is shown/hidden.
355 tooltip.VisibleChanged += delegate (object sender, EventArgs args) {
356 if (tooltip.Visible == true)
357 OnUIAPopup (this, new PopupEventArgs (UIAControl, UIAControl, false, Size.Empty));
358 else if (tooltip.Visible == false)
359 OnUIAUnPopup (this, new PopupEventArgs (UIAControl, UIAControl, false, Size.Empty));
364 public ErrorProvider(ContainerControl parentControl) : this ()
366 container = parentControl;
370 public ErrorProvider (IContainer container) : this ()
372 container.Add (this);
375 #endregion // Public Constructors
377 #region Public Instance Properties
379 [RefreshProperties(RefreshProperties.Repaint)]
380 public int BlinkRate {
390 [DefaultValue(ErrorBlinkStyle.BlinkIfDifferentError)]
391 public ErrorBlinkStyle BlinkStyle {
402 public ContainerControl ContainerControl {
414 [Editor ("System.Windows.Forms.Design.DataMemberListEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
415 public string DataMember {
422 // FIXME - add binding magic and also update BindToDataAndErrors with it
429 [AttributeProvider (typeof (IListSource))]
431 [TypeConverter("System.Windows.Forms.Design.DataSourceConverter, " + Consts.AssemblySystem_Design)]
433 public object DataSource {
440 // FIXME - add binding magic and also update BindToDataAndErrors with it
451 if (value != null && (value.Height != 16 || value.Width != 16))
452 icon = new Icon (value, 16, 16);
458 public override ISite Site {
465 [MonoTODO ("RTL not supported")]
467 [DefaultValue (false)]
468 public virtual bool RightToLeft {
469 get { return right_to_left; }
470 set { right_to_left = value; }
473 [Localizable (false)]
475 [TypeConverter (typeof (StringConverter))]
476 [DefaultValue (null)]
477 [MWFCategory ("Data")]
479 get { return this.tag; }
480 set { this.tag = value; }
483 #endregion // Public Instance Properties
485 #region Public Instance Methods
487 public void BindToDataAndErrors(object newDataSource, string newDataMember) {
488 datasource = newDataSource;
489 datamember = newDataMember;
493 public bool CanExtend(object extendee) {
494 if (!(extendee is Control)) {
498 if ((extendee is Form) || (extendee is ToolBar)) {
508 foreach (ErrorProperty ep in controls.Values)
509 ep.Text = string.Empty;
515 public string GetError(Control control) {
516 return GetErrorProperty(control).Text;
520 [DefaultValue(ErrorIconAlignment.MiddleRight)]
521 public ErrorIconAlignment GetIconAlignment(Control control) {
522 return GetErrorProperty(control).Alignment;
527 public int GetIconPadding(Control control) {
528 return GetErrorProperty(control).padding;
531 public void SetError(Control control, string value) {
532 GetErrorProperty(control).Text = value;
535 public void SetIconAlignment(Control control, ErrorIconAlignment value) {
536 GetErrorProperty(control).Alignment = value;
539 public void SetIconPadding(Control control, int padding) {
540 GetErrorProperty(control).Padding = padding;
544 public void UpdateBinding() {
546 #endregion // Public Instance Methods
548 #region Protected Instance Methods
549 protected override void Dispose(bool disposing) {
550 base.Dispose (disposing);
554 [EditorBrowsableAttribute (EditorBrowsableState.Advanced)]
555 protected virtual void OnRightToLeftChanged (EventArgs e)
557 EventHandler eh = (EventHandler)(Events[RightToLeftChangedEvent]);
562 #endregion // Protected Instance Methods
564 #region Private Methods
565 private ErrorProperty GetErrorProperty(Control control) {
566 ErrorProperty ep = (ErrorProperty)controls[control];
568 ep = new ErrorProperty(this, control);
569 controls[control] = ep;
573 #endregion // Private Methods
576 void ISupportInitialize.BeginInit ()
580 void ISupportInitialize.EndInit ()
585 #region Public Events
587 static object RightToLeftChangedEvent = new object ();
589 public event EventHandler RightToLeftChanged {
590 add { Events.AddHandler (RightToLeftChangedEvent, value); }
591 remove { Events.RemoveHandler (RightToLeftChangedEvent, value); }
596 #region UIA Framework: Events, Properties and Methods
599 // We are using Reflection to add/remove internal events.
600 // Class ToolTipListener uses the events.
602 // - UIAControlHookUp. Event used to associate UserControl with ErrorProvider
603 // - UIAControlUnhookUp. Event used to disassociate UserControl with ErrorProvider
604 // - UIAErrorProviderHookUp. Event used to associate Control with ErrorProvider
605 // - UIAErrorProviderUnhookUp. Event used to disassociate Control with ErrorProvider
606 // - UIAPopup. Event used show Popup
607 // - UIAUnPopup. Event used to hide popup.
609 private Control uia_control;
611 internal Control UIAControl {
612 get { return uia_control; }
613 set { uia_control = value; }
616 internal Rectangle UIAToolTipRectangle {
617 get { return tooltip.Bounds; }
620 internal static event ControlEventHandler UIAControlHookUp;
621 internal static event ControlEventHandler UIAControlUnhookUp;
622 internal static event ControlEventHandler UIAErrorProviderHookUp;
623 internal static event ControlEventHandler UIAErrorProviderUnhookUp;
624 internal static event PopupEventHandler UIAPopup;
625 internal static event PopupEventHandler UIAUnPopup;
627 internal static void OnUIAPopup (ErrorProvider sender, PopupEventArgs args)
629 if (UIAPopup != null)
630 UIAPopup (sender, args);
633 internal static void OnUIAUnPopup (ErrorProvider sender, PopupEventArgs args)
635 if (UIAUnPopup != null)
636 UIAUnPopup (sender, args);
639 internal static void OnUIAControlHookUp (object sender, ControlEventArgs args)
641 if (UIAControlHookUp != null)
642 UIAControlHookUp (sender, args);
645 internal static void OnUIAControlUnhookUp (object sender, ControlEventArgs args)
647 if (UIAControlUnhookUp != null)
648 UIAControlUnhookUp (sender, args);
651 internal static void OnUIAErrorProviderHookUp (object sender, ControlEventArgs args)
653 if (UIAErrorProviderHookUp != null)
654 UIAErrorProviderHookUp (sender, args);
657 internal static void OnUIAErrorProviderUnhookUp (object sender, ControlEventArgs args)
659 if (UIAErrorProviderUnhookUp != null)
660 UIAErrorProviderUnhookUp (sender, args);