From 509b79481a362c7297dde0fe50d87515bee38ece Mon Sep 17 00:00:00 2001 From: Kathy Date: Wed, 8 Jul 2009 10:55:05 +0000 Subject: [PATCH] --- .../Volian.Controls.Library/DisplaySearch.cs | 2 +- PROMS/Volian.Controls.Library/DisplayTags.cs | 1 + PROMS/Volian.Controls.Library/DisplayText.cs | 316 +++---- PROMS/Volian.Controls.Library/LinkText.cs | 115 +++ PROMS/Volian.Controls.Library/StepRTB.cs | 798 +++++++++++------- 5 files changed, 741 insertions(+), 491 deletions(-) create mode 100644 PROMS/Volian.Controls.Library/LinkText.cs diff --git a/PROMS/Volian.Controls.Library/DisplaySearch.cs b/PROMS/Volian.Controls.Library/DisplaySearch.cs index b3d53240..22b274c1 100644 --- a/PROMS/Volian.Controls.Library/DisplaySearch.cs +++ b/PROMS/Volian.Controls.Library/DisplaySearch.cs @@ -1136,7 +1136,7 @@ namespace Volian.Controls.Library // to name button use unicode rather than desc, desc may have spaces or odd chars btnCM.Name = "btnCM" + sym.Unicode.ToString(); btnCM.Tooltip = sym.Desc; - btnCM.Tag = string.Format(@"\u{0}", sym.Unicode); + btnCM.Tag = string.Format(@"{0}", sym.Unicode); btnCM.FontBold = true; btnCM.Click += new System.EventHandler(btnSym_Click); galSymbols.SubItems.Add(btnCM); diff --git a/PROMS/Volian.Controls.Library/DisplayTags.cs b/PROMS/Volian.Controls.Library/DisplayTags.cs index f45d3ba5..62dad797 100644 --- a/PROMS/Volian.Controls.Library/DisplayTags.cs +++ b/PROMS/Volian.Controls.Library/DisplayTags.cs @@ -189,6 +189,7 @@ namespace Volian.Controls.Library } else { + _MyStepTypeInd.Clear(); foreach (StepDataRetval sdr in sdl) { listBoxStepTypes.Items.Add(sdr.Name); diff --git a/PROMS/Volian.Controls.Library/DisplayText.cs b/PROMS/Volian.Controls.Library/DisplayText.cs index c585c21b..0b0adad8 100644 --- a/PROMS/Volian.Controls.Library/DisplayText.cs +++ b/PROMS/Volian.Controls.Library/DisplayText.cs @@ -33,24 +33,24 @@ namespace VEPROMS.CSLA.Library get { return _textFont; } set { _textFont = value; } } + public string StartText; public string OriginalText; // compare for save to see if change. - public string OriginalConfigText; private FormatInfo _MyFormat; #endregion #region Constructors /// /// DisplayText constructor: - /// Creates a DisplayText object that converts the database text into a list of - /// displayTextElement elements. + /// Creates a DisplayText object that converts the database text into rtf text /// Arguments are: /// ItemInfo itemInfo - the item whose text will be resolved /// E_EditPrintMode ep_mode - edit or print. /// E_ViewMode vw_mode - view or edit. + /// bool noEdit - flags whether to edit or not (used to set data in + /// rtb as resolved replacewords for non-active rtb. /// public DisplayText(ItemInfo itemInfo, E_EditPrintMode epMode, E_ViewMode vwMode, bool noEdit) { _MyItemInfo = itemInfo; - DisplayTextElementList = new List(); OriginalText = itemInfo.MyContent.Text; TextFont = GetItemFont(); string text = _MyItemInfo.MyContent.Text; @@ -63,33 +63,47 @@ namespace VEPROMS.CSLA.Library // adjust formatting of exponents if (!_MyFormat.PlantFormat.FormatData.SectData.StepSectionData.FortranFormatNumbers && (epMode == E_EditPrintMode.Print || vwMode == E_ViewMode.View || noEdit)) text = DoFortranFormat(text); - // as a precaution, convert any \~ to \u160?. This is for Hard spaces.. see the commentary in the + // as a precaution, convert any \~ to \u160?. This is for Hard spaces. see the commentary in the // save portion of this code for an explanation. text = text.Replace(@"\~", @"\u160?"); text = text.Replace(@"\r\n", @"\par "); - // replace the dash/hyphen or whatever you want to call it, with a hard hyphen. The 16-bit program - // treated the dash/hyphen as such. Translate back on any data saves. - if (itemInfo.ItemID == 1275) - Console.WriteLine("here"); - // text = text.Replace(@"-", @"\u8209?"); - // displayTextElement List items are created for anything that is handled differently in RTB, i.e. - // symbols, ros, trans, text. - int startIndex = 0; - int index = -1; - while ((index = FindTokenChar(text, startIndex))>-1) + text = text.Replace(@"\line", @"\par"); + + // add colors around links: + text = Regex.Replace(text, @"( startIndex) DoTextElement(text, startIndex, index); - if (text[index + 1] == 'v') - index = DoLink(text, index); - else - index = DoSymbol(text, startIndex, index); - startIndex = index; // +1; - if (startIndex >= text.Length) break; + int indxend = text.IndexOf(@"\v", indxcf); + text = text.Insert(indxend, @"\cf0 "); + indxcf = text.IndexOf(@"cf1", indxend); } - // Add any remaining text. - if (startIndex < text.Length) DoTextElement(text, startIndex, index); + + // Now put symbol (for fixed fonts) or unicode font (proportional) around symbols + // These fonts are VESymbFix & Arial Unicode MS respectively, and the font table + // is actually defined in the StepRTB code. + int indxsym = text.IndexOf(@"\u"); + while (indxsym != -1) + { + int incrindx = 3; + if (text[indxsym + 2] != 'l') + { + text = text.Insert(indxsym, @"\f1 "); + int indxendsym = text.IndexOfAny(@"\ ?".ToCharArray(),indxsym+5); + if (indxendsym == -1) // must be end of line: + text = text.Insert(text.Length-1,@"\f0 "); + else + { + if (text[indxendsym]=='?') indxendsym++; + text = text.Insert(indxendsym, @"\f0 "); // TODO: do I need a space?? + } + incrindx = 5; + } + indxsym = text.IndexOf(@"\u",indxsym + incrindx); + } + StartText = text; } private string DoFortranFormat(string text) @@ -117,38 +131,60 @@ namespace VEPROMS.CSLA.Library { try { - List origList = GetLinkList(DisplayTextElementList); - // massage string to store in DisplayTextElementList... - RtfToDisplayTextElements(rtb); - // take the list & convert to data in the format to save to the database. - string modtext = DteToString(); + Item itm = _MyItemInfo.Get(); + // check for different text, i.e. text from this itm doesn't match + // original text, a change occurred in database, but not from this user. + if (OriginalText != itm.MyContent.Text) + { + Console.WriteLine("Save Failed because text changed outside of this edit session."); + return false; + } + + // remove rtf codes that aren't defining attributes, symbols, or links + string modtext = RtfToDbText(rtb.Rtf); if (modtext != OriginalText) { - Item itm = _MyItemInfo.Get(); - // check for different text, i.e. text from this itm doesn't match - // original text. - if (OriginalText != itm.MyContent.Text) + // if there are links, we'll need to do extra processing to see if + // there were additions, deletions or modifications. + bool haslinks = ((modtext.IndexOf(@" -1) || (OriginalText != null && OriginalText != "" && OriginalText.IndexOf(@" -1)); + if (haslinks) { - Console.WriteLine("Save Failed because text changed outside of this edit session."); - return false; + // Get all links in original list + RtfToDisplayTextElements(OriginalText); + List origList = GetLinkList(DisplayTextElementList); + // now get new text into displaytext elements for comparison for links: + RtfToDisplayTextElements(rtb.Rtf); + + // Compare ro/transition lists and delete or add any to the item for any ros/transitions that have been + // added/deleted or modified. + ProcessRoTranChanges(itm, origList); + itm.MyContent.Text = DteToString(); } - // Compare ro/transition lists and delete or add any to the item for any ros/transitions that have been - // added/deleted or modified. - ProcessRoTranChanges(itm, origList); - itm.MyContent.Text = DteToString(); - Dictionary ctReplacements = BuildCtReplacements(itm.MyContent.ContentTransitions); - Dictionary roUsgReplacements = BuildRoUsgReplacements(itm.MyContent.ContentRoUsages); - itm.Save(); - if (ctReplacements.Count > 0) + else { - itm.MyContent.Text = FixCtReplacements(itm.MyContent.Text, ctReplacements); + itm.MyContent.Text = modtext; itm.Save(); } - if (roUsgReplacements.Count > 0) + + if (haslinks) { - itm.MyContent.Text = FixRoUsgReplacements(itm.MyContent.Text, roUsgReplacements); + // if new transitions/ros, we need to 'fix' the string in the embedded link to contain the + // transition or usage record. + Dictionary ctReplacements = BuildCtReplacements(itm.MyContent.ContentTransitions); + Dictionary roUsgReplacements = BuildRoUsgReplacements(itm.MyContent.ContentRoUsages); itm.Save(); + if (ctReplacements.Count > 0) + { + itm.MyContent.Text = FixCtReplacements(itm.MyContent.Text, ctReplacements); + itm.Save(); + } + if (roUsgReplacements.Count > 0) + { + itm.MyContent.Text = FixRoUsgReplacements(itm.MyContent.Text, roUsgReplacements); + itm.Save(); + } + modtext = itm.MyContent.Text; } OriginalText = modtext; } @@ -162,7 +198,6 @@ namespace VEPROMS.CSLA.Library } return true; } - private string DteToString() { StringBuilder sret = new StringBuilder(); @@ -187,7 +222,6 @@ namespace VEPROMS.CSLA.Library } return p; } - private Dictionary BuildRoUsgReplacements(ContentRoUsages contentRoUsages) { Dictionary retval = new Dictionary(); @@ -205,7 +239,6 @@ namespace VEPROMS.CSLA.Library } return p; } - private Dictionary BuildCtReplacements(ContentTransitions contentTransitions) { Dictionary retval = new Dictionary(); @@ -356,35 +389,18 @@ namespace VEPROMS.CSLA.Library } return retList; } - private void RtfToDisplayTextElements(RichTextBox rtb) + private void RtfToDisplayTextElements(string text) { - // For hardspaces, the windows richtextbox does some 'quirky' things: - // A unicode representation of \u160? is sent INTO the rtb. Coming out, - // that \u160? was translated to a \~ (by the underlying windows rtb). - // Note that if the \~ is sent to the rtb, it is treated as a regular space, - // i.e. no longer a hardspace, and actually is converted to a regular space. - // SO, on the way out, convert any \~ to \u160? - string noExtraRtfStr = rtb.Rtf.Replace(@"\~", @"\u160?"); + // get original text into displaytext elements for comparison for links: + if (DisplayTextElementList == null) + DisplayTextElementList = new List(); + else + DisplayTextElementList.Clear(); - // Check for two links in a row & if found, add separating rtf comment - // commands (these get removed in the richtextbox: - noExtraRtfStr = noExtraRtfStr.Replace(@"[END>\v0 \v -1) @@ -402,56 +418,31 @@ namespace VEPROMS.CSLA.Library // Add any remaining text. if (startIndex < noExtraRtfStr.Length) DoTextElement(noExtraRtfStr, startIndex, index); } - private int SaveTextElement(string data, int startIndex, int index) + private string RtfToDbText(string text) { - displayTextElement vte = new displayTextElement(); - vte.Type = E_TextElementType.Text; - int len = (index == -1) ? data.Length - startIndex : index - startIndex; - vte.Text = data.Substring(startIndex, len); - DisplayTextElementList.Add(vte); - return index; - } - private int SaveSymbolTE(string data, int startIndex) - { - displayLinkElement vte = new displayLinkElement(); - vte.Type = E_TextElementType.Symbol; - // symbols are just the unicode/rtf command, no font associated with it - // by the time it gets here... A symbol can be represented by \'xy or \uxyz? - // if the \'xy is used the length of the symbol number will always be two, - // otherwise find the index of the '?' to find the end. - int endindx = -1; - if (data[startIndex + 1] == '\'') endindx = startIndex + 3; - else endindx = data.IndexOf("?", startIndex); - if (endindx == -1) return startIndex; // not found - error - vte.Text = data.Substring(startIndex, endindx - startIndex + 1); - DisplayTextElementList.Add(vte); - if (endindx+1(); - // return unicode (symbol) font number, if it exists, to expedite finding - // the font for symbols. - int unicodeFont = -1; - int bindx = rtf.IndexOf(@"{\fonttbl"); - if (bindx < -1) return -1; - int eindx = rtf.IndexOf("}}", bindx); - // get font table string and then do regular expressions to get font number - // with font name. - string tbl = rtf.Substring(bindx + 9, eindx - bindx - 8); - tbl = tbl.Replace("{", "<"); - tbl = tbl.Replace("}", ">"); - string pat = @"(?:<\\f)([0-9]+)(?:[\S]+ )([\w ]+)"; - StringBuilder sb = new StringBuilder(); - foreach (Match m in Regex.Matches(tbl, pat)) - { - int num = Convert.ToInt32(m.Result("${1}")); - string nam = m.Result("${2}"); - dicRtfFontTable.Add(num, nam); - if ((unicodeFont == -1) && (nam == "Arial Unicode MS")) unicodeFont = num; - } - return unicodeFont; + // For hardspaces, the windows richtextbox does some 'quirky' things: + // A unicode representation of \u160? is sent INTO the rtb. Coming out, + // that \u160? was translated to a \~ (by the underlying windows rtb). + // Note that if the \~ is sent to the rtb, it is treated as a regular space, + // i.e. no longer a hardspace, and actually is converted to a regular space. + // SO, on the way out, convert any \~ to \u160? + string noExtraRtfStr = text.Replace(@"\~", @"\u160?"); + + // Check for two links in a row & if found, add separating rtf comment + // commands (these get removed in the richtextbox: + noExtraRtfStr = noExtraRtfStr.Replace(@"[END>\v0 \v -1) noExtraRtfStr = noExtraRtfStr.Replace(@"\'05", "\x05"); + + return noExtraRtfStr; } private string RemoveRtfStyles(string rtf) { @@ -524,11 +515,12 @@ namespace VEPROMS.CSLA.Library if (m.Value == @"\line") return m.Value; break; case 'p': - if (m.Value == @"\par") return "\r\n"; + if (m.Value == @"\par") return @"\par"; //if (m.Value == @"\protect") // return m.Value; //if (m.Value == @"\protect0") // return m.Value; + if (m.Value.Length>=6 && m.Value.Substring(0,6) == "\\par\r\n") return m.Value.Replace("\r\n", " "); break; case 'f': // handle fonts separately because they may or may not have a space after them if (m.Value[2]>='0' && m.Value[2]<='9')return m.Value; @@ -542,6 +534,12 @@ namespace VEPROMS.CSLA.Library // are rtf so were getting removed and/or not handled correctly. string retval = rtf.Replace(@"\{", @"(!["); retval = retval.Replace(@"\}", @"(!]"); + + // remove carriage return/newlines after \par commands (these are introduced by rtb + // for hard returns, goes into rtb as \par and comes out as \par\r\n): + retval = Regex.Replace(retval, @"\\par\r\n([^\\.*?])", "\\par $1"); + retval = Regex.Replace(retval, @"\\par\r\n([\\.*?])", "\\par$1"); + retval = Regex.Replace(retval, @"[\r\n]", "", RegexOptions.Singleline); // Strip Carriage Returns and Newlines retval = Regex.Replace(retval, @"^\{(.*)\}$", "$1", RegexOptions.Singleline); // Strip Opening and Closing Braces retval = Regex.Replace(retval, @"\{[^{]*?\}", "", RegexOptions.Singleline); // Strip Clauses - remove anything from curly braces @@ -549,10 +547,13 @@ namespace VEPROMS.CSLA.Library retval = Regex.Replace(retval, @"\\f[0-9] ", ""); // remove font command with ending space retval = Regex.Replace(retval, @"\\f[0-9]", ""); // remove font command without ending space retval = Regex.Replace(retval, @"\\[^ \\?]+", new MatchEvaluator(ReplaceRTFClause)); // take backslash xyz and evaluates them - // remove a space if there is one as the first character.. + // remove a space if there is one as the first character or the last character if (retval[0]==' ')retval = retval.Remove(0, 1); - // remove \r\n at end of string - this was added with the \par at the end of string by the rtf box + retval = retval.TrimEnd(' '); + // remove \r\n and \par at end of string. if (retval.Substring(retval.Length - 2, 2) == "\r\n") retval = retval.Remove(retval.Length - 2, 2); + if (retval.Substring(retval.Length - 4, 4) == @"\par") retval = retval.Remove(retval.Length - 4, 4); + if (retval.Length == 0) return ""; if (retval.Substring(retval.Length - 2, 2) == @"\v") retval = retval.Remove(retval.Length - 2, 2); retval = RemoveRtfStyles(retval); @@ -592,16 +593,6 @@ namespace VEPROMS.CSLA.Library bool done = false; while (!done) { - // There were two links in a row, very special case, handle here... - //if (TwoLinksInARow) - //{ - // int tindx = txt.IndexOf(" 0) - // { - // TwoLinksInARow = false; - // return tindx; - // } - //} int indx = txt.IndexOf('\\', startIndex); if (indx < 0) return indx; // see if symbol (but not underline) or another rtf command: has a 'u' @@ -623,18 +614,6 @@ namespace VEPROMS.CSLA.Library DisplayTextElementList.Add(vte); return index+1; } - private string CreateLink(E_TextElementType type, string linktxt) - { - string retlink = ""; - if (type == E_TextElementType.ReferencedObject) - retlink = "#Link:ReferencedObject:" + linktxt; - else if (type == E_TextElementType.Transition) - retlink = "#Link:Transition:" + linktxt; - else - retlink = "#Link:TransitionRange:" + linktxt; - - return retlink; - } private int DoLink(string text, int startIndex) { int retval = -1; @@ -645,7 +624,6 @@ namespace VEPROMS.CSLA.Library retval = DoTran(text, startIndex); return retval; } - //bool TwoLinksInARow = false; private int DoRO(string text, int index) { displayLinkElement vte = new displayLinkElement(); @@ -677,7 +655,6 @@ namespace VEPROMS.CSLA.Library vte.Type = (text[linkindx+16]=='R')?E_TextElementType.TransitionRange:E_TextElementType.Transition; return DoLinkElements(text, index, vte); } - private int DoLinkElements(string text, int index, displayLinkElement vte) { // Find the 'end comment' for the ", endLinkIndx + 3); // get past end of link int endComment = text.IndexOf(@"\v0", endToken); - //// if the above is at end of string, don't bother with looking for another - //// startToken) // don't worry about two links in a row.... - //{ - int retlen = 4; - if (endComment + 3 == text.Length) retlen = 3; - else if (text[endComment + 3] == '\\') retlen = 3; - vte.TextAndLink = text.Substring(index, endComment - index + retlen); - rettoken = endComment + retlen; - - //} - //else - //{ - // TwoLinksInARow = true; - // vte.TextAndLink = text.Substring(index, startToken - index) + @"\v0 "; - // rettoken = endComment + 5; // 5 for "\v0 " - //} + int retlen = 4; + if (endComment + 3 == text.Length) retlen = 3; + else if (text[endComment + 3] == '\\') retlen = 3; + vte.TextAndLink = text.Substring(index, endComment - index + retlen); + rettoken = endComment + retlen; if (vte.Type != E_TextElementType.ReferencedObject) vte.TextAndLink = vte.TextAndLink = vte.TextAndLink.Replace("(Resolved Transition Text)", tmptxt); DisplayTextElementList.Add(vte); return rettoken; @@ -751,12 +713,12 @@ namespace VEPROMS.CSLA.Library #endregion #region ReplaceWords private ReplaceStr _rs; - private string ReplaceIt(Match m) - { - string s = m.ToString(); - string t = s.Replace(_rs.ReplaceWord, _rs.ReplaceWith); - return m.ToString().Replace(_rs.ReplaceWord, _rs.ReplaceWith); - } + //private string ReplaceIt(Match m) + //{ + // string s = m.ToString(); + // string t = s.Replace(_rs.ReplaceWord, _rs.ReplaceWith); + // return m.ToString().Replace(_rs.ReplaceWord, _rs.ReplaceWith); + //} private string DoReplaceWords(string Text) { ReplaceStrList rsl = _MyFormat.PlantFormat.FormatData.SectData.ReplaceStrList; diff --git a/PROMS/Volian.Controls.Library/LinkText.cs b/PROMS/Volian.Controls.Library/LinkText.cs new file mode 100644 index 00000000..a168a31f --- /dev/null +++ b/PROMS/Volian.Controls.Library/LinkText.cs @@ -0,0 +1,115 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Text.RegularExpressions; +namespace VEPROMS.CSLA.Library +{ + public partial class LinkText + { + public LinkText(string linkInfoText) + { + _LinkInfoText = linkInfoText; + } + public void ParseLink() + { + if (_MyParsedLinkType == ParsedLinkType.NotParsed) + { + if (_LinkInfoText == null) return; + // First parse the string + _LinkInfoText = _LinkInfoText.Replace(@"\v ", ""); + // for tran : "2, #, #, # and 4#Link:TransitionRange:2 10 173 166" + Match m = Regex.Match(_LinkInfoText, @"(.*)[#]Link:([A-Za-z]*):(.*)"); + _MyValue = m.Groups[1].Value; + _MyLink = "#Link:" + m.Groups[2].Value + ":" + m.Groups[3].Value; + switch (m.Groups[2].Value) + { + case "ReferencedObject": + _MyParsedLinkType = ParsedLinkType.ReferencedObject; + string[] subs = m.Groups[3].Value.Split(" ".ToCharArray()); + if (subs[0] == "") + _MyRoUsageInfo = null; + else + { + int roUsageid = Convert.ToInt32(subs[0]); + _MyRoUsageInfo = RoUsageInfo.Get(roUsageid); + } + break; + case "Transition": + case "TransitionRange": + _MyParsedLinkType = (ParsedLinkType)Enum.Parse(_MyParsedLinkType.GetType(), m.Groups[2].Value); + if (m.Groups[3].Value.Split(" ".ToCharArray())[1] == "") + _MyTransitionInfo = null; + else + { + int transitionID = Convert.ToInt32(m.Groups[3].Value.Split(" ".ToCharArray())[1]); + _MyTransitionInfo = TransitionInfo.Get(transitionID); + } + break; + } + } + } + private string _LinkInfoText; + public string LinkInfoText + { + get { return _LinkInfoText; } + } + private TransitionInfo _MyTransitionInfo = null; + public TransitionInfo MyTransitionInfo + { + get { ParseLink(); return _MyTransitionInfo; } + } + public ItemInfo MyTranToItemInfo + { + get { ParseLink(); return _MyTransitionInfo.MyItemToID; } + } + public ItemInfo MyTranRangeItemInfo + { + get { ParseLink(); return _MyTransitionInfo.MyItemRangeID; } + } + private string _MyValue = null; + //public string MyValue + //{ + // get { ParseLink(); return _MyValue; } + //} + private string _MyLink = null; + //public string MyLink + //{ + // get { ParseLink(); return _MyLink; } + //} + private RoUsageInfo _MyRoUsageInfo; + public RoUsageInfo MyRoUsageInfo + { + get { ParseLink(); return _MyRoUsageInfo; } + } + //private string _Roid = null; // TODO: need to return Referenced Object rather than just roid + //public string Roid + //{ + // get { ParseLink(); return _Roid; } + //} + //private string _RoUsageid = null; // TODO: need to return Referenced Object rather than just roid + //public string RoUsageid + //{ + // get { ParseLink(); return _RoUsageid; } + //} + //private string _RoDbid = null; // TODO: need to return Referenced Object rather than just roid + //public string RoDbid + //{ + // get { ParseLink(); return _RoDbid; } + //} + private ParsedLinkType _MyParsedLinkType = ParsedLinkType.NotParsed; + //public ParsedLinkType MyParsedLinkType + //{ + // get { ParseLink(); return _MyParsedLinkType; } + //} + + } + #region enums + public enum ParsedLinkType : int + { + NotParsed = 0, + Transition = 1, + TransitionRange = 2, + ReferencedObject = 3 + } + #endregion +} diff --git a/PROMS/Volian.Controls.Library/StepRTB.cs b/PROMS/Volian.Controls.Library/StepRTB.cs index 75e59f90..d3ccdec3 100644 --- a/PROMS/Volian.Controls.Library/StepRTB.cs +++ b/PROMS/Volian.Controls.Library/StepRTB.cs @@ -77,6 +77,14 @@ namespace Volian.Controls.Library // return prams; // } //} + 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 { @@ -146,13 +154,37 @@ namespace Volian.Controls.Library // 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); + AddRtfText(vlntxt.StartText); AddRtfStyles(); ReadOnly = !(EpMode == E_EditPrintMode.Edit && VwMode == E_ViewMode.Edit); _InitializingRTB = false; _IsDirty = false; ClearUndo(); RightMargin = Width; + // figure out if needs outlined, depends on table/figure type + if (!edit) + { + RemoveEventHandlers(); + if (_MyItemInfo.IsTable || _MyItemInfo.IsFigure) + { + int typ = ((int)_MyItemInfo.MyContent.Type) % 10000; + OutlineTable(_MyItemInfo.ActiveFormat.PlantFormat.FormatData.StepDataList[typ].Type.IndexOf(@"Borderless")<0); + FindAllLinks(); + AdjustSizeForContents(); // TODO: this is not quite right yet. + } + SelectAll(); + 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(); + } _MyItemInfo.MyConfig.PropertyChanged += new PropertyChangedEventHandler(MyConfig_PropertyChanged); } private bool _ProcessKeystrokes = true; @@ -223,31 +255,22 @@ namespace Volian.Controls.Library get { return _MyLinkText; } set { - if (value != _MyLinkText) - { + //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 - /// - /// 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. - /// public StepRTB() { InitializeComponent(); SetUp(); + AddEventHandlers(); } public StepRTB(IContainer container) { @@ -255,20 +278,31 @@ namespace Volian.Controls.Library InitializeComponent(); _Container = container; SetUp(); + AddEventHandlers(); } //protected override void OnMouseWheel(MouseEventArgs e) //{ - // //_MyStepItem.MyStepPanel.MouseWheel(e); - // OnMouseWheel(this,e); - // //base.OnMouseWheel(e); + // _MyStepItem.MyStepPanel.MouseWheel(e); + // //base.OnMouseWheel(e); //} - private void SetUp() + 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.ScrollBars = RichTextBoxScrollBars.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); @@ -276,8 +310,24 @@ namespace Volian.Controls.Library 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 SetUp() + { + 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(); @@ -323,44 +373,35 @@ namespace Volian.Controls.Library { 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); + } public void SetSelectedCase(char type) { - // do not change link text + // do not change case on linked text RangeStatus rs = FindRangeStatus(); + string tmp = null; if (rs == RangeStatus.NoContainedLinks) - { - Console.WriteLine("Text = {0}, Rtf = {1}", Text, Rtf); - Console.WriteLine("SelectedRtf = {0}", SelectedRtf); - switch (type) - { - case 'l': - string tmp=null; - for (int i = 0; i < SelectionLength; i++) - { - char x = SelectedText[i]; - if (Char.IsLetter(x)) - { - Console.WriteLine("isletter: {0}", x); - x = char.ToLower(x); - } - tmp = string.Format("{0}{1}", tmp, x.ToString()); - } - Console.WriteLine("Tolower: text = {0}", tmp); - SelectedText = tmp; - Console.WriteLine("Text = {0}, Rtf = {1}", Text, Rtf); - break; - case 'U': - SelectedText = SelectedText.ToUpper(); - break; - case 'T': - SelectedText = SelectedText.Substring(0, 1).ToUpper() + SelectedText.Substring(1, SelectedText.Length - 1).ToLower(); - break; - } - } + SetCase(type); else { int start = SelectionStart; @@ -379,20 +420,8 @@ namespace Volian.Controls.Library { SelectionStart = start; SelectionLength = ll.Start - start; - switch (type) - { - case 'l': - SelectedText = SelectedText.ToLower(); - break; - case 'U': - SelectedText = SelectedText.ToUpper(); - break; - case 'T': - sb.Append(Text.Substring(start, ll.Start - start).Substring(0, 1).ToUpper() + SelectedText.Substring(1, SelectedText.Length - 1).ToLower()); - break; - } + SetCase(type); } - //sb.Append(Text.Substring(ll.Start, ll.End - ll.Start)); start = ll.End + 1; break; } @@ -402,27 +431,51 @@ namespace Volian.Controls.Library { SelectionStart = start; SelectionLength = end-start; - switch (type) - { - case 'l': - SelectedText = SelectedText.ToLower(); - break; - case 'U': - SelectedText = SelectedText.ToUpper(); - break; - case 'T': - //sb.Append(Text.Substring(start, ll.Start - start).Substring(0, 1).ToUpper() + SelectedText.Substring(1, SelectedText.Length - 1).ToLower()); - break; - } + SetCase(type); start = end + 1; } } SelectionStart = ostart; SelectionLength = end - ostart; - //SelectedText = sb.ToString(); - //FindAllLinks(); } } + + 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() @@ -450,18 +503,11 @@ namespace Volian.Controls.Library } #endregion #region AddRtfTextAndStyles - private void AddRtfText(DisplayText myDisplayText) + private void AddRtfText(string txt) { 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); - } + _RtfPrefix = _SelectedRtfSB.ToString(); + _SelectedRtfSB.Append(txt); SelectedRtf = _SelectedRtfSB.ToString() + "}"; FindAllLinks(); } @@ -486,14 +532,22 @@ namespace Volian.Controls.Library 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;}}"); // {\colortbl ;\red255\green0\blue0;}"); + 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" + this.Font.SizeInPoints * 2 + @" "); // \f0\fs" + this.Font.SizeInPoints * 2 + @" " + myDisplayTextElement.Text + @"}"; } - private void AddRtf(displayTextElement myDisplayTextElement) + + private bool FontIsFixed() { - _SelectedRtfSB.Append(@"\f0 " + myDisplayTextElement.Text); + 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) { @@ -521,16 +575,12 @@ namespace Volian.Controls.Library 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 + @"}"; + SelectedRtf = _RtfPrefix + @"\f1\fs" + this.Font.SizeInPoints * 2 + @" " + str + @"}"; Select(position, 1); RTBAPI.SetFontStyle(this, fs); Select(position + 1, 0); @@ -540,18 +590,6 @@ namespace Volian.Controls.Library { 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\cf1 "); - _SelectedRtfSB.Append(myDisplayLinkElement.TextAndLink); //.Replace(@"\u916?",@"\f1\u916?\f0 ")); - //_SelectedRtfSB.Append(@"\cf0 "); - } - } public void AddRtfLink(string linkUrl, string linkValue) { if (CreateParams.ClassName == "RICHEDIT50W") @@ -563,9 +601,9 @@ namespace Volian.Controls.Library private void AddLink20(string linkValue, string linkUrl) { this.DetectUrls = false; - int position = SelectionStart; // before inserttran = this.TextLength; + int position = SelectionStart; SelectionLength = 0; - SelectedRtf = @"{\rtf1\ansi\v \v0 }"; + SelectedRtf = @"{\rtf1\ansi{\colortbl ;\red255\green0\blue0;}\v \v0 }"; this.SelectionLength = 0; this.SelectionStart = position; FindAllLinks(); @@ -573,7 +611,7 @@ namespace Volian.Controls.Library private void AddLink50(string linkValue, string linkUrl) { this.DetectUrls = false; - int position = SelectionStart; // before inserttran = this.TextLength; + 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; @@ -753,16 +791,6 @@ namespace Volian.Controls.Library _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) @@ -780,6 +808,7 @@ namespace Volian.Controls.Library private bool _ProcessingDelete; private void HandleSelectionChange() { + //vlnStackTrace.ShowStackLocal("HandleSelectionChangeStack", 1, 10); bool startingValue = _AdjustingSelection; if (_IdentifyingLinks || _ProcessingDelete) return; if (ProcessKeystrokes) @@ -844,12 +873,19 @@ namespace Volian.Controls.Library 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 bool _CheckSelection = false; #endregion #region Delete Handlers - private void HandleDeleteKeyWithSelectedText(KeyEventArgs e, char keychar) + private void HandleDeleteKeyWithSelectedText(KeyEventArgs e, string keychars) { _ProcessingDelete = true; FindRangeStatus(); @@ -861,43 +897,43 @@ namespace Volian.Controls.Library case RangeStatus.Before_EndLink: case RangeStatus.Before_EndBox: default: - DeleteCurrentSelection(keychar); + DeleteCurrentSelection(keychars); e.SuppressKeyPress = true; break; case RangeStatus.Before_Between: //myRTB1.SelectedText.EndsWith(@"[END> /// This inserts a space in between two links. @@ -942,7 +984,7 @@ namespace Volian.Controls.Library SetSelection(SelectionStart - 7, SelectionLength + 7); // Expand selection to include start //_AdjustingSelection = false; } - private void DeleteBetweenBetweenLinks(char keychar) + private void DeleteBetweenBetweenLinks(string keychars) { DebugSelection("DeleteBetweenBetweenLinks"); @@ -951,7 +993,7 @@ namespace Volian.Controls.Library 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 + DeleteCurrentSelection(keychars);// Delete Selection } /// /// This is added to handle a glitch in richtextbox. Depending on @@ -959,29 +1001,32 @@ namespace Volian.Controls.Library /// a replacement or delete may not work, you'll just get a 'beep'. /// This approach consistently works. /// - private void DeleteCurrentSelection(char key) + public bool WasXDelete = false; + private void DeleteCurrentSelection(string keys) { DebugPrint("vvvvvvvvvvvvxxxxxxxxxxxx>"); DebugSelection("Before X"); - SelectedText = key==0?"X":key.ToString(); // replace text with X + + SelectedText = keys==null?"X":keys; // replace text with X + WasXDelete = (keys == null); DebugSelection("After X"); DebugPrint("------------xxxxxxxxxxxx>"); - if (key == 0) + if (keys == null) { _SendBackSpace = true; RtbSendKeys("{BS}"); // remove X - this.ClearUndo(); // undo was redisplay 'X' and then deleted text + //this.ClearUndo(); // undo was redisplay 'X' and then deleted text Application.DoEvents(); DebugSelection("After BS"); } DebugPrint("^^^^^^^^^^^^xxxxxxxxxxxx>"); } - private void DeleteSelection(int start, int length, char keychar) + private void DeleteSelection(int start, int length, string keychars) { SetSelection(start, length); - DeleteCurrentSelection(keychar); + DeleteCurrentSelection(keychars); } - private void DeleteEndBetweenLinks(char keychar) + private void DeleteEndBetweenLinks(string keychars) { _ProcessingKeys++; DebugSelection("DeleteEndBetweenLinks"); @@ -990,11 +1035,11 @@ namespace Volian.Controls.Library // This puts a space at the link that starts at the end of the selection InsertCharBetweenLinks(_RangeEndLink.NextLink); //_AdjustingSelection = true; - DeleteSelection(sstart, slen, keychar); + DeleteSelection(sstart, slen, keychars); //_AdjustingSelection = false; _ProcessingKeys--; } - private void DeleteStartBetweenLinks(char keychar) + private void DeleteStartBetweenLinks(string keychars) { _ProcessingKeys++; DebugSelection("DeleteStartBetweenLinks"); @@ -1002,10 +1047,10 @@ namespace Volian.Controls.Library int sstart = SelectionStart - 7; //LinkLocation ll = FindBetweenLinks(SelectionStart); InsertCharBetweenLinks(_RangeStartLink); - DeleteSelection(sstart, slen, keychar); + DeleteSelection(sstart, slen, keychars); _ProcessingKeys--; } - private void DeleteFromStartOfBox(char keychar) + private void DeleteFromStartOfBox(string keychars) { _ProcessingKeys++; DebugSelection("DeleteFromStartOfBox"); @@ -1013,10 +1058,10 @@ namespace Volian.Controls.Library SetSelection(0, 0); //RtbSendKeys(" "); // open for space between links which separates END/START tokens SelectedText = " "; - DeleteSelection(0, slen + 8, keychar); + DeleteSelection(0, slen + 8, keychars); _ProcessingKeys--; } - private void DeleteFromStartOfBoxEndBetweenLinks(char keychar) + private void DeleteFromStartOfBoxEndBetweenLinks(string keychars) { _ProcessingKeys++; DebugSelection("DeleteFromStartOfBoxEndBetweenLinks"); @@ -1029,7 +1074,7 @@ namespace Volian.Controls.Library 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); + DeleteSelection(0, sLen, keychars); _ProcessingKeys--; } #endregion @@ -1061,7 +1106,17 @@ namespace Volian.Controls.Library switch (e.KeyCode) { case Keys.V: - string buff = Clipboard.GetText(TextDataFormat.UnicodeText); + 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); @@ -1182,7 +1237,7 @@ namespace Volian.Controls.Library if (SelectionStart >= lls.Start - 7 && SelectionStart < lls.End) { SetSelection(lls);// Select the link to the right - HandleDeleteKeyWithSelectedText(e, '\x0'); + HandleDeleteKeyWithSelectedText(e, null); e.SuppressKeyPress = true; return; } @@ -1195,7 +1250,7 @@ namespace Volian.Controls.Library } } else - HandleDeleteKeyWithSelectedText(e, '\x0'); + HandleDeleteKeyWithSelectedText(e, null); break; case Keys.Back: if (_SendBackSpace) @@ -1215,7 +1270,7 @@ namespace Volian.Controls.Library } } } - if (SelectionLength > 0) HandleDeleteKeyWithSelectedText(e, '\x0'); + if (SelectionLength > 0) HandleDeleteKeyWithSelectedText(e, null); break; } } @@ -1246,14 +1301,9 @@ namespace Volian.Controls.Library // 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 >= ' ') @@ -1261,16 +1311,20 @@ namespace Volian.Controls.Library LinkLocation ll = FindBetweenLinks(); if (ll != null && SelectionLength == 0) // SelectionLength = 0 means insert { - InsertCharBetweenLinks(ll, e.KeyChar); + 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), e.KeyChar); + HandleDeleteKeyWithSelectedText(new KeyEventArgs(Keys.None), strpressed); e.Handled = true; } } - if (!done) + if (!e.Handled) { if (e.KeyChar == '-') AddSymbol(@"\u8209?"); @@ -1282,6 +1336,7 @@ namespace Volian.Controls.Library 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; } @@ -1313,18 +1368,6 @@ namespace Volian.Controls.Library } #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; @@ -1336,33 +1379,6 @@ namespace Volian.Controls.Library } 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 '= 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); - } - return SelectionStart; - } - } - return SelectionStart; - } - - private void DeleteLink() - { - SelectedText = ""; - MyLinkText = null; - FindAllLinks(); - } #endregion #endregion #region SelectionStack @@ -1414,7 +1430,7 @@ namespace Volian.Controls.Library _AdjustingSelection = true; PushSelection(); FindLinks(); - IdentifyLinks(); + //IdentifyLinks(); PopSelection(); LinkLocation llx = FindLinkLocation(); if (_CheckSelection) @@ -1445,24 +1461,6 @@ namespace Volian.Controls.Library _LinkLocations.Add(thisLink); } } - private void IdentifyLinks() - { - if (_LinkLocations.Count == 0) return; - _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; - // changing selections causes 'undo' to be wrong, i.e. it highlights the last selected link. - // if there is way to pop the undo stack, that could be solution. - this.ClearUndo(); - } private LinkLocation FindBetweenLinks() { return FindBetweenLinks(SelectionStart); @@ -1475,21 +1473,13 @@ namespace Volian.Controls.Library 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>"); + //DebugPrint("FL----------------Location>"); if (_LinkLocations == null) return null; foreach (LinkLocation ll in _LinkLocations) { @@ -1544,17 +1534,10 @@ namespace Volian.Controls.Library } 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; - } + if ((SelectionStart >= ll.Start) && (SelectionStart <= ll.End)) return ll.Start; } - DebugPrint("FINDSTARTUP - Not in link"); return -1; } public void SetSelection(LinkLocation ll) @@ -1571,29 +1554,29 @@ namespace Volian.Controls.Library 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; + //#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 - ); - } - } + // SelectionFont = new Font( + // currentFont.FontFamily, + // currentFont.Size, + // fs + // ); + // } + //} /// /// Returns a Font with: /// 1) The font applying to the entire selection, if none is the default font. @@ -1601,68 +1584,68 @@ namespace Volian.Controls.Library /// 3) A style containing the attributes that are common to the entire selection, default regular. /// /// - public Font GetFontDetails() - { - //This method should handle cases that occur when multiple fonts/styles are selected + //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; + // 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. - } + // 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; + // // 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; + // //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; + // // 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); + // // 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 reply for different style + // replystyle = replystyle & _rtbTemp.SelectionFont.Style; - // Check font - if (replyfont != _rtbTemp.SelectionFont.FontFamily.Name) - replyfont = ""; + // // Check font + // if (replyfont != _rtbTemp.SelectionFont.FontFamily.Name) + // replyfont = ""; - // Check font size - if (replyfontsize != _rtbTemp.SelectionFont.Size) - replyfontsize = (float)0.0; - } + // // 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; + // // 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; + // if (replyfontsize == 0.0) + // replyfontsize = _rtbTemp.Font.Size; - // generate reply font - Font reply - = new Font(replyfont, replyfontsize, replystyle); + // // generate reply font + // Font reply + // = new Font(replyfont, replyfontsize, replystyle); - return reply; - } - #endregion + // return reply; + //} + //#endregion #region EnumsSelectionRange private enum StartStatus : int { @@ -1739,12 +1722,12 @@ namespace Volian.Controls.Library 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 (_RangeStartLink != null) + // _RangeStartLink.Show("startLink"); + //if (_RangeEndLink != null) + // _RangeEndLink.Show("endLink"); + //if (foundLink != null) + // foundLink.Show("foundLink"); if (foundLink == null) return RTBRangeStatus = RangeStatus.NoContainedLinks; @@ -1774,6 +1757,195 @@ namespace Volian.Controls.Library 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' + }; + public static string Repeat(string str, int count) + { + StringBuilder lStr = new StringBuilder(); + for (int i = 0; i < count; i++) + lStr.Append(str); + return lStr.ToString(); + } + public void OutlineTable(bool withBorder) + { + // Determine the number of characters per line + int w = MaxCharacterWidth(); + string horzLine = Repeat(withBorder ? @"\u9472?" : " ", w); + // Determine the number of lines + int l = Lines.Length; + for (int row = 0; row < Lines.Length; row++) + { + //int spaces = w - line.Length; + int offset = GetFirstCharIndexFromLine(row); + Select(offset, 0); + string cleanLine = RemoveLinkComments(Lines[row]); + int w2 = Lines[row].Length; + int w3 = cleanLine.Length; + offset = SelectionStart + w2 + (w - w3) + 1; + SelectedRtf = RtfPrefix + (withBorder ? @"\u9474?" : " ") + "}"; + Select(SelectionStart + w2, 0); + if (w3 < w) + { + SelectedText = "".PadRight(w - w3); + Select(offset, 0); + } + SelectedRtf = RtfPrefix + (withBorder ? @"\u9474?" : " ") + "}"; + } + // Add the top line + Select(0, 0); + SelectedRtf = RtfPrefix + (withBorder ? @"\u9484?" : " ") + horzLine + (withBorder ? @"\u9488?\par " : @" \par ") + "}"; + // Add the bottom line + Select(TextLength, 0); + SelectedRtf = RtfPrefix + (withBorder ? @"\par\u9492?" : @"\par ") + horzLine + (withBorder ? @"\u9496?" : @" ") + "}"; + + ReplaceLinesInTable(withBorder); + } + 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; + } + private string RemoveLinkComments(string line) + { + StringBuilder sb = new StringBuilder(); + int lastIndex = 0; + MatchCollection mc = Regex.Matches(line, @""); + 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 + return sb.ToString(); + } + private void ReplaceLinesInTable(bool withBorder) + { + int rowWidth = Lines[0].Length; + for (int row=1;row"); + 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); + SelectedRtf = RtfPrefix + TableCharsU[tableCharIndx] + "?}"; + } + #endregion #region Debug private bool _ShowDebug = false; public bool ShowDebug