Subversion Repositories DevTools

Rev

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