* TreeView.cs: Don't draw the selected node when we lose
[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 // COMPLETE
28
29 using System;
30 using System.Collections;
31 using System.ComponentModel;
32 using System.Drawing;
33
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;
43                         public int                      padding;
44                         public string                   text;
45                         public Control                  control;
46                         public ErrorProvider            ep;
47                         private UserControl             window;
48                         private bool                    visible;
49                         private int                     blink_count;
50                         private EventHandler            tick;
51                         private System.Windows.Forms.Timer      timer;
52
53                         public ErrorProperty(ErrorProvider ep, Control control) {
54                                 this.ep = ep;
55                                 this.control = control;
56
57                                 alignment = ErrorIconAlignment.MiddleRight;
58                                 padding = 0;
59                                 text = string.Empty;
60                                 blink_count = 0;
61
62                                 tick = new EventHandler(window_Tick);
63
64                                 window = new UserControl();
65                                 window.Visible = false;
66                                 window.Width = ep.icon.Width;
67                                 window.Height = ep.icon.Height;
68
69                                 if (ep.container != null) {
70                                         ep.container.Controls.Add(window);
71                                         ep.container.Controls.SetChildIndex(window, 0);
72                                 } else {
73                                         control.parent.Controls.Add(window);
74                                         control.parent.Controls.SetChildIndex(window, 0);
75                                 }
76
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
83
84                                 CalculateAlignment();
85                         }
86
87                         public string Text {
88                                 get {
89                                         return text;
90                                 }
91
92                                 set {
93                                         text = value;
94                                         if (text != String.Empty) {
95                                                 window.Visible = true;
96                                         } else {
97                                                 window.Visible = false;
98                                         }
99
100                                         if (ep.blinkstyle != ErrorBlinkStyle.NeverBlink) {
101                                                 if (timer == null) {
102                                                         timer = new System.Windows.Forms.Timer();
103                                                 }
104                                                 timer.Interval = ep.blinkrate;
105                                                 timer.Tick += tick;
106                                                 blink_count = 0;
107                                                 timer.Enabled = true;
108                                         }
109                                 }
110                         }
111
112                         public ErrorIconAlignment Alignment {
113                                 get {
114                                         return alignment;
115                                 }
116
117                                 set {
118                                         if (alignment != value) {
119                                                 alignment = value;
120                                                 CalculateAlignment();
121                                         }
122                                 }
123                         }
124
125                         public int Padding {
126                                 get {
127                                         return padding;
128                                 }
129
130                                 set {
131                                         if (padding != value) {
132                                                 padding = value;
133                                                 CalculateAlignment();
134                                         }
135                                 }
136                         }
137
138                         private void CalculateAlignment() {
139                                 if (visible) {
140                                         visible = false;
141                                         ep.tooltip.Visible = false;
142                                 }
143
144                                 switch (alignment) {
145                                         case ErrorIconAlignment.TopLeft: {
146                                                 window.Left = control.Left - ep.icon.Width - padding;
147                                                 window.Top = control.Top;
148                                                 break;
149                                         }
150
151                                         case ErrorIconAlignment.TopRight: {
152                                                 window.Left = control.Left + control.Width + padding;
153                                                 window.Top = control.Top;
154                                                 break;
155                                         }
156
157                                         case ErrorIconAlignment.MiddleLeft: {
158                                                 window.Left = control.Left - ep.icon.Width - padding;
159                                                 window.Top = control.Top + (control.Height - ep.icon.Height) / 2;
160                                                 break;
161                                         }
162
163                                         case ErrorIconAlignment.MiddleRight: {
164                                                 window.Left = control.Left + control.Width + padding;
165                                                 window.Top = control.Top + (control.Height - ep.icon.Height) / 2;
166                                                 break;
167                                         }
168
169                                         case ErrorIconAlignment.BottomLeft: {
170                                                 window.Left = control.Left - ep.icon.Width - padding;
171                                                 window.Top = control.Top + control.Height - ep.icon.Height;
172                                                 break;
173                                         }
174
175                                         case ErrorIconAlignment.BottomRight: {
176                                                 window.Left = control.Left + control.Width + padding;
177                                                 window.Top = control.Top + control.Height - ep.icon.Height;
178                                                 break;
179                                         }
180                                 }
181                         }
182
183                         private void window_Paint(object sender, PaintEventArgs e) {
184                                 if (text != string.Empty) {
185                                         e.Graphics.DrawIcon(this.ep.icon, 0, 0);
186                                 }
187                         }
188
189                         private void window_MouseEnter(object sender, EventArgs e) {
190                                 if (!visible) {
191                                         Size    size;
192                                         Point   pt;
193
194                                         visible = true;
195
196                                         pt = Control.MousePosition;
197
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;
202
203                                         if ((pt.X + size.Width) < SystemInformation.WorkingArea.Width) {
204                                                 ep.tooltip.Left = pt.X;
205                                         } else {
206                                                 ep.tooltip.Left = pt.X - size.Width;
207                                         }
208
209                                         if ((pt.Y + size.Height) < (SystemInformation.WorkingArea.Height - 16)) {
210                                                 ep.tooltip.Top = pt.Y + 16;
211                                         } else {
212                                                 ep.tooltip.Top = pt.Y - size.Height;
213                                         }
214                                         ep.tooltip.Visible = true;
215                                 }
216                         }
217
218                         private void window_MouseLeave(object sender, EventArgs e) {
219                                 if (visible) {
220                                         visible = false;
221                                         ep.tooltip.Visible = false;
222                                 }
223                         }
224
225                         private void control_SizeLocationChanged(object sender, EventArgs e) {
226                                 if (visible) {
227                                         visible = false;
228                                         ep.tooltip.Visible = false;
229                                 }
230                                 CalculateAlignment();
231                         }
232
233                         private void window_Tick(object sender, EventArgs e) {
234                                 if (timer.Enabled) {
235                                         Graphics g;
236
237                                         blink_count++;
238
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);
243                                         } else {
244                                                 g.DrawIcon(this.ep.icon, 0, 0);
245                                         }
246                                         g.Dispose();
247
248                                         if ((blink_count > 6) && (ep.blinkstyle == ErrorBlinkStyle.BlinkIfDifferentError)) {
249                                                 timer.Stop();
250                                                 blink_count = 0;
251                                         }
252                                 }
253                         }
254                 }
255                 #endregion
256
257                 #region Local Variables
258                 private int                     blinkrate;
259                 private ErrorBlinkStyle         blinkstyle;
260                 private string                  datamember;
261                 private object                  datasource;
262                 private ContainerControl        container;
263                 private Icon                    icon;
264                 private Hashtable               controls;
265                 private ToolTip.ToolTipWindow   tooltip;
266                 #endregion      // Local Variables
267
268                 #region Public Constructors
269                 public ErrorProvider() {
270                         controls = new Hashtable();
271
272                         blinkrate = 250;
273                         blinkstyle = ErrorBlinkStyle.BlinkIfDifferentError;
274
275                         icon = (Icon)Locale.GetResource("errorProvider.ico");
276                         tooltip = new ToolTip.ToolTipWindow(null);
277                 }
278
279                 public ErrorProvider(ContainerControl parentControl) : this() {
280                         container = parentControl;
281                 }
282                 #endregion      // Public Constructors
283
284                 #region Public Instance Properties
285                 [DefaultValue(250)]
286                 [RefreshProperties(RefreshProperties.Repaint)]
287                 public int BlinkRate {
288                         get {
289                                 return blinkrate;
290                         }
291
292                         set {
293                                 blinkrate = value;
294                         }
295                 }
296
297                 [DefaultValue(ErrorBlinkStyle.BlinkIfDifferentError)]
298                 public ErrorBlinkStyle BlinkStyle {
299                         get {
300                                 return blinkstyle;
301                         }
302
303                         set {
304                                 blinkstyle = value;
305                         }
306                 }
307
308                 [DefaultValue(null)]
309                 public ContainerControl ContainerControl {
310                         get {
311                                 return container;
312                         }
313
314                         set {
315                                 container = value;
316                         }
317                 }
318
319                 [MonoTODO]
320                 [DefaultValue(null)]
321                 [Editor ("System.Windows.Forms.Design.DataMemberListEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
322                 public string DataMember {
323                         get {
324                                 return datamember;
325                         }
326
327                         set {
328                                 datamember = value;
329                                 // FIXME - add binding magic and also update BindToDataAndErrors with it
330                         }
331                 }
332
333                 [MonoTODO]
334                 [DefaultValue(null)]
335                 [TypeConverter("System.Windows.Forms.Design.DataSourceConverter, " + Consts.AssemblySystem_Design)]
336                 public object DataSource {
337                         get {
338                                 return datasource;
339                         }
340
341                         set {
342                                 datasource = value;
343                                 // FIXME - add binding magic and also update BindToDataAndErrors with it
344                         }
345                 }
346
347                 [Localizable(true)]
348                 public Icon Icon {
349                         get {
350                                 return icon;
351                         }
352
353                         set {
354                                 icon = value;
355                         }
356                 }
357
358                 public override ISite Site {
359                         set {
360                                 base.Site = value;
361                         }
362                 }
363                 #endregion      // Public Instance Properties
364
365                 #region Public Instance Methods
366                 [MonoTODO]
367                 public void BindToDataAndErrors(object newDataSource, string newDataMember) {
368                         datasource = newDataSource;
369                         datamember = newDataMember;
370                         // FIXME - finish
371                 }
372
373                 public bool CanExtend(object extendee) {
374                         if (!(extendee is Control)) {
375                                 return false;
376                         }
377
378                         if ((extendee is Form) || (extendee is ToolBar)) {
379                                 return false;
380                         }
381
382                         return true;
383                 }
384
385                 [Localizable(true)]
386                 [DefaultValue("")]
387                 public string GetError(Control control) {
388                         return GetErrorProperty(control).Text;
389                 }
390
391                 [Localizable(true)]
392                 [DefaultValue(ErrorIconAlignment.MiddleRight)]
393                 public ErrorIconAlignment GetIconAlignment(Control control) {
394                         return GetErrorProperty(control).Alignment;
395                 }
396
397                 [Localizable(true)]
398                 [DefaultValue(0)]
399                 public int GetIconPadding(Control control) {
400                         return GetErrorProperty(control).padding;
401                 }
402
403                 public void SetError(Control control, string value) {
404                         GetErrorProperty(control).Text = value;
405                 }
406
407                 public void SetIconAlignment(Control control, ErrorIconAlignment value) {
408                         GetErrorProperty(control).Alignment = value;
409                 }
410
411                 public void SetIconPadding(Control control, int padding) {
412                         GetErrorProperty(control).Padding = padding;
413                 }
414
415                 [MonoTODO]
416                 public void UpdateBinding() {
417                 }
418                 #endregion      // Public Instance Methods
419
420                 #region Protected Instance Methods
421                 protected override void Dispose(bool disposing) {
422                         base.Dispose (disposing);
423                 }
424                 #endregion      // Protected Instance Methods
425
426                 #region Private Methods
427                 private ErrorProperty GetErrorProperty(Control control) {
428                         ErrorProperty ep;
429
430                         ep = (ErrorProperty)controls[control];
431                         if (ep == null) {
432                                 ep = new ErrorProperty(this, control);
433                                 controls[control] = ep;
434                         }
435
436                         return ep;
437                 }
438                 #endregion      // Private Methods
439         }
440 }