/** * Changes the text, and Sets it all to have the same styling * as the the first character has. * If you care about styling, do SetText on a RichTextRun instead */ public void SetRawText(String s) { // Save the new text to the atoms storeText(s); RichTextRun fst = _rtRuns[0]; // Finally, zap and re-do the RichTextRuns for(int i=0; i<_rtRuns.Length; i++) { _rtRuns[i] = null; } _rtRuns = new RichTextRun[1]; _rtRuns[0] = fst; // Now handle record stylings: // If there isn't styling // no Change, stays with no styling // If there is styling: // everthing Gets the same style that the first block has if(_styleAtom != null) { LinkedList pStyles = _styleAtom.GetParagraphStyles(); while(pStyles.Count > 1) { pStyles.RemoveLast(); } LinkedList cStyles = _styleAtom.GetCharacterStyles(); while(cStyles.Count > 1) { cStyles.RemoveLast(); } _rtRuns[0].SetText(s); } else { // Recreate rich text run with no styling _rtRuns[0] = new RichTextRun(this,0,s.Length); } }
// Update methods follow /** * Adds the supplied text onto the end of the TextRun, * creating a new RichTextRun (returned) for it to * sit in. * In many cases, before calling this, you'll want to add * a newline onto the end of your last RichTextRun */ public RichTextRun AppendText(String s) { // We will need a StyleTextProp atom ensureStyleAtomPresent(); // First up, append the text to the // underlying text atom int oldSize = GetRawText().Length; storeText( GetRawText() + s ); // If either of the previous styles overran // the text by one, we need to shuffle that // extra character onto the new ones int pOverRun = _styleAtom.GetParagraphTextLengthCovered() - oldSize; int cOverRun = _styleAtom.GetCharacterTextLengthCovered() - oldSize; if(pOverRun > 0) { TextPropCollection tpc = (TextPropCollection) _styleAtom.GetParagraphStyles().GetLast(); tpc.updateTextSize( tpc.GetCharactersCovered() - pOverRun ); } if(cOverRun > 0) { TextPropCollection tpc = (TextPropCollection) _styleAtom.GetCharacterStyles().GetLast(); tpc.updateTextSize( tpc.GetCharactersCovered() - cOverRun ); } // Next, add the styles for its paragraph and characters TextPropCollection newPTP = _styleAtom.AddParagraphTextPropCollection(s.Length+pOverRun); TextPropCollection newCTP = _styleAtom.AddCharacterTextPropCollection(s.Length+cOverRun); // Now, create the new RichTextRun RichTextRun nr = new RichTextRun( this, oldSize, s.Length, newPTP, newCTP, false, false ); // Add the new RichTextRun onto our list RichTextRun[] newRuns = new RichTextRun[_rtRuns.Length+1]; Array.Copy(_rtRuns, 0, newRuns, 0, _rtRuns.Length); newRuns[newRuns.Length-1] = nr; _rtRuns = newRuns; // And return the new run to the caller return nr; }
/** * Handles an update to the text stored in one of the Rich Text Runs * @param run * @param s */ public void ChangeTextInRichTextRun(RichTextRun Run, String s) { // Figure out which run it is int RunID = -1; for(int i=0; i<_rtRuns.Length; i++) { if(Run.Equals(_rtRuns[i])) { RunID = i; } } if(RunID == -1) { throw new ArgumentException("Supplied RichTextRun wasn't from this TextRun"); } // Ensure a StyleTextPropAtom is present, Adding if required ensureStyleAtomPresent(); // Update the text length for its Paragraph and Character stylings // If it's shared: // * calculate the new length based on the Run's old text // * this should leave in any +1's for the end of block if needed // If it isn't shared: // * reset the length, to the new string's length // * add on +1 if the last block // The last run needs its stylings to be 1 longer than the raw // text is. This is to define the stylings that any new text // that is Added will inherit TextPropCollection pCol = Run._getRawParagraphStyle(); TextPropCollection cCol = Run._getRawCharacterStyle(); int newSize = s.Length; if(RunID == _rtRuns.Length-1) { newSize++; } if(Run._isParagraphStyleShared()) { pCol.updateTextSize( pCol.GetCharactersCovered() - Run.GetLength() + s.Length ); } else { pCol.updateTextSize(newSize); } if(Run._isCharacterStyleShared()) { cCol.updateTextSize( cCol.GetCharactersCovered() - Run.GetLength() + s.Length ); } else { cCol.updateTextSize(newSize); } // Build up the new text // As we go through, update the start position for all subsequent Runs // The building relies on the old text still being present StringBuilder newText = new StringBuilder(); for(int i=0; i<_rtRuns.Length; i++) { int newStartPos = newText.Length; // Build up the new text if(i != RunID) { // Not the affected Run, so keep old text newText.Append(_rtRuns[i].GetRawText()); } else { // Affected Run, so use new text newText.Append(s); } // Do we need to update the start position of this Run? // (Need to Get the text before we update the start pos) if(i <= RunID) { // Change is after this, so don't need to change start position } else { // Change has occured, so update start position _rtRuns[i].updateStartPosition(newStartPos); } } // Now we can save the new text storeText(newText.ToString()); }
public void buildRichTextRuns(LinkedList pStyles, LinkedList cStyles, String RunRawText){ // Handle case of no current style, with a default if(pStyles.Count == 0 || cStyles.Count == 0) { _rtRuns = new RichTextRun[1]; _rtRuns[0] = new RichTextRun(this, 0, RunRawText.Length); } else { // Build up Rich Text Runs, one for each // character/paragraph style pair Vector rtrs = new Vector(); int pos = 0; int curP = 0; int curC = 0; int pLenRemain = -1; int cLenRemain = -1; // Build one for each run with the same style while(pos <= RunRawText.Length && curP < pStyles.Count && curC < cStyles.Count) { // Get the Props to use TextPropCollection pProps = (TextPropCollection)pStyles.Get(curP); TextPropCollection cProps = (TextPropCollection)cStyles.Get(curC); int pLen = pProps.GetCharactersCovered(); int cLen = cProps.GetCharactersCovered(); // Handle new pass bool freshSet = false; if(pLenRemain == -1 && cLenRemain == -1) { freshSet = true; } if(pLenRemain == -1) { pLenRemain = pLen; } if(cLenRemain == -1) { cLenRemain = cLen; } // So we know how to build the eventual run int RunLen = -1; bool pShared = false; bool cShared = false; // Same size, new styles - neither shared if(pLen == cLen && freshSet) { RunLen = cLen; pShared = false; cShared = false; curP++; curC++; pLenRemain = -1; cLenRemain = -1; } else { // Some sharing // See if we are already in a shared block if(pLenRemain < pLen) { // Existing shared p block pShared = true; // Do we end with the c block, or either side of it? if(pLenRemain == cLenRemain) { // We end at the same time cShared = false; RunLen = pLenRemain; curP++; curC++; pLenRemain = -1; cLenRemain = -1; } else if(pLenRemain < cLenRemain) { // We end before the c block cShared = true; RunLen = pLenRemain; curP++; cLenRemain -= pLenRemain; pLenRemain = -1; } else { // We end after the c block cShared = false; RunLen = cLenRemain; curC++; pLenRemain -= cLenRemain; cLenRemain = -1; } } else if(cLenRemain < cLen) { // Existing shared c block cShared = true; // Do we end with the p block, or either side of it? if(pLenRemain == cLenRemain) { // We end at the same time pShared = false; RunLen = cLenRemain; curP++; curC++; pLenRemain = -1; cLenRemain = -1; } else if(cLenRemain < pLenRemain) { // We end before the p block pShared = true; RunLen = cLenRemain; curC++; pLenRemain -= cLenRemain; cLenRemain = -1; } else { // We end after the p block pShared = false; RunLen = pLenRemain; curP++; cLenRemain -= pLenRemain; pLenRemain = -1; } } else { // Start of a shared block if(pLenRemain < cLenRemain) { // Shared c block pShared = false; cShared = true; RunLen = pLenRemain; curP++; cLenRemain -= pLenRemain; pLenRemain = -1; } else { // Shared p block pShared = true; cShared = false; RunLen = cLenRemain; curC++; pLenRemain -= cLenRemain; cLenRemain = -1; } } } // Wind on int prevPos = pos; pos += RunLen; // Adjust for end-of-run extra 1 length if(pos > RunRawText.Length) { RunLen--; } // Save RichTextRun rtr = new RichTextRun(this, prevPos, RunLen, pProps, cProps, pShared, cShared); rtrs.Add(rtr); } // Build the array _rtRuns = new RichTextRun[rtrs.Count]; rtrs.copyInto(_rtRuns); } }