Fixed typo
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / ErrorProvider.cs
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:
8 // 
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
11 // 
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.
19 //
20 // Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
21 //
22 // Authors:
23 //      Peter Bartok    (pbartok@novell.com)
24 //
25 //
26
27 using System;
28 using System.Collections;
29 using System.ComponentModel;
30 using System.Drawing;
31
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 #if NET_2_0
38         [ComplexBindingProperties ("DataSource", "DataMember")]
39 #endif
40         public class ErrorProvider : Component, IExtenderProvider
41 #if NET_2_0
42             , ISupportInitialize
43 #endif
44         {
45                 private class ErrorWindow : UserControl
46                 {
47                         public ErrorWindow ()
48                         {
49                                 SetStyle (ControlStyles.Selectable, false);
50                         }
51                 }
52
53                 #region Private Classes
54                 private class ErrorProperty {
55                         public ErrorIconAlignment       alignment;
56                         public int                      padding;
57                         public string                   text;
58                         public Control                  control;
59                         public ErrorProvider            ep;
60                         private ErrorWindow             window;
61                         private bool                    visible;
62                         private int                     blink_count;
63                         private EventHandler            tick;
64                         private System.Windows.Forms.Timer      timer;
65
66                         public ErrorProperty(ErrorProvider ep, Control control) {
67                                 this.ep = ep;
68                                 this.control = control;
69
70                                 alignment = ErrorIconAlignment.MiddleRight;
71                                 padding = 0;
72                                 text = string.Empty;
73                                 blink_count = 0;
74
75                                 tick = new EventHandler(window_Tick);
76
77                                 window = new ErrorWindow ();
78                                 window.Visible = false;
79                                 window.Width = ep.icon.Width;
80                                 window.Height = ep.icon.Height;
81
82                                 if (ep.container != null) {
83                                         ep.container.Controls.Add(window);
84                                         ep.container.Controls.SetChildIndex(window, 0);
85                                 } else if (control.Parent != null) {
86                                         control.Parent.Controls.Add(window);
87                                         control.Parent.Controls.SetChildIndex(window, 0);
88                                 }
89
90                                 window.Paint += new PaintEventHandler(window_Paint);
91                                 window.MouseEnter += new EventHandler(window_MouseEnter);
92                                 window.MouseLeave += new EventHandler(window_MouseLeave);
93                                 control.SizeChanged += new EventHandler(control_SizeLocationChanged);
94                                 control.LocationChanged += new EventHandler(control_SizeLocationChanged);
95                                 control.ParentChanged += new EventHandler (control_ParentChanged);
96                                 // Do we want to block mouse clicks? if so we need a few more events handled
97
98                                 CalculateAlignment();
99                         }
100
101                         public string Text {
102                                 get {
103                                         return text;
104                                 }
105
106                                 set {
107                                         if (value == null)
108                                                 value = string.Empty;
109
110                                         bool differentError = text != value;
111                                         text = value;
112
113                                         if (text != String.Empty) {
114                                                 window.Visible = true;
115                                         } else {
116                                                 window.Visible = false;
117                                                 return;
118                                         }
119
120                                         // even if blink style is NeverBlink we need it to allow
121                                         // the timer to elapse at least once to get the icon to 
122                                         // display
123                                         if (differentError || ep.blinkstyle == ErrorBlinkStyle.AlwaysBlink) {
124                                                 if (timer == null) {
125                                                         timer = new System.Windows.Forms.Timer();
126                                                         timer.Tick += tick;
127                                                 }
128                                                 timer.Interval = ep.blinkrate;
129                                                 blink_count = 0;
130                                                 timer.Enabled = true;
131                                         }
132                                 }
133                         }
134
135                         public ErrorIconAlignment Alignment {
136                                 get {
137                                         return alignment;
138                                 }
139
140                                 set {
141                                         if (alignment != value) {
142                                                 alignment = value;
143                                                 CalculateAlignment();
144                                         }
145                                 }
146                         }
147
148                         public int Padding {
149                                 get {
150                                         return padding;
151                                 }
152
153                                 set {
154                                         if (padding != value) {
155                                                 padding = value;
156                                                 CalculateAlignment();
157                                         }
158                                 }
159                         }
160
161                         private void CalculateAlignment() {
162                                 if (visible) {
163                                         visible = false;
164                                         ep.tooltip.Visible = false;
165                                 }
166
167                                 switch (alignment) {
168                                         case ErrorIconAlignment.TopLeft: {
169                                                 window.Left = control.Left - ep.icon.Width - padding;
170                                                 window.Top = control.Top;
171                                                 break;
172                                         }
173
174                                         case ErrorIconAlignment.TopRight: {
175                                                 window.Left = control.Left + control.Width + padding;
176                                                 window.Top = control.Top;
177                                                 break;
178                                         }
179
180                                         case ErrorIconAlignment.MiddleLeft: {
181                                                 window.Left = control.Left - ep.icon.Width - padding;
182                                                 window.Top = control.Top + (control.Height - ep.icon.Height) / 2;
183                                                 break;
184                                         }
185
186                                         case ErrorIconAlignment.MiddleRight: {
187                                                 window.Left = control.Left + control.Width + padding;
188                                                 window.Top = control.Top + (control.Height - ep.icon.Height) / 2;
189                                                 break;
190                                         }
191
192                                         case ErrorIconAlignment.BottomLeft: {
193                                                 window.Left = control.Left - ep.icon.Width - padding;
194                                                 window.Top = control.Top + control.Height - ep.icon.Height;
195                                                 break;
196                                         }
197
198                                         case ErrorIconAlignment.BottomRight: {
199                                                 window.Left = control.Left + control.Width + padding;
200                                                 window.Top = control.Top + control.Height - ep.icon.Height;
201                                                 break;
202                                         }
203                                 }
204                         }
205
206                         private void window_Paint(object sender, PaintEventArgs e) {
207                                 if (text != string.Empty) {
208                                         e.Graphics.DrawIcon(this.ep.icon, 0, 0);
209                                 }
210                         }
211
212                         private void window_MouseEnter(object sender, EventArgs e) {
213                                 if (!visible) {
214                                         Size    size;
215                                         Point   pt;
216
217                                         visible = true;
218
219                                         pt = Control.MousePosition;
220
221                                         size = ThemeEngine.Current.ToolTipSize(ep.tooltip, text);
222                                         ep.tooltip.Width = size.Width;
223                                         ep.tooltip.Height = size.Height;
224                                         ep.tooltip.Text = text;
225
226                                         if ((pt.X + size.Width) < SystemInformation.WorkingArea.Width) {
227                                                 ep.tooltip.Left = pt.X;
228                                         } else {
229                                                 ep.tooltip.Left = pt.X - size.Width;
230                                         }
231
232                                         if ((pt.Y + size.Height) < (SystemInformation.WorkingArea.Height - 16)) {
233                                                 ep.tooltip.Top = pt.Y + 16;
234                                         } else {
235                                                 ep.tooltip.Top = pt.Y - size.Height;
236                                         }
237                                         ep.tooltip.Visible = true;
238                                 }
239                         }
240
241                         private void window_MouseLeave(object sender, EventArgs e) {
242                                 if (visible) {
243                                         visible = false;
244                                         ep.tooltip.Visible = false;
245                                 }
246                         }
247
248                         private void control_SizeLocationChanged(object sender, EventArgs e) {
249                                 if (visible) {
250                                         visible = false;
251                                         ep.tooltip.Visible = false;
252                                 }
253                                 CalculateAlignment();
254                         }
255
256                         private void control_ParentChanged (object sender, EventArgs e)
257                         {
258                                 if (ep.container != null)
259                                         return;
260                                 control.Parent.Controls.Add (window);
261                                 control.Parent.Controls.SetChildIndex (window, 0);
262                         }
263
264                         private void window_Tick(object sender, EventArgs e) {
265                                 if (timer.Enabled && control.IsHandleCreated && control.Visible) {
266                                         Graphics g;
267
268                                         blink_count++;
269
270                                         g = window.CreateGraphics();
271                                         if ((blink_count % 2) == 0) {
272                                                 g.FillRectangle(ThemeEngine.Current.ResPool.GetSolidBrush(window.Parent.BackColor), window.ClientRectangle);
273                                         } else {
274                                                 g.DrawIcon(this.ep.icon, 0, 0);
275                                         }
276                                         g.Dispose();
277
278                                         switch (ep.blinkstyle) {
279                                         case ErrorBlinkStyle.AlwaysBlink:
280                                                 break;
281                                         case ErrorBlinkStyle.BlinkIfDifferentError:
282                                                 if (blink_count > 10)
283                                                         timer.Stop();
284                                                 break;
285                                         case ErrorBlinkStyle.NeverBlink:
286                                                 timer.Stop ();
287                                                 break;
288                                         }
289
290                                         if (blink_count == 11)
291                                                 blink_count = 1;
292                                 }
293                         }
294                 }
295                 #endregion
296
297                 #region Local Variables
298                 private int                     blinkrate;
299                 private ErrorBlinkStyle         blinkstyle;
300                 private string                  datamember;
301                 private object                  datasource;
302                 private ContainerControl        container;
303                 private Icon                    icon;
304                 private Hashtable               controls;
305                 private ToolTip.ToolTipWindow   tooltip;
306
307 #if NET_2_0
308                 private object tag;
309 #endif
310                 #endregion      // Local Variables
311
312                 #region Public Constructors
313                 public ErrorProvider()
314                 {
315                         controls = new Hashtable();
316
317                         blinkrate = 250;
318                         blinkstyle = ErrorBlinkStyle.BlinkIfDifferentError;
319
320                         icon = (Icon)Locale.GetResource("errorProvider.ico");
321                         tooltip = new ToolTip.ToolTipWindow();
322                 }
323
324                 public ErrorProvider(ContainerControl parentControl) : this ()
325                 {
326                         container = parentControl;
327                 }
328                 
329 #if NET_2_0
330                 public ErrorProvider (IContainer container) : this ()
331                 {
332                         container.Add (this);
333                 }
334 #endif
335                 #endregion      // Public Constructors
336
337                 #region Public Instance Properties
338                 [DefaultValue(250)]
339                 [RefreshProperties(RefreshProperties.Repaint)]
340                 public int BlinkRate {
341                         get {
342                                 return blinkrate;
343                         }
344
345                         set {
346                                 blinkrate = value;
347                         }
348                 }
349
350                 [DefaultValue(ErrorBlinkStyle.BlinkIfDifferentError)]
351                 public ErrorBlinkStyle BlinkStyle {
352                         get {
353                                 return blinkstyle;
354                         }
355
356                         set {
357                                 blinkstyle = value;
358                         }
359                 }
360
361                 [DefaultValue(null)]
362                 public ContainerControl ContainerControl {
363                         get {
364                                 return container;
365                         }
366
367                         set {
368                                 container = value;
369                         }
370                 }
371
372                 [MonoTODO]
373                 [DefaultValue(null)]
374                 [Editor ("System.Windows.Forms.Design.DataMemberListEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
375                 public string DataMember {
376                         get {
377                                 return datamember;
378                         }
379
380                         set {
381                                 datamember = value;
382                                 // FIXME - add binding magic and also update BindToDataAndErrors with it
383                         }
384                 }
385
386                 [MonoTODO]
387                 [DefaultValue(null)]
388 #if NET_2_0
389                 [AttributeProvider (typeof (IListSource))]
390 #else
391                 [TypeConverter("System.Windows.Forms.Design.DataSourceConverter, " + Consts.AssemblySystem_Design)]
392 #endif
393                 public object DataSource {
394                         get {
395                                 return datasource;
396                         }
397
398                         set {
399                                 datasource = value;
400                                 // FIXME - add binding magic and also update BindToDataAndErrors with it
401                         }
402                 }
403
404                 [Localizable(true)]
405                 public Icon Icon {
406                         get {
407                                 return icon;
408                         }
409
410                         set {
411                                 icon = value;
412                         }
413                 }
414
415                 public override ISite Site {
416                         set {
417                                 base.Site = value;
418                         }
419                 }
420
421 #if NET_2_0
422                 [Localizable (false)]
423                 [Bindable (true)]
424                 [TypeConverter (typeof (StringConverter))]
425                 [DefaultValue (null)]
426                 [MWFCategory ("Data")]
427                 public object Tag {
428                         get { return this.tag; }
429                         set { this.tag = value; }
430                 }
431 #endif
432                 #endregion      // Public Instance Properties
433
434                 #region Public Instance Methods
435                 [MonoTODO]
436                 public void BindToDataAndErrors(object newDataSource, string newDataMember) {
437                         datasource = newDataSource;
438                         datamember = newDataMember;
439                         // FIXME - finish
440                 }
441
442                 public bool CanExtend(object extendee) {
443                         if (!(extendee is Control)) {
444                                 return false;
445                         }
446
447                         if ((extendee is Form) || (extendee is ToolBar)) {
448                                 return false;
449                         }
450
451                         return true;
452                 }
453
454                 [Localizable(true)]
455                 [DefaultValue("")]
456                 public string GetError(Control control) {
457                         return GetErrorProperty(control).Text;
458                 }
459
460                 [Localizable(true)]
461                 [DefaultValue(ErrorIconAlignment.MiddleRight)]
462                 public ErrorIconAlignment GetIconAlignment(Control control) {
463                         return GetErrorProperty(control).Alignment;
464                 }
465
466                 [Localizable(true)]
467                 [DefaultValue(0)]
468                 public int GetIconPadding(Control control) {
469                         return GetErrorProperty(control).padding;
470                 }
471
472                 public void SetError(Control control, string value) {
473                         GetErrorProperty(control).Text = value;
474                 }
475
476                 public void SetIconAlignment(Control control, ErrorIconAlignment value) {
477                         GetErrorProperty(control).Alignment = value;
478                 }
479
480                 public void SetIconPadding(Control control, int padding) {
481                         GetErrorProperty(control).Padding = padding;
482                 }
483
484                 [MonoTODO]
485                 public void UpdateBinding() {
486                 }
487                 #endregion      // Public Instance Methods
488
489                 #region Protected Instance Methods
490                 protected override void Dispose(bool disposing) {
491                         base.Dispose (disposing);
492                 }
493                 #endregion      // Protected Instance Methods
494
495                 #region Private Methods
496                 private ErrorProperty GetErrorProperty(Control control) {
497                         ErrorProperty ep = (ErrorProperty)controls[control];
498                         if (ep == null) {
499                                 ep = new ErrorProperty(this, control);
500                                 controls[control] = ep;
501                         }
502                         return ep;
503                 }
504                 #endregion      // Private Methods
505
506 #if NET_2_0
507                 void ISupportInitialize.BeginInit ()
508                 {
509                 }
510
511                 void ISupportInitialize.EndInit ()
512                 {
513                 }
514 #endif
515         }
516 }