Subversion Repositories DevTools

Rev

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

Rev Author Line No. Line
2088 ghuddy 1
using System;
2
using System.Drawing;
3
using System.Collections;
2094 ghuddy 4
using System.Text;
2088 ghuddy 5
using System.ComponentModel;
6
using System.Windows.Forms;
7
using Word;
2092 ghuddy 8
using Microsoft.Office.Core;
2088 ghuddy 9
 
2092 ghuddy 10
 
2088 ghuddy 11
namespace EA_DocGen
12
{
13
 
14
 
15
   /// <summary>
16
   /// Summary description for createWordDoc.
17
   /// </summary>
18
   public class createWordDoc : System.Windows.Forms.Form
19
   {
20
      // Enterprise Architect Model related data
21
      private EA.Repository EA_Repository = null;
22
      private EA.Package EA_ParentPackage = null;
23
      private EA.Project EA_Project;
2094 ghuddy 24
 
2088 ghuddy 25
      private EA_Utilities EA_Utils = null;
26
 
2094 ghuddy 27
      private TabularContent TableUtils = null;
28
      private TextualContent TextUtils = null;
29
      private StyleContent   StyleUtils = null;
30
 
2088 ghuddy 31
      private bool oneShot_skipRootPackage = false;
2094 ghuddy 32
      private bool oneShot_skipRootElementHeading = false;
2088 ghuddy 33
 
2094 ghuddy 34
      // This data is designed to support unit test traceability. As such, it is only of real use
35
      // when making s/w design documents. It allows all non-private classes to be collected into
36
      // a list in order to generate a design-to-unit-test traceability table.
37
      private bool recordingNonPrivateClasses = false;
38
      private ArrayList nonPrivateClasses = null;
39
      private ArrayList classesWithUnitTests = null;
40
      private Word.Table utTraceabilityTable = null;
41
 
2088 ghuddy 42
      // MS-Office Word related data
43
      private Word.Application WordApp = null;
44
      private Word.Document WordDocument = null;
2094 ghuddy 45
 
2088 ghuddy 46
      private int[] DocSection = null;
47
      private int   iDocSection = 0;
48
 
49
      private System.Windows.Forms.TextBox textBox_template;
50
      private System.Windows.Forms.Button button_browse_template;
51
      private System.Windows.Forms.TextBox textBox_output_file;
52
      private System.Windows.Forms.Button button_browse_output_file;
53
      private System.Windows.Forms.Button button_cancel;
54
      private System.Windows.Forms.Button button_generate;
55
      private System.Windows.Forms.Button button_view_output;
56
      private System.Windows.Forms.Label label1;
57
      private System.Windows.Forms.Label label2;
58
      private System.Windows.Forms.TextBox textBox_progress;
59
      private System.Windows.Forms.Label label3;
60
      private System.Windows.Forms.CheckBox checkBox_WordVisibility;
61
      /// <summary>
62
      /// Required designer variable.
63
      /// </summary>
64
      private System.ComponentModel.Container components = null;
65
 
66
      public createWordDoc(EA.Repository theRepository, EA.Package theParentPackage, EA_Utilities theEA_Utils)
67
      {
68
         //
69
         // Required for Windows Form Designer support
70
         //
71
         InitializeComponent();
72
 
73
         EA_Repository    = theRepository;
74
         EA_ParentPackage = theParentPackage;
75
         EA_Project       = EA_Repository.GetProjectInterface();
76
 
77
         EA_Utils         = theEA_Utils;
78
 
2094 ghuddy 79
         TableUtils       = new TabularContent(WordApp, WordDocument);
80
         TextUtils        = new TextualContent(WordApp, WordDocument);
81
         StyleUtils       = new StyleContent(WordApp, WordDocument);
82
 
83
 
2088 ghuddy 84
         DocSection = new int[12];
85
         for (int i=0; i<DocSection.Length; i++)
86
         {
87
            DocSection[i] = 0;
88
         }
89
 
90
         WordApp = new Word.Application();
91
      }
92
 
2094 ghuddy 93
 
2088 ghuddy 94
      /// <summary>
95
      /// Clean up any resources being used.
96
      /// </summary>
97
      protected override void Dispose( bool disposing )
98
      {
99
         if( disposing )
100
         {
101
            if(components != null)
102
            {
103
               components.Dispose();
104
            }
105
         }
106
         base.Dispose( disposing );
107
      }
108
 
109
 
110
 
111
 
112
      #region Windows Form Designer generated code
113
      /// <summary>
114
      /// Required method for Designer support - do not modify
115
      /// the contents of this method with the code editor.
116
      /// </summary>
117
      private void InitializeComponent()
118
      {
119
         this.textBox_template = new System.Windows.Forms.TextBox();
120
         this.button_browse_template = new System.Windows.Forms.Button();
121
         this.textBox_output_file = new System.Windows.Forms.TextBox();
122
         this.button_browse_output_file = new System.Windows.Forms.Button();
123
         this.button_cancel = new System.Windows.Forms.Button();
124
         this.button_generate = new System.Windows.Forms.Button();
125
         this.button_view_output = new System.Windows.Forms.Button();
126
         this.label1 = new System.Windows.Forms.Label();
127
         this.label2 = new System.Windows.Forms.Label();
128
         this.textBox_progress = new System.Windows.Forms.TextBox();
129
         this.label3 = new System.Windows.Forms.Label();
130
         this.checkBox_WordVisibility = new System.Windows.Forms.CheckBox();
131
         this.SuspendLayout();
132
         // 
133
         // textBox_template
134
         // 
135
         this.textBox_template.Location = new System.Drawing.Point(16, 40);
136
         this.textBox_template.Name = "textBox_template";
137
         this.textBox_template.Size = new System.Drawing.Size(592, 22);
138
         this.textBox_template.TabIndex = 0;
139
         this.textBox_template.Text = "";
140
         this.textBox_template.TextChanged += new System.EventHandler(this.textBox_template_TextChanged);
141
         // 
142
         // button_browse_template
143
         // 
144
         this.button_browse_template.Location = new System.Drawing.Point(616, 40);
145
         this.button_browse_template.Name = "button_browse_template";
146
         this.button_browse_template.Size = new System.Drawing.Size(80, 23);
147
         this.button_browse_template.TabIndex = 1;
148
         this.button_browse_template.Text = "Browse";
149
         this.button_browse_template.Click += new System.EventHandler(this.button_browse_template_Click);
150
         // 
151
         // textBox_output_file
152
         // 
153
         this.textBox_output_file.Location = new System.Drawing.Point(16, 112);
154
         this.textBox_output_file.Name = "textBox_output_file";
155
         this.textBox_output_file.Size = new System.Drawing.Size(592, 22);
156
         this.textBox_output_file.TabIndex = 2;
157
         this.textBox_output_file.Text = "";
158
         this.textBox_output_file.TextChanged += new System.EventHandler(this.textBox_output_file_TextChanged);
159
         // 
160
         // button_browse_output_file
161
         // 
162
         this.button_browse_output_file.Location = new System.Drawing.Point(616, 112);
163
         this.button_browse_output_file.Name = "button_browse_output_file";
164
         this.button_browse_output_file.Size = new System.Drawing.Size(80, 24);
165
         this.button_browse_output_file.TabIndex = 3;
166
         this.button_browse_output_file.Text = "Browse";
167
         this.button_browse_output_file.Click += new System.EventHandler(this.button_browse_output_file_Click);
168
         // 
169
         // button_cancel
170
         // 
171
         this.button_cancel.Location = new System.Drawing.Point(616, 384);
172
         this.button_cancel.Name = "button_cancel";
173
         this.button_cancel.Size = new System.Drawing.Size(80, 23);
174
         this.button_cancel.TabIndex = 4;
175
         this.button_cancel.Text = "Close";
176
         this.button_cancel.Click += new System.EventHandler(this.button_cancel_Click);
177
         // 
178
         // button_generate
179
         // 
180
         this.button_generate.Location = new System.Drawing.Point(496, 384);
181
         this.button_generate.Name = "button_generate";
182
         this.button_generate.Size = new System.Drawing.Size(96, 24);
183
         this.button_generate.TabIndex = 5;
184
         this.button_generate.Text = "Generate";
185
         this.button_generate.Click += new System.EventHandler(this.button_generate_Click);
186
         // 
187
         // button_view_output
188
         // 
2098 ghuddy 189
         this.button_view_output.Enabled = false;
2088 ghuddy 190
         this.button_view_output.Location = new System.Drawing.Point(376, 384);
191
         this.button_view_output.Name = "button_view_output";
192
         this.button_view_output.Size = new System.Drawing.Size(96, 23);
193
         this.button_view_output.TabIndex = 6;
194
         this.button_view_output.Text = "View Output";
195
         this.button_view_output.Click += new System.EventHandler(this.button_view_output_Click);
196
         // 
197
         // label1
198
         // 
199
         this.label1.Location = new System.Drawing.Point(16, 16);
200
         this.label1.Name = "label1";
201
         this.label1.Size = new System.Drawing.Size(224, 23);
202
         this.label1.TabIndex = 7;
203
         this.label1.Text = "Input Template or Document Name";
204
         // 
205
         // label2
206
         // 
207
         this.label2.Location = new System.Drawing.Point(16, 88);
208
         this.label2.Name = "label2";
209
         this.label2.Size = new System.Drawing.Size(280, 23);
210
         this.label2.TabIndex = 8;
211
         this.label2.Text = "Output Document Name";
212
         // 
213
         // textBox_progress
214
         // 
215
         this.textBox_progress.Location = new System.Drawing.Point(16, 184);
216
         this.textBox_progress.Multiline = true;
217
         this.textBox_progress.Name = "textBox_progress";
218
         this.textBox_progress.ReadOnly = true;
219
         this.textBox_progress.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
220
         this.textBox_progress.Size = new System.Drawing.Size(680, 168);
221
         this.textBox_progress.TabIndex = 9;
222
         this.textBox_progress.Text = "";
223
         // 
224
         // label3
225
         // 
226
         this.label3.Location = new System.Drawing.Point(16, 152);
227
         this.label3.Name = "label3";
228
         this.label3.TabIndex = 10;
229
         this.label3.Text = "Progress";
230
         // 
231
         // checkBox_WordVisibility
232
         // 
233
         this.checkBox_WordVisibility.Location = new System.Drawing.Point(16, 384);
234
         this.checkBox_WordVisibility.Name = "checkBox_WordVisibility";
235
         this.checkBox_WordVisibility.Size = new System.Drawing.Size(256, 24);
236
         this.checkBox_WordVisibility.TabIndex = 17;
237
         this.checkBox_WordVisibility.Text = "Show MS-WORD During Construction";
238
         // 
239
         // createWordDoc
240
         // 
241
         this.AutoScaleBaseSize = new System.Drawing.Size(6, 15);
242
         this.ClientSize = new System.Drawing.Size(712, 432);
243
         this.Controls.Add(this.checkBox_WordVisibility);
244
         this.Controls.Add(this.label3);
245
         this.Controls.Add(this.textBox_progress);
246
         this.Controls.Add(this.textBox_output_file);
247
         this.Controls.Add(this.textBox_template);
248
         this.Controls.Add(this.label2);
249
         this.Controls.Add(this.label1);
250
         this.Controls.Add(this.button_view_output);
251
         this.Controls.Add(this.button_generate);
252
         this.Controls.Add(this.button_cancel);
253
         this.Controls.Add(this.button_browse_output_file);
254
         this.Controls.Add(this.button_browse_template);
255
         this.Name = "createWordDoc";
256
         this.Text = "createWordDoc";
257
         this.Closing += new System.ComponentModel.CancelEventHandler(this.createWordDoc_Closing);
258
         this.ResumeLayout(false);
259
 
260
      }
261
      #endregion
262
 
263
 
264
      #region Message handlers
265
      private void button_view_output_Click(object sender, System.EventArgs e)
266
      {
267
         if (WordApp != null)
268
         {
269
            WordApp.Visible = true;
270
         }
2094 ghuddy 271
         button_view_output.Enabled = false;
2088 ghuddy 272
      }
273
 
274
 
275
 
276
 
277
      private void button_generate_Click(object sender, System.EventArgs e)
278
      {
279
         if (this.textBox_template.Text.Length > 0)
280
         {
281
            if (this.textBox_output_file.Text.Length > 0)
282
            {
2094 ghuddy 283
               button_generate.Enabled = false;
2088 ghuddy 284
               createTheWordDoc();
285
            }
286
            else
287
            {
288
               MessageBox.Show("Error - must specify an output file");
289
            }
290
         }
291
         else
292
         {
293
            MessageBox.Show("Error - must specify an input template file");
294
         }
295
      }
296
 
297
      private void button_cancel_Click(object sender, System.EventArgs e)
298
      {
299
         this.Close();   
300
      }
301
 
302
      private void button_browse_template_Click(object sender, System.EventArgs e)
303
      {
304
         OpenFileDialog dialog = new OpenFileDialog();
305
         dialog.Filter = "Word Files (*.doc;*.dot)|*.doc;*.dot|All files(*.*)|*.*";
306
         dialog.FilterIndex = 1;
307
         dialog.ShowDialog();
308
         this.textBox_template.Text = dialog.FileName;
309
 
310
      }
311
 
312
      private void button_browse_output_file_Click(object sender, System.EventArgs e)
313
      {
314
         OpenFileDialog dialog = new OpenFileDialog();
315
         dialog.Filter = "Word Files (*.doc;*.dot)|*.doc;*.dot|All files(*.*)|*.*";
316
         dialog.FilterIndex = 1;
317
         dialog.CheckFileExists = false;
318
         dialog.ShowDialog();
319
         this.textBox_output_file.Text = dialog.FileName;
320
      }
321
 
322
      private void textBox_template_TextChanged(object sender, System.EventArgs e)
323
      {
324
 
325
      }
326
 
327
      private void textBox_output_file_TextChanged(object sender, System.EventArgs e)
328
      {
329
 
330
      }
331
 
332
      private void createWordDoc_Closing(object sender, System.ComponentModel.CancelEventArgs e)
333
      {
334
         if (WordApp != null)
335
         {
336
            // try-catch just in case user closed the application themselves whilst viewing the
337
            // generated output document
338
            try 
339
            {
340
               object nothing = Type.Missing;
341
               object notTrue = false;
342
 
343
               WordApp.Application.Quit( ref notTrue, ref nothing, ref nothing);
344
            }
345
            catch (Exception createWordDoc_Closing_exception)
346
            {
347
               // dummy statement
348
               String s = createWordDoc_Closing_exception.Message;
349
            }
350
         }
351
      }
352
 
353
      #endregion
354
 
355
 
356
      #region word document generation code
357
 
358
      /// <summary>
359
      /// This class is one derived from the EA_UtilitiesRecursionWorker base class so that
360
      /// an instance of it can be used as a parameter in the EA_Utilities.findAndProcessPackageElements
361
      /// method which recursively parses a given package. Thus, clients can parse EA model structure but
362
      /// specify their own functionality to be carried out on packages and elements found in the 
363
      /// parsing.
364
      /// This particular derived class is designed to collect a list of element names from the
365
      /// package, from elements that have a type that is acceptable.
366
      /// </summary>
367
      public class ElementAccumulator : EA_UtilitiesRecursionWorker
368
      {
369
         public ArrayList Elements = null;
370
 
371
         private ArrayList validElementTypes = null;
372
 
2094 ghuddy 373
         private EA_Utilities EA_Utils = null;
374
 
375
         public ElementAccumulator(ArrayList elementTypeList, EA_Utilities theEA_Utils): base()
2088 ghuddy 376
         {
377
            validElementTypes = elementTypeList;
2094 ghuddy 378
            EA_Utils = theEA_Utils;
2088 ghuddy 379
            Elements = new ArrayList();
380
         }
381
 
382
         public override void processElement( EA.Element theElement )
383
         {
384
            if (validElementTypes.Contains( theElement.Type ))
385
            {
2094 ghuddy 386
               //if ( (theElement.Type == "Requirement") && (theElement.Status == "Rejected") )
387
               //   return;
2088 ghuddy 388
 
2094 ghuddy 389
               if (   0 == theElement.Type.CompareTo("Class")
390
                  && true == EA_Utils.options.opt_SuppressPrivateClasses
391
                  && true == theElement.Visibility.StartsWith("Private") )
392
               {
393
                  // do nothing
394
               }
395
               else
2098 ghuddy 396
               {
2094 ghuddy 397
                  Elements.Add( theElement );
2098 ghuddy 398
               }
2088 ghuddy 399
            }
400
         }
401
      }
402
 
403
 
404
      private void trackDocSection(int recurse_level)
405
      {
406
         iDocSection = recurse_level;
407
         DocSection[iDocSection]++;     
408
         for (int i=iDocSection+1; i<DocSection.Length; i++)
409
            DocSection[i] = 0;
410
      }
411
 
412
 
413
      /// <summary>
414
      /// Displays progress of the document generation in the createWordDocument dialog
415
      /// </summary>
416
      /// <param name="prefix"></param>
417
      /// <param name="EA_string"></param>
418
      private void displayProgress(string prefix, string EA_string)
419
      {
420
         textBox_progress.AppendText( prefix + EA_string + "\r\n" );
421
 
422
         // Display to the output tab as well - as a longer term record of what happened
2094 ghuddy 423
         StringBuilder sb = new StringBuilder("");
2088 ghuddy 424
         for (int i = 1; i<=iDocSection; i++)
425
         {
426
            if (i!=1)
2094 ghuddy 427
               sb.Append(".");
428
            sb.Append(DocSection[i].ToString());
2088 ghuddy 429
         }
2094 ghuddy 430
         while (sb.Length < 30)
431
            sb.Append(" ");
2088 ghuddy 432
 
2094 ghuddy 433
         sb.Append(prefix);
434
         sb.Append(EA_string);
435
 
436
         EA_Repository.WriteOutput( Main.GUI_OUTPUT_TAB_NAME, sb.ToString(), 0);
2088 ghuddy 437
      }
438
 
439
 
440
      /// <summary>
441
      /// This method takes the specified EA diagram element and puts the diagram image
442
      /// into the clipboard from where it can be pasted into the word document. After
443
      /// pasting it into the document, it sets the style and other aspects of the image.
444
      /// </summary>
445
      /// <param name="theDiagram"></param>
446
      private void appendAndSelectDiagramViaClipboard(EA.Diagram theDiagram)
447
      {
448
         // open the diagram in EA and copy it's image to the clipboard
449
         if (EA_Project.PutDiagramImageOnClipboard(theDiagram.DiagramGUID,0))
450
         {
2094 ghuddy 451
            object startLocation;
452
            object endLocation;
453
 
2098 ghuddy 454
            TextUtils.appendDescription( theDiagram.Notes, EA_Utils );
455
 
2088 ghuddy 456
            // create a range at the end of the document
457
            startLocation = WordDocument.Content.End;
458
            WordDocument.Content.InsertParagraphAfter();
459
            endLocation = WordDocument.Content.End;
2094 ghuddy 460
            Word.Range WordRange = WordDocument.Range(ref startLocation, ref endLocation);
2088 ghuddy 461
            object direction = Word.WdCollapseDirection.wdCollapseEnd;
462
            WordRange.Collapse(ref direction);  // collapse prevents existing content being replaced
463
 
464
            // Get ready for the diagram paste and the formatting we want to do on it with the
465
            // selection object.
2094 ghuddy 466
            TextUtils.SelectInsertionPointAtEndOfDocument();
2088 ghuddy 467
 
468
            // Paste the diagram into the document
469
            WordRange.Paste();           
470
 
471
            // Set style of the diagram to "Normal" so that it can occupy space all the way to the left margin
2094 ghuddy 472
            object l_style = EA_Constants.styleName_Normal;
2088 ghuddy 473
            endLocation = WordDocument.Content.End;
474
            WordRange = WordDocument.Range(ref startLocation, ref endLocation);
475
            WordRange.set_Style(ref l_style);
476
 
477
            // Center the diagram on the page
478
            object unit = Word.WdUnits.wdLine;
479
            object missing = Type.Missing;
480
            object count = 1;
481
            WordApp.Selection.MoveDown( ref unit, ref count, ref missing);
482
            WordApp.Selection.ParagraphFormat.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter;
483
 
484
            // Add a caption
485
            WordDocument.Content.InsertParagraphAfter();
2094 ghuddy 486
            TextUtils.SelectInsertionPointAtEndOfDocument();         
2088 ghuddy 487
            object Label = "Figure";
488
            object Title = Type.Missing;
489
            object TitleAutoText = Type.Missing;
490
            object Position = Word.WdCaptionPosition.wdCaptionPositionAbove;
491
            object ExcludeLabel = 0;
492
            WordApp.Selection.InsertCaption( ref Label, ref Title, ref TitleAutoText, ref Position, ref ExcludeLabel);
493
            WordApp.Selection.TypeText( ": " + theDiagram.Name.ToString());
494
            WordApp.Selection.ParagraphFormat.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter;
495
 
496
            // experimental code to create a bookmark for the figure caption
497
            //WordDocument.Paragraphs[ WordDocument.Paragraphs.Count ].Range.Select();
498
            //object lastParaRange = WordDocument.Paragraphs[ WordDocument.Paragraphs.Count ].Range;
499
            //string bookmarkName = theDiagram.Name;
500
            //bookmarkName = bookmarkName.Replace(' ', '_');
501
            //WordDocument.Bookmarks.Add( bookmarkName, ref lastParaRange );
502
 
503
            // Close the diagram in EA
504
            EA_Repository.CloseDiagram(theDiagram.DiagramID);
505
         }
506
      }
507
 
508
 
2094 ghuddy 509
      #region special element processing functions (link elements, table and text elements, etc)
2088 ghuddy 510
      /// <summary>
511
      /// This is an attempt to create a table similar in style to those made by the ERG doc template macros.
512
      /// It is not exaclty that same though, and further work could be done to align it more precisely.
513
      /// </summary>
514
      /// <param name="tableTitle"></param>
515
      /// <param name="numRows"></param>
516
      /// <param name="numCols"></param>
517
      /// <returns></returns>
2094 ghuddy 518
 
2088 ghuddy 519
      /// <summary>
520
      /// This function process a package link element, parsing each linked package by the
521
      /// parse_package() recursive function.
522
      /// </summary>
523
      /// <param name="theElement"></param>
524
      /// <param name="recurse_level"></param>
525
      private void processPackageLink(EA.Element theElement, int recurse_level)
526
      {
527
         string [] EA_DocGenPkgLnk = null;
528
         string delimStr = "\r\n";
529
         char [] delim = delimStr.ToCharArray();
530
         EA_DocGenPkgLnk = theElement.Notes.ToString().Split(delim,100);
531
         string linkedName = "";
532
 
533
         foreach(string s in EA_DocGenPkgLnk)
534
         {
535
            if (s.Length > 0 && s != "\n" && s != "\r")
536
            {
537
               if (s == "skiproot")
538
               {
539
                  oneShot_skipRootPackage = true;
540
               }
541
               else if (s[0] == '{')
542
               {
543
                  EA.Package theFoundPackage = EA_Utils.EA_Finder.findPackageInRepositoryByGUID(s);
544
                  if (theFoundPackage != null)
545
                  {
546
                     parse_package(theFoundPackage, recurse_level);
547
                  }
548
                  else
549
                  {
550
                     MessageBox.Show("WARNING - Could not find linked package : " + linkedName );
551
                  }
552
               }
553
               else
554
               {
555
                  linkedName = s;
556
               }            
557
            }
558
         }
559
      }
560
 
561
 
562
      /// <summary>
563
      /// This function process a diagram link element, using the appendAndSelectDiagramViaClipboard()
564
      /// for each linked diagram.
565
      /// </summary>
566
      /// <param name="theElement"></param>
567
      private void processDiagramLink(EA.Element theElement)
568
      {
569
         string [] EA_DocGenDiagLnk = null;
570
         string delimStr = "\r\n";
571
         char [] delim = delimStr.ToCharArray();
572
         EA_DocGenDiagLnk = theElement.Notes.ToString().Split(delim,100);
573
         string linkedName = "";
574
 
575
         foreach(string s in EA_DocGenDiagLnk)
576
         {
577
            if (s.Length > 0 && s != "\n" && s != "\r" )
578
            {
579
               if (s[0] == '{')
580
               {
581
                  EA.Diagram theFoundDiagram = EA_Utils.EA_Finder.findDiagramInRepositoryByGUID(s);
582
                  if (theFoundDiagram != null)
583
                  {
584
                     displayProgress( "DIAGRAM: ", theFoundDiagram.Name.ToString() );
585
                     appendAndSelectDiagramViaClipboard( theFoundDiagram );
586
                  }
587
                  else 
588
                  {
589
                     MessageBox.Show("WARNING - Could not find linked diagram : " + linkedName );
590
                  }
591
               }
592
               else
593
               {
594
                  linkedName = s;
595
               }            
596
            }
597
         }         
598
      }
599
 
600
 
601
      /// <summary>
602
      /// This function process an element link element, parsing each linked element by the
603
      /// parse_element() recursive function.
604
      /// </summary>
605
      /// <param name="theElement"></param>
606
      /// <param name="recurse_level"></param>
607
      private void processElementLink(EA.Element theElement, int recurse_level )
608
      {
609
         string [] EA_DocGenEleLnk = null;
610
         string delimStr = "\r\n";
611
         char [] delim = delimStr.ToCharArray();
612
         EA_DocGenEleLnk = theElement.Notes.ToString().Split(delim,100);
613
         string linkedName = "";
614
 
615
         foreach(string s in EA_DocGenEleLnk)
616
         {
617
            if (s.Length > 0 && s != "\n" && s != "\r")
618
            {
2094 ghuddy 619
               if (s == "skiproot")
2088 ghuddy 620
               {
2094 ghuddy 621
                  oneShot_skipRootElementHeading = true;
622
               }
623
               else if ( s[0] == '{')
624
               {
2088 ghuddy 625
                  EA.Element theFoundElement = EA_Utils.EA_Finder.findElementInRepositoryByGUID(s);
626
                  if (theFoundElement != null)
627
                  {
628
                     parse_element( theFoundElement, recurse_level );
629
                  }
630
                  else 
631
                  {
632
                     MessageBox.Show("WARNING - Could not find linked element : " + linkedName );
633
                  }
634
               }
635
               else
636
               {
637
                  linkedName = s;
638
               }            
639
            }
640
         }         
641
      }
642
 
643
 
644
      /// <summary>
645
      /// This method creates a table from the content of an EA_DocGenTable element in the model.
646
      /// The elements notes section contains the table parameters and cell content.
647
      /// See the EA_Utilities::AddTableElement() method for the layout of this content.
648
      /// </summary>
649
      /// <param name="theElement"></param>
650
      /// <param name="recurse_level"></param>
651
      private void processTableElement(EA.Element theElement, int recurse_level )
652
      {
653
         string [] EA_DocGenTable = null;
654
         string [] cells = null;
655
 
656
         string delimStr = "\r\n";
657
         char [] delim = delimStr.ToCharArray();
658
 
659
         string trimStr = " ";
660
         char [] trimChars = trimStr.ToCharArray();
661
 
662
         EA_DocGenTable = theElement.Notes.ToString().Split(delim,200);
663
 
664
         int columnCount = 0;
665
         int rowCount = 0;
666
         char seperator = ',';
667
         string tableTitle = "";
668
         bool gotSeperator = false;
669
         bool gotTitle = false;
670
 
2100 ghuddy 671
         ArrayList colWidths = new ArrayList();
672
         int indent = 0;
673
 
2088 ghuddy 674
         // Scan the notes content line by line looking for table parameters and counting
675
         // the number of table rows (which is not specified as an explicit table parameter).
676
         int s_ElementsConsumedByTableParams = 0;
677
         foreach(string s in EA_DocGenTable)
678
         {
679
            if (s.Length > 0 && s != "\n" && s != "\r" )
680
            {
681
               if (gotTitle == false && s.StartsWith("title"))
682
               {
683
                  s_ElementsConsumedByTableParams++;
684
                  tableTitle = EA_Utils.options.getOptionValue(s, tableTitle);
685
                  gotTitle = true;
686
                  if (tableTitle == "")
687
                  {
688
                     MessageBox.Show( "Table Element Serialisation Failed - Bad Title" );
689
                     break;
690
                  }
691
               }
692
 
693
               else if (columnCount == 0 && s.StartsWith("columns"))
694
               {
695
                  s_ElementsConsumedByTableParams++;
696
                  columnCount = EA_Utils.options.getOptionValue(s, columnCount);
697
                  if (columnCount == 0)
698
                  {
699
                     MessageBox.Show( "Table Element Serialisation Failed - bad column count" );
700
                     break;
701
                  }
702
               }
2100 ghuddy 703
 
2088 ghuddy 704
               else if (gotSeperator == false && s.StartsWith("seperator"))
705
               {
706
                  s_ElementsConsumedByTableParams++;
707
                  seperator = EA_Utils.options.getOptionValue(s, seperator);
708
                  gotSeperator = true;
709
               }
2100 ghuddy 710
 
711
               else if (s.StartsWith("widths"))
712
               {
713
                  s_ElementsConsumedByTableParams++;
714
                  string optValStr = EA_Utils.options.getOptionValue(s, "");
715
 
716
                  string width_delimStr = ",";
717
                  char [] width_delim = width_delimStr.ToCharArray();
718
 
719
                  string [] width_strings = optValStr.Split(width_delim, 50);
720
 
721
                  foreach (string ws in width_strings)
722
                  {
723
                     if (ws.Length > 0 && ws != "\n" && ws != "\r" )
724
                     {
725
                        colWidths.Add( System.Convert.ToDouble(ws) );
726
                     }
727
                  }
728
               }
729
               else if (s.StartsWith("indent"))
730
               {
731
                  s_ElementsConsumedByTableParams++;
732
                  indent = EA_Utils.options.getOptionValue(s, 0);
733
               }
2088 ghuddy 734
               else
735
               {
736
                  rowCount++;
737
               }
738
            }
739
         }
740
 
741
         if (gotTitle == true && gotSeperator == true && columnCount != 0)
742
         {
743
            if (rowCount < 2)
744
            {
745
               MessageBox.Show( "Table Element Serialisation Failed - Insufficient Rows" );
746
            }
747
            else
748
            {
749
               // create the table in the word doc
2094 ghuddy 750
               int tableNum = TableUtils.Table_Create( tableTitle, rowCount, columnCount );
2088 ghuddy 751
               Word.Table table = WordDocument.Tables[tableNum];
752
               object center = Word.WdParagraphAlignment.wdAlignParagraphCenter;
753
 
2100 ghuddy 754
               int col = 1;
755
               foreach (double d in colWidths)
756
               {
757
                  if (col <= columnCount)
758
                     table.Columns[col].SetWidth( WordApp.CentimetersToPoints((float)d), Word.WdRulerStyle.wdAdjustNone );
759
                  col++;
760
               }
761
 
762
               if (indent > 0)
763
               {
764
                  table.Select();
765
                  while (indent > 0)
766
                  {
767
                     WordApp.Selection.Paragraphs.Indent();
768
                     indent--;
769
                  }
770
               }
771
 
2088 ghuddy 772
               // scan the element notes again to extract the cell content and add it to the
773
               // table we just created.
774
               int row = 1;
2100 ghuddy 775
               col = 0;
2088 ghuddy 776
               foreach(string s in EA_DocGenTable)
777
               {
778
                  if (s.Length > 0 && s != "\n" && s != "\r" )
779
                  {
780
                     if (s_ElementsConsumedByTableParams > 0)
781
                     {
782
                        s_ElementsConsumedByTableParams--;
783
                     }
784
                     else
785
                     {
786
                        delimStr = seperator.ToString();
787
                        delim = delimStr.ToCharArray();
788
                        cells = s.Split(delim,columnCount);
789
 
790
                        if (cells.Length != columnCount)
791
                        {
792
                           MessageBox.Show( "Table Element Serialisation Failed - Bad Row" );
793
                           break;
794
                        }
795
                        else
796
                        {
797
                           // serialise table row
798
                           for(col=1; col<=columnCount; col++)
799
                           {
800
                              cells[col-1].TrimStart( trimChars );
801
                              cells[col-1].TrimEnd( trimChars );
802
 
803
                              table.Cell(row,col).Range.Text = cells[col-1];
804
 
805
                              // special handling for heading row
806
                              if (row == 1)
807
                              {
808
                                 table.Cell(row,col).Range.ParagraphFormat.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter;
809
                                 table.Cell(row,col).Range.Font.Bold = 1;
810
                              }
811
                           }
812
                           row++;
813
                        }                     
814
                     }
815
                  }
816
               }
817
            }
818
         }
819
         else
820
         {
821
            MessageBox.Show( "Table Element Serialisation Failed - Table Parameters Incomplete" );
822
         }
823
      }
824
 
825
 
2094 ghuddy 826
 
2088 ghuddy 827
      /// <summary>
2094 ghuddy 828
      /// This function processes a test link element
829
      /// </summary>
830
      /// <param name="theElement"></param>
831
      /// <param name="recurse_level"></param>
832
      private void processTestLink(EA.Element theElement, int recurse_level )
833
      {
834
         string [] EA_DocGenEleLnk = null;
835
         string delimStr = "\r\n";
836
         char [] delim = delimStr.ToCharArray();
837
         EA_DocGenEleLnk = theElement.Notes.ToString().Split(delim,100);
838
         string linkedName = "";
839
 
840
         foreach(string s in EA_DocGenEleLnk)
841
         {
842
            if (s.Length > 0 && s != "\n" && s != "\r")
843
            {
844
               if ( s[0] == '{')
845
               {
846
                  try
847
                  {
848
                     // try to find the GUID as a package
849
                     EA.Package theFoundPackage = EA_Utils.EA_Finder.findPackageInRepositoryByGUID(s);
850
                     if (theFoundPackage != null)
851
                        TextUtils.appendUnitTestSuite(theFoundPackage, recurse_level, ref classesWithUnitTests);
852
                     else 
853
                     {
854
                        // try to find the GUID as an element
855
                        EA.Element theFoundElement = EA_Utils.EA_Finder.findElementInRepositoryByGUID(s);
856
                        if (theFoundElement != null)
857
                           TextUtils.appendUnitTestSuite(theFoundElement, recurse_level, ref classesWithUnitTests);
858
                        else 
859
                           MessageBox.Show("WARNING - Could not find linked element : " + linkedName );
860
                     }
861
                  }
862
                  catch 
863
                  {
864
                     // try to find the GUID as an element
865
                     EA.Element theFoundElement = EA_Utils.EA_Finder.findElementInRepositoryByGUID(s);
866
                     if (theFoundElement != null)
867
                        TextUtils.appendUnitTestSuite(theFoundElement, recurse_level, ref classesWithUnitTests);
868
                     else 
869
                        MessageBox.Show("WARNING - Could not find linked element : " + linkedName );
870
                  }
871
               }
872
               else
873
               {
874
                  linkedName = s;
875
               }            
876
            }
877
         }         
878
      }
879
 
880
 
881
 
882
      /// <summary>
2088 ghuddy 883
      /// This function process a text element. It is a simple wrapper for the 
884
      /// appendAndSelectText()function.
885
      /// </summary>
886
      /// <param name="theElement"></param>
887
      /// <param name="recurse_level"></param>
888
      private void processTextElement(EA.Element theElement, int recurse_level )
889
      {
2094 ghuddy 890
         TextUtils.appendAndSelectText( theElement.Notes.ToString(), EA_Constants.styleName_Body1 );
2088 ghuddy 891
      }
892
 
893
 
2094 ghuddy 894
      /// <summary>
895
      /// This function will insert a relationship matrix table into the document, built from content
896
      /// specified in options that are provided in the notes section of the special element that
897
      /// has led to this function being called.
898
      /// </summary>
899
      /// <param name="theElement"></param>
900
      /// <param name="recurse_level"></param>
901
      private void processRelationshipMatrixElement( EA.Element theElement, int recurse_level )
902
      {
903
         int tableNum = 0;
904
         Word.Table table = null;
905
 
906
         // process the options for the relationship matrix
907
         EA_RelationshipMatrix EA_RelMatrix = new EA_RelationshipMatrix(EA_Utils);
908
         if (!EA_RelMatrix.processRelationshipMatrixOptions( theElement ))
909
         {
910
            return;  // must have been an error
911
         }
912
 
913
         // Scan the fromPackage to find all the "from elements".
914
         ElementAccumulator fromLister = new ElementAccumulator(EA_RelMatrix.fromElementTypes, EA_Utils);
915
         EA_Utils.findAndProcessPackageElements( EA_RelMatrix.fromPackage, fromLister, EA_RelMatrix.fromPackageRecursion );
916
 
917
         // Sort the "from elements"
918
         elementSortByName sorter = new elementSortByName();
919
         fromLister.Elements.Sort( sorter );
920
 
921
         // dictionary to support from-to table construction.
922
         ArrayList fromToDictionary = new ArrayList();
923
 
924
         // dictionary to support to-from table construction.
925
         ArrayList toFromDictionary = new ArrayList();
926
 
927
         bool needFromToTable = false;
928
         if (EA_RelMatrix.fromToTableTitle != null && EA_RelMatrix.fromToTableTitle.Length > 0)
929
            needFromToTable = true;
930
 
931
         bool needToFromTable = false;
932
         if (EA_RelMatrix.toFromTableTitle != null && EA_RelMatrix.toFromTableTitle.Length > 0)
933
            needToFromTable = true;
934
 
935
         // NOTE: this code has to execute even if no from-to table is needed, in order to support the
936
         // generation of a to-from table, assuming the user has requested one.
937
         int numberOfFromToRows = 0;
938
 
939
         foreach(EA.Element fromElement in fromLister.Elements)
940
         {
941
            // look at the elements connection collection to find references to the
942
            // destination elements
943
            bool foundToElement = false;
944
 
945
            EA.Collection conCollection = fromElement.Connectors;
946
 
947
            foreach (EA.Connector thisCon in conCollection)
948
            {
949
               EA.Element destE = EA_Repository.GetElementByID( thisCon.SupplierID );
950
               if (destE == null)
951
                  continue;
952
 
953
               // ignore self-referential connections
954
               if (fromElement.ElementID == thisCon.SupplierID)
955
                  continue;
956
 
957
               // if the destination element is of a type that the user has requested to include...
958
               if (!EA_RelMatrix.toElementTypes.Contains( destE.Type ))
959
                  continue;
960
 
961
               // Capture the from-to relationship in a dictionary where the key is the
962
               // "from element", and the value is the "to element".
963
               DictionaryEntry newFromToEntry = new DictionaryEntry(fromElement, destE);
964
               fromToDictionary.Add( newFromToEntry );
965
               foundToElement = true;
966
 
967
               // Capture the from-to relationship in a dictionary where the key is the
968
               // ID of the destination element, and the value is the from element name.
969
               // This dictionary will enable rapid construction of the to-from table if
970
               // the user has requested it, from the exact same relationship info used
971
               // to construct the from-to table.
972
               if (needToFromTable)
973
               {
974
                  DictionaryEntry newToFromEntry = new DictionaryEntry(destE.ElementID, fromElement.Name);
975
                  toFromDictionary.Add( newToFromEntry );
976
               }
977
            }
978
 
979
            // If we found a from-to relationship that table needs a new row.
980
            if (foundToElement)
981
            {
982
               numberOfFromToRows++;
983
            }
984
               // If we did not find a from-to relationship that table still needs a new row 
985
               // if the user wants all "from elements", even if some have no "to elements".
986
            else if (EA_RelMatrix.fromPackageTrimming == false)
987
            {
988
               DictionaryEntry newFromToEntry = new DictionaryEntry(fromElement, null);
989
               fromToDictionary.Add( newFromToEntry );
990
               numberOfFromToRows++;
991
            }
992
         }
993
 
994
 
995
         if (needFromToTable)
996
         {
997
            // Now we can actually serialise the table
998
 
999
            if (EA_RelMatrix.fromIntroText != null && EA_RelMatrix.fromIntroText.Length > 0)
1000
            {
1001
               TextUtils.appendAndSelectText( EA_RelMatrix.fromIntroText, EA_Constants.styleName_Body1 );
1002
            }
1003
 
1004
            // create the from-to table in the word doc
1005
            tableNum = TableUtils.Table_Create( EA_RelMatrix.fromToTableTitle, numberOfFromToRows + 1, 2 );
1006
            table = WordDocument.Tables[tableNum];
1007
 
1008
            TableUtils.Table_SetTableColumnTitle(table, EA_RelMatrix.fromColumnTitle, 1);
1009
            TableUtils.Table_SetTableColumnTitle(table, EA_RelMatrix.toColumnTitle, 2);
1010
 
1011
            int row = 1;
1012
            int lastFromElementId = -1;
1013
            bool firstFromToCon = true;
1014
            foreach (DictionaryEntry de in fromToDictionary)
1015
            {
1016
               if ( ((EA.Element)de.Key).ElementID != lastFromElementId )
1017
               {
1018
                  lastFromElementId = ((EA.Element)de.Key).ElementID;
1019
                  row++;
1020
                  table.Cell(row,1).Range.Text = ((EA.Element)de.Key).Name;
1021
                  firstFromToCon = true;
1022
               }
1023
 
1024
               if (((EA.Element)de.Value) != null)
1025
               {
1026
                  if (firstFromToCon)
1027
                  {
1028
                     firstFromToCon = false;
1029
                     table.Cell(row,2).Range.Text = ((EA.Element)de.Value).Name;
1030
                  }
1031
                  else
1032
                  {
1033
                     table.Cell(row,2).Range.Text += ((EA.Element)de.Value).Name;
1034
                  }
1035
               }
1036
               else
1037
               {
1038
                  table.Cell(row,2).Range.Text = "Un-allocated relationship!";
1039
                  table.Cell(row,2).Range.Font.Color = Word.WdColor.wdColorRed;
1040
               }
1041
            }
1042
         }
1043
 
1044
         // Does user want a to-from table ?
1045
         if (needToFromTable)
1046
         {
1047
            // re-use the fromToDictionary to prepare the to-from table content 
1048
            fromToDictionary.Clear();
1049
 
1050
            // find all elements for the left hand column of the to-from table.
1051
            ElementAccumulator toLister = new ElementAccumulator(EA_RelMatrix.toElementTypes, EA_Utils);
1052
            EA_Utils.findAndProcessPackageElements( EA_RelMatrix.toPackage, toLister, EA_RelMatrix.toPackageRecursion );
1053
 
1054
            // Sort the "to" elements
1055
            toLister.Elements.Sort( sorter );
1056
 
1057
 
1058
            // To make the to-from table, we use the dictionary that was built when making the from-to
1059
            // table. The dictionary will allow rapid determination of what "from" items belong to each
1060
            // "to" item, without us having to go back to EA and enquire on the database.
1061
            // We build a new fromToDictionary from the toFromDictionary, in advance of actually making 
1062
            // the table so that we can figure out how many rows the table needs to have.
1063
            numberOfFromToRows = 0;
1064
 
1065
            foreach(EA.Element toElement in toLister.Elements)
1066
            {
1067
               bool foundToElement = false;
1068
 
1069
               // right-column cell content
1070
               foreach (DictionaryEntry de in toFromDictionary)
1071
               {
1072
                  if ((int)de.Key == toElement.ElementID)
1073
                  {
1074
                     DictionaryEntry newFromToEntry = new DictionaryEntry(toElement, (string)de.Value);
1075
                     fromToDictionary.Add( newFromToEntry );
1076
                     foundToElement = true;
1077
                  }
1078
               }
1079
 
1080
               // If we found a from-to relationship that table needs a new row.
1081
               if (foundToElement)
1082
               {
1083
                  numberOfFromToRows++;
1084
               }
1085
                  // if user wants all "from elements", even if some have no "to elements", then add a dictionary
1086
                  // entry and bump row count.
1087
               else if (EA_RelMatrix.toPackageTrimming == false)
1088
               {
1089
                  DictionaryEntry newFromToEntry = new DictionaryEntry(toElement, "");
1090
                  fromToDictionary.Add( newFromToEntry );
1091
                  numberOfFromToRows++;
1092
               }
1093
            }
1094
 
1095
            // Now begin to add the to-from table to the word document
1096
            if (EA_RelMatrix.toIntroText != null && EA_RelMatrix.toIntroText.Length > 0)
1097
            {
1098
               TextUtils.appendAndSelectText( EA_RelMatrix.toIntroText, EA_Constants.styleName_Body1 );
1099
            }
1100
 
1101
            // create the table in the word doc
1102
            tableNum = TableUtils.Table_Create( EA_RelMatrix.toFromTableTitle, numberOfFromToRows + 1, 2 );
1103
            table = WordDocument.Tables[tableNum];
1104
 
1105
            TableUtils.Table_SetTableColumnTitle(table, EA_RelMatrix.toColumnTitle, 1);
1106
            TableUtils.Table_SetTableColumnTitle(table, EA_RelMatrix.fromColumnTitle, 2);
2088 ghuddy 1107
 
2094 ghuddy 1108
            int lastFromElementId = -1;
1109
            bool firstToFromCon = true;
1110
            int row = 1;
1111
            foreach (DictionaryEntry de in fromToDictionary)
1112
            {
1113
               if ( ((EA.Element)de.Key).ElementID != lastFromElementId )
1114
               {
1115
                  lastFromElementId = ((EA.Element)de.Key).ElementID;
1116
                  row++;
1117
                  table.Cell(row,1).Range.Text = ((EA.Element)de.Key).Name;
1118
                  firstToFromCon = true;
1119
               }
1120
 
1121
               if (((string)de.Value).Length > 0)
1122
               {
1123
                  if (firstToFromCon)
1124
                  {
1125
                     firstToFromCon = false;
1126
                     table.Cell(row,2).Range.Text = (string)de.Value;
1127
                  }
1128
                  else
1129
                  {
1130
                     table.Cell(row,2).Range.Text += (string)de.Value;
1131
                  }
1132
               }
1133
               else
1134
               {
1135
                  table.Cell(row,2).Range.Text = "Un-allocated relationship!";
1136
                  table.Cell(row,2).Range.Font.Color = Word.WdColor.wdColorRed;
1137
               }
1138
            }
1139
         }
1140
      }
2088 ghuddy 1141
 
2094 ghuddy 1142
 
1143
      private void processTestTraceability( EA.Element theElement, int recurse_level )
1144
      {
1145
         if (nonPrivateClasses.Count > 0)
1146
         {
1147
            if (theElement.Notes.Length > 0)
1148
            {
1149
               TextUtils.appendAndSelectText( theElement.Notes, EA_Constants.styleName_Body1);
1150
            }
1151
            int tableNum = TableUtils.Table_Create("Design Element to Unit Test Suite Traceability", 2, 2);
1152
            utTraceabilityTable = WordDocument.Tables[tableNum];
1153
 
1154
            TableUtils.Table_SetTableColumnTitle(utTraceabilityTable, "Design Element (class)", 1);
1155
            TableUtils.Table_SetTableColumnTitle(utTraceabilityTable, "Test Suite", 2);
1156
         }
1157
      }
1158
 
1159
 
1160
      private void completeTestTraceability()
1161
      {
1162
         if (utTraceabilityTable != null)
1163
         {
1164
            int numClassesRemaining = nonPrivateClasses.Count;
1165
            int row = 2;
1166
            foreach(int elementId in nonPrivateClasses)
1167
            {
1168
               EA.Element theElement = EA_Repository.GetElementByID( elementId );
1169
               if (theElement != null)
1170
               {
1171
                  utTraceabilityTable.Cell(row,1).Range.Text = theElement.Name;
1172
 
1173
                  if (classesWithUnitTests.Contains( elementId ))
1174
                  {
1175
                     utTraceabilityTable.Cell(row,2).Range.Text = TextUtils.testSuiteName(theElement);
1176
                  }
1177
                  else
1178
                  {
1179
                     utTraceabilityTable.Cell(row,2).Range.Text = "Missing tests!";
1180
                     utTraceabilityTable.Cell(row,2).Range.Font.Color = Word.WdColor.wdColorRed;
1181
                  }
1182
               }
1183
 
1184
               numClassesRemaining--;
1185
               if (numClassesRemaining > 0)
1186
               {
1187
                  TableUtils.Table_InsertNewRowAfterThisRow(utTraceabilityTable, row);
1188
                  row++;
1189
               }
1190
            }
1191
         }
1192
      }
1193
 
1194
      #endregion
1195
 
1196
      #region special section processing functions (references, terminology, etc)
2088 ghuddy 1197
      /// <summary>
1198
      /// This function processes elements as if they represented document references for
1199
      /// the References section of a document.
1200
      /// </summary>
1201
      /// <param name="thePackage"></param>
1202
      private void createReferencesSection(EA.Package thePackage)
1203
      {
1204
         foreach(EA.Element theElement in thePackage.Elements)
1205
         {
1206
            // Here we want to apply the special ERG template styles for each reference
1207
            // item.
2094 ghuddy 1208
            TextUtils.appendAndSelectText( theElement.Name.ToString(), EA_Constants.styleName_RefListNum );
1209
            TextUtils.appendAndSelectText( theElement.Notes.ToString(), EA_Constants.styleName_RefListText );
2088 ghuddy 1210
         }
1211
      }
1212
 
1213
 
1214
      private void createTerminologySection(EA.Package thePackage)
1215
      {
1216
         // Use local package elements as source of glossary, but if none are present, resort to using
1217
         // the project glossary in the repository 
1218
         int numItems = thePackage.Elements.Count;
1219
         if (numItems == 0)
1220
         {
1221
            numItems = EA_Repository.Terms.Count;
1222
         }
1223
 
1224
         if (numItems > 0)
1225
         {
1226
            // Create a table
2094 ghuddy 1227
            int tableNum = TableUtils.Table_Create("Terminology", numItems+1, 2);
2088 ghuddy 1228
            Word.Table table = WordDocument.Tables[tableNum];
1229
            object center = Word.WdParagraphAlignment.wdAlignParagraphCenter;
2094 ghuddy 1230
 
1231
            TableUtils.Table_SetTableColumnTitle(table, "Term", 1);
1232
            TableUtils.Table_SetTableColumnTitle(table, "Definition", 2);
2088 ghuddy 1233
            table.Columns[1].SetWidth(100, Word.WdRulerStyle.wdAdjustSameWidth );
1234
            int row = 2;
1235
 
1236
            if (thePackage.Elements.Count > 0)
1237
            {
1238
               // The advantage of using the package content is that the elements come out alphabetically
1239
               // sorted already (assuming user has not over-riden the sort order in the project browser).
1240
               // Also, the glossary content can be exactly tailored to what the document requires.
1241
               foreach(EA.Element theElement in thePackage.Elements)
1242
               {
1243
                  table.Cell(row,1).Range.Text = theElement.Name.ToString();
1244
                  table.Cell(row,2).Range.Text = theElement.Notes.ToString();
1245
                  row++;
1246
               }
1247
            }
1248
            else // default to using the project glossary in the repository
1249
            {
1250
               // TODO 
1251
               // 1. Alphabetically Sort the glossary terms before adding them to the table
1252
               //    The Repository glossary seems to be provided in non-sorted order unfortunately.
1253
 
1254
               // inject the glossary into the table
1255
               foreach(EA.Term theTerm in EA_Repository.Terms)
1256
               {
1257
                  table.Cell(row,1).Range.Text = theTerm.Term;
1258
                  table.Cell(row,2).Range.Text = theTerm.Meaning;
1259
                  row++;
1260
               }
1261
            }
1262
         }
1263
      }
1264
 
2094 ghuddy 1265
      #endregion
2088 ghuddy 1266
 
1267
      private bool generatePackageHeadingAndDescription( EA.Package thePackage, int recurse_level )
1268
      {
1269
         // disarm the one-shot package skipping feature if it was armed, and exit the function.
1270
         if (oneShot_skipRootPackage == true)
1271
         {
1272
            oneShot_skipRootPackage = false;
1273
            return false;
1274
         }
1275
 
1276
         // The package name is a heading, and the package notes are paragraphs 
1277
         // directly under that heading
1278
         displayProgress( "PACKAGE: ", thePackage.Name.ToString() );
1279
 
2094 ghuddy 1280
         TextUtils.appendAndSelectHeadingText( thePackage.Name.ToString(), recurse_level );
2088 ghuddy 1281
 
1282
         // Special handling for package called "Terminology" 
1283
         if (thePackage.Name == "Terminology")
1284
         {
2094 ghuddy 1285
            TextUtils.appendAndSelectText( thePackage.Notes.ToString(), EA_Constants.styleName_Body1 );
2088 ghuddy 1286
            createTerminologySection(thePackage);
1287
            return true;
1288
         }
1289
 
1290
         if (thePackage.Name == "References")
1291
         {
2094 ghuddy 1292
            TextUtils.appendAndSelectText( thePackage.Notes.ToString(), EA_Constants.styleName_Body1 );
2088 ghuddy 1293
            createReferencesSection(thePackage);
1294
            return true;
1295
         }
1296
 
1297
         // use the package notes as body text and indicate to caller that package elements 
1298
         // have not been consumed
2094 ghuddy 1299
         TextUtils.appendAndSelectText( thePackage.Notes.ToString(), EA_Constants.styleName_Body1 );      
2088 ghuddy 1300
         return false;
1301
      }
1302
 
1303
 
1304
      private void generatePackageDiagrams( EA.Package thePackage )
1305
      {
1306
         // default handling of diagrams
1307
         foreach(EA.Diagram theDiagram in thePackage.Diagrams)
1308
         {
1309
            displayProgress( "DIAGRAM: ", theDiagram.Name.ToString() );
1310
 
1311
            appendAndSelectDiagramViaClipboard( theDiagram );
1312
         }
1313
      }
1314
 
1315
 
2094 ghuddy 1316
      private void generateMethodContent( EA.Element theElement, int recurse_level )
2088 ghuddy 1317
      {
1318
         recurse_level++;
2098 ghuddy 1319
         if (recurse_level > EA_Constants.MAX_HEADING_LEVEL - 1)  // -1 because this function generates two heading levels 
2094 ghuddy 1320
         {
2098 ghuddy 1321
            throw new System.StackOverflowException(EA_Constants.maxRecursionDepthException );
2094 ghuddy 1322
         }
1323
 
1324
         // Get all the methods into an array list and sort them by their position in the class's
1325
         // method list (ie. sort order is determined by the Pos value in each method).
1326
         ArrayList theMethods = new ArrayList();
1327
         foreach(EA.Method theMethod in theElement.Methods)
1328
            theMethods.Add( theMethod );
1329
         methodSortByPos sorter = new methodSortByPos();
1330
         theMethods.Sort( sorter );
1331
 
1332
         // filter out methods with certain characteristics?
1333
         // eg. Users may only want to document public and protected methods.
1334
         int numMethodsRemaining = 0;
1335
         foreach(EA.Method theMethod in theMethods)
1336
         {
1337
            if (EA_Utils.options.opt_SuppressPrivateMethods == false
1338
               || !theMethod.Visibility.StartsWith("Private"))
1339
               numMethodsRemaining++;
1340
         }
1341
 
1342
         Word.Range wr;
1343
         StringBuilder sb;
1344
 
1345
         if (numMethodsRemaining > 0)
1346
         {
1347
            // Print the "<Class Name> Operations" headings
1348
            sb = new StringBuilder();
1349
            sb.Append( theElement.Name );
1350
            sb.Append( " Operations" );
1351
            TextUtils.appendAndSelectHeadingText(sb.ToString(), recurse_level);
1352
 
1353
            // Iterate through the class's methods
1354
            foreach(EA.Method theMethod in theMethods)
1355
            {
1356
               sb = new StringBuilder();
1357
 
1358
               if (EA_Utils.options.opt_SuppressPrivateMethods == false
1359
                  || !theMethod.Visibility.StartsWith("Private"))
1360
               {
1361
                  // Print the Method name as a sub heading, and its description
1362
                  TextUtils.appendAndSelectHeadingText(theMethod.Name , recurse_level + 1);
1363
                  TextUtils.appendDescription(theMethod.Notes, EA_Utils);
1364
 
1365
                  // Get a list of the method's parameters and sort them by the position field setup 
1366
                  // in EA by the designer
1367
                  ArrayList theParams = new ArrayList();
1368
                  foreach(EA.Parameter theParam in theMethod.Parameters)
1369
                     theParams.Add( theParam );
1370
                  parameterSortByPos paramSorter = new parameterSortByPos();
1371
                  theParams.Sort( paramSorter );
1372
 
1373
                  // Print the prototype heading
2098 ghuddy 1374
                  wr = TextUtils.appendAndSelectText("\nPrototype:", EA_Constants.styleName_Body1_Left_2_5cm_Italic);
2094 ghuddy 1375
 
1376
                  // begin to build the prototype string
1377
                  sb = new StringBuilder();
1378
                  sb.Append( theMethod.ReturnType );
1379
                  sb.Append( " " );
1380
                  sb.Append( theMethod.Name );
1381
                  sb.Append( "(" );
1382
 
1383
                  if (theParams.Count > 0)
1384
                  {
1385
                     int numParamsRemaining = theParams.Count;
1386
 
1387
                     // print what we have so far constructed for the prototype
2098 ghuddy 1388
                     wr = TextUtils.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_3_5cm);
2094 ghuddy 1389
 
1390
                     // Now form a new string for the params
1391
                     sb = new StringBuilder();
1392
                     foreach(EA.Parameter theParam in theParams)
1393
                     {
1394
                        // each parameter is   "[in|out|inout] type name [= default-value]"
1395
                        // where the default value is optional
1396
                        sb.Append( "[" );
1397
                        sb.Append( theParam.Kind );
1398
                        sb.Append( "] " );
1399
                        sb.Append( theParam.Type );
1400
                        sb.Append( " " );
1401
                        sb.Append( theParam.Name );
1402
                        if (theParam.Default.Length > 0)
1403
                        {
1404
                           sb.Append( " = " );
1405
                           sb.Append( theParam.Default );
1406
                        }
1407
 
1408
                        // if there are more parameters after this one, add a comma and newline
1409
                        if (numParamsRemaining > 1)
1410
                           sb.Append( ",\n" );
1411
 
1412
                        numParamsRemaining--;
1413
                     }
1414
 
1415
                     // complete the prototype and print it.
1416
                     sb.Append( ")" );
2098 ghuddy 1417
                     wr = TextUtils.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_4_5cm);
2094 ghuddy 1418
                  }
1419
                  else
1420
                  {
1421
                     // complete the prototype and print it.
1422
                     sb.Append( ")" );
2098 ghuddy 1423
                     wr = TextUtils.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_3_5cm);
2094 ghuddy 1424
                  }
1425
 
1426
 
1427
                  // Prototype Attributes/Characteristics
1428
                  sb = new StringBuilder();
1429
                  sb.Append( theMethod.Visibility );
1430
 
1431
                  if (theMethod.IsStatic)
1432
                     sb.Append("\nStatic");
1433
 
1434
                  if (theMethod.Abstract)
1435
                     sb.Append("\nAbstract");
1436
 
1437
                  if (theMethod.IsPure)
1438
                     sb.Append("\nPure (c++)");
1439
 
1440
                  if (theMethod.IsSynchronized)
1441
                     sb.Append("\nSynchronised");
1442
 
1443
                  if (theMethod.Concurrency != null && theMethod.Concurrency.Length > 0 && !theMethod.Concurrency.StartsWith("Sequential") )
1444
                  {
1445
                     sb.Append("\n");
1446
                     sb.Append(theMethod.Concurrency);
1447
                  }
1448
 
1449
                  if (theMethod.IsConst)
1450
                     sb.Append("\nConst");
1451
 
1452
                  if (theMethod.IsQuery)
1453
                     sb.Append("\nIs Querry (does not alter class variables)");
1454
 
1455
                  if (theMethod.IsLeaf)
1456
                     sb.Append("\nIs Leaf (cannot be overriden)");
1457
 
1458
                  if (theMethod.ReturnIsArray)
1459
                     sb.Append( "\nReturn value is an array" );
1460
 
1461
                  if (theMethod.Throws != null && theMethod.Throws.Length > 0)
1462
                  {
1463
                     sb.Append("\n");
1464
                     sb.Append( theMethod.Throws );
1465
                  }
1466
 
1467
                  if (sb.Length > 0)
1468
                  {
2098 ghuddy 1469
                     wr = TextUtils.appendAndSelectText("Characteristics:", EA_Constants.styleName_Body1_Left_2_5cm_Italic);
2094 ghuddy 1470
 
2098 ghuddy 1471
                     wr = TextUtils.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_3_5cm);
2094 ghuddy 1472
                  }
1473
 
1474
                  // Parameter Descriptions
1475
                  if (theParams.Count > 0)
1476
                  {
2098 ghuddy 1477
                     wr = TextUtils.appendAndSelectText("Parameters:", EA_Constants.styleName_Body1_Left_2_5cm_Italic);
2094 ghuddy 1478
 
1479
                     foreach(EA.Parameter theParam in theParams)
1480
                     {
2098 ghuddy 1481
                        wr = TextUtils.appendAndSelectText( theParam.Name + "\t", EA_Constants.stylename_Parameter_Description);
1482
                        // do notes in seperate step since we want to call the appendDescription() method which 
1483
                        // automatically alerts us to missing descriptions in the generated document.
1484
                        wr = TextUtils.appendDescription( theParam.Notes, EA_Constants.stylename_Parameter_Description, EA_Utils, true);
2094 ghuddy 1485
                     }
1486
                  }
1487
               }
1488
            }
1489
         }
1490
      }
1491
 
1492
 
1493
      /// <summary>
1494
      /// This method serialises a class's attributes to the document. 
1495
      /// </summary>
1496
      /// <param name="theElement"></param>
1497
      /// <param name="recurse_level"></param>
1498
      private void generateAttributeContent( EA.Element theElement, int recurse_level )
1499
      {
1500
         recurse_level++;
2098 ghuddy 1501
         if (recurse_level > EA_Constants.MAX_HEADING_LEVEL)
2088 ghuddy 1502
         {
2098 ghuddy 1503
            throw new System.StackOverflowException(EA_Constants.maxRecursionDepthException );
2088 ghuddy 1504
         }
2094 ghuddy 1505
 
1506
         // Get all the attributes into an array list and sort them by their position in the class's
1507
         // attribute list (ie. sort order is determined by the Pos value in each attribute).
1508
         ArrayList theAttrs = new ArrayList();
1509
         foreach(EA.Attribute theAttr in theElement.Attributes)
1510
            theAttrs.Add( theAttr );
1511
         attributeSortByPos sorter = new attributeSortByPos();
1512
         theAttrs.Sort( sorter );
1513
 
1514
         // TODO
1515
         // filter out attributes with certain characteristics?
1516
         // eg. Users may only want to document public and protected attributes.
1517
 
1518
         int numAttrsRemaining = 0;
1519
         foreach(EA.Attribute theAttr in theAttrs)
1520
         {
1521
            if (EA_Utils.options.opt_SuppressPrivateAttributes == false
1522
               || !theAttr.Visibility.StartsWith("Private"))
1523
               numAttrsRemaining++;
1524
         }
1525
 
1526
         if (numAttrsRemaining > 0)
1527
         {
1528
            StringBuilder sb = new StringBuilder();
1529
 
1530
            sb.Append( theElement.Name );
1531
            sb.Append( " Attributes" );
1532
            TextUtils.appendAndSelectHeadingText(sb.ToString(), recurse_level);
1533
 
1534
            // serialise the attributes to the document.
1535
            foreach(EA.Attribute theAttr in theAttrs)
1536
            {
1537
               if (EA_Utils.options.opt_SuppressPrivateAttributes == false
1538
                  || !theAttr.Visibility.StartsWith("Private"))
1539
               {
1540
                  // Begin to build content string for the "Attribute" table column 
1541
                  sb = new StringBuilder();
1542
 
1543
                  // <type> <name>
1544
                  sb.Append("\n");
1545
                  sb.Append(theAttr.Type);
1546
                  sb.Append(" ");
1547
                  sb.Append(theAttr.Name);
1548
                  Word.Range wr = TextUtils.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1);
1549
                  wr.Font.Bold = 1;
1550
 
1551
                  wr = TextUtils.appendDescription(theAttr.Notes, EA_Utils);
1552
                  wr.ParagraphFormat.LeftIndent = WordApp.CentimetersToPoints((float)3.5);
1553
 
1554
                  // The approach here is to display as much of the attribute as we can but try to keep the output
1555
                  // uncluttered by omitting items the user has not set via the EA GUI.
1556
 
1557
                  // Begin to build content string for the "Other Information" table cell
1558
                  sb = new StringBuilder();
1559
 
1560
                  sb.Append(theAttr.Visibility);
1561
                  sb.Append("\n");
1562
 
1563
                  if (theAttr.IsConst)
1564
                     sb.Append("Constant\n");
1565
 
1566
                  if (theAttr.IsStatic)
1567
                     sb.Append("Static\n");
1568
 
1569
                  if (theAttr.IsDerived)
1570
                     sb.Append("Derived\n");
1571
 
1572
                  if (theAttr.IsOrdered)
1573
                  {
1574
                     sb.Append("Is Ordered\n");
1575
                  }
1576
 
1577
                  if (theAttr.IsCollection)
1578
                  {
1579
                     sb.Append("Is A Collection\n");
1580
                  }
1581
 
1582
                  if (theAttr.Length.Length > 0 && System.Convert.ToInt32(theAttr.Length) > 0)
1583
                  {
1584
                     sb.Append("Length = ");
1585
                     sb.Append(theAttr.Length);
1586
                     sb.Append("\n");
1587
                  }
1588
 
1589
                  if (!theAttr.Containment.StartsWith("Not Specified"))
1590
                  {
1591
                     sb.Append("Containment =");
1592
                     sb.Append(theAttr.Containment);
1593
                     sb.Append("\n");
1594
                  }
1595
 
1596
                  if (theAttr.Container.Length > 0)
1597
                  {
1598
                     sb.Append("Container Type = ");
1599
                     sb.Append(theAttr.Container);
1600
                     sb.Append("\n");
1601
                  }
1602
 
1603
                  if (theAttr.Style.Length > 0)
1604
                  {
1605
                     sb.Append("Style = ");
1606
                     sb.Append(theAttr.Style);
1607
                     sb.Append("\n");
1608
                  }
1609
 
1610
                  if (  System.Convert.ToInt32(theAttr.LowerBound) > 1
1611
                     || System.Convert.ToInt32(theAttr.UpperBound) > 1)
1612
                  {
1613
                     sb.Append("Multiplicity [");
1614
                     sb.Append(theAttr.LowerBound);
1615
                     sb.Append("..");
1616
                     sb.Append(theAttr.UpperBound);
1617
                     sb.Append("]\n");
1618
                  }
1619
 
1620
                  if (theAttr.Scale.Length > 0 && System.Convert.ToInt32(theAttr.Scale) > 0)
1621
                  {
1622
                     sb.Append("Scale = ");
1623
                     sb.Append(theAttr.Scale);
1624
                     sb.Append( "\n" );
1625
                  }
1626
                  if (theAttr.Precision.Length > 0 && System.Convert.ToInt32(theAttr.Precision) > 0)
1627
                  {
1628
                     sb.Append("Precision = ");
1629
                     sb.Append(theAttr.Precision);
1630
                     sb.Append( "\n" );
1631
                  }
1632
 
1633
                  if (theAttr.Default.Length > 0)
1634
                  {
1635
                     sb.Append("Default Value = ");
1636
                     sb.Append(theAttr.Default);
1637
                     sb.Append( "\n" );
1638
                  }
1639
 
1640
                  // Now look at the constraint and tagged value collections and add any found info to the
1641
                  // right hand column
1642
                  short i;
1643
                  for(i=0; i<theAttr.Constraints.Count; i++)
1644
                  {
1645
                     EA.AttributeConstraint theCons = (EA.AttributeConstraint)theAttr.Constraints.GetAt(i);
1646
                     sb.Append( theCons.Type );
1647
                     sb.Append( ": {" );
1648
                     sb.Append( theCons.Name );
1649
                     sb.Append( "}\n" );
1650
                     //sb.Append( theCons.Notes  );
1651
                     //sb.Append( "\n" );
1652
                  }
1653
 
1654
                  for(i=0; i<theAttr.TaggedValues.Count; i++)
1655
                  {
1656
                     EA.AttributeTag theTag = (EA.AttributeTag)theAttr.TaggedValues.GetAt(i);
1657
                     sb.Append( "[" );
1658
                     sb.Append( theTag.Name );
1659
                     sb.Append( "="  );
1660
                     sb.Append( theTag.Value );
1661
                     sb.Append( "]\n" );
1662
                     //sb.Append( theTag.Notes );
1663
                     //sb.Append( "\n" );
1664
                  }
1665
 
1666
                  if (sb.Length > 0)
1667
                  {
1668
                     // remove the trailing "\n"
1669
                     sb.Remove( sb.ToString().Length - 1, 1);
1670
 
2098 ghuddy 1671
                     wr = TextUtils.appendAndSelectText("Characteristics:", EA_Constants.styleName_Body1_Left_3_5cm_Italic);
2094 ghuddy 1672
 
2098 ghuddy 1673
                     wr = TextUtils.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_4_5cm);
2094 ghuddy 1674
                  }
1675
 
1676
                  numAttrsRemaining--;
1677
               }
1678
            }
1679
         }
1680
      }
1681
 
1682
 
1683
      private void generateClassCharacteristics( EA.Element theElement, int recurse_level )
1684
      {
1685
         StringBuilder sb = new StringBuilder();
1686
 
1687
         sb.Append( "Characteristics:" );
2098 ghuddy 1688
         Word.Range wr = TextUtils.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_2_5cm_Italic);
2088 ghuddy 1689
 
2094 ghuddy 1690
         sb = new StringBuilder();
1691
         sb.Append( theElement.Visibility );
1692
 
1693
         if (System.Convert.ToInt32(theElement.Abstract) == 1)
1694
            sb.Append( "\nAbstract" );
1695
 
2098 ghuddy 1696
         wr = TextUtils.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_3_5cm);
2094 ghuddy 1697
 
1698
         sb = new StringBuilder();
1699
         foreach(EA.Element baseClass in theElement.BaseClasses)
2088 ghuddy 1700
         {
2094 ghuddy 1701
            sb.Append( baseClass.Name);
1702
         }
1703
         if (sb.Length > 0)
1704
         {
2098 ghuddy 1705
            wr = TextUtils.appendAndSelectText("Base Class(es):", EA_Constants.styleName_Body1_Left_2_5cm_Italic);
2088 ghuddy 1706
 
2098 ghuddy 1707
            wr = TextUtils.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_3_5cm);
2094 ghuddy 1708
         }
1709
 
1710
         sb = new StringBuilder();
1711
         foreach(EA.Element intf in theElement.Realizes)
1712
         {
1713
            sb.Append( intf.Name);
1714
         }
1715
         if (sb.Length > 0)
1716
         {
2098 ghuddy 1717
            wr = TextUtils.appendAndSelectText("Realises:", EA_Constants.styleName_Body1_Left_2_5cm_Italic);
2094 ghuddy 1718
 
2098 ghuddy 1719
            wr = TextUtils.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_3_5cm);
2094 ghuddy 1720
         }
1721
      }
1722
 
1723
 
1724
      private void generateClassRequirements( EA.Element theElement, int recurse_level )
1725
      {
1726
         StringBuilder sb = new StringBuilder();
1727
 
1728
         sb.Append( "Requirements:" );
2098 ghuddy 1729
         Word.Range wr = TextUtils.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_2_5cm_Italic);
2094 ghuddy 1730
 
1731
         foreach(EA.Requirement theReq in theElement.Requirements)
1732
         {
1733
            sb = new StringBuilder();
1734
            sb.Append( theReq.Name );
2098 ghuddy 1735
            wr = TextUtils.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_3_5cm);
2094 ghuddy 1736
            sb = new StringBuilder();
1737
            sb.Append( theReq.Notes );
1738
            if (sb.Length > 0)
2088 ghuddy 1739
            {
2098 ghuddy 1740
               wr = TextUtils.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_4_5cm);
2088 ghuddy 1741
            }
2094 ghuddy 1742
         }
1743
      }
1744
 
1745
 
1746
      private void generateClassConstraints( EA.Element theElement, int recurse_level )
1747
      {
1748
         StringBuilder sb = new StringBuilder();
1749
 
1750
         sb.Append( "Constraints:" );
2098 ghuddy 1751
         Word.Range wr = TextUtils.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_2_5cm_Italic);
2094 ghuddy 1752
 
1753
         foreach(EA.Constraint theCons in theElement.Constraints)
1754
         {
1755
            sb = new StringBuilder();
1756
            sb.Append( theCons.Type );
1757
            sb.Append( ": {" );
1758
            sb.Append( theCons.Name );
1759
            sb.Append( "}" );
1760
 
2098 ghuddy 1761
            wr = TextUtils.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_3_5cm);
2094 ghuddy 1762
 
1763
            if (theCons.Notes.Length > 0)
2088 ghuddy 1764
            {
2094 ghuddy 1765
               sb = new StringBuilder();
1766
               sb.Append( theCons.Notes );
2098 ghuddy 1767
               wr = TextUtils.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_4_5cm);
2094 ghuddy 1768
            }
1769
         }
1770
      }
1771
 
1772
 
1773
      private void generateElementContent( EA.Element theElement, int recurse_level )
1774
      {
1775
         // track recursion level to control heading style formatting requirements
1776
         if (oneShot_skipRootElementHeading == false)
1777
            recurse_level++;
1778
 
1779
         if (EA_Utils.options.elementTypeFoundInEA_DocGen( theElement.Type ))
1780
         {
1781
            // pass the element to the requirement element serialisation function. It
1782
            // will tell us if it did anything with it. If not, then carry out the default
1783
            // element serialisation.
1784
            if (false == TextUtils.generateRequirementText(theElement, EA_Utils))
1785
            {
1786
               bool isClass = theElement.Type.StartsWith("Class");
1787
 
1788
               if (  true == isClass
1789
                  && true == EA_Utils.options.opt_SuppressPrivateClasses
1790
                  && true == theElement.Visibility.StartsWith("Private") )
2088 ghuddy 1791
               {
2094 ghuddy 1792
                  // do nothing
2088 ghuddy 1793
               }
1794
               else
2094 ghuddy 1795
               {
2098 ghuddy 1796
                  if (recurse_level > EA_Constants.MAX_HEADING_LEVEL)
1797
                  {
1798
                     throw new System.StackOverflowException(EA_Constants.maxRecursionDepthException);
1799
                  }
1800
 
2094 ghuddy 1801
                  trackDocSection(recurse_level);
1802
                  displayProgress( "ELEMENT: ", theElement.Name );
1803
 
2098 ghuddy 1804
                  // Determine if element is filtered out by a NO_DOC tagged value
1805
                  // Having written this code, I realised it might be a bad idea to let users filter out
1806
                  // elements by tagged values. The reason is, if that content is not in a document model
1807
                  // but in a design model, then it might be used by >1 document model made by different
1808
                  // users, so one users choice of filtering might not suit another users. The only way we 
1809
                  // could get this to work is if the tagged values were somehow made specific to a document
1810
                  // model, but how do you do this? GUIDs are the only safe way to key to something but we
1811
                  // dont want every tagged value key to contain a GUID do we?
1812
//                  bool noDocGen = false;
1813
//                  string str_noDocGen = EA_Utils.ReadTag(theElement, "NO_DOC");
1814
//                  if (str_noDocGen.Length > 0)
1815
//                  {
1816
//                     str_noDocGen = str_noDocGen.ToLower();
1817
//                     if (str_noDocGen.CompareTo("true"))
1818
//                     {
1819
//                        noDocGen = true;
1820
//                        displayProgress( "FILTERED: ", theElement.Type );
1821
//                        oneShot_skipRootElementHeading = false;
1822
//                        return;
1823
//                     }
1824
//                  }                     
1825
 
2094 ghuddy 1826
                  // disarm the one-shot element (heading) skipping feature if it was armed, and 
1827
                  // by-pass the code to generate a new heading level for the element
1828
                  if (oneShot_skipRootElementHeading == false)
1829
                  {
1830
                     // Default element serialisation
1831
                     if (  EA_Utils.options.opt_ElementHeadingTransitionLevel > 0
1832
                        && EA_Utils.options.opt_ElementHeadingTransitionLevel <= recurse_level )
1833
                        TextUtils.appendAndSelectNumParaText( theElement.Name, recurse_level );
1834
                     else
1835
                        TextUtils.appendAndSelectHeadingText( theElement.Name, recurse_level );
1836
                  }
1837
                  else
1838
                  {
1839
                     oneShot_skipRootElementHeading = false;
1840
                  }
1841
 
1842
                  TextUtils.appendDescription( theElement.Notes, EA_Utils );
1843
 
1844
                  if (true == isClass)
1845
                  {
1846
                     // If accumulation of non-private classes is enabled, then do so.
1847
                     if (recordingNonPrivateClasses)
1848
                     {
1849
                        if (!theElement.Visibility.StartsWith("Private"))
1850
                        {
1851
                           nonPrivateClasses.Add( theElement.ElementID );
1852
                        }
1853
                     }
1854
 
1855
                     generateClassCharacteristics(theElement, recurse_level);
1856
                  }
1857
 
1858
                  // Requirement collection
1859
                  if (theElement.Requirements.Count > 0)
1860
                  {
1861
                     generateClassRequirements(theElement, recurse_level);
1862
                  }
1863
 
1864
                  // Constraint collection
1865
                  if (theElement.Constraints.Count > 0)
1866
                  {
1867
                     generateClassConstraints(theElement, recurse_level);
1868
                  }
1869
 
1870
                  if (theElement.Issues.Count > 0)
1871
                  {
1872
                  }
1873
 
1874
                  // Attribute collection
1875
                  if (theElement.Attributes.Count > 0)
1876
                  {
1877
                     generateAttributeContent(theElement, recurse_level);
1878
                  }
1879
 
1880
                  // Method collection
1881
                  if (theElement.Methods.Count > 0)
1882
                  {
1883
                     generateMethodContent(theElement, recurse_level);
1884
                  }
1885
               }
2088 ghuddy 1886
            }
2094 ghuddy 1887
            else
1888
            {
1889
               trackDocSection(recurse_level);
1890
               displayProgress( "ELEMENT: ", theElement.Name );
1891
            }
2088 ghuddy 1892
         }
1893
         else
1894
         {
1895
            displayProgress( "FILTERED: ", theElement.Type );
1896
         }
1897
         // TODO
1898
         // We will probably have to put special code in here at some point for attributes
1899
         // of, and collections of things within elements. This will become apparent once
1900
         // someone tries to produce a design document where such things need to be included
1901
         // in the generated document. Lots of work needed here eventually.
1902
 
2094 ghuddy 1903
         // disarm element heading skip control
1904
         oneShot_skipRootElementHeading = false;
2088 ghuddy 1905
      }
1906
 
2094 ghuddy 1907
 
2088 ghuddy 1908
      /// <summary>
1909
      /// This function searches for the old content in the document in order to remove it
1910
      /// prior to adding in the new content from the latest EA model data.
1911
      /// </summary>
1912
      private void removeExistingDocumentContent()
1913
      {
1914
         //WordApp.Visible = true;  // enable this when debugging this horrible function
1915
         Word.Selection aSelection;
2094 ghuddy 1916
         object findStyle = StyleUtils.getStyle( EA_Constants.styleName_Heading1 );
2088 ghuddy 1917
 
1918
         WordApp.Selection.WholeStory();
1919
         aSelection = WordApp.Selection;
1920
 
1921
         aSelection.Find.ClearFormatting();
1922
         aSelection.Find.set_Style( ref findStyle );
1923
         aSelection.Find.Text = "Introduction";
1924
         aSelection.Find.Replacement.Text = "";
1925
         aSelection.Find.Forward = true;
1926
         aSelection.Find.MatchCase = false;
1927
         aSelection.Find.MatchWholeWord = false;
1928
         aSelection.Find.MatchWildcards = false;
1929
         aSelection.Find.MatchSoundsLike = false;
1930
         aSelection.Find.MatchAllWordForms = false;
1931
 
1932
         object missingValue = Type.Missing;
1933
         if (aSelection.Find.Execute(ref missingValue, ref missingValue, 
1934
            ref missingValue, ref missingValue, ref missingValue, 
1935
            ref missingValue, ref missingValue, ref missingValue, 
1936
            ref missingValue, ref missingValue, ref missingValue, 
1937
            ref missingValue, ref missingValue, ref missingValue, 
1938
            ref missingValue)) 
1939
         { 
1940
            // found Introduction with Heading 1 style so we are now at the point in the 
1941
            // document where everything here on must be deleted in readiness for the newly
1942
            // generated content. Extend the range to the end of the document and cut out the
1943
            // old content.
1944
            Word.Range range = aSelection.Range;
1945
            range.End = WordDocument.Content.End;
1946
            range.Cut();
2092 ghuddy 1947
            // try and ensure that no heading style is left in place following the removal
2094 ghuddy 1948
            object style = EA_Constants.styleName_Body1;
2092 ghuddy 1949
            range.set_Style(ref style);
2088 ghuddy 1950
         }
1951
      }
1952
 
1953
 
1954
      /// <summary>
1955
      /// Parses an element (because elements can contain sub-elements).
1956
      /// This is also the function that identifies the occurrences of the special
1957
      /// EA_DocGenXXX elements.
1958
      /// </summary>
1959
      /// <param name="theElement"></param>
1960
      /// <param name="recurse_level"></param>
1961
      private void parse_element(EA.Element theElement, int recurse_level)
1962
      {
1963
         // First look for and handle special elements that control the doc-gen process
1964
 
1965
         // The EA_DocGenPackageLink can contain a list of GUIDs in its notes section
1966
         // that point to model structure outside of the localised structure forming the
1967
         // document. This enables a document to grab content from other external models
1968
         // as long as they are loaded into the repository.
2094 ghuddy 1969
         if (theElement.Name.StartsWith(EA_Constants.EA_DocGenPackageLink))
2088 ghuddy 1970
         {
1971
            processPackageLink( theElement, recurse_level );
1972
         }
1973
 
1974
            // The EA_DocGenDiagramLink can contain a list of GUIDs in its notes section
1975
            // that point to diagram elements anywhere in the repository.
2094 ghuddy 1976
         else if (theElement.Name.StartsWith(EA_Constants.EA_DocGenDiagramLink))
2088 ghuddy 1977
         {
1978
            processDiagramLink( theElement );
1979
         }
1980
 
1981
            // The EA_DocGenDiagramLink can contain a list of GUIDs in its notes section
1982
            // that point to diagram elements anywhere in the repository.
2094 ghuddy 1983
         else if (theElement.Name.StartsWith(EA_Constants.EA_DocGenElementLink))
2088 ghuddy 1984
         {
1985
            processElementLink( theElement, recurse_level );
1986
         }
1987
 
1988
            // The EA_DocGenTable element can contain table content in its notes section
1989
            // and must be dealt with in a special way.
2094 ghuddy 1990
         else if (theElement.Name.StartsWith(EA_Constants.EA_DocGenTable))
2088 ghuddy 1991
         {
1992
            processTableElement( theElement, recurse_level );
1993
         }
1994
 
1995
            // The EA_DocGenText element can contain text content in its notes section
1996
            // that must be appended to the doc in Body 1 style within the current
1997
            // section.
2094 ghuddy 1998
         else if (theElement.Name.StartsWith(EA_Constants.EA_DocGenText))
2088 ghuddy 1999
         {
2000
            processTextElement( theElement, recurse_level );
2001
         }
2002
 
2094 ghuddy 2003
         else if (theElement.Name.StartsWith(EA_Constants.EA_DocGenRelationshipMatrix))
2088 ghuddy 2004
         {
2005
            processRelationshipMatrixElement( theElement, recurse_level );
2006
         }
2007
 
2094 ghuddy 2008
         else if (theElement.Name.StartsWith(EA_Constants.EA_DocGenTestLink))
2088 ghuddy 2009
         {
2094 ghuddy 2010
            processTestLink( theElement, recurse_level );
2011
         }
2012
 
2013
         else if (theElement.Name.StartsWith(EA_Constants.EA_DocGenTestTraceability))
2014
         {
2015
            processTestTraceability( theElement, recurse_level );
2016
         }
2017
 
2018
 
2019
            // we are aware of the other ERG EA add-in, EA_ReqPro! That other add-in creates 
2020
            // ReqProDB stereotyped elements. Never consume them in the document generation process.
2021
         else if ( theElement.Stereotype != EA_Constants.stereotype_ReqProDB )    
2022
         {
2088 ghuddy 2023
            generateElementContent( theElement, recurse_level );
2024
         }      
2025
      }
2026
 
2027
 
2028
      /// <summary>
2029
      /// Parses the package and all of its content, extracting information as needed, and
2030
      /// adding it to the word document. This method is recursive, since recursion is the
2031
      /// easiest way to walk thru' the package levels in the model.
2032
      /// </summary>
2033
      /// <param name="parentPackage"></param>
2034
      /// <param name="recurse_level"></param>
2035
      private void parse_package(EA.Package thePackage, int recurse_level)
2036
      {
2037
         // track recursion level to control heading style formatting requirements
2038
         // The one-shot skiproot feature of the EA_DocGenPackageLink element handling has an effect
2039
         // here, as you can see. 
2040
         bool rootPackageWasSkipped = !oneShot_skipRootPackage;
2041
         if (oneShot_skipRootPackage == false)
2042
         {
2043
            recurse_level++;
2044
            trackDocSection(recurse_level);
2045
         }
2046
 
2098 ghuddy 2047
         if (recurse_level > EA_Constants.MAX_HEADING_LEVEL)
2088 ghuddy 2048
         {
2098 ghuddy 2049
            throw new System.StackOverflowException(EA_Constants.maxRecursionDepthException );
2088 ghuddy 2050
         }
2051
 
2094 ghuddy 2052
         // If we have reached a "Detailed Design" section, we should begin to capture in a list, all public 
2053
         // classes so that we know later on what classes need to be considered in the unit testing section
2054
         // of the document, assuming that this is a s/w design document being generated ofcoarse. 
2055
         bool nameStartedWithDetailedDesign = false;
2056
         if (recordingNonPrivateClasses == false && thePackage.Name.StartsWith("Detailed Design"))
2057
         {
2058
            recordingNonPrivateClasses = true;
2059
            nameStartedWithDetailedDesign = true;
2060
         }
2061
 
2088 ghuddy 2062
         // generate package heading and description. This may, depending on the package name,
2063
         // consume the elements in the package. If it does not, then consume them (and any diagrams)
2064
         // locally here.
2065
         if (false == generatePackageHeadingAndDescription( thePackage, recurse_level ))
2066
         {
2067
            // consume diagrams
2068
            generatePackageDiagrams( thePackage );
2069
 
2070
            // consume elements - we have to use a special sorting class here because of peculiarties
2071
            // in the way EA holds the elements in the collections. 
2072
            EA_ElementSorter elementSorter = new EA_ElementSorter(thePackage);
2073
            EA.Element theElement = null;
2074
            int theElementsRelativeLevel = 0;
2075
            if (true == elementSorter.getFirst(ref theElement, ref theElementsRelativeLevel))
2076
            {
2077
               do
2078
               {
2079
                  int theElementsRecurseLevel = recurse_level + theElementsRelativeLevel;
2080
 
2081
                  parse_element( theElement, theElementsRecurseLevel );
2082
 
2083
               } while (true == elementSorter.getNext(ref theElement, ref theElementsRelativeLevel));
2084
            }
2085
         }
2086
 
2087
         // Scan through the packages within this package.
2088
         foreach(EA.Package lowerLevelPackage in thePackage.Packages)
2089
         {
2090
            // recurse
2091
            parse_package(lowerLevelPackage, recurse_level);
2092
         }
2093
 
2094 ghuddy 2094
         // If appropriate, turn off non-private class accumulation.
2095
         if (nameStartedWithDetailedDesign)
2096
            recordingNonPrivateClasses = false;
2088 ghuddy 2097
      }
2098
 
2099
 
2100
      /// <summary>
2101
      /// This is the overall generate document method. It creates a word document from 
2102
      /// an input template, sets various characteristics of the document, schedules the
2103
      /// EA parsing function, before finally saving the document to the output file name.
2104
      /// </summary>
2105
      private void createTheWordDoc()
2106
      {
2092 ghuddy 2107
         // caputre initial security settings
2108
         MsoAutomationSecurity  securityBefore = WordApp.AutomationSecurity;
2109
 
2088 ghuddy 2110
         try 
2111
         {
2112
            object template       = this.textBox_template.Text;
2113
            object newTemplate    = Type.Missing;
2114
            object outputFilename = this.textBox_output_file.Text;
2115
 
2116
            object docType = Type.Missing;
2117
            object visible = Type.Missing;
2118
            object nothing = Type.Missing;
2119
            object notTrue = false;
2120
 
2121
            EA_Repository.WriteOutput( Main.GUI_OUTPUT_TAB_NAME, "", 0);
2122
            EA_Repository.WriteOutput( Main.GUI_OUTPUT_TAB_NAME, 
2123
                                       String.Format( "Generating Document {0}", this.textBox_output_file.Text), 0 );
2124
 
2092 ghuddy 2125
            // tell word not to show itself unless user has checked the option to say otherwise
2088 ghuddy 2126
            WordApp.Visible = this.checkBox_WordVisibility.Checked;
2092 ghuddy 2127
 
2128
            // disable VB macros from running in the document
2129
            WordApp.AutomationSecurity = MsoAutomationSecurity.msoAutomationSecurityForceDisable;
2130
            WordApp.DisplayAlerts = Word.WdAlertLevel.wdAlertsNone;
2131
 
2088 ghuddy 2132
            // Create a document from the input template
2133
            WordDocument = WordApp.Documents.Add(ref template, ref newTemplate, ref docType, ref visible);
2134
 
2094 ghuddy 2135
            TableUtils.AcceptWordAppAndDoc(WordApp, WordDocument);
2136
            TextUtils.AcceptWordAppAndDoc(WordApp, WordDocument);
2137
            StyleUtils.AcceptWordAppAndDoc(WordApp, WordDocument);
2138
 
2088 ghuddy 2139
            // Remove all old content from the input document/template. Note that this assumes
2140
            // that content will begin at section 1 with the title "Introduction" and it will have
2141
            // "Heading 1" style.
2142
            removeExistingDocumentContent();
2143
 
2144
            // turn off grammar and spell checking
2145
            WordDocument.GrammarChecked = false;
2146
            WordDocument.SpellingChecked = false;
2147
 
2094 ghuddy 2148
            // arm the public class list accumulator.
2149
            recordingNonPrivateClasses = false;
2150
            nonPrivateClasses = new ArrayList();
2151
            classesWithUnitTests = new ArrayList();
2152
 
2092 ghuddy 2153
            // If the input template does not contain the styles needed for requirement documents, 
2154
            // programmatically create them just in case.
2094 ghuddy 2155
            StyleUtils.createRequirementStylesIfNecessary();
2092 ghuddy 2156
 
2098 ghuddy 2157
            StyleUtils.createElementDetailsStyles();
2158
 
2088 ghuddy 2159
            // Parse EA_DocGen Document Model. The parent package is the document model itself
2160
            // and the packages within it are the top level packages only.
2161
            // Question: do we have to parse diagrams and elements at this top level? So far,
2162
            // this has been found to be unecessary, but you never know. For now, dont do it.
2163
            foreach(EA.Package thePackage in EA_ParentPackage.Packages)
2164
            {
2165
               parse_package(thePackage, 0);
2166
            }
2167
 
2094 ghuddy 2168
            // for design docs, a user may have used the test traceability element in their document model,
2169
            // which means that now we are finished with parse 1 of the document, we can complete the traceability
2170
            // table (if any) that was begun when that special element was first encountered.
2171
            completeTestTraceability();
2088 ghuddy 2172
 
2094 ghuddy 2173
            // Save the document to the output file before we try and update the fields. This is because
2174
            // I have seen Fields.Update() fail on a few occasions and it is very annoying
2175
            // to lose what has thus far been generated.
2176
            WordDocument.SaveAs( ref outputFilename, 
2177
               ref nothing, ref nothing, ref nothing, ref nothing, 
2178
               ref nothing, ref nothing, ref nothing, ref nothing,
2179
               ref nothing, ref nothing, ref nothing, ref nothing,
2180
               ref nothing, ref nothing, ref nothing);
2088 ghuddy 2181
 
2094 ghuddy 2182
            object noSave = Word.WdSaveOptions.wdDoNotSaveChanges;
2183
            object format = Word.WdOriginalFormat.wdWordDocument;
2184
            WordDocument.Close(ref noSave, ref format, ref nothing);
2185
 
2186
            // Re-load the document to update the fields. For some as yet unknown reason, doing this 
2187
            // sometimes fails, but by doing it in a re-loaded instance of the word document
2188
            // the failures seem to be reduced.
2189
            WordDocument = WordApp.Documents.Add(ref outputFilename, ref newTemplate, ref docType, ref visible);
2190
            WordDocument.Fields.Update();
2088 ghuddy 2191
            WordDocument.SaveAs( ref outputFilename, 
2192
               ref nothing, ref nothing, ref nothing, ref nothing, 
2193
               ref nothing, ref nothing, ref nothing, ref nothing,
2194
               ref nothing, ref nothing, ref nothing, ref nothing,
2195
               ref nothing, ref nothing, ref nothing);
2196
 
2197
            // Tell user the process completed ok
2198
            textBox_progress.AppendText( "---Completed---" );
2199
            MessageBox.Show("Document Generation Complete");
2098 ghuddy 2200
 
2201
            button_view_output.Enabled = true;
2088 ghuddy 2202
         }
2203
         catch (Exception createTheWordDoc_exception)
2204
         {
2205
            MessageBox.Show("Document Generation Failed\n\n" + createTheWordDoc_exception.Message);
2206
         }
2092 ghuddy 2207
 
2208
         // restore security settings
2209
         WordApp.AutomationSecurity = securityBefore;
2088 ghuddy 2210
      }
2211
 
2092 ghuddy 2212
 
2213
      /// <summary>
2094 ghuddy 2214
      /// Class to sort EA elements alphabetically, in a case insensitive way.
2215
      /// This is used by the processRelationshipMatrixElement method.
2092 ghuddy 2216
      /// </summary>
2094 ghuddy 2217
      public class elementSortByName : IComparer
2092 ghuddy 2218
      {
2094 ghuddy 2219
         int IComparer.Compare( object x, object y)
2092 ghuddy 2220
         {
2094 ghuddy 2221
            if (x!=null & y!= null)
2222
               return (new CaseInsensitiveComparer()).Compare( ((EA.Element)x).Name, ((EA.Element)y).Name );
2223
            else
2224
               return 0;
2092 ghuddy 2225
         }
2226
      }
2227
 
2094 ghuddy 2228
 
2229
      public class attributeSortByPos : IComparer
2092 ghuddy 2230
      {
2094 ghuddy 2231
         int IComparer.Compare( object x, object y)
2092 ghuddy 2232
         {
2094 ghuddy 2233
            if (x!=null & y!= null)
2234
               return ((EA.Attribute)x).Pos - ((EA.Attribute)y).Pos;
2235
            else
2236
               return 0;
2092 ghuddy 2237
         }
2238
      }
2239
 
2088 ghuddy 2240
 
2094 ghuddy 2241
      public class methodSortByPos : IComparer
2088 ghuddy 2242
      {
2243
         int IComparer.Compare( object x, object y)
2244
         {
2245
            if (x!=null & y!= null)
2094 ghuddy 2246
               return ((EA.Method)x).Pos - ((EA.Method)y).Pos;
2088 ghuddy 2247
            else
2248
               return 0;
2249
         }
2250
      }
2094 ghuddy 2251
 
2088 ghuddy 2252
 
2094 ghuddy 2253
      public class parameterSortByPos : IComparer
2088 ghuddy 2254
      {
2094 ghuddy 2255
         int IComparer.Compare( object x, object y)
2088 ghuddy 2256
         {
2094 ghuddy 2257
            if (x!=null & y!= null)
2258
               return ((EA.Parameter)x).Position - ((EA.Parameter)y).Position;
2259
            else
2260
               return 0;
2088 ghuddy 2261
         }
2262
      }
2263
 
2264
 
2265
      #endregion
2266
   }
2267
}