2010-10-07 17:08:16 +00:00

2771 lines
91 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;
using Volian.Base.Library;
namespace Volian.Controls.Library
{
public delegate void StepRTBEvent(object sender, EventArgs args);
public delegate void StepRTBCursorKeysEvent(object sender, KeyEventArgs args);
public delegate void StepRTBCursorMovementEvent(object sender, StepRTBCursorMovementEventArgs args);
public delegate void StepRTBModeChangeEvent(object sender, StepRTBModeChangeEventArgs args);
//public delegate void StepRTBMouseWheelEvent(object sender, MouseEventArgs 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);
}
public event StepRTBCursorKeysEvent CursorKeyPress;
private void OnCursorKeyPress(object sender, KeyEventArgs args)
{
if (CursorKeyPress != null) CursorKeyPress(sender, args);
}
public event StepRTBCursorMovementEvent CursorMovement;
private void OnCursorMovement(object sender, StepRTBCursorMovementEventArgs args)
{
if (CursorMovement != null) CursorMovement(sender, args);
}
public event StepRTBModeChangeEvent ModeChange;
private void OnModeChange(object sender, StepRTBModeChangeEventArgs args)
{
//_MyModeChangeEventArgs = args;
if (ModeChange != null) ModeChange(sender, args);
else MessageBox.Show("StepRTB - no mode change defined");
}
//public event StepRTBMouseWheelEvent MouseWheel;
//private void OnMouseWheel(object sender, MouseEventArgs args)
//{
// if (MouseWheel != null) MouseWheel(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
private static FontFamily _MyFontFamily = null;
public static FontFamily MyFontFamily
{
get { return StepRTB._MyFontFamily; }
set { StepRTB._MyFontFamily = value; }
}
// 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 E_FieldToEdit _FieldToEdit = E_FieldToEdit.StepText;
public E_FieldToEdit FieldToEdit
{
get { return _FieldToEdit; }
set { _FieldToEdit = value; }
}
private string _RtfPrefix; // contains Font table and styles (bold/underline/italics) for rtb from step style
public string RtfPrefix
{
get
{
return _RtfPrefix + @"\f1\fs" + this.Font.SizeInPoints * 2 + " ";
}
}
private StepItem _MyStepItem;
public StepItem MyStepItem
{
get { return _MyStepItem; }
set { _MyStepItem = value; }
}
// August 5, 2009 - KBR & RHM:
// Insert/Overwrite will be developed later if needed. various issues
// were found during initial development that made its scope larger than
// expected. Problems were related to having overstrike on in the following
// cases:
// 1) left arrow when on link - positions after link
// 2) left arrow and after link - does not move
// 3) shift left arrow does not move past links correctly and also, first
// shift left arrow looks more like insert mode.
// private bool _OverWrite;
// _IsDirty compares the original rtf to the current rtf from the
// richtextbox to see if a change was made.
private bool _IsDirty
{
get { return _origRTF != Rtf; }
}
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; }
}
public bool ViewRTB = true;
private ItemInfo _MyItemInfo;
public ItemInfo MyItemInfo
{
get { return _MyItemInfo; }
set
{
_MyItemInfo = value;
if (value != null)
{
RTBFillIn(!ViewRTB);
SetBackColor();
//ViewRTB = MyStepItem.MyStepPanel.PanelViewEditMode == E_ViewMode.View;
}
}
}
public void SetBackColor()
{
if (MyStepItem == null || MyStepItem.MyStepPanel == null) return;
if (!Focused)BackColor = _MyItemInfo.ItemAnnotationCount == 0 ? MyStepItem.MyStepPanel.InactiveColor : Color.FromArgb(255, 255, 128);
}
public void HighlightBackColor()
{
// Don't try to highlight if this rtb is used on property pages.
if (MyStepItem == null || MyStepItem.MyStepPanel == null) return;
BackColor = Color.Gray;
}
private string _origRTF;
public void RTBFillIn(bool edit)
{
if (edit && _MyStepItem != null && (_MyItemInfo.IsTable || _MyItemInfo.IsFigure))
{
// First get ColR
int colR = MyStepItem.MyStepPanel.ToDisplay(MyStepItem.MyStepSectionLayoutData.ColRTable, MyItemInfo.ColumnMode);
// Second get WidS
int widS = /* _WidthAdjust + borderWidth + */ MyStepItem.MyStepPanel.ToDisplay(MyStepItem.MyStepSectionLayoutData.WidSTableEdit, MyItemInfo.ColumnMode);
//int wNew = _MyStepItem.MyStepPanel.ToDisplay(_MyStepItem.MyStepSectionLayoutData.WidT);
int wNew = 70 + widS + colR * MyItemInfo.ColumnMode;
if(wNew > _MyStepItem.ItemWidth)
_MyStepItem.ItemWidth= wNew;
}
_InitializingRTB = true;
_SelectedRtfSB.Remove(0, _SelectedRtfSB.Length);
DisplayText vlntxt = new DisplayText(_MyItemInfo, EpMode, VwMode, !edit, FieldToEdit, true);
//if (_origDisplayText != null && vlntxt.StartText == _origDisplayText.StartText)
//{
// ReadOnly = !(EpMode == E_EditPrintMode.Edit && VwMode == E_ViewMode.Edit);
// if (!ReadOnly && !edit) ReadOnly = true;
// return;
//}
_origDisplayText = vlntxt;
Font formatFont = _origDisplayText.TextFont.WindowsFont;
if (_MyItemInfo.IsTable || _MyItemInfo.IsFigure)
Font = formatFont;
else
{
if (VlnSettings.DebugMode)
Font = new Font(_MyFontFamily == null ? formatFont.FontFamily : _MyFontFamily, formatFont.Size, formatFont.Style);
else
Font = new Font("Bookman Old Style", formatFont.Size, formatFont.Style);
// TODO: Release Mode
//Font = _origDisplayText.TextFont.WindowsFont; // font defined in plant's format
}
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.StartText);
//AddRtfStyles();
// set readonly based on initial modes, however, these may change if
// user selected view mode.
ReadOnly = !(EpMode == E_EditPrintMode.Edit && VwMode == E_ViewMode.Edit);
if (!ReadOnly && !edit) ReadOnly = true;
ClearUndo();
RightMargin = Width;
// figure out if needs outlined, depends on table/figure type
if (!edit)
{
RemoveEventHandlers();
if ((!_MyItemInfo.IsSection && !_MyItemInfo.IsProcedure) && (_MyItemInfo.IsTable || _MyItemInfo.IsFigure))
{
int newwidth = (int)_MyStepItem.TableWidth(Font, Text, true);
if (_MyStepItem.ItemWidth != newwidth)
{
_MyStepItem.ItemWidth = newwidth;
}
// int typ = ((int)_MyItemInfo.MyContent.Type) % 10000;
// OutlineTable(_MyItemInfo.ActiveFormat.PlantFormat.FormatData.StepDataList[typ].Type.IndexOf(@"Borderless")<0);
// FindAllLinks();
}
SelectAll();
if (SelectionHangingIndent !=0) SelectionHangingIndent = 0;
int indchar = 0;
string indentToken = _MyItemInfo.ActiveFormat.PlantFormat.FormatData.SectData.StepSectionData.IndentToken;
if (indentToken == null) indentToken = "\x5";
while ((indchar = Find(indentToken, indchar, RichTextBoxFinds.None)) >= 0)
{
Point indent = GetPositionFromCharIndex(indchar);
SelectionHangingIndent = indent.X;
indchar++;
}
AddEventHandlers();
}
//else
//{
// if (_MyStepItem != null && (_MyItemInfo.IsTable || _MyItemInfo.IsFigure))
// {
// //_MyStepItem.ItemWidth = (int)_MyStepItem.TableWidth(Font, Text,false);
// _MyStepItem.ItemWidth = _MyStepItem.MyStepPanel.ToDisplay(_MyStepItem.MyStepSectionLayoutData.WidT);
// }
//}
_origRTF = Rtf;
_InitializingRTB = false;
_MyItemInfo.MyConfig.PropertyChanged += new PropertyChangedEventHandler(MyConfig_PropertyChanged);
AdjustSizeForContents(!edit); // TODO: this is not quite right yet.
if (MyStepItem != null) MyStepItem.ChangeBar = MyStepItem.MyItemInfo.HasChangeBar();
}
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 = new Rectangle(0,0,0,0);
public Rectangle ContentsRectangle
{
get
{
if (_ContentsRectangle.X == 0 && _ContentsRectangle.Y == 0 && _ContentsRectangle.Width == 0 && _ContentsRectangle.Height == 0)
_ContentsRectangle = this.ClientRectangle;
return _ContentsRectangle;
}
set
{
_ContentsRectangle = value;
AdjustSizeForContents(false);
}
}
public Size ContentsSize
{
get { return _ContentsRectangle.Size; }
}
private Size _AdjustSize = new Size(0,0); // if 0,0 puts text right next to bottom of box.
public Size AdjustSize
{
get { return _AdjustSize; }
set
{
_AdjustSize = value;
AdjustSizeForContents(false);
}
}
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)
//{
// updates to the info panel were not always occurring when the previous two
// lines were active
_MyLinkText = value;
OnLinkChanged(this, new StepPanelLinkEventArgs(_MyStepItem, _MyLinkText));
//}
}
}
#endregion
#region Constructors
public StepRTB()
{
InitializeComponent();
SetUpStepRTB();
AddEventHandlers();
}
public StepRTB(IContainer container)
{
container.Add(this);
InitializeComponent();
_Container = container;
SetUpStepRTB();
AddEventHandlers();
}
protected override void OnMouseWheel(MouseEventArgs e)
{
_MyStepItem.MyStepPanel.MouseWheel(e);
//base.OnMouseWheel(e);
}
private void RemoveEventHandlers()
{
ContentsResized -= new ContentsResizedEventHandler(StepRTB_ContentsResized);
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.MouseLeave -= new EventHandler(StepRTB_MouseLeave);
this.SelectionChanged -= new EventHandler(StepRTB_SelectionChanged);
}
private void AddEventHandlers()
{
BorderStyle = System.Windows.Forms.BorderStyle.None;
this.DetectUrls = true;
ContentsResized += new ContentsResizedEventHandler(StepRTB_ContentsResized);
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.MouseLeave += new EventHandler(StepRTB_MouseLeave);
this.SelectionChanged +=new EventHandler(StepRTB_SelectionChanged);
this.ContextMenuStripChanged += new EventHandler(StepRTB_ContextMenuStripChanged);
this.RTBSelectionChanged += new StepRTBEvent(StepRTB_RTBSelectionChanged);
}
void StepRTB_RTBSelectionChanged(object sender, EventArgs args)
{
//Console.WriteLine("RTBSelectionChanged id= {0}", MyItemInfo.ItemID);
if (!Focused) Focus();
}
void StepRTB_ContextMenuStripChanged(object sender, EventArgs e)
{
//Console.WriteLine("********** StepRTB_ContextMenuStripChanged");
int sublocation = 0;
try
{
//Console.WriteLine("{0}", ContextMenuStrip.GetType().FullName);
this.MyStepItem.MyStepPanel.MyStepTabPanel.MyStepTabRibbon.ClearContextMenu();
sublocation = 1;
_ContextMenuStripChanged = true;
sublocation = 2;
_ContextMenuStepRTB = this;
sublocation = 3;
_ContextMenuStrip = ContextMenuStrip;
sublocation = 4;
}
catch(Exception ex)
{
Console.WriteLine("StepRTB_ContextMenuStripChanged {0} - {1} [{2}]", ex.GetType().Name, ex.Message, sublocation);
}
}
private void SetUpStepRTB()
{
C1SpellChecker2.SetActiveSpellChecking(this, true);
this.Height = 10; // initialize the height to 10, the default height was too big for the cells in grid tables
BorderStyle = System.Windows.Forms.BorderStyle.None;
this.ScrollBars = RichTextBoxScrollBars.None;
this.DetectUrls = true;
}
// An event is needed to set MouseDown to false on mouse leave, because additional rtb's may
// have been exposed based on entering a step, which causes the underlying item/rtb for which
// the mouse event occurs to not be the current rtb. RTB gets selected on MouseDown, MouseEnter
// and MouseUp are
void StepRTB_MouseLeave(object sender, EventArgs e)
{
_MouseDown = false;
}
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)
{
//Console.WriteLine("StepRTB_SelectionChanged id= {0}", MyItemInfo.ItemID);
if (_InitializingRTB) return;
HandleSelectionChange();
}
private bool _MouseDown = false;
private bool _ContextMenuStripChanged = false;
private void StepRTB_MouseDown(object sender, MouseEventArgs e)
{
_MouseDown = true;
//Console.WriteLine("vvvvvvvvvv StepRTB Mouse Down id= {0}",MyItemInfo.ItemID);
if (!_ContextMenuStripChanged && this.MyStepItem != null)
this.MyStepItem.MyStepPanel.MyStepTabPanel.MyStepTabRibbon.SetContextMenu();
_ContextMenuStripChanged = false;
}
void StepRTB_MouseUp(object sender, MouseEventArgs e)
{
_MouseDown = false;
//Console.WriteLine("^^^^^^^^^^ StepRTB Mouse Up id= {0}", MyItemInfo.ItemID);
if(this.Focused) // Only HandleSelectionChange if this control has focus.
{
HandleSelectionChange();
// save our context menu to add to the spell checker's context menu
ThisContextMenuStrip = this.ContextMenuStrip;
}
}
#endregion
#region ApplicationSupport
public void ToggleEditView()
{
SaveText();
//ItemInfo tmp = MyItemInfo;
//MyItemInfo = null;
ReadOnly = !ReadOnly;
EpMode = ReadOnly ? E_EditPrintMode.Print : E_EditPrintMode.Edit;
VwMode = ReadOnly ? E_ViewMode.View : E_ViewMode.Edit;
ViewRTB = ReadOnly;
Clear();
RTBFillIn(!ViewRTB);
//MyItemInfo = tmp;
SelectionStart = 0;
SelectionLength = 0;
OnModeChange(this, new StepRTBModeChangeEventArgs(ViewRTB?E_ViewMode.View:E_ViewMode.Edit));
}
public void InsertRO(string value, string link)
{
AddRtfLink(value, link);
}
public void InsertTran(string value, string link)
{
AddRtfLink(value, link);
}
public void InsertSymbol(int symbcode)
{
string sym = string.Format(symbcode < 256 ? "\'{0:X2}" : @"\u{0}", symbcode);
if (symbcode < 256)
AddText(((char)symbcode).ToString());
else
AddSymbol(sym); // Adds font commands around symbol, needed for higher codes
}
public void InsertSymbol(string symbol)
{
AddSymbol(symbol);
}
public void InsertIndent()
{
string indentToken = _MyItemInfo.ActiveFormat.PlantFormat.FormatData.SectData.StepSectionData.IndentToken;
if (indentToken == null) indentToken = "\x5";
AddText(indentToken);
}
public void InsertText(string txt)
{
AddText(txt);
}
private void ToggleCase()
{
char type = 'l';
// do not change case on linked text
RangeStatus rs = FindRangeStatus();
string tmp = null;
if (rs != RangeStatus.NoContainedLinks)
{
int start = SelectionStart;
int ostart = SelectionStart;
int end = SelectionStart + SelectionLength;
bool processed = false;
while (!processed && start <= end)
{
foreach (LinkLocation ll in LinkLocations)
{
if (ll.Start >= start && ll.End <= end)
{
processed = true;
if (start < ll.Start)
{
SelectionStart = start;
SelectionLength = ll.Start - start;
}
start = ll.End + 1;
break;
}
}
}
}
string ostring = SelectedText;
if ((char.IsUpper(ostring, 0) && char.IsUpper(ostring, 1)) ||
(char.IsLower(ostring, 0) && char.IsUpper(ostring, 1))) type = 'l'; // lower case
else if ((char.IsUpper(ostring, 0) && char.IsLower(ostring, 1))) type = 'U'; // upper case
else type = 'T'; // Title case
SetSelectedCase(type);
}
public void SetSelectedCase(char type)
{
// do not change case on linked text
RangeStatus rs = FindRangeStatus();
string tmp = null;
if (rs == RangeStatus.NoContainedLinks)
SetCase(type);
else
{
int start = SelectionStart;
int ostart = SelectionStart;
int end = SelectionStart + SelectionLength;
StringBuilder sb = new StringBuilder();
while (start <= end)
{
bool processed = false;
foreach (LinkLocation ll in LinkLocations)
{
if (ll.Start >= start && ll.End <= end)
{
processed = true;
if (start < ll.Start)
{
SelectionStart = start;
SelectionLength = ll.Start - start;
SetCase(type);
}
start = ll.End + 1;
break;
}
}
// if none were processed, no more links, copy over any remaining text.
if (!processed)
{
SelectionStart = start;
SelectionLength = end-start;
SetCase(type);
start = end + 1;
}
}
SelectionStart = ostart;
SelectionLength = end - ostart;
}
}
private void SetCase(char type)
{
int ostart = SelectionStart;
int olen = SelectionLength;
string ostring = SelectedText;
string tmp = null;
bool docap = true;
// go character by character. Because of symbols, setting entire
// to upper or lower set symbols incorrectly some of time (depending
// on symbol) .
for (int i = 0; i < olen; i++)
{
SelectionStart = ostart + i;
SelectionLength = 1;
switch (type)
{
case 'l':
if (SelectedText[0] >= 'A' && SelectedText[0] <= 'Z')
SelectedText = SelectedText.ToLower();
break;
case 'U':
if (SelectedText[0] >= 'a' && SelectedText[0] <= 'z')
SelectedText = SelectedText.ToUpper();
break;
case 'T':
if (docap && SelectedText[0] >= 'a' && SelectedText[0] <= 'z')
SelectedText = SelectedText.ToUpper();
else if (!docap && SelectedText[0] >= 'A' && SelectedText[0] <= 'Z')
SelectedText = SelectedText.ToLower();
docap = ostring[i] == ' ';
break;
}
}
SelectionStart = ostart;
SelectionLength = olen;
}
#endregion
#region SaveData
public void SaveText(bool force)
{
if (ReadOnly) return;
if (ViewRTB) return;
if (!force && !_IsDirty && Text.Contains("(Resolved Transition Text)") == false) return;
bool success = _origDisplayText.Save((RichTextBox)this);
if (success)
{
FindAllLinks();
_origRTF = Rtf;
ClearUndo();
}
}
public void SaveText()
{
if (ReadOnly) return;
if (ViewRTB) return;
if (!_IsDirty && Text.Contains("(Resolved Transition Text)") == false) return;
bool success = _origDisplayText.Save((RichTextBox)this);
if (success)
{
FindAllLinks();
_origRTF = Rtf;
ClearUndo();
}
}
public void SaveConfig()
{
if (!_MyItemInfo.MyConfig.IsDirty) return;
using (Item itm = _MyItemInfo.Get())
{
itm.MyContent.Config = _MyItemInfo.MyConfig.ToString();
itm.Save();
}
_MyItemInfo.MyConfig.IsDirty = false;
}
#endregion
#region AddRtfTextAndStyles
private void AddRtfText(string txt)
{
AddFontTable();
_RtfPrefix = _SelectedRtfSB.ToString();
_SelectedRtfSB.Append(txt);
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 + @"}}";
if (!FontIsFixed())
_SelectedRtfSB.Append(@"{\f1\fnil\fcharset0 Arial Unicode MS;}}{\colortbl ;\red255\green0\blue0;}");
else
_SelectedRtfSB.Append(@"{\f1\fnil\fcharset0 VESymbFix;}}{\colortbl ;\red255\green0\blue0;}");
_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" + Convert.ToInt32(this.Font.SizeInPoints * 2).ToString() + @" "); // \f0\fs" + this.Font.SizeInPoints * 2 + @" " + myDisplayTextElement.Text + @"}";
}
private bool FontIsFixed()
{
Graphics grph = Graphics.FromHwnd(this.Handle);
SizeF sfW = grph.MeasureString("W", this.Font);
SizeF sfE = grph.MeasureString("!", this.Font);
if (sfW.Width == sfE.Width) return true;
return false;
}
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(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 = _RtfPrefix + @"\f1\fs" + this.Font.SizeInPoints * 2 + @" " + str + @"}";
Select(position, 1);
RTBAPI.SetFontStyle(this, fs);
Select(position + 1, 0);
SelectionFont = _origDisplayText.TextFont.WindowsFont;
}
private string GetAddSymbolText(string symtxt)
{
return (@"{\f0\fs" + this.Font.SizeInPoints * 2 + @" " + symtxt + @"}");
}
public void AddRtfLink(string linkUrl, string linkValue)
{
if (CreateParams.ClassName == "RICHEDIT50W")
AddLink50(linkUrl, linkValue);
else
AddLink20(linkUrl, linkValue);
}
private string FontTable
{
get
{
StringBuilder sb = new StringBuilder();
sb.Append(@"{\fonttbl{\f0\fnil\fcharset2 " + this.Font.FontFamily.Name + @";}");
if (!FontIsFixed())
sb.Append(@"{\f1\fnil\fcharset0 Arial Unicode MS;}}");
else
sb.Append(@"{\f1\fnil\fcharset0 VESymbFix;}}");
return sb.ToString();
}
}
private string FontSize
{
get
{
Match match = Regex.Match(Rtf, @"\\fs[0-9]*");
return match.Value;
}
}
private void AddLink20(string linkValue, string linkUrl)
{
string fonttab = FontTable;
string fontsize = FontSize;
this.DetectUrls = false;
//if (SelectionLength > 0) DeleteCurrentSelection(null);
if (SelectionLength > 0)HandleDeleteKeyWithSelectedText(new KeyEventArgs(Keys.None), null);
int position = SelectionStart;
SelectionLength = 0;
//Console.WriteLine(this.Rtf);
linkValue = linkValue.Replace("\\u8209?", "\\f1\\u8209?\\f0 ");
SelectedRtf = @"{\rtf1\ansi"+FontTable+@"{\colortbl ;\red255\green0\blue0;}\v"+FontSize+@" <START]\v0\cf1 " + linkValue + @"\cf0\v " + linkUrl + @"[END>\v0 }";
//Console.WriteLine(this.Rtf);
this.SelectionLength = 0;
this.SelectionStart = position;
FindAllLinks();
}
private void AddLink50(string linkValue, string linkUrl)
{
this.DetectUrls = false;
int position = SelectionStart;
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);
}
// Bug Fix
// The code below was changed to select all of the text and then
// apply the underlining to the selected text, because if the
// the underlining was applied to RTBAPI.RTBSelection.SCF_ALL
// the Links were changed so that they were no longer hidden.
if ((_origDisplayText.TextFont.Style & E_Style.Underline) > 0)
// RTBAPI.ToggleUnderline(true, this, RTBAPI.RTBSelection.SCF_ALL);
{
this.SelectAll();
RTBAPI.ToggleUnderline(true, this, RTBAPI.RTBSelection.SCF_SELECTION);
this.Select(0, 0);
}
// Bug Fix
// The code below was changed to select all of the text and then
// apply the italics to the selected text, because if the
// the italics was applied to RTBAPI.RTBSelection.SCF_ALL
// the Links were changed so that they were no longer hidden.
if ((_origDisplayText.TextFont.Style & E_Style.Italics) > 0)
// RTBAPI.ToggleItalic(true, this, RTBAPI.RTBSelection.SCF_ALL);
{
this.SelectAll();
RTBAPI.ToggleItalic(true, this, RTBAPI.RTBSelection.SCF_SELECTION);
this.Select(0, 0);
}
}
#endregion
#region HeightSupport
public event StepRTBEvent HeightChanged;
private void OnHeightChanged(object sender, EventArgs args)
{
if (HeightChanged != null) HeightChanged(sender, args);
}
private void AdjustSizeForContents(bool adjustWidth)
{
if (!_InitializingRTB)
{
Size offset = Size - ClientSize;
int widthNew = ContentsSize.Width + offset.Width + AdjustSize.Width ;
int heightNew = ContentsSize.Height + offset.Height + AdjustSize.Height;
// Don't make the window narrower unless it has text - RHM - 20100107
Size szNew = new Size(((Text != "" && adjustWidth) ? widthNew : (widthNew > Width ? widthNew : Width)), heightNew);
if (this.Size != szNew)
{
this.Size = szNew;
OnHeightChanged(this, new EventArgs());
}
}
}
private float GetStringWidth(string strMeasureString)
{
using (Graphics g = Graphics.FromHwnd(Handle))
{
return g.MeasureString(strMeasureString, Font).Width;
}
}
private int Ceiling(float f)
{
return (int)(Math.Ceiling(f));
}
public void AdjustWidthForContent()
{
int widthNL = Ceiling(GetStringWidth("\n"));
int widthMax = 0;
int widthMaxWW = 0;
int indexStart = 0;
int lineCountFromLines = Lines.Length;
int lineCountFromGet = GetLineFromCharIndex(TextLength)+1;
for (int i = 0; i < Lines.Length; i++)
{
int lineStart = GetLineFromCharIndex(indexStart);
int indexEnd = indexStart + Lines[i].Length;
int lineEnd = GetLineFromCharIndex(indexEnd);
Point pointStart = GetPositionFromCharIndex(indexStart);
Point pointEnd = GetPositionFromCharIndex(indexEnd);
int indexEndPos = GetCharIndexFromPosition(pointEnd);
if (indexEndPos + 1 < indexEnd) // This indicates that the text is wider than the Rich Text Box
{
int w = pointEnd.X + (indexEnd - indexEndPos) * widthNL;
if (w > widthMaxWW)
{
widthMaxWW = w;
}
}
if (lineEnd > lineStart)// this indicates that there was word-wrap on this line.
{
int w = pointEnd.X + Width * (lineEnd - lineStart);
if (w > widthMaxWW)
widthMaxWW = w;
}
else
{
if (pointEnd.X > widthMax)
widthMax = pointEnd.X;
}
indexStart = indexEnd + 1;
}
if (widthMaxWW == 0)
{
int widthBorder = Width - ClientSize.Width;
int w = widthMax + widthNL + widthBorder;
if (Width != w)
{
Width = w;
AdjustWidthForContent();// Try one more time
}
}
else
{
Width = widthMaxWW;
AdjustWidthForContent();
}
}
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);
}
#endregion
#region TextAndContentsEvents
void StepRTB_TextChanged(object sender, EventArgs e)
{
if (_InitializingRTB) return;
// Was setting _IsDirty to true here, but this was getting called from
// 'dotnetbar' when text was NOT Changed. So _IsDirty was made into
// a property and compared original rtf versus current richtextbox's
// rtf.
FindAllLinks();
}
void StepRTB_ContentsResized(object sender, ContentsResizedEventArgs e)
{
ContentsRectangle = e.NewRectangle;
}
#endregion
#region Selection Handlers
bool _AdjustingSelection = false;
private bool _ProcessingDelete;
private bool _HandlingCtrlA = false;
private void HandleLocalSelectionChange()
{
if (MyStepItem.MyStepPanel.SelectedStepRTB != this)
return;
HandleSelectionChange();
}
private void HandleSelectionChange()
{
if (_HandlingCtrlA) return;
if (!_HandlingCtrlA && this.TextLength == this.SelectionLength && this.SelectedRtf.EndsWith("\\par\r\n}\r\n"))
{
_HandlingCtrlA = true;
SelectAll();
_HandlingCtrlA = false;
}
//HandleOverWrite();
//vlnStackTrace.ShowStackLocal("HandleSelectionChangeStack", 1, 10);
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());
if (SelectionLength > 0 && IsSelectionLinked(SelectionStart, SelectionLength))
{
if (SelectedText.IndexOf(@"[END>") > 0) MyLinkText = SelectedText.Substring(0, SelectedText.IndexOf(@"[END>"));
else MyLinkText = SelectedText;
}
else
MyLinkText = null;
OnRTBSelectionChanged(this, new EventArgs());
}
//private void HandleOverWrite()
//{
// if (!_OverWrite) return;
// if (SelectionLength > 0) return;
// if (SelectionStart == TextLength) return;
// Console.WriteLine("Handle Overwrite, SelectionStart = {0}, SelectionLength = {1}", SelectionStart, SelectionLength);
// SelectionLength = 1;
//}
private bool _CheckSelection = false;
#endregion
#region Delete Handlers
private void HandleDeleteKeyWithSelectedText(KeyEventArgs e, string keychars)
{
_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(keychars);
e.SuppressKeyPress = true;
break;
case RangeStatus.Before_Between: //myRTB1.SelectedText.EndsWith(@"[END><START]")
DeleteEndBetweenLinks(keychars);
e.SuppressKeyPress = true;
break;
case RangeStatus.Between_EndBox:
case RangeStatus.Between_EndLink:
case RangeStatus.Between_After:
DeleteStartBetweenLinks(keychars);
e.SuppressKeyPress = true;
break;
case RangeStatus.Between_Between:
DeleteBetweenBetweenLinks(keychars);
e.SuppressKeyPress = true;
break;
case RangeStatus.StartLink_EndBox:
case RangeStatus.StartLink_EndLink:
case RangeStatus.StartLink_After:
ExpandSelectionToIncludeStart();
DeleteCurrentSelection(keychars);
e.SuppressKeyPress = true;
break;
case RangeStatus.StartLink_Between:
ExpandSelectionToIncludeStart();
DeleteEndBetweenLinks(keychars);
e.SuppressKeyPress = true;
break;
case RangeStatus.StartBox_EndLink:
case RangeStatus.StartBox_EndBox:
case RangeStatus.StartBox_After:
DeleteFromStartOfBox(keychars);
e.SuppressKeyPress = true;
break;
case RangeStatus.StartBox_Between:
DeleteFromStartOfBoxEndBetweenLinks(keychars);
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, string strToAdd)
{
InsertCharBetweenLinks(ll, strToAdd, true);
}
private void InsertCharBetweenLinks(LinkLocation ll, string strToAdd, bool setSelect)
{
Rtf = Rtf.Substring(0, ll.StartRtf) + @"\v0 " + strToAdd + @"\v " + Rtf.Substring(ll.StartRtf);
if (setSelect)
SelectionStart = ll.Start - 6; // account for <START] - 1 for the character typed
}
/// <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(string keychars)
{
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(keychars);// 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>
public bool WasXDelete = false;
private void DeleteCurrentSelection(string keys)
{
DebugPrint("vvvvvvvvvvvvxxxxxxxxxxxx>");
DebugSelection("Before X");
SelectedText = keys==null?"X":keys; // replace text with X
WasXDelete = (keys == null);
DebugSelection("After X");
DebugPrint("------------xxxxxxxxxxxx>");
if (keys == null)
{
_SendBackSpace = true;
RtbSendKeys("{BS}"); // remove X
//this.ClearUndo(); // undo was redisplay 'X' and then deleted text
Application.DoEvents();
DebugSelection("After BS");
}
DebugPrint("^^^^^^^^^^^^xxxxxxxxxxxx>");
}
private void DeleteSelection(int start, int length, string keychars)
{
SetSelection(start, length);
DeleteCurrentSelection(keychars);
}
private void DeleteEndBetweenLinks(string keychars)
{
_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, keychars);
//_AdjustingSelection = false;
_ProcessingKeys--;
}
private void DeleteStartBetweenLinks(string keychars)
{
_ProcessingKeys++;
DebugSelection("DeleteStartBetweenLinks");
int slen = SelectionLength + 8;
int sstart = SelectionStart - 7;
//LinkLocation ll = FindBetweenLinks(SelectionStart);
InsertCharBetweenLinks(_RangeStartLink);
DeleteSelection(sstart, slen, keychars);
_ProcessingKeys--;
}
private void DeleteFromStartOfBox(string keychars)
{
_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, keychars);
_ProcessingKeys--;
}
private void DeleteFromStartOfBoxEndBetweenLinks(string keychars)
{
_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, keychars);
_ProcessingKeys--;
}
#endregion
#region KeyboardHandling
void StepRTB_KeyUp(object sender, KeyEventArgs e)
{
if (e.Control)
{
if (this.MyStepItem != null)
{
if (e.Alt)
{
switch (e.KeyCode)
{
case Keys.M:
this.MyStepItem.MyStepPanel.MyStepTabPanel.MyStepTabRibbon.btnAnnots_Click(sender, e);
e.Handled = true;
break;
default:
break;
}
}
if (e.Shift)
{
switch (e.KeyCode)
{
case Keys.F:
this.MyStepItem.MyStepPanel.MyStepTabPanel.MyStepTabRibbon.ShortCutContextMenu("InsFigure");
e.Handled = true;
break;
case Keys.T:
this.MyStepItem.MyStepPanel.MyStepTabPanel.MyStepTabRibbon.ShortCutContextMenu("InsTable");
e.Handled = true;
break;
case Keys.N:
this.MyStepItem.MyStepPanel.MyStepTabPanel.MyStepTabRibbon.ShortCutContextMenu("InsNote");
e.Handled = true;
break;
case Keys.C:
this.MyStepItem.MyStepPanel.MyStepTabPanel.MyStepTabRibbon.ShortCutContextMenu("InsCaution");
e.Handled = true;
break;
case Keys.S:
this.MyStepItem.MyStepPanel.MyStepTabPanel.MyStepTabRibbon.ShortCutContextMenu("InsSubStps");
e.Handled = true;
break;
case Keys.H:
this.MyStepItem.MyStepPanel.MyStepTabPanel.MyStepTabRibbon.ShortCutContextMenu("InsHLS");
e.Handled = true;
break;
case Keys.R:
this.MyStepItem.MyStepPanel.MyStepTabPanel.MyStepTabRibbon.ShortCutContextMenu("InsRNO");
e.Handled = true;
break;
}
}
}
}
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;
case Keys.Space:
if (e.Control) // Hardspace - Ctrl+Shift+Space
InsertSymbol(@"\u160?");
break;
case Keys.F3: // shift F3
e.Handled = true;
ToggleCase(); // toggle through Upper, Lower, and Title case
break;
default:
break;
}
}
private string GetSelectedDisplayableText()
{
StepRTB srtb = new StepRTB();
srtb.Rtf = this.SelectedRtf.Replace(@"\u8209?", "-");
string rtnstr = "";
string ctxt = srtb.Text;//this.SelectedText;
if (ctxt.EndsWith("<START]"))
ctxt = ctxt.Substring(0, ctxt.Length - 7);
int idx = 0;
int strtidx = ctxt.IndexOf("<START]");
int lnkidx = ctxt.IndexOf("#Link");
int endidx = ctxt.IndexOf("[END>");
if ((strtidx == -1 || strtidx > lnkidx) && lnkidx > -1 && endidx > -1)
{
rtnstr += ctxt.Substring(idx, lnkidx);
idx = endidx + 5;
strtidx = ctxt.IndexOf("<START]", idx);
lnkidx = ctxt.IndexOf("#Link:", idx);
endidx = ctxt.IndexOf("[END>", idx);
}
while (strtidx > -1)
{
rtnstr += ctxt.Substring(idx, strtidx - idx);
idx = strtidx + 7;
rtnstr += ctxt.Substring(idx, lnkidx - idx);
idx = endidx + 5;
strtidx = ctxt.IndexOf("<START]", idx);
lnkidx = ctxt.IndexOf("#Link:", idx);
endidx = ctxt.IndexOf("[END>", idx);
}
if (idx < ctxt.Length)
rtnstr += ctxt.Substring(idx);
return rtnstr;
}
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.X: //ctrl-X
case Keys.C: //ctrl-C
// handle the clipboard copy and cut when a Transition or RO is selected
// For now, we are coping/cutting just the displayed text to the clipboard (like 16-bit VE-PROMS)
Clipboard.SetText(GetSelectedDisplayableText());
e.Handled = true;
e.SuppressKeyPress = true;
if (e.KeyCode == Keys.X) // cut to clipboard - delete the selected text
HandleDeleteKeyWithSelectedText(e, null);
break;
case Keys.V:
IDataObject iData = Clipboard.GetDataObject();
if (!iData.GetDataPresent(DataFormats.Text) && !iData.GetDataPresent(DataFormats.Rtf))
{
MessageBox.Show("Cannot paste, text has special characters or symbols that will not paste correctly.");
}
else
{
Paste();
if (SelectionLength == 0) SelectionFont = MyStyleFont.WindowsFont;
}
e.Handled = true;
return;
case Keys.Home:
StepRTB_HomeEndPressed(e);
e.Handled = true;
break;
case Keys.End:
StepRTB_HomeEndPressed(e);
e.Handled = true;
break;
case Keys.Enter:
if (this.MyStepItem != null)
{
this.MyStepItem.MyStepPanel.MyStepTabPanel.MyStepTabRibbon.btnInsPgBrk_Click(sender, e);
e.Handled = true;
}
break;
}
}
switch (e.KeyCode)
{
case Keys.Left:
if (e.Shift)
{
int newstart = FindStart(); // find start of link ending on.
// if not link, don't do special processing
if (newstart == SelectionStart - 1) return;
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;
}
HandleLocalSelectionChange();
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
{
HandleLocalSelectionChange();
}
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;
}
HandleLocalSelectionChange();
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);
HandleLocalSelectionChange();
e.Handled = true;
return;
}
if (!e.Shift) HandleLocalSelectionChange();
// 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, null);
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, null);
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, null);
break;
case Keys.Insert:
//_OverWrite = !_OverWrite;
//if (_OverWrite)
//{
// HandleSelectionChange();
//}
//else
//{
// SelectionLength = 0;
// HandleSelectionChange();
//}
// For now, don't allow for toggling between insert/overwrite mode - see
// comment on _OverWrite
e.Handled = true;
break;
case Keys.F5:
if (this.MyStepItem != null)
{
if (e.Shift)
{
e.Handled = true;
if (MyStepItem.MyStepPanel.MyStepTabPanel.MyDisplayTabControl.MyCopyStep == null) return;
MyStepItem.MyStepPanel.MyStepTabPanel.MyStepTabRibbon.ShortCutContextMenu("StepPaste");
}
else if (!e.Control && !e.Alt)
{
e.Handled = true;
this.MyStepItem.MyStepPanel.MyStepTabPanel.MyStepTabRibbon.DoCopyStep();
}
}
break;
case Keys.F6:
e.Handled = true;
SendKeys.Send("%H{ESC}");
break;
case Keys.Tab:
e.SuppressKeyPress = true;
e.Handled = true;
break;
case Keys.Enter:
if (!e.Control && !e.Shift && !e.Alt)
{
if (MyStepItem != null && !MyStepItem.MyItemInfo.IsTablePart)
{
e.Handled = true;
MyStepItem.MyStepPanel.MyStepTabPanel.MyStepTabRibbon.ProcessEnterKey();
}
}
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); // Replaced with an event
if (keyargs.Control) OnCursorKeyPress(this, keyargs);
}
private void StepRTB_PageKeyPressed(KeyEventArgs keyargs)
{
if (MyItemInfo.IsProcedure || MyItemInfo.IsSection) return;
//_MyStepItem.MyStepPanel.StepCursorKeys(this, keyargs); Replaced with an event
OnCursorKeyPress(this, keyargs);
}
public void StepRTB_ArrowPressed(E_ArrowKeys key)
{
Point cp = PointToClient(Cursor.Position);
//_MyStepItem.MyStepPanel.CursorMovement(this, cp, key); Replaced with an event
OnCursorMovement(this, new StepRTBCursorMovementEventArgs(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)
{
string strpressed = null;
if (e.KeyChar == '-')
strpressed = GetAddSymbolText(@"\u8209?");
else
strpressed = e.KeyChar.ToString();
if (e.KeyChar >= ' ')
{
LinkLocation ll = FindBetweenLinks();
if (ll != null && SelectionLength == 0) // SelectionLength = 0 means insert
{
if (e.KeyChar == '}')
strpressed = @"\}";
else if (e.KeyChar == '{')
strpressed = @"\{";
InsertCharBetweenLinks(ll, strpressed); // e.KeyChar);
e.Handled = true;
}
else if (SelectionLength != 0)
{
HandleDeleteKeyWithSelectedText(new KeyEventArgs(Keys.None), strpressed);
e.Handled = true;
}
}
if (!e.Handled)
{
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.
}
if (e.Handled && SelectionLength != 0) SelectionFont = MyStyleFont.WindowsFont;
}
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
public bool IsSelectionLinked(int index, int len)
{
if (_LinkLocations == null)return false;
int sel = index;
int selLength = len;
foreach (LinkLocation ll in _LinkLocations)
{
// When the selector moved to the right of a link, the GOTO button was still lit.
// Removing the "+7" seems to have fixed this. - jsj 1/08/2010
//if (sel >= ll.Start && sel < ll.Start + ll.Length + 7) return true;
if (sel >= ll.Start && sel < ll.Start + ll.Length) return true;
}
return false;
}
/// <summary>
/// For use in Find/Replace.
/// If text is found is part of the link information and not the link value,
/// then we want to continue searching.
/// </summary>
/// <param name="index"></param>
/// <param name="len"></param>
/// <returns></returns>
public bool SkipLinkInfo(int index, int len)
{
if (_LinkLocations == null)return false;
int sel = index;
int selLength = len;
foreach (LinkLocation ll in _LinkLocations)
{
if (sel >= ll.Start - 7 && sel < ll.Start + ll.Length)
{
int pos = ll.Text.IndexOf("#Link:");
if (sel < ll.Start || sel >= ll.Start-7+pos)
return (true);
}
}
return false;
}
#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>", RegexOptions.Singleline);
MatchCollection matchesRtf = Regex.Matches(Rtf, "<START](.*?)[[]END>", RegexOptions.Singleline);
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 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 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;
}
public DialogResult ReplaceText(string rpltxt, string fndstr, bool caseSensitive, bool matchWholeWord, bool reverse, bool prompt, IWin32Window fndrpldlg)
{
DialogResult dlgrslt = DialogResult.Yes;
if (SelectionLength > 0)
{
if (IsSelectionLinked(SelectionStart, SelectionLength))
{
MessageBox.Show(fndrpldlg,"Cannot replace linked text!", "Find/Replace");
dlgrslt = DialogResult.No;
}
else
{
if (prompt)
dlgrslt = MessageBox.Show(fndrpldlg,"Replace This Occurence?", "Replace Text", MessageBoxButtons.YesNoCancel);
if (dlgrslt == DialogResult.Yes)
SelectedText = rpltxt;
}
}
return dlgrslt;
}
private RichTextBoxFinds _FindOptions = RichTextBoxFinds.None;
public bool FindText(string str, bool caseSensitive, bool matchWholeWord, bool reverse)
{
StepRTB savRTF = new StepRTB();
int startpos = SelectionStart + SelectionLength;
savRTF.Text = this.Text;
_FindOptions = RichTextBoxFinds.None;
if (caseSensitive)
_FindOptions |= RichTextBoxFinds.MatchCase;
if (matchWholeWord)
_FindOptions |= RichTextBoxFinds.WholeWord;
if (reverse)
{
_FindOptions |= RichTextBoxFinds.Reverse;
savRTF.Text = this.Text.Substring(0, SelectionStart);
startpos = savRTF.Text.Length;
if (startpos == 0)
return false; // at beginning of rtfbox during a reverse find
}
else
{
if (startpos >= savRTF.Text.Length)
return false; // at end of rtfbox during a forward find
}
// look for the find string in the temporary rtfbox
// then set the cursor selection in the real rtfbox
bool keepgoing = true;
while (keepgoing)
{
int pos = savRTF.Find(str, startpos, _FindOptions);
keepgoing = false;
if (pos >= 0)
{
if (this.SkipLinkInfo(pos, str.Length))
{
if (reverse)
{
startpos--;
savRTF.Text = savRTF.Text.Substring(0, startpos);
}
else
startpos++;
if (startpos > 0 && startpos < savRTF.Text.Length)
keepgoing = true;
}
else
{
SelectionStart = pos;
SelectionLength = str.Length;
}
}
else
return false;
}
return true;
}
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()
{
foreach (LinkLocation ll in _LinkLocations)
{
if ((SelectionStart >= ll.Start) && (SelectionStart <= ll.End)) return ll.Start;
}
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;
public 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 OutlineTable
private string _CheckRight = "-\u2500\u2011";
public string CheckRight
{
get { return _CheckRight; }
set { _CheckRight = value; }
}
private string _CheckAbove = "|\u2502\u2514\u252c\u253c\u251c\u250c\u2534\u2510\u2524";
public string CheckAbove
{
get { return _CheckAbove; }
set { _CheckAbove = value; }
}
private string _CheckLeft = "-\u2500\u2524\u252c\u251c\u253c\u250c\u2510\u2514\u2011";
public string CheckLeft
{
get { return _CheckLeft; }
set { _CheckLeft = value; }
}
private string _CheckBelow = "|\u2502";
public string CheckBelow
{
get { return _CheckBelow; }
set { _CheckBelow = value; }
}
// This is a table of graphics characters
// The index into this table (0-15) is a bitmask with each bit representing
// a different direction from the current character.
// Right is Bit 0 (0 or 1)
// Above is Bit 1 (0 or 2)
// Left is Bit 2 (0 or 4)
// Below is Bit 3 (0 or 8)
// The index is contolled in the following way:
// If there is a graphics character to the right, then you add 1
// If there is a graphics character above, then you add 2
// If there is a graphics character left, then you add 4
// If there is a graphics character below, then you add 8
// The total results in an index into this array and gives the appropriate character
// combining horizontal and vertical lines.
static private string [] TableCharsU = {
"\x0", // HEX"\x0", // No character
@"\u9472", // HEX@"\u2500",// - Horizontal line - 16-bit char: '\xC4'
@"\u9474", // HEX@"\u2502",// | Vertical line - 16-bit char: '\xB3'
@"\u9492", // HEX@"\u2514",// L Bottom Left corner - 16-bit char: '\xC0'
@"\u9472", // HEX@"\u2500",// - Horizontal line - 16-bit char: '\xC4'
@"\u9472", // HEX@"\u2500",// - Horizontal line - 16-bit char: '\xC4'
@"\u9496", // HEX@"\u2518",// Bottom Right Corner - 16-bit char: '\xD9'
@"\u9524", // HEX@"\u2534",// Bottom Tee - 16-bit char: '\xC1'
@"\u9474", // HEX@"\u2502",// | Vertical Bar - 16-bit char: '\xB3'
@"\u9484", // HEX@"\u250c",// Upper Left corner - 16-bit char: '\xDA'
@"\u9474", // HEX@"\u2502",// | Vertical Bar - 16-bit char: '\xB3'
@"\u9500", // HEX@"\u251c",// Left Tee - 16-bit char: '\xC3'
@"\u9488", // HEX@"\u2510",// Upper Right corner - 16-bit char: '\xBF'
@"\u9516", // HEX@"\u252c",// T Top Tee - 16-bit char: '\xC2'
@"\u9508", // HEX@"\u2524",// Right Tee - 16-bit char: '\xB4'
@"\u9532", // HEX@"\u253c" // + Plus - 16-bit char: '\xC5'
};
private int MaxCharacterWidth()
{
// loop through lines and get the width in characters
int w = 0;
foreach (string line in Lines)
{
string cleanLine = RemoveLinkComments(line);
if (w < cleanLine.Length)
w = cleanLine.Length;
}
return w;
}
internal static string RemoveLinkComments(string line)
{
StringBuilder sb = new StringBuilder();
int lastIndex = 0;
MatchCollection mc = Regex.Matches(line, @"<START\](.*?)#Link.*?\[END>");
foreach (Match m in mc)
{
sb.Append(line.Substring(lastIndex, m.Index - lastIndex)); // Append text before the link
sb.Append(m.Groups[1].Value); // Append the text portion of the link
lastIndex = m.Index + m.Length; // Calculate the beginning of the remaining text
}
sb.Append(line.Substring(lastIndex)); // Append the text following the last link
string result = sb.ToString();
result = result.Replace(@"<START]", "");
MatchCollection mcEnd = Regex.Matches(result, @"#Link.*?\[END>");
if (mcEnd.Count > 0)
{
result = result.Substring(0, mcEnd[0].Index) + result.Substring(mcEnd[0].Index + mcEnd[0].Length);
}
return result;
}
private void ReplaceLinesInTable(bool withBorder)
{
int rowWidth = Lines[0].Length;
for (int row=1;row<Lines.Length-1;row++)
{
string line = Lines[row];
string lineAbove = RemoveLinkComments(Lines[row-1]);
string lineBelow = RemoveLinkComments(Lines[row+1]);
int rowOffset = GetFirstCharIndexFromLine(row);
MatchCollection matchCollection = Regex.Matches(line, @"<START\](.*?)#Link.*?\[END>"); //, RegexOptions.Singleline);
if (matchCollection.Count == 0) matchCollection = Regex.Matches(line, @"<START\]");
if (matchCollection.Count == 0) matchCollection = Regex.Matches(line, @"#Link.*?\[END>");
Match match = matchCollection.Count > 0 ? matchCollection[0] : null;
int matchOffset = 0;
for (int col = 1; col < rowWidth - 1; col++)
{
if (match != null && match.Index == matchOffset + col)
{
matchOffset += match.Length - match.Groups[1].Length; // Increment the offset by the link comment length
col += match.Groups[1].Length; // increment the column by the link value length
if (col >= rowWidth - 1) break;// Don't continue if beyond the contents
match = match.NextMatch(); // Watch for the next match
}
int coll = matchOffset + col;
char chr = line[coll];
char chrLast = line[coll - 1];
char chrNext = line[coll + 1];
char chrAbove = lineAbove[col];
char chrBelow = lineBelow[col];
// The following is all using symbol font (either unicode for proportional or
// VeSymbFix for fixed font):
// if this character is a table line draw character, i.e. a dash or vertical bar, or
// graphics characters for those, look around it to see what table character it is
// replaced with
// Look for -||-- (last three are graphics chars or unicode dash)
if ("-|\u2500\u2502\u2011".IndexOf(chr) > -1)
{
bool horizontalCharacter = "-\u2500\u2011".IndexOf(chr) > -1;
int lineDrawRight = (CheckRight.IndexOf(chrNext) > -1 || (horizontalCharacter && "\u2502".IndexOf(chrNext) > -1)) ? 1 : 0;
int lineDrawAbove = (CheckAbove.IndexOf(chrAbove) > -1 || (!horizontalCharacter && "\u2500\u2011".IndexOf(chrAbove) > -1)) ? 2 : 0;
int lineDrawLeft = (CheckLeft.IndexOf(chrLast) > -1 || (horizontalCharacter && "\u2502".IndexOf(chrLast) > -1)) ? 4 : 0;
int lineDrawBelow = (CheckBelow.IndexOf(chrBelow) > -1 || (!horizontalCharacter && "-\u2500\u2011".IndexOf(chrBelow) > -1)) ? 8 : 0;
int tableCharIndx = lineDrawRight + lineDrawAbove + lineDrawLeft + lineDrawBelow;
if (tableCharIndx > 0)
{
SetTableChar(row, coll, tableCharIndx);
if (withBorder) // Adjust the border as it intersects with lines within the box
{
if (row == 1 && !horizontalCharacter ) SetTableChar(row - 1, col, 13); // Top Row
if (row == Lines.Length - 2 && !horizontalCharacter) SetTableChar(row + 1, col, 7); // Bottom Row
if (col == 1 && horizontalCharacter && ((tableCharIndx & 4)==4)) SetTableChar(row, col - 1, 11); // First Column
if (col == rowWidth - 2 && horizontalCharacter && ((tableCharIndx & 1) == 1)) SetTableChar(row, coll + 1, 14); // Last Column
}
}
}
}
}
}
private void SetTableChar(int row, int col, int tableCharIndx)
{
int rowOffset = GetFirstCharIndexFromLine(row);
Select(rowOffset + col, 1);
string charToBeReplaced = SelectedText;
if (Text.Length > (rowOffset + col + 7) && Text.Substring(rowOffset + col + 1, 6) != "#Link:")
SelectedRtf = RtfPrefix + TableCharsU[tableCharIndx] + "?}";
else
{
SelectionStart++;
int lenComment = 1 + SelectionStart - (rowOffset + col);
//Console.WriteLine("{0},{1},{2}", rowOffset + col, SelectionStart, SelectionLength);
Select(rowOffset + col, 0);
SelectedRtf = RtfPrefix + TableCharsU[tableCharIndx] + "?}";
Select(rowOffset + col, lenComment);
//Console.WriteLine("'{0}',{1},{2},{3}", SelectedText, lenComment, SelectionLength, SelectionStart);
//Console.WriteLine("'{0}'", SelectedRtf);
SelectedRtf = SelectedRtf.Replace(" " + charToBeReplaced, "");
}
}
#endregion
#region SpellChecker
// We made the Spell Checker method a static so that all of the StepRTB boxes will sbare the same instace of the dictionary.
// This allow all the StepRTB's to automatically update when a new word is added.
private static C1.Win.C1SpellChecker.C1SpellChecker _C1SpellChecker2;
private static C1.Win.C1SpellChecker.C1SpellChecker C1SpellChecker2
{
get
{
if (_C1SpellChecker2 == null)
{
_C1SpellChecker2 = new C1.Win.C1SpellChecker.C1SpellChecker();
_C1SpellChecker2.ContextMenuCreated += new C1.Win.C1SpellChecker.ContextMenuEventHandler(_C1SpellChecker2_ContextMenuCreated);
//_C1SpellChecker2.UserDictionary.FileName = @"C:\Development\proms\VEPROMS User Interface\bin\Debug\MYDictionary.dct";
}
return StepRTB._C1SpellChecker2;
}
}
// Get or Save our context menu
// This is added to the the spell checker's context menu for a mis-spelled word
private static ContextMenuStrip _ThisContextMenuStrip;
public ContextMenuStrip ThisContextMenuStrip
{
get { return _ThisContextMenuStrip; }
set { _ThisContextMenuStrip = value; }
}
private static StepRTB _ContextMenuStepRTB;
private static object _ContextMenuStrip;
static void _C1SpellChecker2_ContextMenuCreated(object sender, C1.Win.C1SpellChecker.ContextMenuEventArgs e)
{
// Adjust their bad word context menu
//Console.WriteLine("==========> spell check context menu {0}",e.Menu.Items[0].Text);
if (e.Menu.Equals(_ContextMenuStrip))
{
// Add an item for our "Edit Menu" context menu on their spell check context menu
// This gives the user access to our regular context menu when on a mis-spelled word
ToolStripItem tsi = e.Menu.Items.Add("Edit Menu");
tsi.Click += new EventHandler(tsi_Click);
//Now replace their "Spell" item with ours, so that we can display our custom spell check dialog
for (int i = 0; i < e.Menu.Items.Count; i++)
{
ToolStripItem tsi1 = e.Menu.Items[i];
if (tsi1 is ToolStripMenuItem && tsi1.Text == "Spell")
{
e.Menu.Items.RemoveAt(i); // remove their spell check dialog item
ToolStripMenuItem tsi2 = new ToolStripMenuItem("Spell");
tsi2.Click += new EventHandler(tsi2_Click);
e.Menu.Items.Insert(i, tsi2); // add our spell check dialog item
}
}
}
}
static void tsi2_Click(object sender, EventArgs e)
{
C1SpellChecker2.CheckControl(_ContextMenuStepRTB, true, MySpellCheckDlg);
}
// Click event to display our "Edit Menu" (StepRTB context menu)
static void tsi_Click(object sender, EventArgs e)
{
ToolStripMenuItem tsmi = sender as ToolStripMenuItem;
_ContextMenuStepRTB.MyStepItem.MyStepPanel.MyStepTabPanel.MyStepTabRibbon.OpenContextMenu(tsmi.Owner.Location);
}
// This is our customized Spell Check dialog
// This is display when the use clicks the Spell button from the Ribbon
// or when the "Spell" item is selected from the context menu when on a mis-spelled word
static VlnSpellCheckDlg _MySpellCheckDlg;
public static VlnSpellCheckDlg MySpellCheckDlg
{
get
{
if (_MySpellCheckDlg == null)
_MySpellCheckDlg = new VlnSpellCheckDlg();
return _MySpellCheckDlg;
}
}
// This is used when walking through the section doing a spell check
// (from the Spell button on the ribbon)
public bool SpellCheckNext()
{
int nBad = C1SpellChecker2.CheckControl(this, false, MySpellCheckDlg);
return (nBad >= 0); // nBad = -1 means user pressed Cancel button
}
#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
private void StepRTB_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
//Console.WriteLine("StepRTB_PreviewKeyDown");
if ((e.KeyCode == Keys.Tab) && (!e.Alt && !e.Control))
e.IsInputKey = true;
}
}
public partial class StepRTBModeChangeEventArgs : EventArgs
{
private E_ViewMode _ViewMode;
public E_ViewMode ViewMode
{
get { return _ViewMode; }
set { _ViewMode = value; }
}
public StepRTBModeChangeEventArgs(E_ViewMode vmode)
{
_ViewMode = vmode;
}
}
public class StepRTBCursorMovementEventArgs
{
private Point _CursorLocation;
public Point CursorLocation
{
get { return _CursorLocation; }
set { _CursorLocation = value; }
}
private E_ArrowKeys _Key;
public E_ArrowKeys Key
{
get { return _Key; }
set { _Key = value; }
}
public StepRTBCursorMovementEventArgs(Point pt, E_ArrowKeys key)
{
_CursorLocation = pt;
_Key = key;
}
}
#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);
}
// #region ClipboardHandler
// private const int WM_CUT = 0x0300;
// private const int WM_COPY = 0x0301;
// private const int WM_PASTE = 0x0302;
// public delegate void ClipboardEventHandler(object sender, ClipboardEventArgs e);
// [Category("Clipboard")]
// public event ClipboardEventHandler CutText;
// [Category("Clipboard")]
// public event ClipboardEventHandler CopiedText;
// [Category("Clipboard")]
// public event ClipboardEventHandler PastedText;
// protected override void WndProc(ref Message m)
// {
// if (m.Msg == WM_CUT)
// {
// if (CutText != null)
// CutText(this, new ClipboardEventArgs(this.SelectedText));
// }
// else if (m.Msg == WM_COPY)
// {
// if (CopiedText != null)
// CopiedText(this, new ClipboardEventArgs(this.SelectedText));
// }
// else if (m.Msg == WM_PASTE)
// {
// if (PastedText != null)
// PastedText(this, new ClipboardEventArgs(Clipboard.GetText()));
// }
// base.WndProc(ref m);
// }
//}
//public class ClipboardEventArgs : EventArgs
//{
// private string clipboardText;
// public string ClipboardText
// {
// get
// {
// return clipboardText;
// }
// set
// {
// clipboardText = value;
// }
// }
// public ClipboardEventArgs(string clipboardText)
// {
// this.clipboardText = clipboardText;
// }
// #endregion
}
#endregion
}