/// <summary> /// Redact all shapes in a range. /// </summary> /// <param name="StoryRange">A range containing zero or more shapes.</param> private void RedactShapes(Word.Range StoryRange) { if (StoryRange.ShapeRange.Count > 0) { List <int> ShapeLocations = new List <int>(); Dictionary <int, Word.Shape> Shapes = new Dictionary <int, Word.Shape>(); //scan for shapes //since we're messing with the text, we need reorder them back to front by document order (they're in z-order). foreach (Word.Shape Shape in StoryRange.ShapeRange) { Word.Range AnchorRange = Shape.Anchor; ShapeLocations.Add(AnchorRange.Start); Shapes.Add(AnchorRange.Start, Shape); } //sort the anchor locations ShapeLocations.Sort(); for (int i = ShapeLocations.Count - 1; i >= 0; i--) { Word.Shape Shape = Shapes[ShapeLocations[i]]; if (RedactCommon.IsMarkedRange(Shape.Anchor, ShadingColor)) { Debug.WriteLine("Shape from " + Shape.Anchor.Start + " to " + Shape.Anchor.End + "to be redacted."); RedactShape(StoryRange.Document, Shape); } } } }
/// <summary> /// Extends the current range's ending point to the end of the mark. /// </summary> /// <param name="CurrentRange">The range containing the starting point of the search. Changes to the location of the full mark if one is found.</param> /// <param name="Collapse">True to collapse the result to the end of the range, otherwise False.</param> private static void ExtendNextMark(ref Word.Range SelectionRange, bool Collapse) { if (SelectionRange.End < SelectionRange.StoryLength - 1) { //move before the current mark (if we are in one) if (RedactCommon.IsMarkedRange(SelectionRange, ShadingColor)) { Word.Range SearchRange = SelectionRange.Duplicate; while (FindNextMarkInCurrentStoryRange(ref SearchRange)) { if (SearchRange.Start == SelectionRange.End && (bool)SearchRange.get_Information(Word.WdInformation.wdWithInTable) == (bool)SelectionRange.get_Information(Word.WdInformation.wdWithInTable)) { SelectionRange.End = SearchRange.End; if (Collapse) { SelectionRange.Start = SearchRange.End; } //if we didn't progress in this iteration, break if (SelectionRange.Start == SearchRange.Start && SelectionRange.End == SearchRange.End) { break; } } else { break; } } } } }
/// <summary> /// Extends the current range's starting point to the beginning of the mark. /// </summary> /// <param name="CurrentRange">The range containing the starting point of the search. Changes to the location of the full mark if one is found.</param> /// <param name="Collapse">True to collapse the result to the start of the range, otherwise False.</param> private static void ExtendPreviousMark(ref Word.Range SelectionRange, bool Collapse) { if (SelectionRange.Start != 0) { //move before the current mark (if we are in one) if (RedactCommon.IsMarkedRange(SelectionRange, ShadingColor)) { Word.Range SearchRange = SelectionRange.Duplicate; while (FindPreviousMarkInCurrentStoryRange(ref SearchRange)) { if (SearchRange.End == SelectionRange.Start && (bool)SearchRange.get_Information(Word.WdInformation.wdWithInTable) == (bool)SelectionRange.get_Information(Word.WdInformation.wdWithInTable)) { SelectionRange.Start = SearchRange.Start; if (Collapse) { SelectionRange.End = SearchRange.Start; } } else { break; } } } } }
/// <summary> /// Redact a story range (e.g. all textboxes, all first page headers, the main document). /// </summary> /// <param name="StoryRange">The story range to redact.</param> /// <param name="Worker">A BackgroundWorker on which to report progress.</param> private void RedactStoryRange(Word.Range StoryRange, BackgroundWorker Worker) { //textboxes in headers/footers/textboxes/etc. are not in the textbox story. if ((int)StoryRange.StoryType > 5 && StoryRange.ShapeRange.Count > 0) { foreach (Word.Shape Shape in StoryRange.ShapeRange) { Word.Range ShapeRange = RedactCommon.RangeFromShape(Shape); if (ShapeRange != null) { RedactStoryRange(ShapeRange, Worker); } } } //redact all shapes RedactShapes(StoryRange); //remove redaction marks from all paragraph mark glyphs Word.Range ParaMark = StoryRange.Duplicate; foreach (Word.Paragraph Paragraph in StoryRange.Paragraphs) { //select the para mark ParaMark.Start = Paragraph.Range.End - 1; ParaMark.End = ParaMark.Start + 1; if (RedactCommon.IsMarkedRange(ParaMark, ShadingColor)) { ParaMark.Font.Shading.BackgroundPatternColor = Word.WdColor.wdColorAutomatic; } } //run through the collection //since we're messing with the text, we need to go back to front. StoryRange.Collapse(ref CollapseEnd); while (FindPreviousMarkInCurrentStoryRange(ref StoryRange)) { Debug.Assert(StoryRange.Paragraphs.Count < 2, "redacting more than one paragraph - Selection.Move will behave incorrectly in tables"); //break up the range by formatting, so we can maintain layout through the redaction List <RangeDataEx> RangeMarkers = RedactCommon.GetAllMarkedRanges(StoryRange, ShadingColor, false); for (int i = RangeMarkers.Count - 1; i >= 0; i--) { StoryRange.Start = RangeMarkers[i].Start; StoryRange.End = RangeMarkers[i].End; RedactRange(StoryRange, RangeMarkers[i]); //update progress UI if (Worker != null && StoryRange.StoryType == Word.WdStoryType.wdMainTextStory) { Worker.ReportProgress((((StoryRange.StoryLength - RangeMarkers[i].Start) * 100) / StoryRange.StoryLength), null); } } } //get all other stories if (StoryRange.NextStoryRange != null) { RedactStoryRange(StoryRange.NextStoryRange, Worker); } //give each non-main story a small % of the progress bar if (Worker != null && StoryRange.StoryType != Word.WdStoryType.wdMainTextStory) { Worker.ReportProgress(100 + (int)StoryRange.StoryType); } }