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)
30 using System.Collections;
31 using System.ComponentModel;
34 namespace System.Windows.Forms {
35 [ToolboxItemFilter("System.Windows.Forms")]
36 [ProvideProperty("IconAlignment", "System.Windows.Forms.Control, " + Consts.AssemblySystem_Windows_Forms)]
37 [ProvideProperty("IconPadding", "System.Windows.Forms.Control, " + Consts.AssemblySystem_Windows_Forms)]
38 [ProvideProperty("Error", "System.Windows.Forms.Control, " + Consts.AssemblySystem_Windows_Forms)]
39 public class ErrorProvider : Component, IExtenderProvider {
40 #region Private Classes
41 private class ErrorProperty {
42 public ErrorIconAlignment alignment;
45 public Control control;
46 public ErrorProvider ep;
47 private UserControl window;
49 private int blink_count;
50 private EventHandler tick;
51 private System.Windows.Forms.Timer timer;
53 public ErrorProperty(ErrorProvider ep, Control control) {
55 this.control = control;
57 alignment = ErrorIconAlignment.MiddleRight;
62 tick = new EventHandler(window_Tick);
64 window = new UserControl();
65 window.Visible = false;
66 window.Width = ep.icon.Width;
67 window.Height = ep.icon.Height;
69 if (ep.container != null) {
70 ep.container.Controls.Add(window);
71 ep.container.Controls.SetChildIndex(window, 0);
73 control.parent.Controls.Add(window);
74 control.parent.Controls.SetChildIndex(window, 0);
77 window.Paint += new PaintEventHandler(window_Paint);
78 window.MouseEnter += new EventHandler(window_MouseEnter);
79 window.MouseLeave += new EventHandler(window_MouseLeave);
80 control.SizeChanged += new EventHandler(control_SizeLocationChanged);
81 control.LocationChanged += new EventHandler(control_SizeLocationChanged);
82 // Do we want to block mouse clicks? if so we need a few more events handled
94 if (text != String.Empty) {
95 window.Visible = true;
97 window.Visible = false;
100 if (ep.blinkstyle != ErrorBlinkStyle.NeverBlink) {
102 timer = new System.Windows.Forms.Timer();
104 timer.Interval = ep.blinkrate;
107 timer.Enabled = true;
112 public ErrorIconAlignment Alignment {
118 if (alignment != value) {
120 CalculateAlignment();
131 if (padding != value) {
133 CalculateAlignment();
138 private void CalculateAlignment() {
141 ep.tooltip.Visible = false;
145 case ErrorIconAlignment.TopLeft: {
146 window.Left = control.Left - ep.icon.Width - padding;
147 window.Top = control.Top;
151 case ErrorIconAlignment.TopRight: {
152 window.Left = control.Left + control.Width + padding;
153 window.Top = control.Top;
157 case ErrorIconAlignment.MiddleLeft: {
158 window.Left = control.Left - ep.icon.Width - padding;
159 window.Top = control.Top + (control.Height - ep.icon.Height) / 2;
163 case ErrorIconAlignment.MiddleRight: {
164 window.Left = control.Left + control.Width + padding;
165 window.Top = control.Top + (control.Height - ep.icon.Height) / 2;
169 case ErrorIconAlignment.BottomLeft: {
170 window.Left = control.Left - ep.icon.Width - padding;
171 window.Top = control.Top + control.Height - ep.icon.Height;
175 case ErrorIconAlignment.BottomRight: {
176 window.Left = control.Left + control.Width + padding;
177 window.Top = control.Top + control.Height - ep.icon.Height;
183 private void window_Paint(object sender, PaintEventArgs e) {
184 if (text != string.Empty) {
185 e.Graphics.DrawIcon(this.ep.icon, 0, 0);
189 private void window_MouseEnter(object sender, EventArgs e) {
196 pt = Control.MousePosition;
198 size = ThemeEngine.Current.ToolTipSize(ep.tooltip, text);
199 ep.tooltip.Width = size.Width;
200 ep.tooltip.Height = size.Height;
201 ep.tooltip.Text = text;
203 if ((pt.X + size.Width) < SystemInformation.WorkingArea.Width) {
204 ep.tooltip.Left = pt.X;
206 ep.tooltip.Left = pt.X - size.Width;
209 if ((pt.Y + size.Height) < (SystemInformation.WorkingArea.Height - 16)) {
210 ep.tooltip.Top = pt.Y + 16;
212 ep.tooltip.Top = pt.Y - size.Height;
214 ep.tooltip.Visible = true;
218 private void window_MouseLeave(object sender, EventArgs e) {
221 ep.tooltip.Visible = false;
225 private void control_SizeLocationChanged(object sender, EventArgs e) {
228 ep.tooltip.Visible = false;
230 CalculateAlignment();
233 private void window_Tick(object sender, EventArgs e) {
239 // Dunno why this POS doesn't reliably blink
240 g = window.CreateGraphics();
241 if ((blink_count % 2) == 0) {
242 g.FillRectangle(ThemeEngine.Current.ResPool.GetSolidBrush(window.parent.BackColor), window.ClientRectangle);
244 g.DrawIcon(this.ep.icon, 0, 0);
248 if ((blink_count > 6) && (ep.blinkstyle == ErrorBlinkStyle.BlinkIfDifferentError)) {
257 #region Local Variables
258 private int blinkrate;
259 private ErrorBlinkStyle blinkstyle;
260 private string datamember;
261 private object datasource;
262 private ContainerControl container;
264 private Hashtable controls;
265 private ToolTip.ToolTipWindow tooltip;
266 #endregion // Local Variables
268 #region Public Constructors
269 public ErrorProvider() {
270 controls = new Hashtable();
273 blinkstyle = ErrorBlinkStyle.BlinkIfDifferentError;
275 icon = (Icon)Locale.GetResource("errorProvider.ico");
276 tooltip = new ToolTip.ToolTipWindow(null);
279 public ErrorProvider(ContainerControl parentControl) : this() {
280 container = parentControl;
282 #endregion // Public Constructors
284 #region Public Instance Properties
286 [RefreshProperties(RefreshProperties.Repaint)]
287 public int BlinkRate {
297 [DefaultValue(ErrorBlinkStyle.BlinkIfDifferentError)]
298 public ErrorBlinkStyle BlinkStyle {
309 public ContainerControl ContainerControl {
321 [Editor ("System.Windows.Forms.Design.DataMemberListEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
322 public string DataMember {
329 // FIXME - add binding magic and also update BindToDataAndErrors with it
335 [TypeConverter("System.Windows.Forms.Design.DataSourceConverter, " + Consts.AssemblySystem_Design)]
336 public object DataSource {
343 // FIXME - add binding magic and also update BindToDataAndErrors with it
358 public override ISite Site {
363 #endregion // Public Instance Properties
365 #region Public Instance Methods
367 public void BindToDataAndErrors(object newDataSource, string newDataMember) {
368 datasource = newDataSource;
369 datamember = newDataMember;
373 public bool CanExtend(object extendee) {
374 if (!(extendee is Control)) {
378 if ((extendee is Form) || (extendee is ToolBar)) {
387 public string GetError(Control control) {
388 return GetErrorProperty(control).Text;
392 [DefaultValue(ErrorIconAlignment.MiddleRight)]
393 public ErrorIconAlignment GetIconAlignment(Control control) {
394 return GetErrorProperty(control).Alignment;
399 public int GetIconPadding(Control control) {
400 return GetErrorProperty(control).padding;
403 public void SetError(Control control, string value) {
404 GetErrorProperty(control).Text = value;
407 public void SetIconAlignment(Control control, ErrorIconAlignment value) {
408 GetErrorProperty(control).Alignment = value;
411 public void SetIconPadding(Control control, int padding) {
412 GetErrorProperty(control).Padding = padding;
416 public void UpdateBinding() {
418 #endregion // Public Instance Methods
420 #region Protected Instance Methods
421 protected override void Dispose(bool disposing) {
422 base.Dispose (disposing);
424 #endregion // Protected Instance Methods
426 #region Private Methods
427 private ErrorProperty GetErrorProperty(Control control) {
430 ep = (ErrorProperty)controls[control];
432 ep = new ErrorProperty(this, control);
433 controls[control] = ep;
438 #endregion // Private Methods