235 lines
No EOL
6.4 KiB
C#
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
|
|
}
|
|
} |