Subversion Repositories DevTools

Rev

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