JD2022-TU1/main/tools/framework/JD.MessageService/TrayBalloon.cs

235 lines
No EOL
6.4 KiB
C#

using System;
using System.ComponentModel;
using System.Drawing;
using System.Reflection;
using System.Windows.Forms;
using JD.Kernel.Classes;
namespace JD.MessageService
{
/// <summary>
/// Used to show messages in the tray icon.
/// </summary>
/// <remarks>This is a gui object and should be created in the Gui thread.</remarks>
public class TrayBalloon : IDisposable
{
private const int MaxTitleLength = 63;
#region Variables
private readonly object m_lock = new object();
private readonly Container m_components = new Container(); // Must be initialized on Main thread.
private readonly NotifyIcon m_icon;
// Use a custom timer instead of default timeout to hide the icon and to bypass the minimum timeout of NotifyIcon
private readonly System.Timers.Timer m_timer;
private Request m_currentRequest;
#endregion
#region Constructor
public TrayBalloon()
{
m_icon = new NotifyIcon(m_components);
m_icon.Visible = true;
m_icon.Visible = false; // Necessary or the icon is erroneous if shown the first time from another thread than the main thread.
m_icon.BalloonTipClicked += m_icon_Click;
m_icon.MouseUp += m_icon_MouseUp;
m_icon.Icon = ExtractApplicationIcon();
m_timer = new System.Timers.Timer();
m_timer.Elapsed += m_timer_Tick;
}
public void Dispose()
{
DisposableHelper.SafeDispose(m_timer);
DisposableHelper.SafeDispose(m_components);
DisposableHelper.SafeDispose(m_icon);
}
#endregion
#region Methods
/// <summary>
/// Shows a balloon for the requested duration. If there was another balloon, the new call close the old one.
/// </summary>
public IBalloon Show(TimeSpan timeout, string title, string text, ToolTipIcon icon, Action clickHandler)
{
if (m_icon != null)
{
lock (m_lock)
{
// Make sure the balloon does not flicker to infinite when prompting the same message a lot of times.
if (IsOnSameRequest(title, text))
{
return m_currentRequest;
}
m_currentRequest = new Request(this);
// No initialization on single line ...
m_currentRequest.Title = title;
m_currentRequest.Text = text;
m_currentRequest.ClickHandler = clickHandler;
m_icon.Visible = true;
m_timer.Stop();
m_timer.Interval = (int)timeout.TotalMilliseconds;
m_timer.Start();
}
m_icon.ShowBalloonTip((int)timeout.TotalMilliseconds, Truncate(title, MaxTitleLength), Truncate(text, 255), icon);
}
return m_currentRequest;
}
private bool IsOnSameRequest(string title, string text)
{
var request = m_currentRequest;
return request != null && request.Title == title && request.Text == text;
}
private static string Truncate(string value, int length)
{
if (value == null)
{
return string.Empty;
}
return value.Substring(0, Math.Min(value.Length, length));
}
private static Icon ExtractApplicationIcon()
{
try
{
return Icon.ExtractAssociatedIcon(Assembly.GetEntryAssembly().Location);
}
catch
{
return null;
}
}
public void Hide()
{
lock (m_lock)
{
m_timer.Stop();
m_currentRequest = null;
m_icon.Visible = false;
}
}
#endregion
#region Handlers
void m_timer_Tick(object sender, EventArgs e)
{
Hide();
}
void m_icon_Click(object sender, EventArgs e)
{
var currentRequest = m_currentRequest;
if (currentRequest != null)
{
currentRequest.OnClick();
}
}
void m_icon_MouseUp(object sender, MouseEventArgs e)
{
var currentRequest = m_currentRequest;
if (currentRequest != null)
{
currentRequest.OnIconMouseUp();
}
}
#endregion
#region Nested
private class Request : IBalloon
{
private readonly TrayBalloon m_balloon;
private string m_title;
public Request(TrayBalloon balloon)
{
m_balloon = balloon;
}
public void Hide()
{
if (IsActiveRequest)
{
m_balloon.Hide();
}
}
private bool IsActiveRequest
{
get { return m_balloon.m_currentRequest == this; }
}
public string Title
{
get { return m_title; }
set
{
m_title = value;
if (IsActiveRequest)
{
m_balloon.m_icon.Text = Truncate(m_title, MaxTitleLength);
}
}
}
public string Text
{
get;
set;
}
public Action IconMouseUpHandler
{
get;
set;
}
public void OnIconMouseUp()
{
var handler = IconMouseUpHandler;
if (handler != null)
{
IconMouseUpHandler = null;
handler();
}
}
public Action ClickHandler
{
get;
set;
}
public void OnClick()
{
var handler = ClickHandler;
if (handler != null)
{
ClickHandler = null;
handler();
}
}
}
#endregion
}
}