using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
using System.Text.RegularExpressions;
using System.Collections.Generic;
using System.Threading;
namespace Nexus.Client.Controls
{
///
/// A label that allows use of HTML to format the text.
///
public class HtmlLabel : WebBrowser
{
private static Regex HREF_MATCHER = new Regex(@"(?i)\b(href=[""'][^""']+[""'])");
private static Regex TAG_MATCHER = new Regex(@"(?i)(<[^>]*>)");
private static Regex LOOSE_URL_MATCHER = new Regex(@"(?i)\b((?:[a-z][\w-]+:(?:/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'"".,<>?«»“”‘’]))");
private static Regex STRICT_URL_MATCHER = new Regex(@"(?i)\b((?:https?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'"".,<>?«»“”‘’]))");
private string m_strText = null;
#region Properties
///
/// Gets or sets the label's text.
///
/// The label's text.
[Browsable(true)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public override string Text
{
get
{
return m_strText;
}
set
{
m_strText = value;
string strText = m_strText;
if (!string.IsNullOrEmpty(strText))
{
MatchCollection colUrls = TAG_MATCHER.Matches(strText);
if (colUrls.Count == 0)
{
//this appears to be plain text - so convert to html
strText = strText.Replace("\r\n", "
").Replace("\r", "
").Replace("\n", "
").Replace("\t", " ");
}
if (DetectUrls)
{
Dictionary dicProtectedUrls = new Dictionary();
for (Int32 i = colUrls.Count - 1; i >= 0; i--)
{
string strShieldText = "";
strText = strText.Replace(colUrls[i].Value, strShieldText);
dicProtectedUrls[strShieldText] = colUrls[i].Value;
}
colUrls = LOOSE_URL_MATCHER.Matches(strText);
for (Int32 i = colUrls.Count - 1; i >= 0; i--)
{
strText = strText.Remove(colUrls[i].Index, colUrls[i].Length);
strText = strText.Insert(colUrls[i].Index, String.Format("{0}", colUrls[i].Value));
}
foreach (string strKey in dicProtectedUrls.Keys)
strText = strText.Replace(strKey, dicProtectedUrls[strKey]);
}
}
string strStyle = String.Format(@"", BackColor.ToArgb() & 0x00ffffff, Font.FontFamily.Name, Font.SizeInPoints, ForeColor.ToArgb() & 0x00ffffff);
string strHtml = String.Format("{1}{2}{{0}}", AllowSelection ? "" : "cursor:default;", strStyle, AllowSelection ? "" : "");
Navigate("about:blank");
Document.OpenNew(false);
Document.Write(String.Format(strHtml, strText));
Refresh();
SetScrollbarVisibility();
}
}
///
/// Gets or sets whether text selection is allowed.
///
/// Whether text selection is allowed.
[Browsable(true)]
[Category("Behavior")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
[DefaultValue(false)]
public bool AllowSelection { get; set; }
///
/// Gets or sets the of the label's text.
///
///
/// This value may be overridden by formatting passed to .
///
/// The of the label's text.
[Browsable(true)]
[Category("Appearance")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public override Font Font
{
get
{
return base.Font;
}
set
{
base.Font = value;
}
}
///
/// Gets or sets the background colour of the label.
///
///
/// This value may be overridden by formatting passed to .
///
/// The background colour of the label.
[Browsable(true)]
[Category("Appearance")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public override Color BackColor
{
get
{
return base.BackColor;
}
set
{
base.BackColor = value;
}
}
///
/// Gets or sets the text colour of the label.
///
///
/// This value may be overridden by formatting passed to .
///
/// The text colour of the label.
[Browsable(true)]
[Category("Appearance")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public override Color ForeColor
{
get
{
return base.ForeColor;
}
set
{
base.ForeColor = value;
}
}
///
/// Gets or sets the dock style of the control.
///
/// The dock style of the control.
[DefaultValue(typeof(DockStyle), "None")]
public new DockStyle Dock
{
get
{
return base.Dock;
}
set
{
base.Dock = value;
}
}
#region Feature Disabling
///
/// Gets whether navigation is enabled.
///
///
/// Even though this returns true, navigation by clicking links has been disabled.
///
/// Always true.
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new bool AllowNavigation
{
get
{
return true;
}
}
///
/// Gets whether navigation by dropping is enabled.
///
/// Always false.
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new bool AllowWebBrowserDrop
{
get
{
return false;
}
}
///
/// Gets whether the context menu is enabled.
///
/// Always false.
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new bool IsWebBrowserContextMenuEnabled
{
get
{
return false;
}
}
///
/// Gets whether the control has a tab stop.
///
/// Always false.
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new bool TabStop
{
get
{
return false;
}
}
///
/// Gets whether browsing keyboard shorcuts are enabled.
///
/// Always false.
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new bool WebBrowserShortcutsEnabled
{
get
{
return false;
}
}
#endregion
///
/// Gets or sets whether or not URLs in the label text should be
/// turned into active links.
///
/// Whether or not URLs in the label text should be
/// turned into active links.
[Browsable(true)]
[DefaultValue(true)]
[Category("Behavior")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public bool DetectUrls { get; set; }
#endregion
#region Constructors
///
/// The default constructor.
///
public HtmlLabel()
{
base.IsWebBrowserContextMenuEnabled = false;
base.TabStop = false;
base.WebBrowserShortcutsEnabled = false;
base.AllowNavigation = true;
base.AllowWebBrowserDrop = false;
AllowSelection = false;
Dock = DockStyle.None;
BackColor = SystemColors.Control;
Font = new Font(FontFamily.GenericSansSerif, 8.25f);
ForeColor = SystemColors.ControlText;
Size = new Size(35, 20);
ScrollBarsEnabled = false;
DetectUrls = true;
}
#endregion
///
/// Raises the event.
///
///
/// This cancels all navigation events that aren't caused by setting the
/// property. If the navigation is caused by something other than setting the
/// property, the new location is open in the default browser.
///
/// A describing the event arguments.
protected override void OnNavigating(WebBrowserNavigatingEventArgs e)
{
if (!"blank".Equals(e.Url.LocalPath, StringComparison.OrdinalIgnoreCase))
{
e.Cancel = true;
Uri uriUrl = e.Url;
if ("about".Equals(uriUrl.Scheme, StringComparison.OrdinalIgnoreCase))
uriUrl = new Uri(Uri.UriSchemeHttp + Uri.SchemeDelimiter + uriUrl.LocalPath);
System.Diagnostics.Process.Start(uriUrl.ToString());
}
base.OnNavigating(e);
}
///
/// Raises the event.
///
///
/// This enables or disabled the scroll bars as required.
///
/// A describing the event arguments.
protected override void OnSizeChanged(EventArgs e)
{
base.OnSizeChanged(e);
SetScrollbarVisibility();
}
///
/// This enables or disabled the scroll bars as required.
///
protected void SetScrollbarVisibility()
{
if ((Document == null) || (Document.Body == null))
return;
if ((Document.Body.ScrollRectangle.Height > ClientSize.Height) || (Document.Body.ScrollRectangle.Width > ClientSize.Width + 6))
ScrollBarsEnabled = true;
else
ScrollBarsEnabled = false;
}
}
}