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; } } }