Rev 2126 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
using System;using System.Collections;using System.Text;using Word;namespace EA_DocGen{/// <summary>/// Summary description for TextualContent./// </summary>public class TextualContent{private static char[] trim_newlines;public static void initialise(){string s_trim_newlines = "\r\n";trim_newlines = s_trim_newlines.ToCharArray();}public static Word.Range appendDescription(string wordText){return appendDescription(wordText, false);}public static Word.Range appendDescription(string wordText, bool continuation){return appendDescription(wordText, EA_Constants.styleName_Body1, continuation);}public static Word.Range appendDescription(string wordText, string styleName, bool continuation){Word.Range wr = null;if (wordText != null && wordText.Length > 0){wr = appendAndSelectText(wordText, styleName, continuation);}else if (!EA_DocGenOptions.optionValue(EA_DocGenOptions.boolean_options_e.SUPPRESS_ELEMENT_DESC_MISSING_WARNINGS)){wr = appendAndSelectText("Description missing!", styleName, continuation);if (wr.Characters.Last.Text.Equals("\r"))wr.End = wr.End - 1; // dont italicise the \r char at the endwr.Font.Italic = 1;wr.Font.Color = Word.WdColor.wdColorRed;}return wr;}/// <summary>/// Appends a specified text string to the word document, selects the new text, and applies/// the specified style formatting to it./// </summary>/// <param name="wordText"></param>/// <param name="styleText"></param>/// <param name="continuation"></param>public static Word.Range appendAndSelectText(string wordText, string styleText){return appendAndSelectText(wordText, styleText, false );}public static Word.Range appendAndSelectText(string wordText, string styleText, bool continuation ){if (wordText != null && wordText.Length > 0){Word.Range WordRange = null;object startLocation;object endLocation;object style = styleText;int i;startLocation = 0;endLocation = i = createWordDoc.WordDocument.Content.End;WordRange = createWordDoc.WordDocument.Range(ref startLocation, ref endLocation);if (!continuation)WordRange.InsertAfter( "\n" );WordRange.InsertAfter( wordText );// Make a range out of the pasted textstartLocation = i;endLocation = createWordDoc.WordDocument.Content.End;WordRange = createWordDoc.WordDocument.Range(ref startLocation, ref endLocation);// and set the pasted text styleWordRange.set_Style(ref style);// compensate for wierd off by one error in the range object when using continuationif (continuation)WordRange.Start--;return WordRange;}return null;}/// <summary>/// Appends a specified text string to the word document, selects the new text, and applies/// a heading level style to it./// </summary>/// <param name="wordText"></param>/// <param name="level"></param>public static void appendAndSelectHeadingText(string wordText, int level){// A caller is requesting a new heading level so pass the level to the tracking// object so that we can predict exactly what the level numbering should be for// diagnostics and fake heading generation (see below in the switch statement).DocSectionTracking.trackDocSection(level);// Convert level to heading stylestring styleText;switch(level){case 1: styleText = EA_Constants.styleName_Heading1; break;case 2: styleText = EA_Constants.styleName_Heading2; break;case 3: styleText = EA_Constants.styleName_Heading3; break;case 4: styleText = EA_Constants.styleName_Heading4; break;case 5: styleText = EA_Constants.styleName_Heading5; break;case 6: styleText = EA_Constants.styleName_Heading6; break;case 7: styleText = EA_Constants.styleName_Heading7; break;case 8: styleText = EA_Constants.styleName_Heading8; break;case 9: styleText = EA_Constants.styleName_Heading9; break;default:// MS-Word cannot produce headings above level 9 and so we have to// fake a heading by constructing it from our document section tracking data.styleText = EA_Constants.styleName_Heading10OrAbove;wordText = DocSectionTracking.formHeadingString(wordText);break;}// append the text as a headingappendAndSelectText(wordText, styleText);}/// <summary>/// Appends a specified text string to the word document, selects the new text, and applies/// a numpara level style to it./// </summary>/// <param name="wordText"></param>/// <param name="level"></param>public static void appendAndSelectNumParaText(string wordText, int level){// A caller is requesting a new heading level so pass the level to the tracking// object so that we can predict exactly what the level numbering should be for// diagnostics and fake heading generation (see below in the switch statement).DocSectionTracking.trackDocSection(level);// Convert level to heading stylestring styleText;switch(level){case 1: styleText = EA_Constants.styleName_NumPara1; break;case 2: styleText = EA_Constants.styleName_NumPara2; break;case 3: styleText = EA_Constants.styleName_NumPara3; break;case 4: styleText = EA_Constants.styleName_NumPara4; break;case 5: styleText = EA_Constants.styleName_NumPara5; break;case 6: styleText = EA_Constants.styleName_NumPara6; break;case 7: styleText = EA_Constants.styleName_NumPara7; break;case 8: styleText = EA_Constants.styleName_NumPara8; break;case 9: styleText = EA_Constants.styleName_NumPara9; break;default:// MS-Word cannot produce headings above level 9 and so we have to// fake a heading by constructing it from our document section tracking data.styleText = EA_Constants.styleName_NumPara10OrAbove;wordText = DocSectionTracking.formHeadingString(wordText);break;}// append the text as a headingappendAndSelectText(wordText, styleText);}public static string trimTrailingReturns(string s){if (s != null)return s.TrimEnd(trim_newlines);elsereturn null;}public static string testSuiteName(EA.Element theElement){return "Test Suite - " + theElement.Name;}public static void appendUnitTestSuite(EA.Element theElement, int recurse_level, ref ArrayList classList){if (theElement.StereotypeEx.IndexOf("API") < 0){// element does not have an API stereotype, so is not a class for which unit tests are expected.return;}// only feed non-private classes through to the unit test section of a document// NOTE: May need an override option for this filter.if (!theElement.Visibility.StartsWith("Private")){appendAndSelectHeadingText(testSuiteName(theElement), recurse_level+1);if (theElement.Tests.Count > 0){classList.Add( theElement.ElementID );foreach(EA.Test theTest in theElement.Tests){appendAndSelectHeadingText("Test Case - " + theTest.Name, recurse_level+2);if (EA_DocGenOptions.optionValue(EA_DocGenOptions.boolean_options_e.USE_NUM_PARA_FOR_GENERATED_TEST_CASES) == true)appendAndSelectNumParaText("Description", recurse_level+3);elseappendAndSelectHeadingText("Description", recurse_level+3);appendAndSelectText(theTest.Notes, EA_Constants.styleName_Body1);if (EA_DocGenOptions.optionValue(EA_DocGenOptions.boolean_options_e.USE_NUM_PARA_FOR_GENERATED_TEST_CASES) == true)appendAndSelectNumParaText("Inputs", recurse_level+3);elseappendAndSelectHeadingText("Inputs", recurse_level+3);appendAndSelectText(theTest.Input, EA_Constants.styleName_Body1);if (EA_DocGenOptions.optionValue(EA_DocGenOptions.boolean_options_e.USE_NUM_PARA_FOR_GENERATED_TEST_CASES) == true)appendAndSelectNumParaText("Expected Results", recurse_level+3);elseappendAndSelectHeadingText("Expected Results", recurse_level+3);appendAndSelectText(theTest.AcceptanceCriteria, EA_Constants.styleName_Body1);}}else{Word.Range wr = appendAndSelectText("Test Cases missing!", EA_Constants.styleName_Body1);if (wr.Characters.Last.Text.Equals("\r"))wr.End = wr.End - 1; // dont italicise the \r char at the endwr.Font.Italic = 1;wr.Font.Color = Word.WdColor.wdColorRed;}}}public static void appendUnitTestSuite(EA.Package thePackage, int recurse_level, ref ArrayList classList){EA_ElementSorter elementSorter = new EA_ElementSorter(thePackage);EA.Element theElement = null;int theElementsRelativeLevel = 0;if (true == elementSorter.getFirst(ref theElement, ref theElementsRelativeLevel)){do{if (theElement.Type.StartsWith("Class")){appendUnitTestSuite(theElement, recurse_level, ref classList);}} while (true == elementSorter.getNext(ref theElement, ref theElementsRelativeLevel));}// Scan through the packages within this package.foreach(EA.Package lowerLevelPackage in thePackage.Packages){// recurseappendUnitTestSuite(lowerLevelPackage, recurse_level, ref classList);}}public static void SelectInsertionPointAtEndOfDocument(){object unit;object extend;unit = Word.WdUnits.wdStory;extend = Word.WdMovementType.wdMove;createWordDoc.WordApp.Selection.EndKey(ref unit, ref extend);}/// <summary>/// Generates the text for requirements./// </summary>public static bool generateRequirementText( EA.Element theElement ){if (theElement.Type.StartsWith("Requirement")){string reqID = "";string reqShortDesc = "";string reqHeadingStyle ="";string reqParaStyle = "";// Set the style depending on the statusswitch ( theElement.Status ){case "Proposed":reqHeadingStyle = EA_Constants.styleName_ReqPropHdr;reqParaStyle = EA_Constants.styleName_ReqPropBody;break;case "Rejected":reqHeadingStyle = EA_Constants.styleName_ReqRejHdr;reqParaStyle = EA_Constants.styleName_ReqRejBody;break;case "Approved":reqHeadingStyle = EA_Constants.styleName_ReqAppHdr;reqParaStyle = EA_Constants.styleName_ReqAppBody;break;default:reqHeadingStyle = EA_Constants.styleName_ReqAppHdr;reqParaStyle = EA_Constants.styleName_ReqAppBody;break;}// A requirement name is assumed to consist of://// <ID> [ShortDescription]//// Where <ID> is defined as//// <TAG>n[subLevel]//// Where n is a numeric integer and sublevel is defined as//// .n[sublevel]//// Some examples// SPR1 My Requirement// SPR1.1 My Sub-requirement// SPR1.1.1 My Sub-requirements Sub-Requirement// CR1//// Also, it is assumed that the element notes contains a long description// of the requirement.// Pull out the ID from the nameint pos = theElement.Name.IndexOf( " ", 0, theElement.Name.Length );if (pos > 0){reqID = theElement.Name.Substring( 0, pos );}// Count '.' chars in the ID in order to support the progressive indentation// of lower level requirements in the generated documentint numDots = 0;foreach (char c in reqID){if (c == '.')numDots++;}// Calculate what the left/hanging indent should be based on the standard 2.5 cm plus// 0.5cm * number of dots in the ID// Do calculation directly in points (72 points per inch) to avoid having to call// CentimetersToPoints repeatedly in the word app com object, which I have seen// cause unspecified exceptions on rare occasions.float indent_pts = (float)70.866;if (numDots > 0){indent_pts += (float)(14.1732 * numDots);}// Pull out the short description from the rest of the name. If the short description// does not exist, substitute in its place, the element notes.bool doneNotes = false;reqShortDesc = theElement.Name.Substring( pos, theElement.Name.Length-pos );reqShortDesc = reqShortDesc.Trim();if (reqShortDesc.Length == 0){// If there is no short description, then use the element notes insteaddoneNotes = true;if (theElement.Notes != null && theElement.Notes.Length > 0){reqShortDesc = theElement.Notes;}}// Add the ID to the documentWord.Range wr_id = appendAndSelectText( reqID + '\t', reqHeadingStyle );// Add the short description to the documentWord.Range wr_desc = appendAndSelectText( reqShortDesc, reqHeadingStyle, true );if (wr_desc != null){// Bold the short description, but only if the element notes have not been used// as the short description. Element notes may contain a lot of text and having// it all bolded can make the document look a little too busy, and the reader// may lose sight of the real document headings which are ofcoarse naturally bolded.if (!doneNotes){if (wr_desc.Characters.Last.Text.Equals("\r"))wr_desc.End = wr_desc.End - 1; // Dont boldise the \r paragraph markerwr_desc.Font.Bold = 1;}// Indent according to the number of dots in the tagif (numDots > 0){wr_desc.ParagraphFormat.LeftIndent = indent_pts;wr_desc.ParagraphFormat.FirstLineIndent = -indent_pts;}}// Add requirement notes/body, if we have not already consumed them for the// short descriptionif (!doneNotes && theElement.Notes != null && theElement.Notes.Length > 0 && !EA_DocGenOptions.optionValue(EA_DocGenOptions.boolean_options_e.SUPPRESS_REQUIREMENT_NOTES)){TextParser.parse(theElement.Notes, theElement.ElementID, reqParaStyle, numDots > 0 ? indent_pts:0, false );}else{// If the requirement has no body text, its SpaceAfter will be 3, so we adjust it here to 6// just like what the body would have, if it were present.if (wr_desc != null)wr_desc.ParagraphFormat.SpaceAfter = 6;else if (wr_id != null)wr_id.ParagraphFormat.SpaceAfter = 6;}// tack on the end a source reference for the requirement, if it contains one// as evidenced by tagged valuesstring src = EA_Utilities.ReadTag(theElement, "SOURCE");if (src.Length > 0){StringBuilder sb = new StringBuilder();string srcVer = EA_Utilities.ReadTag(theElement, "SOURCE_VERSION");sb.Append("[");sb.Append(src);if (srcVer.Length > 0){sb.Append(" v");sb.Append(srcVer);}string srcSect = EA_Utilities.ReadTag(theElement, "SOURCE_SECTION");if (srcSect.Length > 0){sb.Append(" section ");sb.Append(srcSect);}sb.Append("]");Word.Range wrs_body = appendAndSelectText(sb.ToString(), reqParaStyle);if (wrs_body.Characters.Last.Text.Equals("\r"))wrs_body.End = wrs_body.End - 1; // dont italicise the \r char at the end - doing so causes wierd ms-word exceptions later onwrs_body.Font.Italic = 1;if (numDots > 0){wrs_body.ParagraphFormat.LeftIndent = indent_pts;}}return true;}return false;}}}