632 lines
17 KiB
C#
Raw Normal View History

// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
// Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
//
// Authors:
// Peter Bartok (pbartok@novell.com)
//
//
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
namespace System.Windows.Forms {
[ToolboxItemFilter("System.Windows.Forms")]
[ProvideProperty("IconAlignment", "System.Windows.Forms.Control, " + Consts.AssemblySystem_Windows_Forms)]
[ProvideProperty("IconPadding", "System.Windows.Forms.Control, " + Consts.AssemblySystem_Windows_Forms)]
[ProvideProperty("Error", "System.Windows.Forms.Control, " + Consts.AssemblySystem_Windows_Forms)]
[ComplexBindingProperties ("DataSource", "DataMember")]
public class ErrorProvider : Component, IExtenderProvider, ISupportInitialize
{
private class ErrorWindow : UserControl
{
public ErrorWindow ()
{
SetStyle (ControlStyles.Selectable, false);
}
}
#region Private Classes
private class ErrorProperty {
public ErrorIconAlignment alignment;
public int padding;
public string text;
public Control control;
public ErrorProvider ep;
private ErrorWindow window;
private bool visible;
private int blink_count;
private EventHandler tick;
private System.Windows.Forms.Timer timer;
public ErrorProperty(ErrorProvider ep, Control control) {
this.ep = ep;
this.control = control;
alignment = ErrorIconAlignment.MiddleRight;
padding = 0;
text = string.Empty;
blink_count = 0;
tick = new EventHandler(window_Tick);
window = new ErrorWindow ();
window.Visible = false;
window.Width = ep.icon.Width;
window.Height = ep.icon.Height;
// UIA Framework: Associate ErrorProvider with Control
ErrorProvider.OnUIAErrorProviderHookUp (ep, new ControlEventArgs (control));
// UIA Framework: Generate event to associate UserControl with ErrorProvider
window.VisibleChanged += delegate (object sender, EventArgs args) {
if (window.Visible == true)
ErrorProvider.OnUIAControlHookUp (control, new ControlEventArgs (window));
else
ErrorProvider.OnUIAControlUnhookUp (control, new ControlEventArgs (window));
};
if (control.Parent != null) {
// UIA Framework: Generate event to associate UserControl with ErrorProvider
ErrorProvider.OnUIAControlHookUp (control, new ControlEventArgs (window));
control.Parent.Controls.Add(window);
control.Parent.Controls.SetChildIndex(window, control.Parent.Controls.IndexOf (control) + 1);
}
window.Paint += new PaintEventHandler(window_Paint);
window.MouseEnter += new EventHandler(window_MouseEnter);
window.MouseLeave += new EventHandler(window_MouseLeave);
control.SizeChanged += new EventHandler(control_SizeLocationChanged);
control.LocationChanged += new EventHandler(control_SizeLocationChanged);
control.ParentChanged += new EventHandler (control_ParentChanged);
// Do we want to block mouse clicks? if so we need a few more events handled
CalculateAlignment();
}
public string Text {
get {
return text;
}
set {
if (value == null)
value = string.Empty;
bool differentError = text != value;
text = value;
if (text != String.Empty) {
window.Visible = true;
} else {
window.Visible = false;
return;
}
// even if blink style is NeverBlink we need it to allow
// the timer to elapse at least once to get the icon to
// display
if (differentError || ep.blinkstyle == ErrorBlinkStyle.AlwaysBlink) {
if (timer == null) {
timer = new System.Windows.Forms.Timer();
timer.Tick += tick;
}
timer.Interval = ep.blinkrate;
blink_count = 0;
timer.Enabled = true;
}
}
}
public ErrorIconAlignment Alignment {
get {
return alignment;
}
set {
if (alignment != value) {
alignment = value;
CalculateAlignment();
}
}
}
public int Padding {
get {
return padding;
}
set {
if (padding != value) {
padding = value;
CalculateAlignment();
}
}
}
private void CalculateAlignment() {
if (visible) {
visible = false;
ep.tooltip.Visible = false;
}
switch (alignment) {
case ErrorIconAlignment.TopLeft: {
window.Left = control.Left - ep.icon.Width - padding;
window.Top = control.Top;
break;
}
case ErrorIconAlignment.TopRight: {
window.Left = control.Left + control.Width + padding;
window.Top = control.Top;
break;
}
case ErrorIconAlignment.MiddleLeft: {
window.Left = control.Left - ep.icon.Width - padding;
window.Top = control.Top + (control.Height - ep.icon.Height) / 2;
break;
}
case ErrorIconAlignment.MiddleRight: {
window.Left = control.Left + control.Width + padding;
window.Top = control.Top + (control.Height - ep.icon.Height) / 2;
break;
}
case ErrorIconAlignment.BottomLeft: {
window.Left = control.Left - ep.icon.Width - padding;
window.Top = control.Top + control.Height - ep.icon.Height;
break;
}
case ErrorIconAlignment.BottomRight: {
window.Left = control.Left + control.Width + padding;
window.Top = control.Top + control.Height - ep.icon.Height;
break;
}
}
}
private void window_Paint(object sender, PaintEventArgs e) {
if (text != string.Empty) {
e.Graphics.DrawIcon(this.ep.icon, 0, 0);
}
}
private void window_MouseEnter(object sender, EventArgs e) {
if (!visible) {
Size size;
Point pt;
visible = true;
pt = Control.MousePosition;
size = ThemeEngine.Current.ToolTipSize(ep.tooltip, text);
ep.tooltip.Width = size.Width;
ep.tooltip.Height = size.Height;
ep.tooltip.Text = text;
if ((pt.X + size.Width) < SystemInformation.WorkingArea.Width) {
ep.tooltip.Left = pt.X;
} else {
ep.tooltip.Left = pt.X - size.Width;
}
if ((pt.Y + size.Height) < (SystemInformation.WorkingArea.Height - 16)) {
ep.tooltip.Top = pt.Y + 16;
} else {
ep.tooltip.Top = pt.Y - size.Height;
}
// UIA Framework: Associate Control with ToolTip, used on Popup events
ep.UIAControl = control;
ep.tooltip.Visible = true;
}
}
private void window_MouseLeave(object sender, EventArgs e) {
if (visible) {
visible = false;
ep.tooltip.Visible = false;
}
}
private void control_SizeLocationChanged(object sender, EventArgs e) {
if (visible) {
visible = false;
ep.tooltip.Visible = false;
}
CalculateAlignment();
}
private void control_ParentChanged (object sender, EventArgs e)
{
if (control.Parent != null) {
// UIA Framework: Generate event to disassociate UserControl with ErrorProvider
ErrorProvider.OnUIAControlUnhookUp (control, new ControlEventArgs (window));
control.Parent.Controls.Add (window);
control.Parent.Controls.SetChildIndex (window, control.Parent.Controls.IndexOf (control) + 1);
// UIA Framework: Generate event to associate UserControl with ErrorProvider
ErrorProvider.OnUIAControlHookUp (control, new ControlEventArgs (window));
}
}
private void window_Tick(object sender, EventArgs e) {
if (timer.Enabled && control.IsHandleCreated && control.Visible) {
Graphics g;
blink_count++;
g = window.CreateGraphics();
if ((blink_count % 2) == 0) {
g.FillRectangle(ThemeEngine.Current.ResPool.GetSolidBrush(window.Parent.BackColor), window.ClientRectangle);
} else {
g.DrawIcon(this.ep.icon, 0, 0);
}
g.Dispose();
switch (ep.blinkstyle) {
case ErrorBlinkStyle.AlwaysBlink:
break;
case ErrorBlinkStyle.BlinkIfDifferentError:
if (blink_count > 10)
timer.Stop();
break;
case ErrorBlinkStyle.NeverBlink:
timer.Stop ();
break;
}
if (blink_count == 11)
blink_count = 1;
}
}
}
#endregion
#region Local Variables
private int blinkrate;
private ErrorBlinkStyle blinkstyle;
private string datamember;
private object datasource;
private ContainerControl container;
private Icon icon;
private Hashtable controls;
private ToolTip.ToolTipWindow tooltip;
private bool right_to_left;
private object tag;
#endregion // Local Variables
#region Public Constructors
public ErrorProvider()
{
controls = new Hashtable();
blinkrate = 250;
blinkstyle = ErrorBlinkStyle.BlinkIfDifferentError;
icon = ResourceImageLoader.GetIcon ("errorProvider.ico");
tooltip = new ToolTip.ToolTipWindow();
//UIA Framework: Event used to indicate the ToolTip is shown/hidden.
tooltip.VisibleChanged += delegate (object sender, EventArgs args) {
if (tooltip.Visible == true)
OnUIAPopup (this, new PopupEventArgs (UIAControl, UIAControl, false, Size.Empty));
else if (tooltip.Visible == false)
OnUIAUnPopup (this, new PopupEventArgs (UIAControl, UIAControl, false, Size.Empty));
};
}
public ErrorProvider(ContainerControl parentControl) : this ()
{
container = parentControl;
}
public ErrorProvider (IContainer container) : this ()
{
container.Add (this);
}
#endregion // Public Constructors
#region Public Instance Properties
[DefaultValue(250)]
[RefreshProperties(RefreshProperties.Repaint)]
public int BlinkRate {
get {
return blinkrate;
}
set {
blinkrate = value;
}
}
[DefaultValue(ErrorBlinkStyle.BlinkIfDifferentError)]
public ErrorBlinkStyle BlinkStyle {
get {
return blinkstyle;
}
set {
blinkstyle = value;
}
}
[DefaultValue(null)]
public ContainerControl ContainerControl {
get {
return container;
}
set {
container = value;
}
}
[MonoTODO ("Stub, does nothing")]
[DefaultValue (null)]
[Editor ("System.Windows.Forms.Design.DataMemberListEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
public string DataMember {
get {
return datamember;
}
set {
datamember = value;
// FIXME - add binding magic and also update BindToDataAndErrors with it
}
}
[MonoTODO ("Stub, does nothing")]
[DefaultValue (null)]
[AttributeProvider (typeof (IListSource))]
public object DataSource {
get {
return datasource;
}
set {
datasource = value;
// FIXME - add binding magic and also update BindToDataAndErrors with it
}
}
[Localizable(true)]
public Icon Icon {
get {
return icon;
}
set {
if (value != null && (value.Height != 16 || value.Width != 16))
icon = new Icon (value, 16, 16);
else
icon = value;
}
}
public override ISite Site {
set {
base.Site = value;
}
}
[MonoTODO ("RTL not supported")]
[Localizable (true)]
[DefaultValue (false)]
public virtual bool RightToLeft {
get { return right_to_left; }
set { right_to_left = value; }
}
[Localizable (false)]
[Bindable (true)]
[TypeConverter (typeof (StringConverter))]
[DefaultValue (null)]
[MWFCategory ("Data")]
public object Tag {
get { return this.tag; }
set { this.tag = value; }
}
#endregion // Public Instance Properties
#region Public Instance Methods
[MonoTODO ("Stub, does nothing")]
public void BindToDataAndErrors (object newDataSource, string newDataMember)
{
datasource = newDataSource;
datamember = newDataMember;
// FIXME - finish
}
public bool CanExtend(object extendee) {
if (!(extendee is Control)) {
return false;
}
if ((extendee is Form) || (extendee is ToolBar)) {
return false;
}
return true;
}
public void Clear ()
{
foreach (ErrorProperty ep in controls.Values)
ep.Text = string.Empty;
}
[Localizable(true)]
[DefaultValue("")]
public string GetError(Control control) {
return GetErrorProperty(control).Text;
}
[Localizable(true)]
[DefaultValue(ErrorIconAlignment.MiddleRight)]
public ErrorIconAlignment GetIconAlignment(Control control) {
return GetErrorProperty(control).Alignment;
}
[Localizable(true)]
[DefaultValue(0)]
public int GetIconPadding(Control control) {
return GetErrorProperty(control).padding;
}
public void SetError(Control control, string value) {
GetErrorProperty(control).Text = value;
}
public void SetIconAlignment(Control control, ErrorIconAlignment value) {
GetErrorProperty(control).Alignment = value;
}
public void SetIconPadding(Control control, int padding) {
GetErrorProperty(control).Padding = padding;
}
[MonoTODO ("Stub, does nothing")]
public void UpdateBinding ()
{
}
#endregion // Public Instance Methods
#region Protected Instance Methods
protected override void Dispose(bool disposing) {
base.Dispose (disposing);
}
[EditorBrowsableAttribute (EditorBrowsableState.Advanced)]
protected virtual void OnRightToLeftChanged (EventArgs e)
{
EventHandler eh = (EventHandler)(Events[RightToLeftChangedEvent]);
if (eh != null)
eh (this, e);
}
#endregion // Protected Instance Methods
#region Private Methods
private ErrorProperty GetErrorProperty(Control control) {
ErrorProperty ep = (ErrorProperty)controls[control];
if (ep == null) {
ep = new ErrorProperty(this, control);
controls[control] = ep;
}
return ep;
}
#endregion // Private Methods
void ISupportInitialize.BeginInit ()
{
}
void ISupportInitialize.EndInit ()
{
}
#region Public Events
static object RightToLeftChangedEvent = new object ();
public event EventHandler RightToLeftChanged {
add { Events.AddHandler (RightToLeftChangedEvent, value); }
remove { Events.RemoveHandler (RightToLeftChangedEvent, value); }
}
#endregion
#region UIA Framework: Events, Properties and Methods
// NOTE:
// We are using Reflection to add/remove internal events.
// Class ToolTipListener uses the events.
//
// - UIAControlHookUp. Event used to associate UserControl with ErrorProvider
// - UIAControlUnhookUp. Event used to disassociate UserControl with ErrorProvider
// - UIAErrorProviderHookUp. Event used to associate Control with ErrorProvider
// - UIAErrorProviderUnhookUp. Event used to disassociate Control with ErrorProvider
// - UIAPopup. Event used show Popup
// - UIAUnPopup. Event used to hide popup.
private Control uia_control;
internal Control UIAControl {
get { return uia_control; }
set { uia_control = value; }
}
internal Rectangle UIAToolTipRectangle {
get { return tooltip.Bounds; }
}
internal static event ControlEventHandler UIAControlHookUp;
internal static event ControlEventHandler UIAControlUnhookUp;
internal static event ControlEventHandler UIAErrorProviderHookUp;
internal static event ControlEventHandler UIAErrorProviderUnhookUp;
internal static event PopupEventHandler UIAPopup;
internal static event PopupEventHandler UIAUnPopup;
internal static void OnUIAPopup (ErrorProvider sender, PopupEventArgs args)
{
if (UIAPopup != null)
UIAPopup (sender, args);
}
internal static void OnUIAUnPopup (ErrorProvider sender, PopupEventArgs args)
{
if (UIAUnPopup != null)
UIAUnPopup (sender, args);
}
internal static void OnUIAControlHookUp (object sender, ControlEventArgs args)
{
if (UIAControlHookUp != null)
UIAControlHookUp (sender, args);
}
internal static void OnUIAControlUnhookUp (object sender, ControlEventArgs args)
{
if (UIAControlUnhookUp != null)
UIAControlUnhookUp (sender, args);
}
internal static void OnUIAErrorProviderHookUp (object sender, ControlEventArgs args)
{
if (UIAErrorProviderHookUp != null)
UIAErrorProviderHookUp (sender, args);
}
internal static void OnUIAErrorProviderUnhookUp (object sender, ControlEventArgs args)
{
if (UIAErrorProviderUnhookUp != null)
UIAErrorProviderUnhookUp (sender, args);
}
#endregion
}
}