Subversion Repositories DevTools

Rev

Rev 2106 | Rev 2116 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2094 ghuddy 1
using System;
2
using System.Collections;
2110 ghuddy 3
using System.Text;
2094 ghuddy 4
using Word;
5
 
6
namespace EA_DocGen
7
{
8
	/// <summary>
9
	/// Summary description for TextualContent.
10
	/// </summary>
2106 ghuddy 11
   public class TextualContent
12
   {
13
      private static char[] trim_newlines;
2094 ghuddy 14
 
2106 ghuddy 15
      public static void initialise()
2094 ghuddy 16
      {
2106 ghuddy 17
         string s_trim_newlines = "\r\n";
18
         trim_newlines = s_trim_newlines.ToCharArray();
2094 ghuddy 19
      }
20
 
2106 ghuddy 21
      public static Word.Range appendDescription(string wordText)
2094 ghuddy 22
      {
2106 ghuddy 23
         return appendDescription(wordText, false);
2098 ghuddy 24
      }
25
 
2106 ghuddy 26
      public static Word.Range appendDescription(string wordText, bool continuation)
2098 ghuddy 27
      {
2106 ghuddy 28
         return appendDescription(wordText, EA_Constants.styleName_Body1, continuation);
2098 ghuddy 29
      }
30
 
2106 ghuddy 31
      public static Word.Range appendDescription(string wordText, string styleName, bool continuation)
2098 ghuddy 32
      {
2094 ghuddy 33
         Word.Range wr = null;
34
 
35
         if (wordText != null && wordText.Length > 0)
2106 ghuddy 36
         {
2098 ghuddy 37
            wr = appendAndSelectText(wordText, styleName, continuation);
2106 ghuddy 38
         }
39
         else if (!EA_DocGenOptions.opt_SuppressElementDescriptionMissingWarnings)
2094 ghuddy 40
         {
2098 ghuddy 41
            wr = appendAndSelectText("Description missing!", styleName, continuation);
42
            // For some wierd reason, if continuing on same paragraph, we have to decrement the range start by 1
43
            // otherwise the D of Description, does not get the red color or italic style
44
            if (continuation)
45
               wr.Start--;
2110 ghuddy 46
            if (wr.Characters.Last.Text.Equals("\r"))
47
               wr.End = wr.End - 1;  // dont italicise the \r char at the end
2094 ghuddy 48
            wr.Font.Italic = 1;
49
            wr.Font.Color = Word.WdColor.wdColorRed;
50
         }
51
         return wr;
52
      }
53
 
2098 ghuddy 54
 
2094 ghuddy 55
 
56
      /// <summary>
57
      /// Appends a specified text string to the word document, selects the new text, and applies
58
      /// the specified style formatting to it.
59
      /// </summary>
60
      /// <param name="wordText"></param>
61
      /// <param name="styleText"></param>
62
      /// <param name="continuation"></param>
2106 ghuddy 63
      public static Word.Range appendAndSelectText(string wordText, string styleText) 
2094 ghuddy 64
      { 
65
         return appendAndSelectText(wordText, styleText, false );
66
      }
67
 
68
 
2106 ghuddy 69
      public static Word.Range appendAndSelectText(string wordText, string styleText, bool continuation )
2094 ghuddy 70
      {
71
         if (wordText.Length > 0)
72
         {
73
            Word.Range WordRange = null;
74
            object startLocation;
75
            object endLocation;
76
 
77
            object style = styleText;
78
            int i;
79
            startLocation = 0;
2106 ghuddy 80
            endLocation = i = createWordDoc.WordDocument.Content.End;
2094 ghuddy 81
 
2106 ghuddy 82
            WordRange = createWordDoc.WordDocument.Range(ref startLocation, ref endLocation);
2094 ghuddy 83
 
84
            if (!continuation)
85
               WordRange.InsertAfter( "\n" );
2110 ghuddy 86
 
87
            // TODO
88
            // 1) need to fix the problem with range starting one-char too late when function is called
89
            //    with continuation = true.
90
            //    This will entail finding all the places that call the function with continuation
91
            //    set to true and making sure they do not compensate for the problem, and ofcoarse
92
            //    putting the compensation locally in here instead.
93
 
2094 ghuddy 94
            WordRange.InsertAfter( wordText );
95
 
96
            // Make a range out of the pasted text
97
            startLocation = i;
2106 ghuddy 98
            endLocation = createWordDoc.WordDocument.Content.End;
99
            WordRange = createWordDoc.WordDocument.Range(ref startLocation, ref endLocation);
2094 ghuddy 100
 
101
            // and set the pasted text style
102
            WordRange.set_Style(ref style);
103
            return WordRange;
104
         }
105
         return null;
106
      }
107
 
108
 
109
      /// <summary>
110
      /// Appends a specified text string to the word document, selects the new text, and applies
111
      /// a heading level style to it. 
112
      /// </summary>
113
      /// <param name="wordText"></param>
114
      /// <param name="level"></param>
2106 ghuddy 115
      public static void appendAndSelectHeadingText(string wordText, int level)
2094 ghuddy 116
      {
2104 ghuddy 117
         // A caller is requesting a new heading level so pass the level to the tracking
118
         // object so that we can predict exactly what the level numbering should be for
119
         // diagnostics and fake heading generation (see below in the switch statement).
2106 ghuddy 120
         DocSectionTracking.trackDocSection(level);
2104 ghuddy 121
 
2094 ghuddy 122
         // Convert level to heading style
123
         string styleText;
124
         switch(level)
125
         {
126
            case 1: styleText = EA_Constants.styleName_Heading1; break;
127
            case 2: styleText = EA_Constants.styleName_Heading2; break;
128
            case 3: styleText = EA_Constants.styleName_Heading3; break;
129
            case 4: styleText = EA_Constants.styleName_Heading4; break;
130
            case 5: styleText = EA_Constants.styleName_Heading5; break;
131
            case 6: styleText = EA_Constants.styleName_Heading6; break;
132
            case 7: styleText = EA_Constants.styleName_Heading7; break;
133
            case 8: styleText = EA_Constants.styleName_Heading8; break;
134
            case 9: styleText = EA_Constants.styleName_Heading9; break;
2104 ghuddy 135
 
136
            default: 
137
               // MS-Word cannot produce headings above level 9 and so we have to 
138
               // fake a heading by constructing it from our document section tracking data.
139
               styleText = EA_Constants.styleName_Heading10OrAbove;
2106 ghuddy 140
               wordText = DocSectionTracking.formHeadingString(wordText);
2104 ghuddy 141
               break;
2094 ghuddy 142
         }
143
         // append the text as a heading
144
         appendAndSelectText(wordText, styleText);
145
      }
146
 
2106 ghuddy 147
      public static string trimTrailingReturns(string s)
2094 ghuddy 148
      {
2106 ghuddy 149
          return s.TrimEnd(trim_newlines);
150
      }
151
 
152
 
153
 
154
      public static string testSuiteName(EA.Element theElement)
155
      {
2094 ghuddy 156
         return "Test Suite - " + theElement.Name;
157
      }
158
 
159
 
2106 ghuddy 160
      public static void appendUnitTestSuite(EA.Element theElement, int recurse_level, ref ArrayList classList)
2094 ghuddy 161
      {
2104 ghuddy 162
         if (theElement.StereotypeEx.IndexOf("API") < 0)
163
         {
164
            // element does not have an API stereotype, so is not a class for which unit tests are expected.
165
            return;
166
         }
167
 
2094 ghuddy 168
         // only feed non-private classes through to the unit test section of a document
169
         // NOTE: May need an override option for this filter.
170
         if (!theElement.Visibility.StartsWith("Private"))
171
         {
172
            appendAndSelectHeadingText(testSuiteName(theElement), recurse_level+1);
173
 
174
            if (theElement.Tests.Count > 0)
175
            {
176
               classList.Add( theElement.ElementID );
177
 
178
               foreach(EA.Test theTest in theElement.Tests)
179
               {
180
                  appendAndSelectHeadingText("Test Case - " + theTest.Name, recurse_level+2);
181
 
182
                  appendAndSelectHeadingText("Description", recurse_level+3);
183
                  appendAndSelectText(theTest.Notes, EA_Constants.styleName_Body1);
184
 
185
                  appendAndSelectHeadingText("Inputs", recurse_level+3);
186
                  appendAndSelectText(theTest.Input, EA_Constants.styleName_Body1);
187
 
188
                  appendAndSelectHeadingText("Expected Results", recurse_level+3);
189
                  appendAndSelectText(theTest.AcceptanceCriteria, EA_Constants.styleName_Body1);
190
               }
191
            }
192
            else
193
            {
194
               Word.Range wr = appendAndSelectText("Test Cases missing!", EA_Constants.styleName_Body1);
2110 ghuddy 195
               if (wr.Characters.Last.Text.Equals("\r"))
196
                  wr.End = wr.End - 1;  // dont italicise the \r char at the end
2094 ghuddy 197
               wr.Font.Italic = 1;
198
               wr.Font.Color = Word.WdColor.wdColorRed;
199
            }
200
         }
201
      }
202
 
203
 
2106 ghuddy 204
      public static void appendUnitTestSuite(EA.Package thePackage, int recurse_level, ref ArrayList classList)
2094 ghuddy 205
      {
206
         EA_ElementSorter elementSorter = new EA_ElementSorter(thePackage);
207
         EA.Element theElement = null;
208
         int theElementsRelativeLevel = 0;
209
         if (true == elementSorter.getFirst(ref theElement, ref theElementsRelativeLevel))
210
         {
211
            do
212
            {
213
               if (theElement.Type.StartsWith("Class"))
214
               {
2106 ghuddy 215
                  appendUnitTestSuite(theElement, recurse_level, ref classList);
2094 ghuddy 216
               }
217
 
218
            } while (true == elementSorter.getNext(ref theElement, ref theElementsRelativeLevel));
219
         }
220
 
221
         // Scan through the packages within this package.
222
         foreach(EA.Package lowerLevelPackage in thePackage.Packages)
223
         {
224
            // recurse
2106 ghuddy 225
            appendUnitTestSuite(lowerLevelPackage, recurse_level, ref classList);
2094 ghuddy 226
         }
227
      }
228
 
229
 
2106 ghuddy 230
      public static void SelectInsertionPointAtEndOfDocument()
2094 ghuddy 231
      {
232
         object unit; 
233
         object extend;
234
 
235
         unit = Word.WdUnits.wdStory; 
236
         extend = Word.WdMovementType.wdMove;
2106 ghuddy 237
         createWordDoc.WordApp.Selection.EndKey(ref unit, ref extend);
2094 ghuddy 238
      }
239
 
240
 
241
      /// <summary>
2110 ghuddy 242
      /// Generates the text for requirements.  
2094 ghuddy 243
      /// </summary>
2106 ghuddy 244
      public static bool generateRequirementText( EA.Element theElement )
2094 ghuddy 245
      {
246
         if ( theElement.Type.StartsWith("Requirement"))
247
         {
2104 ghuddy 248
            string reqID = "";
249
            string reqShortDesc = "";
250
            string reqHeadingStyle ="";
251
            string reqParaStyle = "";
2106 ghuddy 252
 
2104 ghuddy 253
 
254
            // Set the style depending on the status
255
            switch ( theElement.Status )
2094 ghuddy 256
            {
2104 ghuddy 257
               case "Proposed":
258
                  reqHeadingStyle = EA_Constants.styleName_ReqPropHdr;
259
                  reqParaStyle    = EA_Constants.styleName_ReqPropBody;
260
                  break;
2094 ghuddy 261
 
2104 ghuddy 262
               case "Rejected":
263
                  reqHeadingStyle = EA_Constants.styleName_ReqRejHdr;
264
                  reqParaStyle    = EA_Constants.styleName_ReqRejBody;
265
                  break;
2094 ghuddy 266
 
2104 ghuddy 267
               case "Approved":
268
                  reqHeadingStyle = EA_Constants.styleName_ReqAppHdr;
269
                  reqParaStyle    = EA_Constants.styleName_ReqAppBody;
270
                  break;
2094 ghuddy 271
 
2104 ghuddy 272
               default:
273
                  reqHeadingStyle = EA_Constants.styleName_ReqAppHdr;
274
                  reqParaStyle    = EA_Constants.styleName_ReqAppBody;
275
                  break;
276
            }
2094 ghuddy 277
 
2110 ghuddy 278
            // A requirement name is assumed to consist of:
279
            //
280
            //    <ID> [ShortDescription]
281
            //
282
            // Where <ID> is defined as
283
            //
284
            //    <TAG>n[subLevel]
285
            //
286
            // Where n is a numeric integer and sublevel is defined as
287
            //
288
            //    .n[sublevel]
289
            // 
290
            // Some examples
291
            //    SPR1  My Requirement
292
            //    SPR1.1 My Sub-requirement
293
            //    SPR1.1.1 My Sub-requirements Sub-Requirement
294
            //    CR1
295
            // 
296
            // Also, it is assumed that the element notes contains a long description
297
            // of the requirement.
298
 
2104 ghuddy 299
            // Pull out the ID from the name
300
            int pos = theElement.Name.IndexOf( " ", 0, theElement.Name.Length );
2106 ghuddy 301
            if (pos > 0)
2110 ghuddy 302
            {
2106 ghuddy 303
               reqID = theElement.Name.Substring( 0, pos );
2110 ghuddy 304
            }
2094 ghuddy 305
 
2110 ghuddy 306
            // Count '.' chars in the ID in order to support the progressive indentation 
307
            // of lower level requirements in the generated document
2106 ghuddy 308
            int numDots = 0;
309
            foreach (char c in reqID)
310
            {
311
               if (c == '.')
312
                  numDots++;
313
            }
314
 
2110 ghuddy 315
            // Calculate what the left/hanging indent should be based on the standard 2.5 cm plus 
316
            // 0.5cm * number of dots in the ID
317
            // Do calculation directly in points (72 points per inch) to avoid having to call
318
            // CentimetersToPoints repeatedly in the word app com object, which I have seen
319
            // cause unspecified exceptions on rare occasions.
320
            float indent_pts = (float)70.866;
321
            if (numDots > 0)
322
            {
323
               indent_pts += (float)(14.1732 * numDots);
324
            }
2106 ghuddy 325
 
2110 ghuddy 326
            // Pull out the short description from the rest of the name. If the short description
327
            // does not exist, substitute in its place, the element notes.
328
            bool doneNotes = false;
2104 ghuddy 329
            reqShortDesc = theElement.Name.Substring( pos, theElement.Name.Length-pos );
330
            reqShortDesc = reqShortDesc.Trim();
2110 ghuddy 331
            if (reqShortDesc.Length == 0)
332
            {
333
               // If there is no short description, then use the element notes instead
334
               doneNotes = true;
335
               if (theElement.Notes != null && theElement.Notes.Length > 0)
336
               {
337
                  reqShortDesc = theElement.Notes;
338
               }
339
            }
2094 ghuddy 340
 
2110 ghuddy 341
            // Add the ID to the document
2106 ghuddy 342
            Word.Range wr_id = appendAndSelectText( reqID + '\t', reqHeadingStyle );
2110 ghuddy 343
 
344
            // Add the short description to the document
2106 ghuddy 345
            Word.Range wr_desc = appendAndSelectText( reqShortDesc, reqHeadingStyle, true );
2110 ghuddy 346
            if (wr_desc != null)
347
            {
348
               // Bold the short description, but only if the element notes have not been used
349
               // as the short description. Element notes may contain a lot of text and having
350
               // it all bolded can make the document look a little too busy, and the reader
351
               // may lose sight of the real document headings which are ofcoarse naturally bolded.
2094 ghuddy 352
 
2110 ghuddy 353
               wr_desc.Start = wr_desc.Start-1;  //compensate for problem in appendAndSelectText();
354
               if (!doneNotes)
355
               {
356
                  if (wr_desc.Characters.Last.Text.Equals("\r"))
357
                     wr_desc.End = wr_desc.End - 1;   // Dont boldise the \r paragraph marker
358
                  wr_desc.Font.Bold = 1;
359
               }
2106 ghuddy 360
 
2110 ghuddy 361
               // Indent according to the number of dots in the tag
362
               if (numDots > 0)
363
               {
364
                  wr_desc.ParagraphFormat.LeftIndent      = indent_pts;
365
 
366
                  wr_desc.ParagraphFormat.FirstLineIndent = -indent_pts;
367
               }
2106 ghuddy 368
            }
369
 
2110 ghuddy 370
            // Add requirement notes/body, if we have not already consumed them for the
371
            // short description
372
            if (!doneNotes && theElement.Notes != null && theElement.Notes.Length > 0)
2106 ghuddy 373
            {
374
               Word.Range wr_body = appendAndSelectText( theElement.Notes, reqParaStyle );
375
 
376
               // indent according to the number of dots in the tag
377
               if (numDots > 0)
378
               {
2110 ghuddy 379
                  wr_body.ParagraphFormat.LeftIndent = indent_pts;
2106 ghuddy 380
               }
381
            }
382
            else
383
            {
384
               // If the requirement has no body text, its SpaceAfter will be 3, so we adjust it here to 6
385
               // just like what the body would have, if it were present.
2110 ghuddy 386
               if (wr_desc != null)
387
                  wr_desc.ParagraphFormat.SpaceAfter = 6;
388
               else if (wr_id != null)
389
                  wr_id.ParagraphFormat.SpaceAfter = 6;
2106 ghuddy 390
            }
391
 
2110 ghuddy 392
            // tack on the end a source reference for the requirement, if it contains one
393
            // as evidenced by tagged values
394
            string src = EA_Utilities.ReadTag(theElement, "SOURCE");
395
            if (src.Length > 0)
396
            {
397
               StringBuilder sb = new StringBuilder();
398
 
399
               string srcVer = EA_Utilities.ReadTag(theElement, "SOURCE_VERSION");
400
               sb.Append("[");
401
               sb.Append(src);
402
 
403
               if (srcVer.Length > 0)
404
               {
405
                  sb.Append(" v");
406
                  sb.Append(srcVer);
407
               }
408
 
409
               string srcSect = EA_Utilities.ReadTag(theElement, "SOURCE_SECTION");
410
               if (srcSect.Length > 0)
411
               {
412
                  sb.Append(" section ");
413
                  sb.Append(srcSect);
414
               }
415
               sb.Append("]");
416
 
417
               Word.Range wrs_body = appendAndSelectText(sb.ToString(), reqParaStyle);
418
               if (wrs_body.Characters.Last.Text.Equals("\r"))
419
                  wrs_body.End = wrs_body.End - 1;  // dont italicise the \r char at the end - doing so causes wierd ms-word exceptions later on
420
               wrs_body.Font.Italic = 1;
421
               if (numDots > 0)
422
               {
423
                  wrs_body.ParagraphFormat.LeftIndent = indent_pts;
424
               }
425
            }
426
 
2104 ghuddy 427
            return true;
428
 
2094 ghuddy 429
         }
430
 
431
         return false;
432
      }
433
 
2106 ghuddy 434
   }
2094 ghuddy 435
}