CEL_Payroll/Payroll.Controls/HtmlRichTextBox.cs
2024-09-17 14:30:13 +06:00

1639 lines
62 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
namespace Payroll.Controls
{
public partial class HtmlRichTextBox : RichTextBox
{
public HtmlRichTextBox()
{
InitializeComponent();
}
private int updating = 0;
private int oldEventMask = 0;
/// <summary>
/// Maintains performance while updating.
/// </summary>
/// <remarks>
/// <para>
/// It is recommended to call this method before doing
/// any major updates that you do not wish the user to
/// see. Remember to call EndUpdate when you are finished
/// with the update. Nested calls are supported.
/// </para>
/// <para>
/// Calling this method will prevent redrawing. It will
/// also setup the event mask of the underlying richedit
/// control so that no events are sent.
/// </para>
/// </remarks>
public void BeginUpdate()
{
// Deal with nested calls.
++updating;
if (updating > 1)
return;
// Prevent the control from raising any events.
oldEventMask = SendMessage(new HandleRef(this, Handle),
EM_SETEVENTMASK, 0, 0);
// Prevent the control from redrawing itself.
SendMessage(new HandleRef(this, Handle),
WM_SETREDRAW, 0, 0);
}
/// <summary>
/// Resumes drawing and event handling.
/// </summary>
/// <remarks>
/// This method should be called every time a call is made
/// made to BeginUpdate. It resets the event mask to it's
/// original value and enables redrawing of the control.
/// </remarks>
public void EndUpdate()
{
// Deal with nested calls.
--updating;
if (updating > 0)
return;
// Allow the control to redraw itself.
SendMessage(new HandleRef(this, Handle),
WM_SETREDRAW, 1, 0);
// Allow the control to raise event messages.
SendMessage(new HandleRef(this, Handle),
EM_SETEVENTMASK, 0, oldEventMask);
}
/// <summary>
/// Returns true when the control is performing some
/// internal updates, specially when is reading or writing
/// HTML text
/// </summary>
public bool InternalUpdating
{
get
{
return (updating != 0);
}
}
#region Win32 Apis
// Constants from the Platform SDK.
private const int EM_FORMATRANGE = 1081;
private const int WM_USER = 0x0400;
private const int EM_GETCHARFORMAT = WM_USER + 58;
private const int EM_SETCHARFORMAT = WM_USER + 68;
private const int EM_SETEVENTMASK = 1073;
private const int EM_GETPARAFORMAT = 1085;
private const int EM_SETPARAFORMAT = 1095;
private const int EM_SETTYPOGRAPHYOPTIONS = 1226;
private const int WM_SETREDRAW = 11;
private const int TO_ADVANCEDTYPOGRAPHY = 1;
// Defines for EM_SETCHARFORMAT/EM_GETCHARFORMAT
private const Int32 SCF_SELECTION = 0x0001;
private const Int32 SCF_WORD = 0x0002;
private const Int32 SCF_ALL = 0x0004;
public const int LF_FACESIZE = 32;
// Defines for STRUCT_CHARFORMAT member dwMask
public const UInt32 CFM_BOLD = 0x00000001;
public const UInt32 CFM_ITALIC = 0x00000002;
public const UInt32 CFM_UNDERLINE = 0x00000004;
public const UInt32 CFM_STRIKEOUT = 0x00000008;
public const UInt32 CFM_PROTECTED = 0x00000010;
public const UInt32 CFM_LINK = 0x00000020;
public const UInt32 CFM_SIZE = 0x80000000;
public const UInt32 CFM_COLOR = 0x40000000;
public const UInt32 CFM_FACE = 0x20000000;
public const UInt32 CFM_OFFSET = 0x10000000;
public const UInt32 CFM_CHARSET = 0x08000000;
public const UInt32 CFM_SUBSCRIPT = CFE_SUBSCRIPT | CFE_SUPERSCRIPT;
public const UInt32 CFM_SUPERSCRIPT = CFM_SUBSCRIPT;
// Defines for STRUCT_CHARFORMAT member dwEffects
public const UInt32 CFE_BOLD = 0x00000001;
public const UInt32 CFE_ITALIC = 0x00000002;
public const UInt32 CFE_UNDERLINE = 0x00000004;
public const UInt32 CFE_STRIKEOUT = 0x00000008;
public const UInt32 CFE_PROTECTED = 0x00000010;
public const UInt32 CFE_LINK = 0x00000020;
public const UInt32 CFE_AUTOCOLOR = 0x40000000;
public const UInt32 CFE_SUBSCRIPT = 0x00010000; /* Superscript and subscript are */
public const UInt32 CFE_SUPERSCRIPT = 0x00020000; /* mutually exclusive */
public const byte CFU_UNDERLINENONE = 0x00;
public const byte CFU_UNDERLINE = 0x01;
public const byte CFU_UNDERLINEWORD = 0x02; /* (*) displayed as ordinary underline */
public const byte CFU_UNDERLINEDOUBLE = 0x03; /* (*) displayed as ordinary underline */
public const byte CFU_UNDERLINEDOTTED = 0x04;
public const byte CFU_UNDERLINEDASH = 0x05;
public const byte CFU_UNDERLINEDASHDOT = 0x06;
public const byte CFU_UNDERLINEDASHDOTDOT = 0x07;
public const byte CFU_UNDERLINEWAVE = 0x08;
public const byte CFU_UNDERLINETHICK = 0x09;
public const byte CFU_UNDERLINEHAIRLINE = 0x0A; /* (*) displayed as ordinary underline */
public const int CFM_SMALLCAPS = 0x0040; /* (*) */
public const int CFM_ALLCAPS = 0x0080; /* Displayed by 3.0 */
public const int CFM_HIDDEN = 0x0100; /* Hidden by 3.0 */
public const int CFM_OUTLINE = 0x0200; /* (*) */
public const int CFM_SHADOW = 0x0400; /* (*) */
public const int CFM_EMBOSS = 0x0800; /* (*) */
public const int CFM_IMPRINT = 0x1000; /* (*) */
public const int CFM_DISABLED = 0x2000;
public const int CFM_REVISED = 0x4000;
public const int CFM_BACKCOLOR = 0x04000000;
public const int CFM_LCID = 0x02000000;
public const int CFM_UNDERLINETYPE = 0x00800000; /* Many displayed by 3.0 */
public const int CFM_WEIGHT = 0x00400000;
public const int CFM_SPACING = 0x00200000; /* Displayed by 3.0 */
public const int CFM_KERNING = 0x00100000; /* (*) */
public const int CFM_STYLE = 0x00080000; /* (*) */
public const int CFM_ANIMATION = 0x00040000; /* (*) */
public const int CFM_REVAUTHOR = 0x00008000;
// Font Weights
public const short FW_DONTCARE = 0;
public const short FW_THIN = 100;
public const short FW_EXTRALIGHT = 200;
public const short FW_LIGHT = 300;
public const short FW_NORMAL = 400;
public const short FW_MEDIUM = 500;
public const short FW_SEMIBOLD = 600;
public const short FW_BOLD = 700;
public const short FW_EXTRABOLD = 800;
public const short FW_HEAVY = 900;
public const short FW_ULTRALIGHT = FW_EXTRALIGHT;
public const short FW_REGULAR = FW_NORMAL;
public const short FW_DEMIBOLD = FW_SEMIBOLD;
public const short FW_ULTRABOLD = FW_EXTRABOLD;
public const short FW_BLACK = FW_HEAVY;
// PARAFORMAT mask values
public const UInt32 PFM_STARTINDENT = 0x00000001;
public const UInt32 PFM_RIGHTINDENT = 0x00000002;
public const UInt32 PFM_OFFSET = 0x00000004;
public const UInt32 PFM_ALIGNMENT = 0x00000008;
public const UInt32 PFM_TABSTOPS = 0x00000010;
public const UInt32 PFM_NUMBERING = 0x00000020;
public const UInt32 PFM_OFFSETINDENT = 0x80000000;
// PARAFORMAT numbering options
public const UInt16 PFN_BULLET = 0x0001;
// PARAFORMAT alignment options
public const UInt16 PFA_LEFT = 0x0001;
public const UInt16 PFA_RIGHT = 0x0002;
public const UInt16 PFA_CENTER = 0x0003;
// It makes no difference if we use PARAFORMAT or
// PARAFORMAT2 here, so I have opted for PARAFORMAT2.
[StructLayout(LayoutKind.Sequential)]
public struct PARAFORMAT
{
public int cbSize;
public uint dwMask;
public short wNumbering;
public short wReserved;
public int dxStartIndent;
public int dxRightIndent;
public int dxOffset;
public short wAlignment;
public short cTabCount;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public int[] rgxTabs;
// PARAFORMAT2 from here onwards.
public int dySpaceBefore;
public int dySpaceAfter;
public int dyLineSpacing;
public short sStyle;
public byte bLineSpacingRule;
public byte bOutlineLevel;
public short wShadingWeight;
public short wShadingStyle;
public short wNumberingStart;
public short wNumberingStyle;
public short wNumberingTab;
public short wBorderSpace;
public short wBorderWidth;
public short wBorders;
}
[StructLayout(LayoutKind.Sequential)]
public struct CHARFORMAT
{
public int cbSize;
public UInt32 dwMask;
public UInt32 dwEffects;
public Int32 yHeight;
public Int32 yOffset;
public Int32 crTextColor;
public byte bCharSet;
public byte bPitchAndFamily;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
public char[] szFaceName;
// CHARFORMAT2 from here onwards.
public short wWeight;
public short sSpacing;
public Int32 crBackColor;
public uint lcid;
public uint dwReserved;
public short sStyle;
public short wKerning;
public byte bUnderlineType;
public byte bAnimation;
public byte bRevAuthor;
public byte bReserved1;
}
[DllImport("user32", CharSet = CharSet.Auto)]
private static extern int SendMessage(HandleRef hWnd,
int msg,
int wParam,
int lParam);
[DllImport("user32", CharSet = CharSet.Auto)]
private static extern int SendMessage(HandleRef hWnd,
int msg,
int wParam,
ref PARAFORMAT lp);
[DllImport("user32", CharSet = CharSet.Auto)]
private static extern int SendMessage(HandleRef hWnd,
int msg,
int wParam,
ref CHARFORMAT lp);
#endregion
//----------------------------
// New, version 1.1
public void SetSuperScript(bool bSet)
{
CHARFORMAT cf = this.CharFormat;
if (bSet)
{
cf.dwMask |= CFM_SUPERSCRIPT;
cf.dwEffects |= CFE_SUPERSCRIPT;
}
else
{
cf.dwEffects &= ~CFE_SUPERSCRIPT;
}
this.CharFormat = cf;
}
public void SetSubScript(bool bSet)
{
CHARFORMAT cf = this.CharFormat;
if (bSet)
{
cf.dwMask |= CFM_SUBSCRIPT;
cf.dwEffects |= CFE_SUBSCRIPT;
}
else
{
cf.dwEffects &= ~CFE_SUBSCRIPT;
}
this.CharFormat = cf;
}
public bool IsSuperScript()
{
CHARFORMAT cf = this.CharFormat;
return ((cf.dwEffects & CFE_SUPERSCRIPT) == CFE_SUPERSCRIPT);
}
public bool IsSubScript()
{
CHARFORMAT cf = this.CharFormat;
return ((cf.dwEffects & CFE_SUBSCRIPT) == CFE_SUBSCRIPT);
}
//----------------------------
public PARAFORMAT ParaFormat
{
get
{
PARAFORMAT pf = new PARAFORMAT();
pf.cbSize = Marshal.SizeOf(pf);
// Get the alignment.
SendMessage(new HandleRef(this, Handle),
EM_GETPARAFORMAT,
SCF_SELECTION, ref pf);
return pf;
}
set
{
PARAFORMAT pf = value;
pf.cbSize = Marshal.SizeOf(pf);
// Set the alignment.
SendMessage(new HandleRef(this, Handle),
EM_SETPARAFORMAT,
SCF_SELECTION, ref pf);
}
}
public PARAFORMAT DefaultParaFormat
{
get
{
PARAFORMAT pf = new PARAFORMAT();
pf.cbSize = Marshal.SizeOf(pf);
// Get the alignment.
SendMessage(new HandleRef(this, Handle),
EM_GETPARAFORMAT,
SCF_ALL, ref pf);
return pf;
}
set
{
PARAFORMAT pf = value;
pf.cbSize = Marshal.SizeOf(pf);
// Set the alignment.
SendMessage(new HandleRef(this, Handle),
EM_SETPARAFORMAT,
SCF_ALL, ref pf);
}
}
public CHARFORMAT CharFormat
{
get
{
CHARFORMAT cf = new CHARFORMAT();
cf.cbSize = Marshal.SizeOf(cf);
// Get the alignment.
SendMessage(new HandleRef(this, Handle),
EM_GETCHARFORMAT,
SCF_SELECTION, ref cf);
return cf;
}
set
{
CHARFORMAT cf = value;
cf.cbSize = Marshal.SizeOf(cf);
// Set the alignment.
SendMessage(new HandleRef(this, Handle),
EM_SETCHARFORMAT,
SCF_SELECTION, ref cf);
}
}
public CHARFORMAT DefaultCharFormat
{
get
{
CHARFORMAT cf = new CHARFORMAT();
cf.cbSize = Marshal.SizeOf(cf);
// Get the alignment.
SendMessage(new HandleRef(this, Handle),
EM_GETCHARFORMAT,
SCF_ALL, ref cf);
return cf;
}
set
{
CHARFORMAT cf = value;
cf.cbSize = Marshal.SizeOf(cf);
// Set the alignment.
SendMessage(new HandleRef(this, Handle),
EM_SETCHARFORMAT,
SCF_ALL, ref cf);
}
}
#region COLORREF helper functions
// convert COLORREF to Color
private Color GetColor(int crColor)
{
byte r = (byte)(crColor);
byte g = (byte)(crColor >> 8);
byte b = (byte)(crColor >> 16);
return Color.FromArgb(r, g, b);
}
// convert COLORREF to Color
private int GetCOLORREF(int r, int g, int b)
{
int r2 = r;
int g2 = (g << 8);
int b2 = (b << 16);
int result = r2 | g2 | b2;
return result;
}
private int GetCOLORREF(Color color)
{
int r = color.R;
int g = color.G;
int b = color.B;
return GetCOLORREF(r, g, b);
}
#endregion
#region "Get HTML text"
// format states
private enum ctformatStates
{
nctNone = 0, // none format applied
nctNew = 1, // new format
nctContinue = 2, // continue with previous format
nctReset = 3 // reset format (close this tag)
}
private enum uMyREType
{
U_MYRE_TYPE_TAG,
U_MYRE_TYPE_EMO,
U_MYRE_TYPE_ENTITY,
}
private struct cMyREFormat
{
public uMyREType nType;
public int nLen;
public int nPos;
public string strValue;
}
public string GetHTML(bool bHTML, bool bParaFormat)
{
//------------------------
// working variables
CHARFORMAT cf;
PARAFORMAT pf;
ctformatStates bold = ctformatStates.nctNone;
ctformatStates bitalic = ctformatStates.nctNone;
ctformatStates bstrikeout = ctformatStates.nctNone;
ctformatStates bunderline = ctformatStates.nctNone;
ctformatStates super = ctformatStates.nctNone;
ctformatStates sub = ctformatStates.nctNone;
ctformatStates bacenter = ctformatStates.nctNone;
ctformatStates baleft = ctformatStates.nctNone;
ctformatStates baright = ctformatStates.nctNone;
ctformatStates bnumbering = ctformatStates.nctNone;
string strFont = "";
Int32 crFont = 0;
Color color = new Color();
int yHeight = 0;
int i = 0;
//-------------------------
//-------------------------
// to store formatting
ArrayList colFormat = new ArrayList();
cMyREFormat mfr;
//-------------------------
//-------------------------
// ok, lets go
int nStart, nEnd;
string strHTML = "";
this.HideSelection = true;
this.BeginUpdate();
nStart = this.SelectionStart;
nEnd = this.SelectionLength;
try
{
//--------------------------------
// replace entities
if (bHTML)
{
char[] ch = { '&', '<', '>', '"', '\'' };
string[] strreplace = { "&amp;", "&lt;", "&gt;", "&quot;", "&apos;" };
for (i = 0; i < ch.Length; i++)
{
char[] ch2 = { ch[i] };
int n = this.Find(ch2, 0);
while (n != -1)
{
mfr = new cMyREFormat();
mfr.nPos = n;
mfr.nLen = 1;
mfr.nType = uMyREType.U_MYRE_TYPE_ENTITY;
mfr.strValue = strreplace[i];
colFormat.Add(mfr);
n = this.Find(ch2, n + 1);
}
}
}
//--------------------------------
string strT = "";
int k = this.TextLength;
char[] chtrim = { ' ', '\x0000' };
//--------------------------------
// this is an inefficient method to get text format
// but RichTextBox doesn't provide another method to
// get something like an array of charformat and paraformat
//--------------------------------
for (i = 0; i < k; i++)
{
// select one character
this.Select(i, 1);
string strChar = this.SelectedText;
if (bHTML)
{
//-------------------------
// get format for this character
cf = this.CharFormat;
pf = this.ParaFormat;
string strfname = new string(cf.szFaceName);
strfname = strfname.Trim(chtrim);
//-------------------------
//-------------------------
// new font format ?
if ((strFont != strfname) || (crFont != cf.crTextColor) || (yHeight != cf.yHeight))
{
if (strFont != "")
{
// close previous <font> tag
mfr = new cMyREFormat();
mfr.nPos = i;
mfr.nLen = 0;
mfr.nType = uMyREType.U_MYRE_TYPE_TAG;
mfr.strValue = "</font>";
colFormat.Add(mfr);
}
//-------------------------
// save this for cache
strFont = strfname;
crFont = cf.crTextColor;
yHeight = cf.yHeight;
//-------------------------
//-------------------------
// font size should be translate to
// html size (Approximately)
double fsize = (double)yHeight / (double)(20 * 5);
//-------------------------
//-------------------------
// color object from COLORREF
color = GetColor(crFont);
//-------------------------
//-------------------------
// add <font> tag
mfr = new cMyREFormat();
string strcolor = string.Concat("#", (color.ToArgb() & 0x00FFFFFF).ToString("X6"));
mfr.nPos = i;
mfr.nLen = 0;
mfr.nType = uMyREType.U_MYRE_TYPE_TAG;
mfr.strValue = "<font face=\"" + strFont + "\" color=\"" + strcolor + "\" size=\"" + fsize + "\">";
colFormat.Add(mfr);
//-------------------------
}
//-------------------------
// are we in another line ?
if ((strChar == "\r") || (strChar == "\n"))
{
// yes?
// then, we need to reset paragraph format
// and character format
if (bParaFormat)
{
bnumbering = ctformatStates.nctNone;
baleft = ctformatStates.nctNone;
baright = ctformatStates.nctNone;
bacenter = ctformatStates.nctNone;
}
// close previous tags
// is italic? => close it
if (bitalic != ctformatStates.nctNone)
{
mfr = new cMyREFormat();
mfr.nPos = i;
mfr.nLen = 0;
mfr.nType = uMyREType.U_MYRE_TYPE_TAG;
mfr.strValue = "</i>";
colFormat.Add(mfr);
bitalic = ctformatStates.nctNone;
}
// is bold? => close it
if (bold != ctformatStates.nctNone)
{
mfr = new cMyREFormat();
mfr.nPos = i;
mfr.nLen = 0;
mfr.nType = uMyREType.U_MYRE_TYPE_TAG;
mfr.strValue = "</b>";
colFormat.Add(mfr);
bold = ctformatStates.nctNone;
}
// is underline? => close it
if (bunderline != ctformatStates.nctNone)
{
mfr = new cMyREFormat();
mfr.nPos = i;
mfr.nLen = 0;
mfr.nType = uMyREType.U_MYRE_TYPE_TAG;
mfr.strValue = "</u>";
colFormat.Add(mfr);
bunderline = ctformatStates.nctNone;
}
// is strikeout? => close it
if (bstrikeout != ctformatStates.nctNone)
{
mfr = new cMyREFormat();
mfr.nPos = i;
mfr.nLen = 0;
mfr.nType = uMyREType.U_MYRE_TYPE_TAG;
mfr.strValue = "</s>";
colFormat.Add(mfr);
bstrikeout = ctformatStates.nctNone;
}
// is super? => close it
if (super != ctformatStates.nctNone)
{
mfr = new cMyREFormat();
mfr.nPos = i;
mfr.nLen = 0;
mfr.nType = uMyREType.U_MYRE_TYPE_TAG;
mfr.strValue = "</sup>";
colFormat.Add(mfr);
super = ctformatStates.nctNone;
}
// is sub? => close it
if (sub != ctformatStates.nctNone)
{
mfr = new cMyREFormat();
mfr.nPos = i;
mfr.nLen = 0;
mfr.nType = uMyREType.U_MYRE_TYPE_TAG;
mfr.strValue = "</sub>";
colFormat.Add(mfr);
sub = ctformatStates.nctNone;
}
}
// now, process the paragraph format,
// managing states: none, new, continue {with previous}, reset
if (bParaFormat)
{
// align to center?
if (pf.wAlignment == PFA_CENTER)
{
if (bacenter == ctformatStates.nctNone)
bacenter = ctformatStates.nctNew;
else
bacenter = ctformatStates.nctContinue;
}
else
{
if (bacenter != ctformatStates.nctNone)
bacenter = ctformatStates.nctReset;
}
if (bacenter == ctformatStates.nctNew)
{
mfr = new cMyREFormat();
mfr.nPos = i;
mfr.nLen = 0;
mfr.nType = uMyREType.U_MYRE_TYPE_TAG;
mfr.strValue = "<p align=\"center\">";
colFormat.Add(mfr);
}
else if (bacenter == ctformatStates.nctReset)
bacenter = ctformatStates.nctNone;
//---------------------
//---------------------
// align to left ?
if (pf.wAlignment == PFA_LEFT)
{
if (baleft == ctformatStates.nctNone)
baleft = ctformatStates.nctNew;
else
baleft = ctformatStates.nctContinue;
}
else
{
if (baleft != ctformatStates.nctNone)
baleft = ctformatStates.nctReset;
}
if (baleft == ctformatStates.nctNew)
{
mfr = new cMyREFormat();
mfr.nPos = i;
mfr.nLen = 0;
mfr.nType = uMyREType.U_MYRE_TYPE_TAG;
mfr.strValue = "<p align=\"left\">";
colFormat.Add(mfr);
}
else if (baleft == ctformatStates.nctReset)
baleft = ctformatStates.nctNone;
//---------------------
//---------------------
// align to right ?
if (pf.wAlignment == PFA_RIGHT)
{
if (baright == ctformatStates.nctNone)
baright = ctformatStates.nctNew;
else
baright = ctformatStates.nctContinue;
}
else
{
if (baright != ctformatStates.nctNone)
baright = ctformatStates.nctReset;
}
if (baright == ctformatStates.nctNew)
{
mfr = new cMyREFormat();
mfr.nPos = i;
mfr.nLen = 0;
mfr.nType = uMyREType.U_MYRE_TYPE_TAG;
mfr.strValue = "<p align=\"right\">";
colFormat.Add(mfr);
}
else if (baright == ctformatStates.nctReset)
baright = ctformatStates.nctNone;
//---------------------
//---------------------
// bullet ?
if (pf.wNumbering == PFN_BULLET)
{
if (bnumbering == ctformatStates.nctNone)
bnumbering = ctformatStates.nctNew;
else
bnumbering = ctformatStates.nctContinue;
}
else
{
if (bnumbering != ctformatStates.nctNone)
bnumbering = ctformatStates.nctReset;
}
if (bnumbering == ctformatStates.nctNew)
{
mfr = new cMyREFormat();
mfr.nPos = i;
mfr.nLen = 0;
mfr.nType = uMyREType.U_MYRE_TYPE_TAG;
mfr.strValue = "<li>";
colFormat.Add(mfr);
}
else if (bnumbering == ctformatStates.nctReset)
bnumbering = ctformatStates.nctNone;
//---------------------
}
//---------------------
// bold ?
if ((cf.dwEffects & CFE_BOLD) == CFE_BOLD)
{
if (bold == ctformatStates.nctNone)
bold = ctformatStates.nctNew;
else
bold = ctformatStates.nctContinue;
}
else
{
if (bold != ctformatStates.nctNone)
bold = ctformatStates.nctReset;
}
if (bold == ctformatStates.nctNew)
{
mfr = new cMyREFormat();
mfr.nPos = i;
mfr.nLen = 0;
mfr.nType = uMyREType.U_MYRE_TYPE_TAG;
mfr.strValue = "<b>";
colFormat.Add(mfr);
}
else if (bold == ctformatStates.nctReset)
{
mfr = new cMyREFormat();
mfr.nPos = i;
mfr.nLen = 0;
mfr.nType = uMyREType.U_MYRE_TYPE_TAG;
mfr.strValue = "</b>";
colFormat.Add(mfr);
bold = ctformatStates.nctNone;
}
//---------------------
//---------------------
// Italic
if ((cf.dwEffects & CFE_ITALIC) == CFE_ITALIC)
{
if (bitalic == ctformatStates.nctNone)
bitalic = ctformatStates.nctNew;
else
bitalic = ctformatStates.nctContinue;
}
else
{
if (bitalic != ctformatStates.nctNone)
bitalic = ctformatStates.nctReset;
}
if (bitalic == ctformatStates.nctNew)
{
mfr = new cMyREFormat();
mfr.nPos = i;
mfr.nLen = 0;
mfr.nType = uMyREType.U_MYRE_TYPE_TAG;
mfr.strValue = "<i>";
colFormat.Add(mfr);
}
else if (bitalic == ctformatStates.nctReset)
{
mfr = new cMyREFormat();
mfr.nPos = i;
mfr.nLen = 0;
mfr.nType = uMyREType.U_MYRE_TYPE_TAG;
mfr.strValue = "</i>";
colFormat.Add(mfr);
bitalic = ctformatStates.nctNone;
}
//---------------------
//---------------------
// strikeout
if ((cf.dwEffects & CFM_STRIKEOUT) == CFM_STRIKEOUT)
{
if (bstrikeout == ctformatStates.nctNone)
bstrikeout = ctformatStates.nctNew;
else
bstrikeout = ctformatStates.nctContinue;
}
else
{
if (bstrikeout != ctformatStates.nctNone)
bstrikeout = ctformatStates.nctReset;
}
if (bstrikeout == ctformatStates.nctNew)
{
mfr = new cMyREFormat();
mfr.nPos = i;
mfr.nLen = 0;
mfr.nType = uMyREType.U_MYRE_TYPE_TAG;
mfr.strValue = "<s>";
colFormat.Add(mfr);
}
else if (bstrikeout == ctformatStates.nctReset)
{
mfr = new cMyREFormat();
mfr.nPos = i;
mfr.nLen = 0;
mfr.nType = uMyREType.U_MYRE_TYPE_TAG;
mfr.strValue = "</s>";
colFormat.Add(mfr);
bstrikeout = ctformatStates.nctNone;
}
//---------------------
//---------------------
// underline ?
if ((cf.dwEffects & CFE_UNDERLINE) == CFE_UNDERLINE)
{
if (bunderline == ctformatStates.nctNone)
bunderline = ctformatStates.nctNew;
else
bunderline = ctformatStates.nctContinue;
}
else
{
if (bunderline != ctformatStates.nctNone)
bunderline = ctformatStates.nctReset;
}
if (bunderline == ctformatStates.nctNew)
{
mfr = new cMyREFormat();
mfr.nPos = i;
mfr.nLen = 0;
mfr.nType = uMyREType.U_MYRE_TYPE_TAG;
mfr.strValue = "<u>";
colFormat.Add(mfr);
}
else if (bunderline == ctformatStates.nctReset)
{
mfr = new cMyREFormat();
mfr.nPos = i;
mfr.nLen = 0;
mfr.nType = uMyREType.U_MYRE_TYPE_TAG;
mfr.strValue = "</u>";
colFormat.Add(mfr);
bunderline = ctformatStates.nctNone;
}
//---------------------
//---------------------
// superscript ?
if ((cf.dwEffects & CFE_SUPERSCRIPT) == CFE_SUPERSCRIPT)
{
if (super == ctformatStates.nctNone)
super = ctformatStates.nctNew;
else
super = ctformatStates.nctContinue;
}
else
{
if (super != ctformatStates.nctNone)
super = ctformatStates.nctReset;
}
if (super == ctformatStates.nctNew)
{
mfr = new cMyREFormat();
mfr.nPos = i;
mfr.nLen = 0;
mfr.nType = uMyREType.U_MYRE_TYPE_TAG;
mfr.strValue = "<sup>";
colFormat.Add(mfr);
}
else if (super == ctformatStates.nctReset)
{
mfr = new cMyREFormat();
mfr.nPos = i;
mfr.nLen = 0;
mfr.nType = uMyREType.U_MYRE_TYPE_TAG;
mfr.strValue = "</sup>";
colFormat.Add(mfr);
super = ctformatStates.nctNone;
}
//---------------------
//---------------------
// subscript ?
if ((cf.dwEffects & CFE_SUBSCRIPT) == CFE_SUBSCRIPT)
{
if (sub == ctformatStates.nctNone)
sub = ctformatStates.nctNew;
else
sub = ctformatStates.nctContinue;
}
else
{
if (sub != ctformatStates.nctNone)
sub = ctformatStates.nctReset;
}
if (sub == ctformatStates.nctNew)
{
mfr = new cMyREFormat();
mfr.nPos = i;
mfr.nLen = 0;
mfr.nType = uMyREType.U_MYRE_TYPE_TAG;
mfr.strValue = "<sub>";
colFormat.Add(mfr);
}
else if (sub == ctformatStates.nctReset)
{
mfr = new cMyREFormat();
mfr.nPos = i;
mfr.nLen = 0;
mfr.nType = uMyREType.U_MYRE_TYPE_TAG;
mfr.strValue = "</sub>";
colFormat.Add(mfr);
sub = ctformatStates.nctNone;
}
//---------------------
}
strT += strChar;
}
if (bHTML)
{
// close pending tags
if (bold != ctformatStates.nctNone)
{
mfr = new cMyREFormat();
mfr.nPos = i;
mfr.nLen = 0;
mfr.nType = uMyREType.U_MYRE_TYPE_TAG;
mfr.strValue = "</b>";
colFormat.Add(mfr);
//strT += "</b>";
}
if (bitalic != ctformatStates.nctNone)
{
mfr = new cMyREFormat();
mfr.nPos = i;
mfr.nLen = 0;
mfr.nType = uMyREType.U_MYRE_TYPE_TAG;
mfr.strValue = "</i>";
colFormat.Add(mfr);
//strT += "</i>";
}
if (bstrikeout != ctformatStates.nctNone)
{
mfr = new cMyREFormat();
mfr.nPos = i;
mfr.nLen = 0;
mfr.nType = uMyREType.U_MYRE_TYPE_TAG;
mfr.strValue = "</s>";
colFormat.Add(mfr);
//strT += "</s>";
}
if (bunderline != ctformatStates.nctNone)
{
mfr = new cMyREFormat();
mfr.nPos = i;
mfr.nLen = 0;
mfr.nType = uMyREType.U_MYRE_TYPE_TAG;
mfr.strValue = "</u>";
colFormat.Add(mfr);
//strT += "</u>";
}
if (super != ctformatStates.nctNone)
{
mfr = new cMyREFormat();
mfr.nPos = i;
mfr.nLen = 0;
mfr.nType = uMyREType.U_MYRE_TYPE_TAG;
mfr.strValue = "</sup>";
colFormat.Add(mfr);
//strT += "</sup>";
}
if (sub != ctformatStates.nctNone)
{
mfr = new cMyREFormat();
mfr.nPos = i;
mfr.nLen = 0;
mfr.nType = uMyREType.U_MYRE_TYPE_TAG;
mfr.strValue = "</sub>";
colFormat.Add(mfr);
//strT += "</sub>";
}
if (strFont != "")
{
// close pending font format
mfr = new cMyREFormat();
mfr.nPos = i;
mfr.nLen = 0;
mfr.nType = uMyREType.U_MYRE_TYPE_TAG;
mfr.strValue = "</font>";
colFormat.Add(mfr);
}
}
//--------------------------
// now, reorder the formatting array
k = colFormat.Count;
for (i = 0; i < k - 1; i++)
{
for (int j = i + 1; j < k; j++)
{
mfr = (cMyREFormat)colFormat[i];
cMyREFormat mfr2 = (cMyREFormat)colFormat[j];
if (mfr2.nPos < mfr.nPos)
{
colFormat.RemoveAt(j);
colFormat.Insert(i, mfr2);
j--;
}
else if ((mfr2.nPos == mfr.nPos) && (mfr2.nLen < mfr.nLen))
{
colFormat.RemoveAt(j);
colFormat.Insert(i, mfr2);
j--;
}
}
}
//--------------------------
//--------------------------
// apply format by replacing and inserting HTML tags
// stored in the Format Array
int nAcum = 0;
for (i = 0; i < k; i++)
{
mfr = (cMyREFormat)colFormat[i];
strHTML += strT.Substring(nAcum, mfr.nPos - nAcum) + mfr.strValue;
nAcum = mfr.nPos + mfr.nLen;
}
if (nAcum < strT.Length)
strHTML += strT.Substring(nAcum);
//--------------------------
}
catch
{
//MessageBox.Show(ex.Message);
}
finally
{
//--------------------------
// finish, restore
this.SelectionStart = nStart;
this.SelectionLength = nEnd;
this.EndUpdate();
this.HideSelection = false;
//--------------------------
}
return strHTML;
}
#endregion
#region "Add HTML text"
public void AddHTML(string strHTML)
{
CHARFORMAT cf;
PARAFORMAT pf;
cf = this.DefaultCharFormat; // to apply character formatting
pf = this.DefaultParaFormat; // to apply paragraph formatting
char[] chtrim = { ' ', '\x0000' };
this.HideSelection = true;
this.BeginUpdate();
try
{
// process text
while (strHTML.Length > 0)
{
string strData = strHTML;
reinit:
// looking for start tags
int nStart = strHTML.IndexOf('<');
if (nStart >= 0)
{
if (nStart > 0)
{
// tag is not the first character, so
// we need to add text to control and continue
// looking for tags at the begining of the text
strData = strHTML.Substring(0, nStart);
strHTML = strHTML.Substring(nStart);
}
else
{
// ok, get tag value
int nEnd = strHTML.IndexOf('>', nStart);
if (nEnd > nStart)
{
if ((nEnd - nStart) > 0)
{
string strTag = strHTML.Substring(nStart, nEnd - nStart + 1);
strTag = strTag.ToLower();
if (strTag == "<b>")
{
cf.dwMask |= CFM_WEIGHT | CFM_BOLD;
cf.dwEffects |= CFE_BOLD;
cf.wWeight = FW_BOLD;
}
else if (strTag == "<i>")
{
cf.dwMask |= CFM_ITALIC;
cf.dwEffects |= CFE_ITALIC;
}
else if (strTag == "<u>")
{
cf.dwMask |= CFM_UNDERLINE | CFM_UNDERLINETYPE;
cf.dwEffects |= CFE_UNDERLINE;
cf.bUnderlineType = CFU_UNDERLINE;
}
else if (strTag == "<s>")
{
cf.dwMask |= CFM_STRIKEOUT;
cf.dwEffects |= CFE_STRIKEOUT;
}
else if (strTag == "<sup>")
{
cf.dwMask |= CFM_SUPERSCRIPT;
cf.dwEffects |= CFE_SUPERSCRIPT;
}
else if (strTag == "<sub>")
{
cf.dwMask |= CFM_SUBSCRIPT;
cf.dwEffects |= CFE_SUBSCRIPT;
}
else if ((strTag.Length > 2) && (strTag.Substring(0, 2) == "<p"))
{
if (strTag.IndexOf("align=\"left\"") > 0)
{
pf.dwMask |= PFM_ALIGNMENT;
pf.wAlignment = (short)PFA_LEFT;
}
else if (strTag.IndexOf("align=\"right\"") > 0)
{
pf.dwMask |= PFM_ALIGNMENT;
pf.wAlignment = (short)PFA_RIGHT;
}
else if (strTag.IndexOf("align=\"center\"") > 0)
{
pf.dwMask |= PFM_ALIGNMENT;
pf.wAlignment = (short)PFA_CENTER;
}
}
else if ((strTag.Length > 5) && (strTag.Substring(0, 5) == "<font"))
{
string strFont = new string(cf.szFaceName);
strFont = strFont.Trim(chtrim);
int crFont = cf.crTextColor;
int yHeight = cf.yHeight;
double dHeight = yHeight;
int nFace = strTag.IndexOf("face=");
if (nFace > 0)
{
int nFaceEnd = strTag.IndexOf('\"', nFace + 6);
if (nFaceEnd > nFace)
strFont = strTag.Substring(nFace + 6, nFaceEnd - nFace - 6);
}
int nSize = strTag.IndexOf("size=");
if (nSize > 0)
{
int nSizeEnd = strTag.IndexOf('\"', nSize + 6);
if (nSizeEnd > nSize)
{
dHeight = double.Parse(strTag.Substring(nSize + 6, nSizeEnd - nSize - 6));
dHeight *= (double)(20 * 5);
yHeight = (int)dHeight;
}
}
int nColor = strTag.IndexOf("color=");
if (nColor > 0)
{
int nColorEnd = strTag.IndexOf('\"', nColor + 7);
if (nColorEnd > nColor)
{
if (strTag.Substring(nColor + 7, 1) == "#")
{
string strCr = strTag.Substring(nColor + 8, nColorEnd - nColor - 8);
int nCr = Convert.ToInt32(strCr, 16);
Color color = Color.FromArgb(nCr);
crFont = GetCOLORREF(color);
}
else
{
crFont = int.Parse(strTag.Substring(nColor + 7, nColorEnd - nColor - 7));
}
}
}
cf.szFaceName = new char[LF_FACESIZE];
strFont.CopyTo(0, cf.szFaceName, 0, Math.Min(LF_FACESIZE - 1, strFont.Length));
//cf.szFaceName = strFont.ToCharArray(0, Math.Min(strFont.Length, LF_FACESIZE));
cf.crTextColor = crFont;
cf.yHeight = yHeight;
cf.dwMask |= CFM_COLOR | CFM_SIZE | CFM_FACE;
cf.dwEffects &= ~CFE_AUTOCOLOR;
}
else if (strTag == "<li>")
{
if (pf.wNumbering != PFN_BULLET)
{
pf.dwMask |= PFM_NUMBERING;
pf.wNumbering = (short)PFN_BULLET;
}
}
else if (strTag == "</b>")
{
cf.dwEffects &= ~CFE_BOLD;
cf.wWeight = FW_NORMAL;
}
else if (strTag == "</i>")
{
cf.dwEffects &= ~CFE_ITALIC;
}
else if (strTag == "</u>")
{
cf.dwEffects &= ~CFE_UNDERLINE;
}
else if (strTag == "</s>")
{
cf.dwEffects &= ~CFM_STRIKEOUT;
}
else if (strTag == "</sup>")
{
cf.dwEffects &= ~CFE_SUPERSCRIPT;
}
else if (strTag == "</sub>")
{
cf.dwEffects &= ~CFE_SUBSCRIPT;
}
else if (strTag == "</font>")
{
}
else if (strTag == "</p>")
{
}
else if (strTag == "</li>")
{
}
//-------------------------------
// now, remove tag from HTML
int nStart2 = strHTML.IndexOf("<", nEnd + 1);
if (nStart2 > 0)
{
// extract partial data
strData = strHTML.Substring(nEnd + 1, nStart2 - nEnd - 1);
strHTML = strHTML.Substring(nStart2);
}
else
{
// get remain text and finish
if ((nEnd + 1) < strHTML.Length)
strData = strHTML.Substring(nEnd + 1);
else
strData = "";
strHTML = "";
}
//-------------------------------s
//-------------------------------
// have we any continuos tag ?
if (strData.Length > 0)
{
// yes, ok, goto to reinit
if (strData[0] == '<')
goto reinit;
}
//-------------------------------
}
else
{
// we have not found any valid tag
strHTML = "";
}
}
else
{
// we have not found any valid tag
strHTML = "";
}
}
}
else
{
// we have not found any tag
strHTML = "";
}
if (strData.Length > 0)
{
//-------------------------------
// replace entities
strData = strData.Replace("&amp;", "&");
strData = strData.Replace("&lt;", "<");
strData = strData.Replace("&gt;", ">");
strData = strData.Replace("&apos;", "'");
strData = strData.Replace("&quot;", "\"");
//-------------------------------
string strAux = strData; // use another copy
while (strAux.Length > 0)
{
//-----------------------
int nLen = strAux.Length;
//-----------------------
//-------------------------------
// now, add text to control
int nStartCache = this.SelectionStart;
string strt = strAux.Substring(0, nLen);
this.SelectedText = strt;
strAux = strAux.Remove(0, nLen);
this.SelectionStart = nStartCache;
this.SelectionLength = strt.Length;
//-------------------------------
//-------------------------------
// apply format
this.ParaFormat = pf;
this.CharFormat = cf;
//-------------------------------
// reposition to final
this.SelectionStart = this.TextLength + 1;
this.SelectionLength = 0;
}
// reposition to final
this.SelectionStart = this.TextLength + 1;
this.SelectionLength = 0;
//-------------------------------
// new paragraph requires to reset alignment
if ((strData.IndexOf("\r\n", 0) >= 0) || (strData.IndexOf("\n", 0) >= 0))
{
pf.dwMask = PFM_ALIGNMENT | PFM_NUMBERING;
pf.wAlignment = (short)PFA_LEFT;
pf.wNumbering = 0;
}
//-------------------------------
}
} // while (strHTML.Length > 0)
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
// reposition to final
this.SelectionStart = this.TextLength + 1;
this.SelectionLength = 0;
this.EndUpdate();
this.HideSelection = false;
}
}
#endregion
}
}