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
46 private class ErrorWindow : UserControl
50 SetStyle (ControlStyles.Selectable, false);
54 #region Private Classes
55 private class ErrorProperty {
56 public ErrorIconAlignment alignment;
59 public Control control;
60 public ErrorProvider ep;
61 private ErrorWindow window;
63 private int blink_count;
64 private EventHandler tick;
65 private System.Windows.Forms.Timer timer;
67 public ErrorProperty(ErrorProvider ep, Control control) {
69 this.control = control;
71 alignment = ErrorIconAlignment.MiddleRight;
76 tick = new EventHandler(window_Tick);
78 window = new ErrorWindow ();
79 window.Visible = false;
80 window.Width = ep.icon.Width;
81 window.Height = ep.icon.Height;
83 if (ep.container != null) {
84 ep.container.Controls.Add(window);
85 ep.container.Controls.SetChildIndex(window, 0);
87 control.Parent.Controls.Add(window);
88 control.Parent.Controls.SetChildIndex(window, 0);
91 window.Paint += new PaintEventHandler(window_Paint);
92 window.MouseEnter += new EventHandler(window_MouseEnter);
93 window.MouseLeave += new EventHandler(window_MouseLeave);
94 control.SizeChanged += new EventHandler(control_SizeLocationChanged);
95 control.LocationChanged += new EventHandler(control_SizeLocationChanged);
96 // Do we want to block mouse clicks? if so we need a few more events handled
108 if (text != String.Empty) {
109 window.Visible = true;
111 window.Visible = false;
114 if (ep.blinkstyle != ErrorBlinkStyle.NeverBlink) {
116 timer = new System.Windows.Forms.Timer();
118 timer.Interval = ep.blinkrate;
121 timer.Enabled = true;
126 public ErrorIconAlignment Alignment {
132 if (alignment != value) {
134 CalculateAlignment();
145 if (padding != value) {
147 CalculateAlignment();
152 private void CalculateAlignment() {
155 ep.tooltip.Visible = false;
159 case ErrorIconAlignment.TopLeft: {
160 window.Left = control.Left - ep.icon.Width - padding;
161 window.Top = control.Top;
165 case ErrorIconAlignment.TopRight: {
166 window.Left = control.Left + control.Width + padding;
167 window.Top = control.Top;
171 case ErrorIconAlignment.MiddleLeft: {
172 window.Left = control.Left - ep.icon.Width - padding;
173 window.Top = control.Top + (control.Height - ep.icon.Height) / 2;
177 case ErrorIconAlignment.MiddleRight: {
178 window.Left = control.Left + control.Width + padding;
179 window.Top = control.Top + (control.Height - ep.icon.Height) / 2;
183 case ErrorIconAlignment.BottomLeft: {
184 window.Left = control.Left - ep.icon.Width - padding;
185 window.Top = control.Top + control.Height - ep.icon.Height;
189 case ErrorIconAlignment.BottomRight: {
190 window.Left = control.Left + control.Width + padding;
191 window.Top = control.Top + control.Height - ep.icon.Height;
197 private void window_Paint(object sender, PaintEventArgs e) {
198 if (text != string.Empty) {
199 e.Graphics.DrawIcon(this.ep.icon, 0, 0);
203 private void window_MouseEnter(object sender, EventArgs e) {
210 pt = Control.MousePosition;
212 size = ThemeEngine.Current.ToolTipSize(ep.tooltip, text);
213 ep.tooltip.Width = size.Width;
214 ep.tooltip.Height = size.Height;
215 ep.tooltip.Text = text;
217 if ((pt.X + size.Width) < SystemInformation.WorkingArea.Width) {
218 ep.tooltip.Left = pt.X;
220 ep.tooltip.Left = pt.X - size.Width;
223 if ((pt.Y + size.Height) < (SystemInformation.WorkingArea.Height - 16)) {
224 ep.tooltip.Top = pt.Y + 16;
226 ep.tooltip.Top = pt.Y - size.Height;
228 ep.tooltip.Visible = true;
232 private void window_MouseLeave(object sender, EventArgs e) {
235 ep.tooltip.Visible = false;
239 private void control_SizeLocationChanged(object sender, EventArgs e) {
242 ep.tooltip.Visible = false;
244 CalculateAlignment();
247 private void window_Tick(object sender, EventArgs e) {
253 // Dunno why this POS doesn't reliably blink
254 g = window.CreateGraphics();
255 if ((blink_count % 2) == 0) {
256 g.FillRectangle(ThemeEngine.Current.ResPool.GetSolidBrush(window.Parent.BackColor), window.ClientRectangle);
258 g.DrawIcon(this.ep.icon, 0, 0);
262 if ((blink_count > 6) && (ep.blinkstyle == ErrorBlinkStyle.BlinkIfDifferentError)) {
271 #region Local Variables
272 private int blinkrate;
273 private ErrorBlinkStyle blinkstyle;
274 private string datamember;
275 private object datasource;
276 private ContainerControl container;
278 private Hashtable controls;
279 private ToolTip.ToolTipWindow tooltip;
284 #endregion // Local Variables
286 #region Public Constructors
287 public ErrorProvider()
289 controls = new Hashtable();
292 blinkstyle = ErrorBlinkStyle.BlinkIfDifferentError;
294 icon = (Icon)Locale.GetResource("errorProvider.ico");
295 tooltip = new ToolTip.ToolTipWindow();
298 public ErrorProvider(ContainerControl parentControl) : this()
300 container = parentControl;
304 public ErrorProvider (IContainer container)
306 container.Add (this);
309 #endregion // Public Constructors
311 #region Public Instance Properties
313 [RefreshProperties(RefreshProperties.Repaint)]
314 public int BlinkRate {
324 [DefaultValue(ErrorBlinkStyle.BlinkIfDifferentError)]
325 public ErrorBlinkStyle BlinkStyle {
336 public ContainerControl ContainerControl {
348 [Editor ("System.Windows.Forms.Design.DataMemberListEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
349 public string DataMember {
356 // FIXME - add binding magic and also update BindToDataAndErrors with it
363 [AttributeProvider (typeof (IListSource))]
365 [TypeConverter("System.Windows.Forms.Design.DataSourceConverter, " + Consts.AssemblySystem_Design)]
367 public object DataSource {
374 // FIXME - add binding magic and also update BindToDataAndErrors with it
389 public override ISite Site {
396 [Localizable (false)]
398 [TypeConverter (typeof (StringConverter))]
399 [DefaultValue (null)]
400 [MWFCategory ("Data")]
402 get { return this.tag; }
403 set { this.tag = value; }
406 #endregion // Public Instance Properties
408 #region Public Instance Methods
410 public void BindToDataAndErrors(object newDataSource, string newDataMember) {
411 datasource = newDataSource;
412 datamember = newDataMember;
416 public bool CanExtend(object extendee) {
417 if (!(extendee is Control)) {
421 if ((extendee is Form) || (extendee is ToolBar)) {
430 public string GetError(Control control) {
431 return GetErrorProperty(control).Text;
435 [DefaultValue(ErrorIconAlignment.MiddleRight)]
436 public ErrorIconAlignment GetIconAlignment(Control control) {
437 return GetErrorProperty(control).Alignment;
442 public int GetIconPadding(Control control) {
443 return GetErrorProperty(control).padding;
446 public void SetError(Control control, string value) {
447 GetErrorProperty(control).Text = value;
450 public void SetIconAlignment(Control control, ErrorIconAlignment value) {
451 GetErrorProperty(control).Alignment = value;
454 public void SetIconPadding(Control control, int padding) {
455 GetErrorProperty(control).Padding = padding;
459 public void UpdateBinding() {
461 #endregion // Public Instance Methods
463 #region Protected Instance Methods
464 protected override void Dispose(bool disposing) {
465 base.Dispose (disposing);
467 #endregion // Protected Instance Methods
469 #region Private Methods
470 private ErrorProperty GetErrorProperty(Control control) {
473 ep = (ErrorProperty)controls[control];
475 ep = new ErrorProperty(this, control);
476 controls[control] = ep;
481 #endregion // Private Methods
484 void ISupportInitialize.BeginInit ()
488 void ISupportInitialize.EndInit ()