1704 lines
53 KiB
C#
1704 lines
53 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
|
|
using System.Drawing;
|
|
using System.Data;
|
|
using System.Text;
|
|
using System.Windows.Forms;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text.RegularExpressions;
|
|
using VEPROMS.CSLA.Library;
|
|
|
|
namespace Volian.Controls.Library
|
|
{
|
|
public delegate void StepRTBEvent(object sender, EventArgs args);
|
|
public partial class StepRTB : RichTextBox , IStepRTB
|
|
{
|
|
#region Events
|
|
public event StepRTBEvent RTBSelectionChanged;
|
|
private void OnRTBSelectionChanged(object sender, EventArgs args)
|
|
{
|
|
if (RTBSelectionChanged != null) RTBSelectionChanged(sender, args);
|
|
}
|
|
public event StepRTBEvent LinkLocationsChanged;
|
|
private void OnLinkLocationChanged(object sender, EventArgs args)
|
|
{
|
|
if (LinkLocationsChanged != null) LinkLocationsChanged(sender, args);
|
|
}
|
|
public event StepRTBEvent RTBRangeStatusChanged;
|
|
private void OnRTBRangeStatusChanged(object sender, EventArgs args)
|
|
{
|
|
if (RTBRangeStatusChanged != null) RTBRangeStatusChanged(sender, args);
|
|
}
|
|
/// <summary>
|
|
/// This event is not raised during all the in-between changes for link deletions
|
|
/// </summary>
|
|
public event StepRTBEvent RTBTextChanged;
|
|
private void OnRTBTextChanged(object sender, EventArgs args)
|
|
{
|
|
if (RTBTextChanged != null) RTBTextChanged(sender, args);
|
|
}
|
|
#endregion
|
|
#region Properties and Variables
|
|
// use newer rich text box....
|
|
//[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
|
|
//static extern IntPtr LoadLibrary(string lpFileName);
|
|
//protected override CreateParams CreateParams
|
|
//{
|
|
// get
|
|
// {
|
|
// CreateParams prams = base.CreateParams;
|
|
// if (LoadLibrary("msftedit.dll") != IntPtr.Zero)
|
|
// {
|
|
// //prams.ExStyle |= 0x020; // transparent
|
|
|
|
// prams.ClassName = "RICHEDIT50W";
|
|
// }
|
|
// return prams;
|
|
// }
|
|
//}
|
|
private StepItem _MyStepItem;
|
|
public StepItem MyStepItem
|
|
{
|
|
get { return _MyStepItem; }
|
|
set { _MyStepItem = value; }
|
|
}
|
|
private bool _IsDirty = false;
|
|
private bool _InitializingRTB;
|
|
private IContainer _Container = null;
|
|
private string _MyClassName=string.Empty;
|
|
public string MyClassName
|
|
{
|
|
get { if (_MyClassName == string.Empty)_MyClassName = CreateParams.ClassName; return _MyClassName; }
|
|
set { _MyClassName = value; }
|
|
}
|
|
private E_EditPrintMode _epMode = E_EditPrintMode.Edit;
|
|
public E_EditPrintMode EpMode
|
|
{
|
|
get { return _epMode; }
|
|
set { _epMode = value; }
|
|
}
|
|
private E_ViewMode _vwMode = E_ViewMode.Edit;
|
|
public E_ViewMode VwMode
|
|
{
|
|
get { return _vwMode; }
|
|
set { _vwMode = value; }
|
|
}
|
|
private VE_Font _MyStyleFont;
|
|
public VE_Font MyStyleFont
|
|
{
|
|
get { return _origDisplayText.TextFont; }
|
|
}
|
|
private ItemInfo _MyItemInfo;
|
|
public ItemInfo MyItemInfo
|
|
{
|
|
get { return _MyItemInfo; }
|
|
set
|
|
{
|
|
_MyItemInfo = value;
|
|
if (value != null)
|
|
{
|
|
_InitializingRTB = true;
|
|
DisplayText vlntxt = new DisplayText(_MyItemInfo, EpMode, VwMode);
|
|
_origDisplayText = vlntxt;
|
|
#if(DEBUG)
|
|
// Use Times New Roman for Debugging
|
|
Font = new Font("Times New Roman", 14, FontStyle.Regular);
|
|
//Font = _origDisplayText.TextFont.WindowsFont;
|
|
#elif(RELEASE)
|
|
Font = _origDisplayText.TextFont.WindowsFont; // font defined in plant's format
|
|
#else //DEMO
|
|
// Comment this out for DEMO to customer
|
|
// UN-Comment this for testing
|
|
//Font = _origDisplayText.TextFont.WindowsFont; // font defined in plant's format
|
|
#endif
|
|
|
|
Text = ""; // Initialize text before add text
|
|
// IMPORTANT: SetLineSpacing must be set before Links, otherwise it
|
|
// was confusing the 'handle' of the rtf box.
|
|
RTBAPI.SetLineSpacing(this, RTBAPI.ParaSpacing.PFS_EXACT);
|
|
AddRtfText(vlntxt);
|
|
AddRtfStyles();
|
|
ReadOnly = !(EpMode == E_EditPrintMode.Edit && VwMode == E_ViewMode.Edit);
|
|
_InitializingRTB = false;
|
|
_IsDirty = false;
|
|
ClearUndo();
|
|
_MyItemInfo.MyConfig.PropertyChanged += new PropertyChangedEventHandler(MyConfig_PropertyChanged);
|
|
}
|
|
}
|
|
}
|
|
private bool _ProcessKeystrokes = true;
|
|
public bool ProcessKeystrokes
|
|
{
|
|
get { return _ProcessKeystrokes; }
|
|
set { _ProcessKeystrokes = value; }
|
|
}
|
|
|
|
//public EnterKeyHandler EnterKeyPressed;
|
|
//protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
|
|
//{
|
|
// const int WM_KEYDOWN = 0x100;
|
|
// const int WM_SYSKEYDOWN = 0x104;
|
|
// if ((msg.Msg == WM_KEYDOWN) || (msg.Msg == WM_SYSKEYDOWN))
|
|
// {
|
|
// switch (keyData)
|
|
// {
|
|
// case Keys.Control | Keys.V:
|
|
// // check for valid data to be inserted:
|
|
// return base.ProcessCmdKey(ref msg, keyData);
|
|
// default:
|
|
// return base.ProcessCmdKey(ref msg, keyData);
|
|
// }
|
|
// }
|
|
// return base.ProcessCmdKey(ref msg, keyData);
|
|
//}
|
|
private Point ScrollPos
|
|
{
|
|
get { return RTBAPI.GetScrollLocation(this); }
|
|
set { RTBAPI.SetScrollLocation(this, value); }
|
|
}
|
|
private Rectangle _ContentsRectangle;
|
|
public Rectangle ContentsRectangle
|
|
{
|
|
get { return _ContentsRectangle; }
|
|
set
|
|
{
|
|
_ContentsRectangle = value;
|
|
AdjustSizeForContents();
|
|
}
|
|
}
|
|
public Size ContentsSize
|
|
{
|
|
get { return _ContentsRectangle.Size; }
|
|
}
|
|
private Size _AdjustSize; // if 0,0 puts text right next to bottom of box.
|
|
public Size AdjustSize
|
|
{
|
|
get { return _AdjustSize; }
|
|
set
|
|
{
|
|
_AdjustSize = value;
|
|
AdjustSizeForContents();
|
|
}
|
|
}
|
|
public System.Windows.Forms.AutoScaleMode AutoScaleMode;
|
|
private DisplayText _origDisplayText;
|
|
private RichTextBox _rtbTemp = new RichTextBox();
|
|
private string _MyLinkText;
|
|
public string MyLinkText
|
|
{
|
|
get { return _MyLinkText; }
|
|
set
|
|
{
|
|
if (value != _MyLinkText)
|
|
{
|
|
_MyLinkText = value;
|
|
OnLinkChanged(this, new StepPanelLinkEventArgs(_MyStepItem, _MyLinkText));
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
#region Constructors
|
|
/// <summary>
|
|
/// vlnRichTextBox constructor:
|
|
/// Creates a MyDisplayRTB with extra support for veproms editing/printing.
|
|
/// Arguments are:
|
|
/// string txtbxname - name to give box (is this needed)
|
|
/// ItemInfo itm - Item for which box is created
|
|
/// int x,y - starting position for box
|
|
/// int iwid - width of box
|
|
/// int tbindx - tab index
|
|
/// E_EditPrintMode ep_mode - edit or print.
|
|
/// E_ViewMode vw_mode - view or edit.
|
|
/// </summary>
|
|
public StepRTB()
|
|
{
|
|
InitializeComponent();
|
|
SetUp();
|
|
}
|
|
public StepRTB(IContainer container)
|
|
{
|
|
container.Add(this);
|
|
InitializeComponent();
|
|
_Container = container;
|
|
SetUp();
|
|
}
|
|
protected override void OnMouseWheel(MouseEventArgs e)
|
|
{
|
|
_MyStepItem.MyStepPanel.MouseWheel(e);
|
|
//base.OnMouseWheel(e);
|
|
}
|
|
private void SetUp()
|
|
{
|
|
BorderStyle = System.Windows.Forms.BorderStyle.None;
|
|
this.DetectUrls = true;
|
|
ContentsResized += new ContentsResizedEventHandler(StepRTB_ContentsResized);
|
|
this.LinkClicked += new LinkClickedEventHandler(StepRTB_LinkClicked);
|
|
this.Click +=new EventHandler(StepRTB_Click);
|
|
this.KeyPress += new KeyPressEventHandler(StepRTB_KeyPress);
|
|
this.KeyDown += new KeyEventHandler(StepRTB_KeyDown);
|
|
this.KeyUp += new KeyEventHandler(StepRTB_KeyUp);
|
|
this.TextChanged += new EventHandler(StepRTB_TextChanged);
|
|
this.MouseUp += new MouseEventHandler(StepRTB_MouseUp);
|
|
this.MouseDown += new MouseEventHandler(StepRTB_MouseDown);
|
|
this.SelectionChanged +=new EventHandler(StepRTB_SelectionChanged);
|
|
}
|
|
|
|
void MyConfig_PropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
{
|
|
SaveConfig();
|
|
}
|
|
private void StepRTB_Click(object sender, EventArgs e)
|
|
{
|
|
if (ReadOnly) return;
|
|
}
|
|
public bool inRoAdd = false;
|
|
void StepRTB_SelectionChanged(object sender, EventArgs e)
|
|
{
|
|
if (_InitializingRTB) return;
|
|
//DebugSelection("SelectionChanged Event ");
|
|
if (SelectionStart == 40 && SelectionLength == 1) vlnStackTrace.ShowStack("SELECTIONCHANGED EVENT");
|
|
HandleSelectionChange();
|
|
}
|
|
private bool _MouseDown = false;
|
|
private void StepRTB_MouseDown(object sender, MouseEventArgs e)
|
|
{
|
|
_MouseDown = true;
|
|
}
|
|
void StepRTB_MouseUp(object sender, MouseEventArgs e)
|
|
{
|
|
_MouseDown = false;
|
|
HandleSelectionChange();
|
|
}
|
|
#endregion
|
|
#region ApplicationSupport
|
|
public void ToggleViewEdit()
|
|
{
|
|
ItemInfo tmp = MyItemInfo;
|
|
MyItemInfo = null;
|
|
ReadOnly = !ReadOnly;
|
|
EpMode = ReadOnly ? E_EditPrintMode.Print : E_EditPrintMode.Edit;
|
|
VwMode = ReadOnly ? E_ViewMode.View : E_ViewMode.Edit;
|
|
Clear();
|
|
MyItemInfo = tmp;
|
|
}
|
|
public void InsertRO(string value, string link)
|
|
{
|
|
Console.WriteLine("Before Insert Called: {0}", Rtf);
|
|
AddRtfLink(value, link);
|
|
}
|
|
public void InsertTran(string value, string link)
|
|
{
|
|
AddRtfLink(value, link);
|
|
}
|
|
public void InsertSymbol(string symbol)
|
|
{
|
|
AddSymbol(symbol);
|
|
}
|
|
public void SetSelectedCase(char type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case 'l':
|
|
SelectedText = SelectedText.ToLower();
|
|
break;
|
|
case 'U':
|
|
SelectedText = SelectedText.ToUpper();
|
|
break;
|
|
case 'T':
|
|
SelectedText = SelectedText.Substring(0, 1).ToUpper() + SelectedText.Substring(1, SelectedText.Length - 1).ToLower();
|
|
break;
|
|
}
|
|
}
|
|
#endregion
|
|
#region SaveData
|
|
public void SaveText()
|
|
{
|
|
if (ReadOnly) return;
|
|
if (!_IsDirty) return;
|
|
if (_IsDirty)
|
|
{
|
|
bool success = _origDisplayText.Save((RichTextBox)this);
|
|
if (success)
|
|
{
|
|
FindAllLinks();
|
|
_IsDirty = false;
|
|
ClearUndo();
|
|
}
|
|
}
|
|
}
|
|
public void SaveConfig()
|
|
{
|
|
if (!_MyItemInfo.MyConfig.IsDirty) return;
|
|
Item itm = _MyItemInfo.Get();
|
|
itm.MyContent.Config = _MyItemInfo.MyConfig.ToString();
|
|
itm.Save();
|
|
_MyItemInfo.MyConfig.IsDirty = false;
|
|
}
|
|
#endregion
|
|
#region AddRtfTextAndStyles
|
|
private void AddRtfText(DisplayText myDisplayText)
|
|
{
|
|
AddFontTable();
|
|
foreach (displayTextElement vte in myDisplayText.DisplayTextElementList)
|
|
{
|
|
if (vte.Type == E_TextElementType.Text)
|
|
AddRtf(vte);
|
|
else if (vte.Type == E_TextElementType.Symbol)
|
|
AddSymbol(vte);
|
|
else
|
|
AddRtfLink((displayLinkElement)vte);
|
|
}
|
|
SelectedRtf = _SelectedRtfSB.ToString() + "}";
|
|
FindAllLinks();
|
|
}
|
|
private StringBuilder _SelectedRtfSB = new StringBuilder();
|
|
private void AddFontTable()
|
|
{
|
|
StringBuilder sbbeg = new StringBuilder();
|
|
StringBuilder sbend = new StringBuilder();
|
|
if (Font.Bold)
|
|
{
|
|
sbbeg.Append(@"\b");
|
|
sbend.Append(@"\b0");
|
|
}
|
|
if (Font.Underline)
|
|
{
|
|
sbbeg.Append(@"\ul");
|
|
sbend.Insert(0, @"\ulnone");
|
|
}
|
|
if (Font.Italic)
|
|
{
|
|
sbbeg.Append(@"\i");
|
|
sbend.Insert(0, @"\i0");
|
|
}
|
|
_SelectedRtfSB.Append(@"{\rtf1\ansi\ansicpg1252\deff0\deflang1033{\fonttbl{\f0\fnil\fcharset2 " + this.Font.FontFamily.Name + @";}"); //}\f0\fs" + this.Font.SizeInPoints * 2 + @" " + myDisplayTextElement.Text + @"}}";
|
|
_SelectedRtfSB.Append(@"{\f1\fnil\fcharset0 Arial Unicode MS;}}");
|
|
_SelectedRtfSB.Append("\r\n");
|
|
// use styles to construct rtf commands to insert into next line (where \b, etc is)
|
|
_SelectedRtfSB.Append(@"\viewkind4\uc1\pard\sl-240\slmult0" + sbbeg.ToString() + @"\fs" + this.Font.SizeInPoints * 2 + @" "); // \f0\fs" + this.Font.SizeInPoints * 2 + @" " + myDisplayTextElement.Text + @"}";
|
|
}
|
|
private void AddRtf(displayTextElement myDisplayTextElement)
|
|
{
|
|
_SelectedRtfSB.Append(@"\f0 " + myDisplayTextElement.Text);
|
|
}
|
|
private void AddRtf(string str)
|
|
{
|
|
// Because we're inserting rtf with { }, the surrounding styles are not included. Get the font
|
|
// style of current position & use it after the insert to set the style.
|
|
RTBAPI.E_FontStyle fs = RTBAPI.GetFontStyle(this);
|
|
int positionStart = SelectionStart;
|
|
SelectedRtf = @"{\rtf1{\fonttbl{\f0\fcharset2 " + this.Font.FontFamily.Name + @";}}\f0\fs" + this.Font.SizeInPoints * 2 + @" " + str + @"}}";
|
|
// Note that SelectedRtf does not contain the inserted text after the previous line. We need
|
|
// to determine how long the inserted string is in order to set its style. SelectionStart contains
|
|
// the location after the insertion.
|
|
int positionAfter = SelectionStart;
|
|
Select(positionStart, positionAfter - positionStart);
|
|
RTBAPI.SetFontStyle(this, fs);
|
|
Select(positionAfter, 0);
|
|
}
|
|
private void AddText(string str)
|
|
{
|
|
// See comments in AddRtf(string str) to explain the font style setting
|
|
RTBAPI.E_FontStyle fs = RTBAPI.GetFontStyle(this);
|
|
int positionStart = SelectionStart;
|
|
SelectedText = str;
|
|
int positionAfter = SelectionStart;
|
|
Select(positionStart, positionAfter - positionStart);
|
|
RTBAPI.SetFontStyle(this, fs);
|
|
Select(positionAfter, 0);
|
|
}
|
|
private void AddSymbol(displayTextElement myDisplayTextElement)
|
|
{
|
|
_SelectedRtfSB.Append(@"\f1 " + myDisplayTextElement.Text);
|
|
}
|
|
private void AddSymbol(string str)
|
|
{
|
|
// See comments in AddRtf(string str) to explain the font style setting
|
|
RTBAPI.E_FontStyle fs = RTBAPI.GetFontStyle(this);
|
|
int position = SelectionStart;
|
|
SelectedRtf = @"{\rtf1{\fonttbl{\f0\fcharset0 Arial Unicode MS;}}\f0\fs" + this.Font.SizeInPoints * 2 + @" " + str + @"}";
|
|
Select(position, 1);
|
|
RTBAPI.SetFontStyle(this, fs);
|
|
Select(position + 1, 0);
|
|
}
|
|
private string GetAddSymbolText(string symtxt)
|
|
{
|
|
return (@"{\f0\fs" + this.Font.SizeInPoints * 2 + @" " + symtxt + @"}");
|
|
}
|
|
private void AddRtfLink(displayLinkElement myDisplayLinkElement)
|
|
{
|
|
if (CreateParams.ClassName == "RICHEDIT50W")
|
|
|
|
AddLink50(myDisplayLinkElement.Text, myDisplayLinkElement.Link);
|
|
else
|
|
{
|
|
_SelectedRtfSB.Append(@"\f0\fs20 ");
|
|
_SelectedRtfSB.Append(myDisplayLinkElement.TextAndLink);
|
|
}
|
|
}
|
|
public void AddRtfLink(string linkUrl, string linkValue)
|
|
{
|
|
if (CreateParams.ClassName == "RICHEDIT50W")
|
|
|
|
AddLink50(linkUrl, linkValue);
|
|
else
|
|
AddLink20(linkUrl, linkValue);
|
|
}
|
|
private void AddLink20(string linkValue, string linkUrl)
|
|
{
|
|
this.DetectUrls = false;
|
|
int position = SelectionStart; // before inserttran = this.TextLength;
|
|
SelectionLength = 0;
|
|
SelectedRtf = @"{\rtf1\ansi\v <START]\v0 " + linkValue + @"\v " + linkUrl + @"\v0 \v [END>\v0 }";
|
|
this.SelectionLength = 0;
|
|
this.SelectionStart = position;
|
|
FindAllLinks();
|
|
}
|
|
private void AddLink50(string linkValue, string linkUrl)
|
|
{
|
|
this.DetectUrls = false;
|
|
int position = SelectionStart; // before inserttran = this.TextLength;
|
|
SelectionLength = 0;
|
|
SelectedRtf = string.Format(@"{{\rtf\field{{\*\fldinst{{HYPERLINK ""www.volian.com #{0}"" }}}}{{\fldrslt{{\cf2\ul {1}}}}}}}", linkUrl, linkValue);
|
|
this.SelectionStart = this.TextLength;
|
|
this.SelectionLength = 0;
|
|
}
|
|
private void AddRtfStyles()
|
|
{
|
|
if ((_origDisplayText.TextFont.Style & E_Style.Bold) > 0)
|
|
{
|
|
this.SelectAll();
|
|
RTBAPI.ToggleBold(true, this, RTBAPI.RTBSelection.SCF_SELECTION);
|
|
this.Select(0, 0);
|
|
}
|
|
if ((_origDisplayText.TextFont.Style & E_Style.Underline) > 0)
|
|
RTBAPI.ToggleUnderline(true, this, RTBAPI.RTBSelection.SCF_ALL);
|
|
if ((_origDisplayText.TextFont.Style & E_Style.Italics) > 0)
|
|
RTBAPI.ToggleItalic(true, this, RTBAPI.RTBSelection.SCF_ALL);
|
|
}
|
|
#endregion
|
|
#region HeightSupport
|
|
public event StepRTBEvent HeightChanged;
|
|
private void OnHeightChanged(object sender, EventArgs args)
|
|
{
|
|
if (HeightChanged != null) HeightChanged(sender, args);
|
|
}
|
|
private void AdjustSizeForContents()
|
|
{
|
|
// The client size should match the new rectangle.
|
|
// First, determine the offset
|
|
Size offset = Size - ClientSize;
|
|
this.Size = ContentsSize + offset + AdjustSize;
|
|
OnHeightChanged(this, new EventArgs());
|
|
}
|
|
public int CalculateHeight()
|
|
{
|
|
if (this.CreateParams.ClassName == "RICHEDIT50W")
|
|
return CalculateHeight50();
|
|
else
|
|
return CalculateHeight20();
|
|
}
|
|
private int CalculateHeight20()
|
|
{
|
|
Application.DoEvents();
|
|
int yBottom = GetPositionFromCharIndex(TextLength).Y;
|
|
int yTop = GetPositionFromCharIndex(0).Y;
|
|
int heightFont = SelectionFont.Height;
|
|
int borderSize = this.Height - this.ClientSize.Height;
|
|
int heightNext = (yBottom - yTop) + heightFont + borderSize + 2;// 2 pixels - 1 at the top and 1 at the bottom
|
|
if (heightNext != Height)
|
|
{
|
|
Height = heightNext;
|
|
|
|
OnHeightChanged(this, new EventArgs());
|
|
ScrollPos = new Point(0, 0); // Scroll to make sure that the first line is displayed as the first line
|
|
}
|
|
return heightNext;
|
|
}
|
|
private int CalculateHeight50()
|
|
{
|
|
Application.DoEvents();
|
|
int heightFont = SelectionFont.Height;
|
|
int borderSize = this.Height - this.ClientSize.Height;
|
|
int heightNext = (1 + GetLineFromCharIndex(TextLength)) * heightFont + borderSize + 2;// 2 pixels - 1 at the top and 1 at the bottom
|
|
return heightNext;
|
|
}
|
|
#endregion
|
|
#region ColorSupport - Not currently used.
|
|
private void SetBackGroundColor(ItemInfo itemInfo)
|
|
{
|
|
string backcolor = null;
|
|
int type = (int)itemInfo.MyContent.Type;
|
|
FormatInfo formatinfo = itemInfo.ActiveFormat;
|
|
if (type == (int)E_FromType.Procedure)
|
|
backcolor = formatinfo.PlantFormat.FormatData.ProcData.BackColor;
|
|
else if (type == (int)E_FromType.Section)
|
|
backcolor = formatinfo.PlantFormat.FormatData.SectData.BackColor;
|
|
else
|
|
{
|
|
int typindx = (int)itemInfo.MyContent.Type - 20000; // what to do for other types rather than steps
|
|
backcolor = formatinfo.PlantFormat.FormatData.StepDataList[typindx].StepLayoutData.BackColor;
|
|
}
|
|
BackColor = Color.FromName(backcolor);
|
|
}
|
|
#endregion
|
|
#region EventSupport
|
|
#region LinkEvents
|
|
private StepPanelLinkEventArgs _MyLinkClickedEventArgs;
|
|
public event StepRTBLinkEvent LinkChanged;
|
|
private void OnLinkChanged(object sender, StepPanelLinkEventArgs args)
|
|
{
|
|
_MyLinkClickedEventArgs = args;
|
|
if (LinkChanged != null) LinkChanged(sender, args);
|
|
}
|
|
public event StepRTBLinkEvent LinkGoTo;
|
|
private void OnLinkGoTo(object sender, StepPanelLinkEventArgs args)
|
|
{
|
|
_MyLinkClickedEventArgs = args;
|
|
if (LinkGoTo != null) LinkGoTo(sender, args);
|
|
}
|
|
public event StepRTBLinkEvent LinkModifyTran;
|
|
private void OnLinkModifyTran(object sender, StepPanelLinkEventArgs args)
|
|
{
|
|
_MyLinkClickedEventArgs = args;
|
|
if (LinkModifyTran != null) LinkModifyTran(sender, args);
|
|
}
|
|
public event StepRTBLinkEvent LinkModifyRO;
|
|
private void OnLinkModifyRO(object sender, StepPanelLinkEventArgs args)
|
|
{
|
|
_MyLinkClickedEventArgs = args;
|
|
if (LinkModifyRO != null) LinkModifyRO(sender, args);
|
|
}
|
|
private Point _savcurpos;
|
|
private void StepRTB_LinkClicked(object sender,LinkClickedEventArgs args)
|
|
{
|
|
if (ReadOnly) return;
|
|
|
|
_MyLinkClickedEventArgs = new StepPanelLinkEventArgs(_MyStepItem, args.LinkText);
|
|
_savcurpos = Cursor.Position;
|
|
SelectLinkFromPoint();
|
|
OnLinkChanged(sender, _MyLinkClickedEventArgs);
|
|
}
|
|
#endregion
|
|
#region TextOrContents
|
|
void StepRTB_TextChanged(object sender, EventArgs e)
|
|
{
|
|
_IsDirty = true;
|
|
FindAllLinks();
|
|
}
|
|
void StepRTB_ContentsResized(object sender, ContentsResizedEventArgs e)
|
|
{
|
|
ContentsRectangle = e.NewRectangle;
|
|
}
|
|
#endregion
|
|
#region Selection Handlers
|
|
bool _AdjustingSelection = false;
|
|
private bool _ProcessingDelete;
|
|
private void HandleSelectionChange()
|
|
{
|
|
bool startingValue = _AdjustingSelection;
|
|
if (_IdentifyingLinks || _ProcessingDelete) return;
|
|
if (ProcessKeystrokes)
|
|
{
|
|
if (!_MouseDown && !_AdjustingSelection)
|
|
{
|
|
if (_LinkLocations != null)
|
|
{
|
|
DebugPrint("HSC===================>Beginning: SelectionStart {0}, SelectionLength {1}", SelectionStart, SelectionLength);
|
|
_AdjustingSelection = true;
|
|
LinkLocation ll = FindLinkLocation();
|
|
LinkLocation llend = null;
|
|
if (SelectionLength != 0)
|
|
llend = FindLinkLocation(SelectionStart + SelectionLength - 1);
|
|
if (ll != null)
|
|
{
|
|
if (SelectionStart == ll.Start && SelectionLength == 0)
|
|
{
|
|
if (SelectionStart >= 7)
|
|
{
|
|
DebugPrint("HSC===================>ll Insert: Sel {0}, Length {1}, Link Start {2}, Link Length {3}", SelectionStart, SelectionLength, ll.Start, ll.Length);
|
|
SelectionStart = ll.Start - 7;
|
|
}
|
|
}
|
|
else if (SelectionStart + SelectionLength > ll.End) // Beyond the end of the starting link
|
|
{
|
|
int end = SelectionStart + SelectionLength;
|
|
if (llend != null) end = llend.End; // If it extends into another link extend the end to the end of that link
|
|
DebugPrint("HSC===================>ll After: Sel {0}, Length {1}, Link Start {2}, Link Length {3}", SelectionStart, SelectionLength, ll.Start, ll.Length);
|
|
SetSelection(ll.Start, end - ll.Start);
|
|
}
|
|
else if (SelectionStart >= ll.Start || SelectionLength > 0)// Within the starting link
|
|
{
|
|
DebugPrint("HSC===================>ll: Sel {0}, Length {1}, Link Start {2}, Link Length {3}", SelectionStart, SelectionLength, ll.Start, ll.Length);
|
|
SetSelection(ll);
|
|
}
|
|
}
|
|
else if (llend != null)
|
|
{
|
|
DebugPrint("HSC===================>llend: Sel {0}, Length {1}, Link Start {2}, Link Length {3}", SelectionStart, SelectionLength, llend.Start, llend.Length);
|
|
// Check to see if the beginning starts before the <START] token. If it does, adjust the start
|
|
int newStart = SelectionStart + (SelectedText.StartsWith("<START]") ? 7 : 0);
|
|
SetSelection(newStart, llend.End - newStart);
|
|
}
|
|
else
|
|
{
|
|
if (SelectedText.EndsWith("<START]") && !SelectedText.EndsWith("[END><START]"))
|
|
{
|
|
DebugPrint("HSC===================>Removing ending <START] token");
|
|
SelectionLength = SelectionLength - 7;
|
|
}
|
|
if (SelectedText.StartsWith("<START]"))
|
|
{
|
|
DebugPrint("HSC===================>Removing starting <START] token");
|
|
SetSelection(SelectionStart + 7, SelectionLength - 7);
|
|
}
|
|
}
|
|
_AdjustingSelection = false;
|
|
}
|
|
}
|
|
}
|
|
if (startingValue != _AdjustingSelection)
|
|
DebugPrint("================> _AdjustingSelection problem");
|
|
DebugPrint("RS------ SelectionChange > {0}", FindRangeStatus());
|
|
OnRTBSelectionChanged(this, new EventArgs());
|
|
}
|
|
private bool _CheckSelection = false;
|
|
#endregion
|
|
#region Delete Handlers
|
|
private void HandleDeleteKeyWithSelectedText(KeyEventArgs e, char keychar)
|
|
{
|
|
_ProcessingDelete = true;
|
|
FindRangeStatus();
|
|
//DebugPrint("RS---------------- Delete > {0}", _RTBRangeStatus);
|
|
switch (_RTBRangeStatus)
|
|
{
|
|
case RangeStatus.NoContainedLinks:
|
|
case RangeStatus.Before_After:
|
|
case RangeStatus.Before_EndLink:
|
|
case RangeStatus.Before_EndBox:
|
|
default:
|
|
DeleteCurrentSelection(keychar);
|
|
e.SuppressKeyPress = true;
|
|
break;
|
|
case RangeStatus.Before_Between: //myRTB1.SelectedText.EndsWith(@"[END><START]")
|
|
DeleteEndBetweenLinks(keychar);
|
|
e.SuppressKeyPress = true;
|
|
break;
|
|
case RangeStatus.Between_EndBox:
|
|
case RangeStatus.Between_EndLink:
|
|
case RangeStatus.Between_After:
|
|
DeleteStartBetweenLinks(keychar);
|
|
e.SuppressKeyPress = true;
|
|
break;
|
|
case RangeStatus.Between_Between:
|
|
DeleteBetweenBetweenLinks(keychar);
|
|
e.SuppressKeyPress = true;
|
|
break;
|
|
case RangeStatus.StartLink_EndBox:
|
|
case RangeStatus.StartLink_EndLink:
|
|
case RangeStatus.StartLink_After:
|
|
ExpandSelectionToIncludeStart();
|
|
DeleteCurrentSelection(keychar);
|
|
e.SuppressKeyPress = true;
|
|
break;
|
|
case RangeStatus.StartLink_Between:
|
|
ExpandSelectionToIncludeStart();
|
|
DeleteEndBetweenLinks(keychar);
|
|
e.SuppressKeyPress = true;
|
|
break;
|
|
case RangeStatus.StartBox_EndLink:
|
|
case RangeStatus.StartBox_EndBox:
|
|
case RangeStatus.StartBox_After:
|
|
DeleteFromStartOfBox(keychar);
|
|
e.SuppressKeyPress = true;
|
|
break;
|
|
case RangeStatus.StartBox_Between:
|
|
DeleteFromStartOfBoxEndBetweenLinks(keychar);
|
|
e.SuppressKeyPress = true;
|
|
break;
|
|
// REMOVE THESE CASES OR PUT A MESSAGE OUT SAYING ERROR IN CODE - CASE
|
|
// NOT HANDLED
|
|
case RangeStatus.Before_StartLink:
|
|
case RangeStatus.Between_StartLink:
|
|
case RangeStatus.StartLink_StartLink:
|
|
case RangeStatus.StartBox_StartLink:
|
|
break;
|
|
}
|
|
_ProcessingDelete = false;
|
|
StepRTB_TextChanged(this, new EventArgs());
|
|
}
|
|
private void InsertCharBetweenLinks(LinkLocation ll)
|
|
{
|
|
InsertCharBetweenLinks(ll, ' ', false);
|
|
}
|
|
private void InsertCharBetweenLinks(LinkLocation ll, char charToAdd)
|
|
{
|
|
InsertCharBetweenLinks(ll, charToAdd, true);
|
|
}
|
|
/// <summary>
|
|
/// This inserts a space in between two links.
|
|
/// It actually inserts "\v0 {space}\v " between the END tag and the START tag
|
|
/// </summary>
|
|
/// <param name="ll"></param>
|
|
/// <param name="charToAdd"></param>
|
|
/// <param name="setSelect"></param>
|
|
private void InsertCharBetweenLinks(LinkLocation ll, char charToAdd, bool setSelect)
|
|
{
|
|
//_InsertingSpaceBetweenLinks = true;
|
|
DebugPrint("ICBLvvvvvvvvvvvvvvv>>>");
|
|
Rtf = Rtf.Substring(0, ll.StartRtf) + @"\v0 " + charToAdd.ToString() + @"\v " + Rtf.Substring(ll.StartRtf);
|
|
//_InsertingSpaceBetweenLinks = false;
|
|
if (setSelect)
|
|
SelectionStart = ll.Start - 6; // account for <START] - 1 for the character typed
|
|
DebugPrint("ICBL^^^^^^^^^^^^^^^>>>");
|
|
}
|
|
private void ExpandSelectionToIncludeStart()
|
|
{
|
|
//_AdjustingSelection = true;
|
|
SetSelection(SelectionStart - 7, SelectionLength + 7); // Expand selection to include start
|
|
//_AdjustingSelection = false;
|
|
}
|
|
private void DeleteBetweenBetweenLinks(char keychar)
|
|
{
|
|
|
|
DebugSelection("DeleteBetweenBetweenLinks");
|
|
int selStart = SelectionStart - 7;
|
|
int selLength = SelectionLength + 2; // Include the two added spaces
|
|
InsertCharBetweenLinks(_RangeEndLink.NextLink); // Add a space at the end link
|
|
InsertCharBetweenLinks(_RangeStartLink); // Add a space a the start link
|
|
SetSelection(selStart, selLength);// Select everything including the spaces
|
|
DeleteCurrentSelection(keychar);// Delete Selection
|
|
}
|
|
/// <summary>
|
|
/// This is added to handle a glitch in richtextbox. Depending on
|
|
/// which direction that selection is made (left -> right or right -> left)
|
|
/// a replacement or delete may not work, you'll just get a 'beep'.
|
|
/// This approach consistently works.
|
|
/// </summary>
|
|
private void DeleteCurrentSelection(char key)
|
|
{
|
|
DebugPrint("vvvvvvvvvvvvxxxxxxxxxxxx>");
|
|
DebugSelection("Before X");
|
|
SelectedText = key==0?"X":key.ToString(); // replace text with X
|
|
DebugSelection("After X");
|
|
DebugPrint("------------xxxxxxxxxxxx>");
|
|
if (key == 0)
|
|
{
|
|
_SendBackSpace = true;
|
|
RtbSendKeys("{BS}"); // remove X
|
|
Application.DoEvents();
|
|
DebugSelection("After BS");
|
|
}
|
|
DebugPrint("^^^^^^^^^^^^xxxxxxxxxxxx>");
|
|
}
|
|
private void DeleteSelection(int start, int length, char keychar)
|
|
{
|
|
SetSelection(start, length);
|
|
DeleteCurrentSelection(keychar);
|
|
}
|
|
private void DeleteEndBetweenLinks(char keychar)
|
|
{
|
|
_ProcessingKeys++;
|
|
DebugSelection("DeleteEndBetweenLinks");
|
|
int sstart = SelectionStart;
|
|
int slen = SelectionLength + 1 - 7;
|
|
// This puts a space at the link that starts at the end of the selection
|
|
InsertCharBetweenLinks(_RangeEndLink.NextLink);
|
|
//_AdjustingSelection = true;
|
|
DeleteSelection(sstart, slen, keychar);
|
|
//_AdjustingSelection = false;
|
|
_ProcessingKeys--;
|
|
}
|
|
private void DeleteStartBetweenLinks(char keychar)
|
|
{
|
|
_ProcessingKeys++;
|
|
DebugSelection("DeleteStartBetweenLinks");
|
|
int slen = SelectionLength + 8;
|
|
int sstart = SelectionStart - 7;
|
|
//LinkLocation ll = FindBetweenLinks(SelectionStart);
|
|
InsertCharBetweenLinks(_RangeStartLink);
|
|
DeleteSelection(sstart, slen, keychar);
|
|
_ProcessingKeys--;
|
|
}
|
|
private void DeleteFromStartOfBox(char keychar)
|
|
{
|
|
_ProcessingKeys++;
|
|
DebugSelection("DeleteFromStartOfBox");
|
|
int slen = SelectionLength;
|
|
SetSelection(0, 0);
|
|
//RtbSendKeys(" "); // open for space between links which separates END/START tokens
|
|
SelectedText = " ";
|
|
DeleteSelection(0, slen + 8, keychar);
|
|
_ProcessingKeys--;
|
|
}
|
|
private void DeleteFromStartOfBoxEndBetweenLinks(char keychar)
|
|
{
|
|
_ProcessingKeys++;
|
|
DebugSelection("DeleteFromStartOfBoxEndBetweenLinks");
|
|
// This puts a space at the link that starts at the end of the selection
|
|
int sLen = SelectionStart + SelectionLength - 7 + 2;// -7 for <START] + 2 for the spaces that are added
|
|
//LinkLocation ll = FindBetweenLinks(SelectionStart + SelectionLength);
|
|
InsertCharBetweenLinks(_RangeEndLink.NextLink);
|
|
//RtbSendKeys("{RIGHT} "); // open for space between links which separates END/START tokens
|
|
//int sLen = myRTB1.SelectionStart;
|
|
SetSelection(0, 0);
|
|
//RtbSendKeys(" "); // open for space between links which separates END/START tokens
|
|
SelectedText = " "; // open for space between links which separates END/START tokens
|
|
DeleteSelection(0, sLen, keychar);
|
|
_ProcessingKeys--;
|
|
}
|
|
#endregion
|
|
#region KeyboardHandling
|
|
void StepRTB_KeyUp(object sender, KeyEventArgs e)
|
|
{
|
|
if (!e.Shift) return;
|
|
switch (e.KeyCode)
|
|
{
|
|
// this was put here rather than in the KeyDown event like the others
|
|
// so that processing of keystroke (StepRTB_KeyDown) would position selectionstart
|
|
// and selectionlength
|
|
case Keys.Down:
|
|
int newend = FindEndDown();
|
|
if (newend > 0) SetSelection(SelectionStart, newend - SelectionStart);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
}
|
|
private bool IsControlChar = false;
|
|
private bool _SendBackSpace = false;
|
|
void StepRTB_KeyDown(object sender, KeyEventArgs e)
|
|
{
|
|
if (e.Control)
|
|
{
|
|
IsControlChar = true;
|
|
switch (e.KeyCode)
|
|
{
|
|
case Keys.V:
|
|
string buff = Clipboard.GetText(TextDataFormat.UnicodeText);
|
|
return;
|
|
case Keys.Home:
|
|
StepRTB_HomeEndPressed(e);
|
|
e.Handled = true;
|
|
break;
|
|
case Keys.End:
|
|
StepRTB_HomeEndPressed(e);
|
|
e.Handled = true;
|
|
break;
|
|
}
|
|
}
|
|
switch (e.KeyCode)
|
|
{
|
|
case Keys.Left:
|
|
if (e.Shift)
|
|
{
|
|
int newstart = FindStart(); // find start of link ending on.
|
|
int len = SelectionLength + SelectionStart - newstart;
|
|
SetSelection(newstart, len);
|
|
e.Handled = true;
|
|
return;
|
|
}
|
|
if (e.Control || SelectionStart == 0)
|
|
{
|
|
StepRTB_ArrowPressed(e.Control ? E_ArrowKeys.CtrlLeft : E_ArrowKeys.Left);
|
|
e.Handled = true;
|
|
}
|
|
HandleSelectionChange();
|
|
break;
|
|
case Keys.Up:
|
|
int ln = GetLineFromCharIndex(SelectionStart);
|
|
if (e.Control || ln == 0)
|
|
{
|
|
StepRTB_ArrowPressed(e.Control ? E_ArrowKeys.CtrlUp : E_ArrowKeys.Up);
|
|
e.Handled = true;
|
|
}
|
|
// if shift-up & at selection had a link, handle this as special case.
|
|
if (e.Shift && SelectionLength>0)
|
|
{
|
|
RangeStatus rs = FindRangeStatus();
|
|
if (rs != RangeStatus.NoContainedLinks)
|
|
{
|
|
int curend = SelectionStart + SelectionLength;
|
|
SelectionLength = 0;
|
|
RtbSendKeys("{Up}");
|
|
Application.DoEvents();
|
|
Select(SelectionStart, curend - SelectionStart);
|
|
e.Handled = true;
|
|
}
|
|
}
|
|
else
|
|
HandleSelectionChange();
|
|
break;
|
|
case Keys.Right:
|
|
// If at beginning of box that starts with a link, don't worry about shift or not,
|
|
// because selection is first character or link without any other selection. Don't
|
|
// need to write code to handle link at beginning of box in Shift Right code because
|
|
// it's handled in HandleSelectionChange.
|
|
if (e.Shift && ((SelectionStart > 0) || (SelectionStart==0 && _LinkLocations.Count>0 && _LinkLocations[0].Start!=7)))
|
|
{
|
|
int newlen = FindEnd();
|
|
int len = SelectionLength + newlen;
|
|
SetSelection(SelectionStart, len);
|
|
e.Handled = true;
|
|
return;
|
|
}
|
|
if (e.Control || SelectionStart == this.Text.Length)
|
|
{
|
|
StepRTB_ArrowPressed(e.Control ? E_ArrowKeys.CtrlRight : E_ArrowKeys.Right);
|
|
e.Handled = true;
|
|
}
|
|
HandleSelectionChange();
|
|
break;
|
|
case Keys.Down:
|
|
int l = GetLineFromCharIndex(SelectionStart);
|
|
Point pos = new Point();
|
|
pos.X = ClientRectangle.Width;
|
|
pos.Y = ClientRectangle.Height;
|
|
int lastIndex = this.GetCharIndexFromPosition(pos);
|
|
int lastLine = this.GetLineFromCharIndex(lastIndex);
|
|
if (e.Control || l == lastLine)
|
|
{
|
|
StepRTB_ArrowPressed(e.Control ? E_ArrowKeys.CtrlDown : E_ArrowKeys.Down);
|
|
HandleSelectionChange();
|
|
e.Handled = true;
|
|
return;
|
|
}
|
|
if (!e.Shift)HandleSelectionChange();
|
|
// if shift-down & on link at beginning of box - do special processing (regular processing
|
|
// didn't handle it correctly.
|
|
if (e.Shift && lastLine > 0 && SelectionStart==0 && _LinkLocations.Count>0 && _LinkLocations[0].Start==7)
|
|
{
|
|
Point cpos = GetPositionFromCharIndex(SelectionStart);
|
|
int addon = ClientRectangle.Height / (lastLine + 1);
|
|
cpos.Y = cpos.Y + addon;
|
|
int selend = GetCharIndexFromPosition(cpos);
|
|
Select(7, selend-7);
|
|
e.Handled = true;
|
|
}
|
|
break;
|
|
case Keys.PageUp:
|
|
StepRTB_PageKeyPressed(e);
|
|
e.Handled = true;
|
|
break;
|
|
case Keys.PageDown:
|
|
StepRTB_PageKeyPressed(e);
|
|
e.Handled = true;
|
|
break;
|
|
case Keys.Delete:
|
|
if (SelectionLength == 0)
|
|
{
|
|
foreach (LinkLocation lls in _LinkLocations)
|
|
{
|
|
if (SelectionStart >= lls.Start - 7 && SelectionStart < lls.End)
|
|
{
|
|
SetSelection(lls);// Select the link to the right
|
|
HandleDeleteKeyWithSelectedText(e, '\x0');
|
|
e.SuppressKeyPress = true;
|
|
return;
|
|
}
|
|
}
|
|
if (SelectionStart != TextLength)
|
|
{
|
|
SelectionStart++;// A Delete can be accomplished with a right arrow followed by a backspace.
|
|
RtbSendKeys("{BS}"); // This is done due to a glitch in the RichTextBox that sometimes causes a beep rather than a delete
|
|
e.SuppressKeyPress = true;
|
|
}
|
|
}
|
|
else
|
|
HandleDeleteKeyWithSelectedText(e, '\x0');
|
|
break;
|
|
case Keys.Back:
|
|
if (_SendBackSpace)
|
|
{
|
|
_SendBackSpace = false;
|
|
return;
|
|
}
|
|
_CheckSelection = true;
|
|
if (SelectionLength == 0)
|
|
{
|
|
foreach (LinkLocation lls in _LinkLocations)
|
|
{
|
|
if (SelectionStart > lls.Start - 7 && SelectionStart <= lls.End)
|
|
{
|
|
SetSelection(lls);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (SelectionLength > 0) HandleDeleteKeyWithSelectedText(e, '\x0');
|
|
break;
|
|
}
|
|
}
|
|
private void StepRTB_HomeEndPressed(KeyEventArgs keyargs)
|
|
{
|
|
if (MyItemInfo.IsProcedure || MyItemInfo.IsSection) return;
|
|
// Cursor moves out of box only if control is pressed too - otherwise key is
|
|
// handled in rtb.
|
|
if (keyargs.Control)_MyStepItem.MyStepPanel.StepCursorKeys(this, keyargs);
|
|
}
|
|
private void StepRTB_PageKeyPressed(KeyEventArgs keyargs)
|
|
{
|
|
if (MyItemInfo.IsProcedure || MyItemInfo.IsSection) return;
|
|
_MyStepItem.MyStepPanel.StepCursorKeys(this, keyargs);
|
|
}
|
|
private void StepRTB_ArrowPressed(E_ArrowKeys key)
|
|
{
|
|
Point cp = PointToClient(Cursor.Position);
|
|
_MyStepItem.MyStepPanel.CursorMovement(this, cp, key);
|
|
}
|
|
private void StepRTB_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
|
|
{
|
|
if (!ReadOnly)
|
|
{
|
|
// add the character with its font depending on the char....
|
|
if (!IsControlChar)
|
|
{
|
|
bool done = false;
|
|
string strpressed = null;
|
|
if (e.KeyChar == '-')
|
|
strpressed = GetAddSymbolText(@"\u8209?");
|
|
else if (e.KeyChar == '{')
|
|
strpressed = "\\{";
|
|
else if (e.KeyChar == '}')
|
|
strpressed = "\\}";
|
|
else
|
|
strpressed = e.KeyChar.ToString();
|
|
if (e.KeyChar >= ' ')
|
|
{
|
|
LinkLocation ll = FindBetweenLinks();
|
|
if (ll != null && SelectionLength == 0) // SelectionLength = 0 means insert
|
|
{
|
|
InsertCharBetweenLinks(ll, e.KeyChar);
|
|
e.Handled = true;
|
|
}
|
|
else if (SelectionLength != 0)
|
|
{
|
|
HandleDeleteKeyWithSelectedText(new KeyEventArgs(Keys.None), e.KeyChar);
|
|
e.Handled = true;
|
|
}
|
|
}
|
|
if (!done)
|
|
{
|
|
if (e.KeyChar == '-')
|
|
AddSymbol(@"\u8209?");
|
|
else if (e.KeyChar == '{')
|
|
AddRtf(@"\{");
|
|
else if (e.KeyChar == '}')
|
|
AddRtf(@"\}");
|
|
else
|
|
return;
|
|
e.Handled = true; // flag that it's been handled, otherwise, will get 2 chars.
|
|
}
|
|
}
|
|
IsControlChar = false;
|
|
}
|
|
}
|
|
private void RtbSendKeys(string keys)
|
|
{
|
|
Focus();
|
|
SendKeys.Send(keys); // With .Net Framework 3.0 this can be replaced with EditingCommands
|
|
// http://msdn.microsoft.com/en-us/library/ms771634.aspx
|
|
}
|
|
|
|
private void DoDeleteEndBetweenLinks()
|
|
{
|
|
DebugSelection("Beginning");
|
|
int sstart = SelectionStart;
|
|
RtbSendKeys("{RIGHT} "); // open for space between links which separates END/START tokens
|
|
SetSelection(sstart, SelectionStart - sstart - 1); // 1 is accounting for typed space
|
|
DebugSelection("SetSelection");
|
|
RtbSendKeys("{DELETE}"); // deletes text including link
|
|
RtbSendKeys("{RIGHT}{BS}"); // deletes space that was added
|
|
}
|
|
private void DoDeleteStartBetweenLinks()
|
|
{
|
|
int slen = SelectionLength;
|
|
RtbSendKeys("{LEFT} ");
|
|
SetSelection(SelectionStart, slen + 7);
|
|
RtbSendKeys("{DELETE}");
|
|
RtbSendKeys("{BS}");
|
|
}
|
|
#endregion
|
|
#region LinkSelectionAndHandling
|
|
private void SelectLinkFromPoint()
|
|
{
|
|
Point cp = PointToClient(_savcurpos);
|
|
int index = GetCharIndexFromPosition(cp);
|
|
SelectLink(index, 0);
|
|
}
|
|
private void SelectLink(int index, int len)
|
|
{
|
|
FindLink(index, len);
|
|
if (SelectedText.IndexOf(@"[END>") > 0) MyLinkText = SelectedText.Substring(0, SelectedText.IndexOf(@"[END>"));
|
|
else MyLinkText = SelectedText;
|
|
}
|
|
public bool IsSelectionLinked(int index, int len)
|
|
{
|
|
if (_LinkLocations == null)return false;
|
|
int sel = index;
|
|
int selLength = len;
|
|
foreach (LinkLocation ll in _LinkLocations)
|
|
{
|
|
if (sel >= ll.Start && sel < ll.Start + ll.Length + 7) return true;
|
|
}
|
|
return false;
|
|
}
|
|
private int FindLink(int startIndex, int len)
|
|
{
|
|
int sel = startIndex;
|
|
int selLength = len;
|
|
foreach (LinkLocation ll in _LinkLocations)
|
|
{
|
|
// add 7 to include the '<START]'
|
|
if (sel >= ll.Start && sel <= ll.Start + ll.Length)
|
|
{
|
|
SetSelection(ll.Start, ll.Length);
|
|
if (SelectionLength == 0)
|
|
{
|
|
// try adding 7 to locEnd
|
|
SetSelection(ll.Start, ll.Length + 7);
|
|
}
|
|
Console.WriteLine(string.Format("\nFindLink Start = {0}, Length = {1}\n", SelectionStart, SelectionLength));
|
|
return SelectionStart;
|
|
}
|
|
}
|
|
return SelectionStart;
|
|
}
|
|
|
|
private void DeleteLink()
|
|
{
|
|
SelectedText = "";
|
|
MyLinkText = null;
|
|
FindAllLinks();
|
|
}
|
|
#endregion
|
|
#endregion
|
|
#region SelectionStack
|
|
Stack<SelectionData> _SelectionStack = new Stack<SelectionData>();
|
|
public void PushSelection()
|
|
{
|
|
_SelectionStack.Push(new SelectionData(this));
|
|
}
|
|
public void PopSelection()
|
|
{
|
|
SelectionData selection = _SelectionStack.Pop();
|
|
Select(selection.SelectionStart, selection.SelectionLength);
|
|
}
|
|
public class SelectionData
|
|
{
|
|
int _SelectionStart;
|
|
public int SelectionStart
|
|
{
|
|
get { return _SelectionStart; }
|
|
set { _SelectionStart = value; }
|
|
}
|
|
int _SelectionLength;
|
|
public int SelectionLength
|
|
{
|
|
get { return _SelectionLength; }
|
|
set { _SelectionLength = value; }
|
|
}
|
|
public SelectionData(RichTextBox richTextBox)
|
|
{
|
|
_SelectionStart = richTextBox.SelectionStart;
|
|
_SelectionLength = richTextBox.SelectionLength;
|
|
}
|
|
}
|
|
#endregion
|
|
#region Link Support
|
|
int _ProcessingKeys = 0;
|
|
|
|
List<LinkLocation> _LinkLocations;
|
|
public List<LinkLocation> LinkLocations
|
|
{
|
|
get { return _LinkLocations; }
|
|
}
|
|
private int _FALLevel = 0;
|
|
private bool _IdentifyingLinks = false;
|
|
public void FindAllLinks()
|
|
{
|
|
if (_IdentifyingLinks || _ProcessingDelete) return;
|
|
//DebugPrint("FAL{0}vvvvvvvvvvvvvvvvvvvvvvvvv>>", ++_FALLevel);
|
|
_AdjustingSelection = true;
|
|
PushSelection();
|
|
FindLinks();
|
|
IdentifyLinks();
|
|
PopSelection();
|
|
LinkLocation llx = FindLinkLocation();
|
|
if (_CheckSelection)
|
|
{
|
|
if (llx != null) SetSelection(llx.End, 0);
|
|
_CheckSelection = false;
|
|
}
|
|
_AdjustingSelection = false;
|
|
if (!_ProcessingDelete)
|
|
OnLinkLocationChanged(this, new EventArgs());
|
|
//DebugPrint("FAL{0}^^^^^^^^^^^^^^^^^^^^^^^^^>>", _FALLevel--);
|
|
|
|
}
|
|
private void FindLinks()
|
|
{
|
|
string str = Text;
|
|
_LinkLocations = new List<LinkLocation>();
|
|
MatchCollection matches = Regex.Matches(str, "<START](.*?)[[]END>");
|
|
MatchCollection matchesRtf = Regex.Matches(Rtf, "<START](.*?)[[]END>");
|
|
LinkLocation thisLink = null;
|
|
for (int i = 0; i < matches.Count; i++) //each (Match match in matches)
|
|
{
|
|
Match match = matches[i];
|
|
Match matchrtf = matchesRtf[i];
|
|
thisLink = new LinkLocation(match.Index + 7, // If the [END> is immediately followed by <START] include it
|
|
match.Length - (((match.Index + match.Length + 7 <= str.Length) && (str.Substring(match.Index + match.Length, 7) == "<START]")) ? 0 : 7),
|
|
match.Value, matchrtf.Index, matchrtf.Length, thisLink);
|
|
_LinkLocations.Add(thisLink);
|
|
}
|
|
}
|
|
private void IdentifyLinks()
|
|
{
|
|
_IdentifyingLinks = true;
|
|
foreach (LinkLocation ll in _LinkLocations)
|
|
{
|
|
SetSelection(ll); // subtract off start token!
|
|
RTBAPI.CharFormatTwo charFormat = RTBAPI.GetCharFormat(this, RTBAPI.RTBSelection.SCF_SELECTION);
|
|
// Protect the link text to avoid manual changes
|
|
charFormat.dwMask = RTBAPI.CharFormatMasks.CFM_LINK; // | RTBAPI.CharFormatMasks.CFM_PROTECTED;
|
|
charFormat.dwEffects = RTBAPI.CharFormatEffects.CFE_LINK; // | RTBAPI.CharFormatEffects.CFE_PROTECTED;
|
|
RTBAPI.SetCharFormat(this, RTBAPI.RTBSelection.SCF_SELECTION, charFormat);
|
|
}
|
|
_IdentifyingLinks = false;
|
|
}
|
|
private LinkLocation FindBetweenLinks()
|
|
{
|
|
return FindBetweenLinks(SelectionStart);
|
|
}
|
|
private LinkLocation FindBetweenLinks(int start)
|
|
{
|
|
DebugPrint("FL----------------Between>");
|
|
foreach (LinkLocation ll in _LinkLocations)
|
|
if (ll.Start == start && ll.StartsBetween)
|
|
return ll;
|
|
return null;
|
|
}
|
|
private LinkLocation FindLinkSelected()
|
|
{
|
|
DebugPrint("FL----------------Selected>");
|
|
if (_LinkLocations == null) return null;
|
|
foreach (LinkLocation ll in _LinkLocations)
|
|
if (ll.Start == SelectionStart && ll.Length == SelectionLength) return ll;
|
|
return null;
|
|
}
|
|
private LinkLocation FindLinkLocation()
|
|
{
|
|
return FindLinkLocation(SelectionStart);
|
|
}
|
|
private LinkLocation FindLinkLocation(int sel)
|
|
{
|
|
DebugPrint("FL----------------Location>");
|
|
if (_LinkLocations == null) return null;
|
|
foreach (LinkLocation ll in _LinkLocations)
|
|
{
|
|
// Moving right:
|
|
// if less than, allows stopping between two links
|
|
if (ll.Start < sel && ll.End > sel)
|
|
{
|
|
DebugPrint("Greater Than {0} {1} {2}", sel, ll.Start, ll.End);
|
|
return ll;
|
|
}
|
|
// if less than or equal, does not stop between two links
|
|
if ((!ll.StartsBetween) && ll.Start <= sel && ll.End > sel)
|
|
{
|
|
DebugPrint("Greater Than or Equal {0} {1} {2}", sel, ll.Start, ll.End);
|
|
return ll;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
private int FindStart()
|
|
{
|
|
foreach (LinkLocation ll in _LinkLocations)
|
|
{
|
|
if (SelectionStart == ll.End) return ll.Start;
|
|
if (SelectionStart == ll.Start)
|
|
{
|
|
if (ll.Start == 7) return 7;
|
|
return ll.Start - 8;
|
|
}
|
|
}
|
|
if (SelectionStart > 0) return SelectionStart - 1;
|
|
return 0;
|
|
}
|
|
private int FindEnd()
|
|
{
|
|
foreach (LinkLocation ll in _LinkLocations)
|
|
{
|
|
if (SelectionStart + SelectionLength + 7 == ll.Start) return ll.Length + 7;
|
|
// this is for in-between links
|
|
if (SelectionStart + SelectionLength == ll.Start) return ll.Length;
|
|
}
|
|
if (SelectionStart + SelectionLength < TextLength) return 1;
|
|
return 0;
|
|
}
|
|
private int FindEndDown()
|
|
{
|
|
foreach (LinkLocation ll in _LinkLocations)
|
|
{
|
|
if (SelectionStart + SelectionLength >= ll.Start && SelectionStart + SelectionLength <= ll.End) return ll.End;
|
|
}
|
|
return 0;
|
|
}
|
|
private int FindStartUp()
|
|
{
|
|
DebugPrint("FINDSTARTUP Start = {0}, Len = {1}", SelectionStart, SelectionLength);
|
|
foreach (LinkLocation ll in _LinkLocations)
|
|
{
|
|
DebugPrint("FINDSTARTUP link start = {0}, link end = {1}", ll.Start, ll.End);
|
|
if ((SelectionStart >= ll.Start) && (SelectionStart <= ll.End))
|
|
{
|
|
DebugPrint("FINDSTARTUP - in link start = {0}, end = {1}", ll.Start, ll.End);
|
|
return ll.Start;
|
|
}
|
|
}
|
|
DebugPrint("FINDSTARTUP - Not in link");
|
|
return -1;
|
|
}
|
|
public void SetSelection(LinkLocation ll)
|
|
{
|
|
SetSelection(ll.Start, ll.Length);
|
|
}
|
|
public void SetSelection(int locStart, int locLength)
|
|
{
|
|
//Application.DoEvents(); // Not needed since SendKeys is always done last.
|
|
if (_IdentifyingLinks)
|
|
DebugPrint("SS------------------------> {0} {1}", locStart, locLength);
|
|
else
|
|
DebugPrint("SS========================> {0} {1}", locStart, locLength);
|
|
Select(locStart, locLength);
|
|
}
|
|
#endregion
|
|
#region FontAndStylesSupport
|
|
private void ToggleFontStyle(FontStyle style, bool att_on)
|
|
{
|
|
int start = SelectionStart;
|
|
int len = SelectionLength;
|
|
System.Drawing.Font currentFont;
|
|
FontStyle fs;
|
|
for (int i = 0; i < len; ++i)
|
|
{
|
|
Select(start + i, 1);
|
|
currentFont = SelectionFont;
|
|
fs = currentFont.Style;
|
|
//add or remove style
|
|
if (!att_on)fs = fs | style;
|
|
else fs = fs & ~style;
|
|
|
|
SelectionFont = new Font(
|
|
currentFont.FontFamily,
|
|
currentFont.Size,
|
|
fs
|
|
);
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Returns a Font with:
|
|
/// 1) The font applying to the entire selection, if none is the default font.
|
|
/// 2) The font size applying to the entire selection, if none is the size of the default font.
|
|
/// 3) A style containing the attributes that are common to the entire selection, default regular.
|
|
/// </summary>
|
|
///
|
|
public Font GetFontDetails()
|
|
{
|
|
//This method should handle cases that occur when multiple fonts/styles are selected
|
|
|
|
int start = SelectionStart;
|
|
int len = SelectionLength;
|
|
int TempStart = 0;
|
|
|
|
if (len <= 1)
|
|
{
|
|
// Return the selection or default font
|
|
if (SelectionFont != null)
|
|
return SelectionFont;
|
|
else
|
|
return Font; // should be default from format.
|
|
}
|
|
|
|
// Step through the selected text one char at a time
|
|
// after setting defaults from first char
|
|
_rtbTemp.Rtf = SelectedRtf;
|
|
|
|
//Turn everything on so we can turn it off one by one
|
|
FontStyle replystyle =
|
|
FontStyle.Bold | FontStyle.Italic | FontStyle.Underline;
|
|
|
|
// Set reply font, size and style to that of first char in selection.
|
|
_rtbTemp.Select(TempStart, 1);
|
|
string replyfont = _rtbTemp.SelectionFont.Name;
|
|
float replyfontsize = _rtbTemp.SelectionFont.Size;
|
|
replystyle = replystyle & _rtbTemp.SelectionFont.Style;
|
|
|
|
// Search the rest of the selection
|
|
for (int i = 1; i < len; ++i)
|
|
{
|
|
_rtbTemp.Select(TempStart + i, 1);
|
|
|
|
// Check reply for different style
|
|
replystyle = replystyle & _rtbTemp.SelectionFont.Style;
|
|
|
|
// Check font
|
|
if (replyfont != _rtbTemp.SelectionFont.FontFamily.Name)
|
|
replyfont = "";
|
|
|
|
// Check font size
|
|
if (replyfontsize != _rtbTemp.SelectionFont.Size)
|
|
replyfontsize = (float)0.0;
|
|
}
|
|
|
|
// Now set font and size if more than one font or font size was selected
|
|
if (replyfont == "")
|
|
replyfont = _rtbTemp.Font.FontFamily.Name;
|
|
|
|
if (replyfontsize == 0.0)
|
|
replyfontsize = _rtbTemp.Font.Size;
|
|
|
|
// generate reply font
|
|
Font reply
|
|
= new Font(replyfont, replyfontsize, replystyle);
|
|
|
|
return reply;
|
|
}
|
|
#endregion
|
|
#region EnumsSelectionRange
|
|
private enum StartStatus : int
|
|
{
|
|
Before = 100,
|
|
Between = 200,
|
|
StartLink = 300,
|
|
StartBox = 400
|
|
};
|
|
private enum EndStatus : int
|
|
{
|
|
After = 1,
|
|
Between = 2,
|
|
EndLink = 3,
|
|
EndBox = 4,
|
|
StartLink = 5
|
|
};
|
|
public enum RangeStatus : int
|
|
{
|
|
NoContainedLinks = 0,
|
|
Before_After = StartStatus.Before + EndStatus.After,
|
|
Before_Between = StartStatus.Before + EndStatus.Between,
|
|
Before_EndLink = StartStatus.Before + EndStatus.EndLink,
|
|
Before_EndBox = StartStatus.Before + EndStatus.EndBox,
|
|
Before_StartLink = StartStatus.Before + EndStatus.StartLink,
|
|
Between_After = StartStatus.Between + EndStatus.After,
|
|
Between_Between = StartStatus.Between + EndStatus.Between,
|
|
Between_EndLink = StartStatus.Between + EndStatus.EndLink,
|
|
Between_EndBox = StartStatus.Between + EndStatus.EndBox,
|
|
Between_StartLink = StartStatus.Between + EndStatus.StartLink,
|
|
StartLink_After = StartStatus.StartLink + EndStatus.After,
|
|
StartLink_Between = StartStatus.StartLink + EndStatus.Between,
|
|
StartLink_EndLink = StartStatus.StartLink + EndStatus.EndLink,
|
|
StartLink_EndBox = StartStatus.StartLink + EndStatus.EndBox,
|
|
StartLink_StartLink = StartStatus.StartLink + EndStatus.StartLink,
|
|
StartBox_After = StartStatus.StartBox + EndStatus.After,
|
|
StartBox_Between = StartStatus.StartBox + EndStatus.Between,
|
|
StartBox_EndLink = StartStatus.StartBox + EndStatus.EndLink,
|
|
StartBox_EndBox = StartStatus.StartBox + EndStatus.EndBox,
|
|
StartBox_StartLink = StartStatus.StartBox + EndStatus.StartLink
|
|
};
|
|
private RangeStatus _RTBRangeStatus;
|
|
public RangeStatus RTBRangeStatus
|
|
{
|
|
get { return _RTBRangeStatus; }
|
|
set
|
|
{
|
|
_RTBRangeStatus = value;
|
|
if (!_ProcessingDelete) OnRTBRangeStatusChanged(this, new EventArgs());
|
|
}
|
|
}
|
|
private LinkLocation _RangeStartLink = null;
|
|
private LinkLocation _RangeEndLink = null;
|
|
private RangeStatus FindRangeStatus()
|
|
{
|
|
_RangeStartLink = null;
|
|
_RangeEndLink = null;
|
|
if (_LinkLocations == null || _LinkLocations.Count == 0)
|
|
{
|
|
return RTBRangeStatus = RangeStatus.NoContainedLinks;
|
|
}
|
|
LinkLocation foundLink = null;
|
|
int start = SelectionStart;
|
|
int end = start + SelectionLength;
|
|
|
|
foreach (LinkLocation ll in _LinkLocations)
|
|
{
|
|
if (foundLink == null && ((ll.Start >= start && ll.Start < end) || (ll.End >= start && ll.End < end)))
|
|
foundLink = ll;
|
|
if (_RangeStartLink == null && start >= ll.Start - 7 && start < ll.End)
|
|
_RangeStartLink = ll;
|
|
if (_RangeEndLink == null && end >= ll.Start && end <= ll.End)
|
|
_RangeEndLink = ll;
|
|
}
|
|
DebugPrint("SelectionStart {0}, SelectionEnd {1}, TextLength {2}",
|
|
SelectionStart, SelectionStart + SelectionLength,
|
|
TextLength);
|
|
if (_RangeStartLink != null)
|
|
_RangeStartLink.Show("startLink");
|
|
if (_RangeEndLink != null)
|
|
_RangeEndLink.Show("endLink");
|
|
if (foundLink != null)
|
|
foundLink.Show("foundLink");
|
|
|
|
if (foundLink == null)
|
|
return RTBRangeStatus = RangeStatus.NoContainedLinks;
|
|
|
|
StartStatus myStartStatus = StartStatus.Before;
|
|
EndStatus myEndStatus = EndStatus.After;
|
|
if (_RangeStartLink != null)
|
|
{
|
|
if (_RangeStartLink.Start == 7)
|
|
myStartStatus = StartStatus.StartBox;
|
|
else if (_RangeStartLink.StartsBetween)
|
|
myStartStatus = StartStatus.Between;
|
|
else
|
|
myStartStatus = StartStatus.StartLink;
|
|
}
|
|
if (_RangeEndLink != null)
|
|
{
|
|
if (_RangeEndLink.End == TextLength)
|
|
myEndStatus = EndStatus.EndBox;
|
|
else if (_RangeEndLink.NextStart == _RangeEndLink.End)
|
|
myEndStatus = EndStatus.Between;
|
|
else if (end == _RangeEndLink.Start)
|
|
myEndStatus = EndStatus.StartLink; // Should not happen because of code in HandleSelectionChange
|
|
else //if (end == endLink.End)
|
|
myEndStatus = EndStatus.EndLink;
|
|
}
|
|
return RTBRangeStatus = (RangeStatus)((int)myStartStatus + (int)myEndStatus);
|
|
}
|
|
#endregion
|
|
#region Debug
|
|
private bool _ShowDebug = false;
|
|
public bool ShowDebug
|
|
{
|
|
get { return _ShowDebug; }
|
|
set { _ShowDebug = value; }
|
|
}
|
|
private void DebugPrint(string where, string format, params object[] myParams)
|
|
{
|
|
DebugPrint(where + string.Format(format, myParams));
|
|
}
|
|
private void DebugPrint(string format, params object[] myParams)
|
|
{
|
|
if (_ShowDebug)
|
|
Console.WriteLine(format, myParams);
|
|
}
|
|
private void DebugSelection(string where)
|
|
{
|
|
DebugPrint(where, ": {0} {1} '{2}'", SelectionStart, SelectionLength, SelectedText);
|
|
}
|
|
#endregion
|
|
}
|
|
#region LinkLocation Class
|
|
public class LinkLocation
|
|
{
|
|
private int _Start;
|
|
public int Start
|
|
{
|
|
get { return _Start; }
|
|
set { _Start = value; }
|
|
}
|
|
private int _Length;
|
|
public int Length
|
|
{
|
|
get { return _Length; }
|
|
set { _Length = value; }
|
|
}
|
|
public int End
|
|
{
|
|
get { return _Length + _Start; }
|
|
}
|
|
private int _StartRtf;
|
|
public int StartRtf
|
|
{
|
|
get { return _StartRtf; }
|
|
set { _StartRtf = value; }
|
|
}
|
|
private int _LengthRtf;
|
|
public int LengthRtf
|
|
{
|
|
get { return _LengthRtf; }
|
|
set { _LengthRtf = value; }
|
|
}
|
|
public int EndRtf
|
|
{
|
|
get { return _LengthRtf + _StartRtf; }
|
|
}
|
|
private string _Text;
|
|
public string Text
|
|
{
|
|
get { return _Text; }
|
|
set { _Text = value; }
|
|
}
|
|
private LinkLocation _PreviousLink = null;
|
|
public LinkLocation PreviousLink
|
|
{
|
|
get { return _PreviousLink; }
|
|
set
|
|
{
|
|
_PreviousLink = value;
|
|
value.NextLink = this;
|
|
}
|
|
}
|
|
private LinkLocation _NextLink = null;
|
|
public LinkLocation NextLink
|
|
{
|
|
get { return _NextLink; }
|
|
set { _NextLink = value; }
|
|
}
|
|
public int PreviousEnd
|
|
{
|
|
get { return PreviousLink == null ? -1 : PreviousLink.End; }
|
|
}
|
|
public bool StartsBetween
|
|
{
|
|
get { return PreviousEnd == Start; }
|
|
}
|
|
public int NextStart
|
|
{
|
|
get { return NextLink == null ? -1 : NextLink.Start; }
|
|
}
|
|
public bool EndsBetween
|
|
{
|
|
get { return NextStart == End; }
|
|
}
|
|
public LinkLocation(int start, int length, string text, int startRtf, int lengthRtf, LinkLocation previousLink)
|
|
{
|
|
_Start = start;
|
|
_Length = length;
|
|
_Text = text;
|
|
_StartRtf = startRtf;
|
|
_LengthRtf = lengthRtf;
|
|
if (previousLink != null) PreviousLink = previousLink;
|
|
}
|
|
public override string ToString()
|
|
{
|
|
return (string.Format("{0}, {1}", Start, End));
|
|
}
|
|
public void Show(string str)
|
|
{
|
|
if (PreviousLink != null)
|
|
Console.WriteLine("LinkLocation: {0}.PreviousLink {1}", str, PreviousLink);
|
|
Console.WriteLine("LinkLocation: {0} {1}", str, this);
|
|
if (NextLink != null)
|
|
Console.WriteLine("LinkLocation: {0}.NextLink {1}", str, NextLink);
|
|
}
|
|
|
|
}
|
|
#endregion
|
|
}
|