Subversion Repositories DevTools

Rev

Rev 2128 | 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;
2136 brianf 4
using System.Web;
5
using System.IO;
6
using Microsoft.Office.Interop.Word;
2094 ghuddy 7
 
8
namespace EA_DocGen
9
{
10
	/// <summary>
11
	/// Summary description for TextualContent.
12
	/// </summary>
2106 ghuddy 13
   public class TextualContent
14
   {
15
      private static char[] trim_newlines;
2094 ghuddy 16
 
2106 ghuddy 17
      public static void initialise()
2094 ghuddy 18
      {
2106 ghuddy 19
         string s_trim_newlines = "\r\n";
20
         trim_newlines = s_trim_newlines.ToCharArray();
2094 ghuddy 21
      }
22
 
2136 brianf 23
       public static Range appendDescription(string wordText)
2094 ghuddy 24
      {
2106 ghuddy 25
         return appendDescription(wordText, false);
2098 ghuddy 26
      }
27
 
2136 brianf 28
       public static Range appendDescription(string wordText, bool continuation)
2098 ghuddy 29
      {
2106 ghuddy 30
         return appendDescription(wordText, EA_Constants.styleName_Body1, continuation);
2098 ghuddy 31
      }
32
 
2136 brianf 33
       public static Range appendDescription(string wordText, string styleName, bool continuation)
2098 ghuddy 34
      {
2136 brianf 35
          Range wr = null;
2094 ghuddy 36
 
37
         if (wordText != null && wordText.Length > 0)
2106 ghuddy 38
         {
2098 ghuddy 39
            wr = appendAndSelectText(wordText, styleName, continuation);
2106 ghuddy 40
         }
2116 ghuddy 41
         else if (!EA_DocGenOptions.optionValue(EA_DocGenOptions.boolean_options_e.SUPPRESS_ELEMENT_DESC_MISSING_WARNINGS))
2094 ghuddy 42
         {
2098 ghuddy 43
            wr = appendAndSelectText("Description missing!", styleName, continuation);
2126 ghuddy 44
 
2110 ghuddy 45
            if (wr.Characters.Last.Text.Equals("\r"))
46
               wr.End = wr.End - 1;  // dont italicise the \r char at the end
2094 ghuddy 47
            wr.Font.Italic = 1;
2136 brianf 48
            wr.Font.Color = WdColor.wdColorRed;
2094 ghuddy 49
         }
50
         return wr;
51
      }
52
 
2098 ghuddy 53
 
2126 ghuddy 54
 
2094 ghuddy 55
      /// <summary>
56
      /// Appends a specified text string to the word document, selects the new text, and applies
57
      /// the specified style formatting to it.
58
      /// </summary>
59
      /// <param name="wordText"></param>
60
      /// <param name="styleText"></param>
61
      /// <param name="continuation"></param>
2136 brianf 62
       public static Range appendAndSelectText(string wordText, string styleText)
2126 ghuddy 63
      {
2094 ghuddy 64
         return appendAndSelectText(wordText, styleText, false );
65
      }
66
 
67
 
2136 brianf 68
       public static Range appendAndSelectText(string wordText, string styleText, bool continuation)
2094 ghuddy 69
      {
2124 ghuddy 70
         if (wordText != null && wordText.Length > 0)
2094 ghuddy 71
         {
2136 brianf 72
            Range WordRange = null;
2094 ghuddy 73
            object startLocation;
74
            object endLocation;
75
 
76
            object style = styleText;
77
            int i;
78
            startLocation = 0;
2106 ghuddy 79
            endLocation = i = createWordDoc.WordDocument.Content.End;
2094 ghuddy 80
 
2106 ghuddy 81
            WordRange = createWordDoc.WordDocument.Range(ref startLocation, ref endLocation);
2094 ghuddy 82
 
83
            if (!continuation)
84
               WordRange.InsertAfter( "\n" );
2110 ghuddy 85
 
2094 ghuddy 86
            WordRange.InsertAfter( wordText );
87
 
88
            // Make a range out of the pasted text
89
            startLocation = i;
2106 ghuddy 90
            endLocation = createWordDoc.WordDocument.Content.End;
91
            WordRange = createWordDoc.WordDocument.Range(ref startLocation, ref endLocation);
2094 ghuddy 92
 
93
            // and set the pasted text style
94
            WordRange.set_Style(ref style);
2126 ghuddy 95
 
96
            // compensate for wierd off by one error in the range object when using continuation
97
            if (continuation)
98
                WordRange.Start--;
99
 
2094 ghuddy 100
            return WordRange;
101
         }
102
         return null;
103
      }
104
 
2126 ghuddy 105
 
2094 ghuddy 106
      /// <summary>
107
      /// Appends a specified text string to the word document, selects the new text, and applies
2126 ghuddy 108
      /// a heading level style to it.
2094 ghuddy 109
      /// </summary>
110
      /// <param name="wordText"></param>
111
      /// <param name="level"></param>
2106 ghuddy 112
      public static void appendAndSelectHeadingText(string wordText, int level)
2094 ghuddy 113
      {
2104 ghuddy 114
         // A caller is requesting a new heading level so pass the level to the tracking
115
         // object so that we can predict exactly what the level numbering should be for
116
         // diagnostics and fake heading generation (see below in the switch statement).
2106 ghuddy 117
         DocSectionTracking.trackDocSection(level);
2104 ghuddy 118
 
2094 ghuddy 119
         // Convert level to heading style
120
         string styleText;
121
         switch(level)
122
         {
123
            case 1: styleText = EA_Constants.styleName_Heading1; break;
124
            case 2: styleText = EA_Constants.styleName_Heading2; break;
125
            case 3: styleText = EA_Constants.styleName_Heading3; break;
126
            case 4: styleText = EA_Constants.styleName_Heading4; break;
127
            case 5: styleText = EA_Constants.styleName_Heading5; break;
128
            case 6: styleText = EA_Constants.styleName_Heading6; break;
129
            case 7: styleText = EA_Constants.styleName_Heading7; break;
130
            case 8: styleText = EA_Constants.styleName_Heading8; break;
131
            case 9: styleText = EA_Constants.styleName_Heading9; break;
2104 ghuddy 132
 
2126 ghuddy 133
            default:
134
               // MS-Word cannot produce headings above level 9 and so we have to
2104 ghuddy 135
               // fake a heading by constructing it from our document section tracking data.
136
               styleText = EA_Constants.styleName_Heading10OrAbove;
2106 ghuddy 137
               wordText = DocSectionTracking.formHeadingString(wordText);
2104 ghuddy 138
               break;
2094 ghuddy 139
         }
140
         // append the text as a heading
141
         appendAndSelectText(wordText, styleText);
142
      }
143
 
2116 ghuddy 144
      /// <summary>
145
      /// Appends a specified text string to the word document, selects the new text, and applies
2126 ghuddy 146
      /// a numpara level style to it.
2116 ghuddy 147
      /// </summary>
148
      /// <param name="wordText"></param>
149
      /// <param name="level"></param>
150
      public static void appendAndSelectNumParaText(string wordText, int level)
151
      {
152
         // A caller is requesting a new heading level so pass the level to the tracking
153
         // object so that we can predict exactly what the level numbering should be for
154
         // diagnostics and fake heading generation (see below in the switch statement).
155
         DocSectionTracking.trackDocSection(level);
156
 
157
         // Convert level to heading style
158
         string styleText;
159
         switch(level)
160
         {
161
            case 1: styleText = EA_Constants.styleName_NumPara1; break;
162
            case 2: styleText = EA_Constants.styleName_NumPara2; break;
163
            case 3: styleText = EA_Constants.styleName_NumPara3; break;
164
            case 4: styleText = EA_Constants.styleName_NumPara4; break;
165
            case 5: styleText = EA_Constants.styleName_NumPara5; break;
166
            case 6: styleText = EA_Constants.styleName_NumPara6; break;
167
            case 7: styleText = EA_Constants.styleName_NumPara7; break;
168
            case 8: styleText = EA_Constants.styleName_NumPara8; break;
169
            case 9: styleText = EA_Constants.styleName_NumPara9; break;
170
 
2126 ghuddy 171
            default:
172
               // MS-Word cannot produce headings above level 9 and so we have to
2116 ghuddy 173
               // fake a heading by constructing it from our document section tracking data.
174
               styleText = EA_Constants.styleName_NumPara10OrAbove;
175
               wordText = DocSectionTracking.formHeadingString(wordText);
176
               break;
177
         }
178
         // append the text as a heading
179
         appendAndSelectText(wordText, styleText);
180
      }
181
 
182
 
2106 ghuddy 183
      public static string trimTrailingReturns(string s)
2094 ghuddy 184
      {
2124 ghuddy 185
         if (s != null)
186
            return s.TrimEnd(trim_newlines);
187
         else
188
            return null;
2106 ghuddy 189
      }
190
 
2126 ghuddy 191
 
192
 
2106 ghuddy 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
            {
2136 brianf 242
               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;
2136 brianf 246
               wr.Font.Color = WdColor.wdColorRed;
2094 ghuddy 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
      {
2126 ghuddy 280
         object unit;
2094 ghuddy 281
         object extend;
282
 
2136 brianf 283
         unit = WdUnits.wdStory;
284
         extend = WdMovementType.wdMove;
2106 ghuddy 285
         createWordDoc.WordApp.Selection.EndKey(ref unit, ref extend);
2094 ghuddy 286
      }
287
 
288
 
289
      /// <summary>
2126 ghuddy 290
      /// Generates the text for requirements.
2094 ghuddy 291
      /// </summary>
2106 ghuddy 292
      public static bool generateRequirementText( EA.Element theElement )
2094 ghuddy 293
      {
2124 ghuddy 294
         if (theElement.Type.StartsWith("Requirement"))
2094 ghuddy 295
         {
2104 ghuddy 296
            string reqID = "";
297
            string reqShortDesc = "";
298
            string reqHeadingStyle ="";
299
            string reqParaStyle = "";
300
 
2126 ghuddy 301
 
2104 ghuddy 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]
2126 ghuddy 337
            //
2110 ghuddy 338
            // Some examples
339
            //    SPR1  My Requirement
340
            //    SPR1.1 My Sub-requirement
341
            //    SPR1.1.1 My Sub-requirements Sub-Requirement
342
            //    CR1
2126 ghuddy 343
            //
2110 ghuddy 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
 
2126 ghuddy 354
            // Count '.' chars in the ID in order to support the progressive indentation
2110 ghuddy 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
 
2126 ghuddy 363
            // Calculate what the left/hanging indent should be based on the standard 2.5 cm plus
2110 ghuddy 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
2136 brianf 390
            Range wr_id = appendAndSelectText( reqID + '\t', reqHeadingStyle );
2126 ghuddy 391
 
2110 ghuddy 392
            // Add the short description to the document
2136 brianf 393
            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
               if (!doneNotes)
402
               {
403
                  if (wr_desc.Characters.Last.Text.Equals("\r"))
404
                     wr_desc.End = wr_desc.End - 1;   // Dont boldise the \r paragraph marker
405
                  wr_desc.Font.Bold = 1;
406
               }
2106 ghuddy 407
 
2110 ghuddy 408
               // Indent according to the number of dots in the tag
409
               if (numDots > 0)
410
               {
411
                  wr_desc.ParagraphFormat.LeftIndent      = indent_pts;
412
 
413
                  wr_desc.ParagraphFormat.FirstLineIndent = -indent_pts;
414
               }
2106 ghuddy 415
            }
416
 
2110 ghuddy 417
            // Add requirement notes/body, if we have not already consumed them for the
418
            // short description
2124 ghuddy 419
            if (!doneNotes && theElement.Notes != null && theElement.Notes.Length > 0 && !EA_DocGenOptions.optionValue(EA_DocGenOptions.boolean_options_e.SUPPRESS_REQUIREMENT_NOTES))
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
 
2136 brianf 458
               Range wrs_body = appendAndSelectText(sb.ToString(), reqParaStyle);
2110 ghuddy 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
 
2136 brianf 475
      public static string HtmlDecode(string sHtml)
476
      {
477
          StringWriter writer = new StringWriter();
478
          HttpUtility.HtmlDecode(sHtml, writer);
479
          return writer.ToString();
480
      }
481
 
2106 ghuddy 482
   }
2094 ghuddy 483
}