Merge pull request #268 from pcc/menudeactivate
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / PictureBox.cs
index 516f2536a2b4983b85a1ec41b08a7277b163d6f4..53b1dcce1795c77abd7da32822ce4db0af666846 100644 (file)
@@ -31,22 +31,27 @@ using System.ComponentModel.Design;
 using System.Drawing;
 using System.Drawing.Imaging;
 using System.Runtime.InteropServices;
+using System.IO;
+using System.Net;
 
 namespace System.Windows.Forms {
        [DefaultProperty("Image")]
        [Designer("System.Windows.Forms.Design.PictureBoxDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
-       public class PictureBox : Control 
-#if NET_2_0
-                                       , ISupportInitialize
-#endif
+       [Docking (DockingBehavior.Ask)]
+       [ClassInterface (ClassInterfaceType.AutoDispatch)]
+       [ComVisible (true)]
+       [DefaultBindingProperty ("Image")]
+       public class PictureBox : Control, ISupportInitialize
        {
                #region Fields
                private Image   image;
                private PictureBoxSizeMode size_mode;
-               private bool    redraw;
-               private bool    recalc;
-               private bool    allow_drop;
+               private Image   error_image;
+               private string  image_location;
                private Image   initial_image;
+               private bool    wait_on_load;
+               private WebClient image_download;
+               private bool image_from_url;
                private int     no_update;
                #endregion      // Fields
 
@@ -55,18 +60,16 @@ namespace System.Windows.Forms {
                #region Public Constructor
                public PictureBox ()
                {
-                       redraw = true;
-                       recalc = true;
-                       allow_drop = false;
-#if NET_2_0
+                       //recalc = true;
+                       no_update = 0;
+
                        SetStyle (ControlStyles.OptimizedDoubleBuffer, true);
-#else
-                       SetStyle (ControlStyles.DoubleBuffer, true);
-#endif
                        SetStyle (ControlStyles.Opaque, false);
                        SetStyle (ControlStyles.Selectable, false);
                        SetStyle (ControlStyles.SupportsTransparentBackColor, true);
                        HandleCreated += new EventHandler(PictureBox_HandleCreated);
+                       initial_image = ResourceImageLoader.Get ("image-x-generic.png");
+                       error_image = ResourceImageLoader.Get ("image-missing.png");
                }
                #endregion      // Public Constructor
 
@@ -80,9 +83,17 @@ namespace System.Windows.Forms {
                                if (size_mode == value)
                                        return;
                                size_mode = value;
+                               
+                               if (size_mode == PictureBoxSizeMode.AutoSize) {
+                                       AutoSize = true;
+                                       SetAutoSizeMode (AutoSizeMode.GrowAndShrink);
+                               } else {
+                                       AutoSize = false;
+                                       SetAutoSizeMode (AutoSizeMode.GrowOnly);
+                               }
+
                                UpdateSize ();
                                if (no_update == 0) {
-                                       Redraw (true);
                                        Invalidate ();
                                }
 
@@ -90,27 +101,11 @@ namespace System.Windows.Forms {
                        }
                }
 
-               [DefaultValue(null)]
+               [Bindable (true)]
                [Localizable(true)]
                public Image Image {
                        get { return image; }
-                       set {
-                               StopAnimation ();
-
-                               image = value;
-
-                               if (IsHandleCreated) {
-                                       UpdateSize ();
-                                       if (image != null && ImageAnimator.CanAnimate (image)) {
-                                               frame_handler = new EventHandler (OnAnimateImage);
-                                               ImageAnimator.Animate (image, frame_handler);
-                                       }
-                                       if (no_update == 0) {
-                                               Redraw (true);
-                                               Invalidate ();
-                                       }
-                               }
-                       }
+                       set { ChangeImage (value, false); }
                }
 
                [DefaultValue(BorderStyle.None)]
@@ -127,14 +122,44 @@ namespace System.Windows.Forms {
                        set { base.CausesValidation = value; }
                }
 
-#if NET_2_0
-               [DefaultValue(null)]
+               [Localizable (true)]
+               [RefreshProperties (RefreshProperties.All)]
+               public Image ErrorImage {
+                       get { return error_image; }
+                       set { error_image = value; }
+               }
+               
+               [RefreshProperties (RefreshProperties.All)]
                [Localizable(true)]
                public Image InitialImage {
                        get { return initial_image; }
                        set { initial_image = value; }
                }
-#endif
+               
+               [Localizable (true)]
+               [DefaultValue (null)]
+               [RefreshProperties (RefreshProperties.All)]
+               public string ImageLocation {
+                       get { return image_location; }
+                       set {
+                               image_location = value;
+
+                               if (!string.IsNullOrEmpty (value)) {
+                                       if (WaitOnLoad)
+                                               Load (value);
+                                       else
+                                               LoadAsync (value);
+                               } else if (image_from_url)
+                                       ChangeImage (null, true);
+                       }
+               }
+               
+               [Localizable (true)]
+               [DefaultValue (false)]
+               public bool WaitOnLoad {
+                       get { return wait_on_load; }
+                       set { wait_on_load = value; }
+               }
 
                [Browsable(false)]
                [EditorBrowsable(EditorBrowsableState.Never)]
@@ -199,14 +224,8 @@ namespace System.Windows.Forms {
                [Browsable(false)]
                [EditorBrowsable(EditorBrowsableState.Never)]
                public override bool AllowDrop {
-                       get {
-                               return allow_drop;
-                       }
-                       set {
-                               if (allow_drop != value) {
-                                       allow_drop = value;
-                               }
-                       }
+                       get { return base.AllowDrop; }
+                       set { base.AllowDrop = value; }
                }
                #endregion      // Public Properties
 
@@ -228,20 +247,20 @@ namespace System.Windows.Forms {
 
                protected override void OnPaint (PaintEventArgs pe)
                {
-                        ThemeEngine.Current.DrawPictureBox (pe.Graphics, pe.ClipRectangle, this);
+                       ThemeEngine.Current.DrawPictureBox (pe.Graphics, pe.ClipRectangle, this);
                        base.OnPaint (pe);
                }
 
                protected override void OnVisibleChanged (EventArgs e)
                {
                        base.OnVisibleChanged (e);
-                       Redraw (true);
                }
 
                protected virtual void OnSizeModeChanged (EventArgs e)
                {
-                       if (SizeModeChanged != null)
-                               SizeModeChanged (this, e);
+                       EventHandler eh = (EventHandler)(Events [SizeModeChangedEvent]);
+                       if (eh != null)
+                               eh (this, e);
                }
 
                protected override void OnEnabledChanged (EventArgs e)
@@ -249,6 +268,32 @@ namespace System.Windows.Forms {
                        base.OnEnabledChanged (e);
                }
 
+               [EditorBrowsable (EditorBrowsableState.Advanced)]
+               protected override void OnHandleCreated (EventArgs e)
+               {
+                       base.OnHandleCreated (e);
+               }
+
+               [EditorBrowsable (EditorBrowsableState.Advanced)]
+               protected override void OnHandleDestroyed (EventArgs e)
+               {
+                       base.OnHandleDestroyed (e);
+               }
+               
+               protected virtual void OnLoadCompleted (AsyncCompletedEventArgs e)
+               {
+                       AsyncCompletedEventHandler eh = (AsyncCompletedEventHandler)(Events[LoadCompletedEvent]);
+                       if (eh != null)
+                               eh (this, e);
+               }
+               
+               protected virtual void OnLoadProgressChanged (ProgressChangedEventArgs e)
+               {
+                       ProgressChangedEventHandler eh = (ProgressChangedEventHandler)(Events[LoadProgressChangedEvent]);
+                       if (eh != null)
+                               eh (this, e);
+               }
+
                protected override void OnParentChanged (EventArgs e)
                {
                        base.OnParentChanged (e);
@@ -257,23 +302,19 @@ namespace System.Windows.Forms {
                protected override void OnResize (EventArgs e)
                {
                        base.OnResize (e);
-                       redraw = true;
-
-                       if (size_mode == PictureBoxSizeMode.CenterImage || size_mode == PictureBoxSizeMode.StretchImage)
-                               Refresh ();
+                       
+                       Invalidate ();
                }
 
-               protected override void SetBoundsCore (int x, int y, int width, int height, BoundsSpecified specified)
+               internal override Size GetPreferredSizeCore (Size proposedSize)
                {
-                       if (size_mode == PictureBoxSizeMode.AutoSize && image != null) {
-                               width = image.Width;
-                               height = image.Height;
-                       }
-                       base.SetBoundsCore (x, y, width, height, specified);
+                       if (image == null)
+                               return base.GetPreferredSizeCore (proposedSize);
+                       else
+                               return image.Size;
                }
                #endregion      // Protected Instance Methods
 
-#if NET_2_0
                #region ISupportInitialize Interface
                void System.ComponentModel.ISupportInitialize.BeginInit() {
                        no_update++;
@@ -284,14 +325,43 @@ namespace System.Windows.Forms {
                                no_update--;
                        }
                        if (no_update == 0) {
-                               Redraw (true);
                                Invalidate ();
                        }
                }
                #endregion      // ISupportInitialize Interface
-#endif
 
-               #region Private Methods
+               #region Private Properties
+               private WebClient ImageDownload {
+                       get { 
+                               if (image_download == null)
+                                       image_download = new WebClient ();
+                                       
+                               return image_download;
+                       }
+               }
+               #endregion
+               
+               #region Private Methods
+
+               private void ChangeImage (Image value, bool from_url)
+               {
+                       StopAnimation ();
+
+                       image_from_url = from_url;
+                       image = value;
+
+                       if (IsHandleCreated) {
+                               UpdateSize ();
+                               if (image != null && ImageAnimator.CanAnimate (image)) {
+                                       frame_handler = new EventHandler (OnAnimateImage);
+                                       ImageAnimator.Animate (image, frame_handler);
+                               }
+                               if (no_update == 0) {
+                                       Invalidate ();
+                               }
+                       }
+               }
+
                private void StopAnimation ()
                {
                        if (frame_handler == null)
@@ -304,27 +374,32 @@ namespace System.Windows.Forms {
                {
                        if (image == null)
                                return;
-                       if (size_mode == PictureBoxSizeMode.AutoSize)
-                               ClientSize = image.Size; 
-               }
 
-               private void Redraw (bool recalc)
-               {
-                       redraw = true;
-                       this.recalc = recalc;
+                       if (Parent != null)
+                               Parent.PerformLayout (this, "AutoSize");
                }
 
                private void OnAnimateImage (object sender, EventArgs e)
                {
                        // This is called from a worker thread,BeginInvoke is used
                        // so the control is updated from the correct thread
+                       
+                       // Check if we have a handle again, since it may have gotten
+                       // destroyed since the last time we checked.
+                       if (!IsHandleCreated)
+                               return;
+                       
                        BeginInvoke (new EventHandler (UpdateAnimatedImage), new object [] { this, e });
                }
 
                private void UpdateAnimatedImage (object sender, EventArgs e)
                {
+                       // Check if we have a handle again, since it may have gotten
+                       // destroyed since the last time we checked.
+                       if (!IsHandleCreated)
+                               return;
+                               
                        ImageAnimator.UpdateFrames (image);
-                       Redraw (false);
                        Refresh ();
                }
 
@@ -335,13 +410,91 @@ namespace System.Windows.Forms {
                                ImageAnimator.Animate (image, frame_handler);
                        }
                        if (no_update == 0) {
-                               Redraw (true);
                                Invalidate ();
                        }
                }
+
+               void ImageDownload_DownloadDataCompleted (object sender, DownloadDataCompletedEventArgs e)
+               {
+                       if (e.Error != null && !e.Cancelled)
+                               Image = error_image;
+                       else if (e.Error == null && !e.Cancelled)
+                               using (MemoryStream ms = new MemoryStream (e.Result))
+                                       Image = Image.FromStream (ms);
+                                       
+                       ImageDownload.DownloadProgressChanged -= new DownloadProgressChangedEventHandler (ImageDownload_DownloadProgressChanged);
+                       ImageDownload.DownloadDataCompleted -= new DownloadDataCompletedEventHandler (ImageDownload_DownloadDataCompleted);
+                       image_download = null;
+                       
+                       OnLoadCompleted (e);
+               }
+
+               private void ImageDownload_DownloadProgressChanged (object sender, DownloadProgressChangedEventArgs e)
+               {
+                       OnLoadProgressChanged (new ProgressChangedEventArgs (e.ProgressPercentage, e.UserState));
+               }
                #endregion      // Private Methods
 
                #region Public Instance Methods
+               public void CancelAsync ()
+               {
+                       if (image_download != null)
+                               image_download.CancelAsync ();
+               }
+               
+               public void Load ()
+               {
+                       Load (image_location);
+               }
+               
+               public void Load (string url)
+               {
+                       if (string.IsNullOrEmpty (url))
+                               throw new InvalidOperationException ("ImageLocation not specified.");
+                       
+                       image_location = url;
+                       
+                       if (url.Contains ("://"))
+                               using (Stream s = ImageDownload.OpenRead (url))
+                                       ChangeImage (Image.FromStream (s), true);
+                       else
+                               ChangeImage (Image.FromFile (url), true);
+               }
+               
+               public void LoadAsync ()
+               {
+                       LoadAsync (image_location);
+               }
+               
+               public void LoadAsync (string url)
+               {
+                       // If WaitOnLoad is true, do not do async
+                       if (wait_on_load) {
+                               Load (url);
+                               return;
+                       }
+
+                       if (string.IsNullOrEmpty (url))
+                               throw new InvalidOperationException ("ImageLocation not specified.");
+
+                       image_location = url;
+                       ChangeImage (InitialImage, true);
+                       
+                       if (ImageDownload.IsBusy)
+                               ImageDownload.CancelAsync ();
+
+                       Uri uri = null;
+                       try {
+                               uri = new Uri (url);
+                       } catch (UriFormatException) {
+                               uri = new Uri (Path.GetFullPath (url));
+                       }
+
+                       ImageDownload.DownloadProgressChanged += new DownloadProgressChangedEventHandler (ImageDownload_DownloadProgressChanged);
+                       ImageDownload.DownloadDataCompleted += new DownloadDataCompletedEventHandler (ImageDownload_DownloadDataCompleted);
+                       ImageDownload.DownloadDataAsync (uri);
+               }
+
                public override string ToString() {
                        return String.Format("{0}, SizeMode: {1}", base.ToString (), SizeMode);
                }
@@ -411,6 +564,19 @@ namespace System.Windows.Forms {
                        remove { base.Leave -= value; }
                }
 
+               static object LoadCompletedEvent = new object ();
+               static object LoadProgressChangedEvent = new object ();
+
+               public event AsyncCompletedEventHandler LoadCompleted {
+                       add { Events.AddHandler (LoadCompletedEvent, value); }
+                       remove { Events.RemoveHandler (LoadCompletedEvent, value); }
+               }
+
+               public event ProgressChangedEventHandler LoadProgressChanged {
+                       add { Events.AddHandler (LoadProgressChangedEvent, value); }
+                       remove { Events.RemoveHandler (LoadProgressChangedEvent, value); }
+               }
+
                [Browsable(false)]
                [EditorBrowsable(EditorBrowsableState.Never)]
                public new event EventHandler RightToLeftChanged {
@@ -439,7 +605,12 @@ namespace System.Windows.Forms {
                        remove { base.TextChanged -= value; }
                }
 
-               public event EventHandler SizeModeChanged;
+               static object SizeModeChangedEvent = new object ();
+               public event EventHandler SizeModeChanged {
+                       add { Events.AddHandler (SizeModeChangedEvent, value); }
+                       remove { Events.RemoveHandler (SizeModeChangedEvent, value); }
+               }
+
                #endregion      // Events
        }
 }