Subversion Repositories DevTools

Rev

Rev 2110 | Rev 2124 | 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
         }
2116 ghuddy 39
         else if (!EA_DocGenOptions.optionValue(EA_DocGenOptions.boolean_options_e.SUPPRESS_ELEMENT_DESC_MISSING_WARNINGS))
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
 
2116 ghuddy 147
      /// <summary>
148
      /// Appends a specified text string to the word document, selects the new text, and applies
149
      /// a numpara level style to it. 
150
      /// </summary>
151
      /// <param name="wordText"></param>
152
      /// <param name="level"></param>
153
      public static void appendAndSelectNumParaText(string wordText, int level)
154
      {
155
         // A caller is requesting a new heading level so pass the level to the tracking
156
         // object so that we can predict exactly what the level numbering should be for
157
         // diagnostics and fake heading generation (see below in the switch statement).
158
         DocSectionTracking.trackDocSection(level);
159
 
160
         // Convert level to heading style
161
         string styleText;
162
         switch(level)
163
         {
164
            case 1: styleText = EA_Constants.styleName_NumPara1; break;
165
            case 2: styleText = EA_Constants.styleName_NumPara2; break;
166
            case 3: styleText = EA_Constants.styleName_NumPara3; break;
167
            case 4: styleText = EA_Constants.styleName_NumPara4; break;
168
            case 5: styleText = EA_Constants.styleName_NumPara5; break;
169
            case 6: styleText = EA_Constants.styleName_NumPara6; break;
170
            case 7: styleText = EA_Constants.styleName_NumPara7; break;
171
            case 8: styleText = EA_Constants.styleName_NumPara8; break;
172
            case 9: styleText = EA_Constants.styleName_NumPara9; break;
173
 
174
            default: 
175
               // MS-Word cannot produce headings above level 9 and so we have to 
176
               // fake a heading by constructing it from our document section tracking data.
177
               styleText = EA_Constants.styleName_NumPara10OrAbove;
178
               wordText = DocSectionTracking.formHeadingString(wordText);
179
               break;
180
         }
181
         // append the text as a heading
182
         appendAndSelectText(wordText, styleText);
183
      }
184
 
185
 
2106 ghuddy 186
      public static string trimTrailingReturns(string s)
2094 ghuddy 187
      {
2106 ghuddy 188
          return s.TrimEnd(trim_newlines);
189
      }
190
 
191
 
192
 
193
      public static string testSuiteName(EA.Element theElement)
194
      {
2094 ghuddy 195
         return "Test Suite - " + theElement.Name;
196
      }
197
 
198
 
2106 ghuddy 199
      public static void appendUnitTestSuite(EA.Element theElement, int recurse_level, ref ArrayList classList)
2094 ghuddy 200
      {
2104 ghuddy 201
         if (theElement.StereotypeEx.IndexOf("API") < 0)
202
         {
203
            // element does not have an API stereotype, so is not a class for which unit tests are expected.
204
            return;
205
         }
206
 
2094 ghuddy 207
         // only feed non-private classes through to the unit test section of a document
208
         // NOTE: May need an override option for this filter.
209
         if (!theElement.Visibility.StartsWith("Private"))
210
         {
211
            appendAndSelectHeadingText(testSuiteName(theElement), recurse_level+1);
212
 
213
            if (theElement.Tests.Count > 0)
214
            {
215
               classList.Add( theElement.ElementID );
216
 
217
               foreach(EA.Test theTest in theElement.Tests)
218
               {
219
                  appendAndSelectHeadingText("Test Case - " + theTest.Name, recurse_level+2);
220
 
2116 ghuddy 221
                  if (EA_DocGenOptions.optionValue(EA_DocGenOptions.boolean_options_e.USE_NUM_PARA_FOR_GENERATED_TEST_CASES) == true)
222
                     appendAndSelectNumParaText("Description", recurse_level+3);
223
                  else
224
                     appendAndSelectHeadingText("Description", recurse_level+3);
2094 ghuddy 225
                  appendAndSelectText(theTest.Notes, EA_Constants.styleName_Body1);
226
 
2116 ghuddy 227
                  if (EA_DocGenOptions.optionValue(EA_DocGenOptions.boolean_options_e.USE_NUM_PARA_FOR_GENERATED_TEST_CASES) == true)
228
                     appendAndSelectNumParaText("Inputs", recurse_level+3);
229
                  else
230
                     appendAndSelectHeadingText("Inputs", recurse_level+3);
2094 ghuddy 231
                  appendAndSelectText(theTest.Input, EA_Constants.styleName_Body1);
232
 
2116 ghuddy 233
                  if (EA_DocGenOptions.optionValue(EA_DocGenOptions.boolean_options_e.USE_NUM_PARA_FOR_GENERATED_TEST_CASES) == true)
234
                     appendAndSelectNumParaText("Expected Results", recurse_level+3);
235
                  else
236
                     appendAndSelectHeadingText("Expected Results", recurse_level+3);
2094 ghuddy 237
                  appendAndSelectText(theTest.AcceptanceCriteria, EA_Constants.styleName_Body1);
238
               }
239
            }
240
            else
241
            {
242
               Word.Range wr = appendAndSelectText("Test Cases missing!", EA_Constants.styleName_Body1);
2110 ghuddy 243
               if (wr.Characters.Last.Text.Equals("\r"))
244
                  wr.End = wr.End - 1;  // dont italicise the \r char at the end
2094 ghuddy 245
               wr.Font.Italic = 1;
246
               wr.Font.Color = Word.WdColor.wdColorRed;
247
            }
248
         }
249
      }
250
 
251
 
2106 ghuddy 252
      public static void appendUnitTestSuite(EA.Package thePackage, int recurse_level, ref ArrayList classList)
2094 ghuddy 253
      {
254
         EA_ElementSorter elementSorter = new EA_ElementSorter(thePackage);
255
         EA.Element theElement = null;
256
         int theElementsRelativeLevel = 0;
257
         if (true == elementSorter.getFirst(ref theElement, ref theElementsRelativeLevel))
258
         {
259
            do
260
            {
261
               if (theElement.Type.StartsWith("Class"))
262
               {
2106 ghuddy 263
                  appendUnitTestSuite(theElement, recurse_level, ref classList);
2094 ghuddy 264
               }
265
 
266
            } while (true == elementSorter.getNext(ref theElement, ref theElementsRelativeLevel));
267
         }
268
 
269
         // Scan through the packages within this package.
270
         foreach(EA.Package lowerLevelPackage in thePackage.Packages)
271
         {
272
            // recurse
2106 ghuddy 273
            appendUnitTestSuite(lowerLevelPackage, recurse_level, ref classList);
2094 ghuddy 274
         }
275
      }
276
 
277
 
2106 ghuddy 278
      public static void SelectInsertionPointAtEndOfDocument()
2094 ghuddy 279
      {
280
         object unit; 
281
         object extend;
282
 
283
         unit = Word.WdUnits.wdStory; 
284
         extend = Word.WdMovementType.wdMove;
2106 ghuddy 285
         createWordDoc.WordApp.Selection.EndKey(ref unit, ref extend);
2094 ghuddy 286
      }
287
 
288
 
289
      /// <summary>
2110 ghuddy 290
      /// Generates the text for requirements.  
2094 ghuddy 291
      /// </summary>
2106 ghuddy 292
      public static bool generateRequirementText( EA.Element theElement )
2094 ghuddy 293
      {
294
         if ( theElement.Type.StartsWith("Requirement"))
295
         {
2104 ghuddy 296
            string reqID = "";
297
            string reqShortDesc = "";
298
            string reqHeadingStyle ="";
299
            string reqParaStyle = "";
2106 ghuddy 300
 
2104 ghuddy 301
 
302
            // Set the style depending on the status
303
            switch ( theElement.Status )
2094 ghuddy 304
            {
2104 ghuddy 305
               case "Proposed":
306
                  reqHeadingStyle = EA_Constants.styleName_ReqPropHdr;
307
                  reqParaStyle    = EA_Constants.styleName_ReqPropBody;
308
                  break;
2094 ghuddy 309
 
2104 ghuddy 310
               case "Rejected":
311
                  reqHeadingStyle = EA_Constants.styleName_ReqRejHdr;
312
                  reqParaStyle    = EA_Constants.styleName_ReqRejBody;
313
                  break;
2094 ghuddy 314
 
2104 ghuddy 315
               case "Approved":
316
                  reqHeadingStyle = EA_Constants.styleName_ReqAppHdr;
317
                  reqParaStyle    = EA_Constants.styleName_ReqAppBody;
318
                  break;
2094 ghuddy 319
 
2104 ghuddy 320
               default:
321
                  reqHeadingStyle = EA_Constants.styleName_ReqAppHdr;
322
                  reqParaStyle    = EA_Constants.styleName_ReqAppBody;
323
                  break;
324
            }
2094 ghuddy 325
 
2110 ghuddy 326
            // A requirement name is assumed to consist of:
327
            //
328
            //    <ID> [ShortDescription]
329
            //
330
            // Where <ID> is defined as
331
            //
332
            //    <TAG>n[subLevel]
333
            //
334
            // Where n is a numeric integer and sublevel is defined as
335
            //
336
            //    .n[sublevel]
337
            // 
338
            // Some examples
339
            //    SPR1  My Requirement
340
            //    SPR1.1 My Sub-requirement
341
            //    SPR1.1.1 My Sub-requirements Sub-Requirement
342
            //    CR1
343
            // 
344
            // Also, it is assumed that the element notes contains a long description
345
            // of the requirement.
346
 
2104 ghuddy 347
            // Pull out the ID from the name
348
            int pos = theElement.Name.IndexOf( " ", 0, theElement.Name.Length );
2106 ghuddy 349
            if (pos > 0)
2110 ghuddy 350
            {
2106 ghuddy 351
               reqID = theElement.Name.Substring( 0, pos );
2110 ghuddy 352
            }
2094 ghuddy 353
 
2110 ghuddy 354
            // Count '.' chars in the ID in order to support the progressive indentation 
355
            // of lower level requirements in the generated document
2106 ghuddy 356
            int numDots = 0;
357
            foreach (char c in reqID)
358
            {
359
               if (c == '.')
360
                  numDots++;
361
            }
362
 
2110 ghuddy 363
            // Calculate what the left/hanging indent should be based on the standard 2.5 cm plus 
364
            // 0.5cm * number of dots in the ID
365
            // Do calculation directly in points (72 points per inch) to avoid having to call
366
            // CentimetersToPoints repeatedly in the word app com object, which I have seen
367
            // cause unspecified exceptions on rare occasions.
368
            float indent_pts = (float)70.866;
369
            if (numDots > 0)
370
            {
371
               indent_pts += (float)(14.1732 * numDots);
372
            }
2106 ghuddy 373
 
2110 ghuddy 374
            // Pull out the short description from the rest of the name. If the short description
375
            // does not exist, substitute in its place, the element notes.
376
            bool doneNotes = false;
2104 ghuddy 377
            reqShortDesc = theElement.Name.Substring( pos, theElement.Name.Length-pos );
378
            reqShortDesc = reqShortDesc.Trim();
2110 ghuddy 379
            if (reqShortDesc.Length == 0)
380
            {
381
               // If there is no short description, then use the element notes instead
382
               doneNotes = true;
383
               if (theElement.Notes != null && theElement.Notes.Length > 0)
384
               {
385
                  reqShortDesc = theElement.Notes;
386
               }
387
            }
2094 ghuddy 388
 
2110 ghuddy 389
            // Add the ID to the document
2106 ghuddy 390
            Word.Range wr_id = appendAndSelectText( reqID + '\t', reqHeadingStyle );
2110 ghuddy 391
 
392
            // Add the short description to the document
2106 ghuddy 393
            Word.Range wr_desc = appendAndSelectText( reqShortDesc, reqHeadingStyle, true );
2110 ghuddy 394
            if (wr_desc != null)
395
            {
396
               // Bold the short description, but only if the element notes have not been used
397
               // as the short description. Element notes may contain a lot of text and having
398
               // it all bolded can make the document look a little too busy, and the reader
399
               // may lose sight of the real document headings which are ofcoarse naturally bolded.
2094 ghuddy 400
 
2110 ghuddy 401
               wr_desc.Start = wr_desc.Start-1;  //compensate for problem in appendAndSelectText();
402
               if (!doneNotes)
403
               {
404
                  if (wr_desc.Characters.Last.Text.Equals("\r"))
405
                     wr_desc.End = wr_desc.End - 1;   // Dont boldise the \r paragraph marker
406
                  wr_desc.Font.Bold = 1;
407
               }
2106 ghuddy 408
 
2110 ghuddy 409
               // Indent according to the number of dots in the tag
410
               if (numDots > 0)
411
               {
412
                  wr_desc.ParagraphFormat.LeftIndent      = indent_pts;
413
 
414
                  wr_desc.ParagraphFormat.FirstLineIndent = -indent_pts;
415
               }
2106 ghuddy 416
            }
417
 
2110 ghuddy 418
            // Add requirement notes/body, if we have not already consumed them for the
419
            // short description
420
            if (!doneNotes && theElement.Notes != null && theElement.Notes.Length > 0)
2106 ghuddy 421
            {
422
               Word.Range wr_body = appendAndSelectText( theElement.Notes, reqParaStyle );
423
 
424
               // indent according to the number of dots in the tag
425
               if (numDots > 0)
426
               {
2110 ghuddy 427
                  wr_body.ParagraphFormat.LeftIndent = indent_pts;
2106 ghuddy 428
               }
429
            }
430
            else
431
            {
432
               // If the requirement has no body text, its SpaceAfter will be 3, so we adjust it here to 6
433
               // just like what the body would have, if it were present.
2110 ghuddy 434
               if (wr_desc != null)
435
                  wr_desc.ParagraphFormat.SpaceAfter = 6;
436
               else if (wr_id != null)
437
                  wr_id.ParagraphFormat.SpaceAfter = 6;
2106 ghuddy 438
            }
439
 
2110 ghuddy 440
            // tack on the end a source reference for the requirement, if it contains one
441
            // as evidenced by tagged values
442
            string src = EA_Utilities.ReadTag(theElement, "SOURCE");
443
            if (src.Length > 0)
444
            {
445
               StringBuilder sb = new StringBuilder();
446
 
447
               string srcVer = EA_Utilities.ReadTag(theElement, "SOURCE_VERSION");
448
               sb.Append("[");
449
               sb.Append(src);
450
 
451
               if (srcVer.Length > 0)
452
               {
453
                  sb.Append(" v");
454
                  sb.Append(srcVer);
455
               }
456
 
457
               string srcSect = EA_Utilities.ReadTag(theElement, "SOURCE_SECTION");
458
               if (srcSect.Length > 0)
459
               {
460
                  sb.Append(" section ");
461
                  sb.Append(srcSect);
462
               }
463
               sb.Append("]");
464
 
465
               Word.Range wrs_body = appendAndSelectText(sb.ToString(), reqParaStyle);
466
               if (wrs_body.Characters.Last.Text.Equals("\r"))
467
                  wrs_body.End = wrs_body.End - 1;  // dont italicise the \r char at the end - doing so causes wierd ms-word exceptions later on
468
               wrs_body.Font.Italic = 1;
469
               if (numDots > 0)
470
               {
471
                  wrs_body.ParagraphFormat.LeftIndent = indent_pts;
472
               }
473
            }
474
 
2104 ghuddy 475
            return true;
476
 
2094 ghuddy 477
         }
478
 
479
         return false;
480
      }
481
 
2106 ghuddy 482
   }
2094 ghuddy 483
}