Subversion Repositories DevTools

Rev

Rev 2094 | Rev 2100 | 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
 
671
         // Scan the notes content line by line looking for table parameters and counting
672
         // the number of table rows (which is not specified as an explicit table parameter).
673
         int s_ElementsConsumedByTableParams = 0;
674
         foreach(string s in EA_DocGenTable)
675
         {
676
            if (s.Length > 0 && s != "\n" && s != "\r" )
677
            {
678
               if (gotTitle == false && s.StartsWith("title"))
679
               {
680
                  s_ElementsConsumedByTableParams++;
681
                  tableTitle = EA_Utils.options.getOptionValue(s, tableTitle);
682
                  gotTitle = true;
683
                  if (tableTitle == "")
684
                  {
685
                     MessageBox.Show( "Table Element Serialisation Failed - Bad Title" );
686
                     break;
687
                  }
688
               }
689
 
690
               else if (columnCount == 0 && s.StartsWith("columns"))
691
               {
692
                  s_ElementsConsumedByTableParams++;
693
                  columnCount = EA_Utils.options.getOptionValue(s, columnCount);
694
                  if (columnCount == 0)
695
                  {
696
                     MessageBox.Show( "Table Element Serialisation Failed - bad column count" );
697
                     break;
698
                  }
699
               }
700
               else if (gotSeperator == false && s.StartsWith("seperator"))
701
               {
702
                  s_ElementsConsumedByTableParams++;
703
                  seperator = EA_Utils.options.getOptionValue(s, seperator);
704
                  gotSeperator = true;
705
               }
706
               else
707
               {
708
                  rowCount++;
709
               }
710
            }
711
         }
712
 
713
         if (gotTitle == true && gotSeperator == true && columnCount != 0)
714
         {
715
            if (rowCount < 2)
716
            {
717
               MessageBox.Show( "Table Element Serialisation Failed - Insufficient Rows" );
718
            }
719
            else
720
            {
721
               // create the table in the word doc
2094 ghuddy 722
               int tableNum = TableUtils.Table_Create( tableTitle, rowCount, columnCount );
2088 ghuddy 723
               Word.Table table = WordDocument.Tables[tableNum];
724
               object center = Word.WdParagraphAlignment.wdAlignParagraphCenter;
725
 
726
               // scan the element notes again to extract the cell content and add it to the
727
               // table we just created.
728
               int row = 1;
729
               int col = 1;
730
               foreach(string s in EA_DocGenTable)
731
               {
732
                  if (s.Length > 0 && s != "\n" && s != "\r" )
733
                  {
734
                     if (s_ElementsConsumedByTableParams > 0)
735
                     {
736
                        s_ElementsConsumedByTableParams--;
737
                     }
738
                     else
739
                     {
740
                        delimStr = seperator.ToString();
741
                        delim = delimStr.ToCharArray();
742
                        cells = s.Split(delim,columnCount);
743
 
744
                        if (cells.Length != columnCount)
745
                        {
746
                           MessageBox.Show( "Table Element Serialisation Failed - Bad Row" );
747
                           break;
748
                        }
749
                        else
750
                        {
751
                           // serialise table row
752
                           for(col=1; col<=columnCount; col++)
753
                           {
754
                              cells[col-1].TrimStart( trimChars );
755
                              cells[col-1].TrimEnd( trimChars );
756
 
757
                              table.Cell(row,col).Range.Text = cells[col-1];
758
 
759
                              // special handling for heading row
760
                              if (row == 1)
761
                              {
762
                                 table.Cell(row,col).Range.ParagraphFormat.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter;
763
                                 table.Cell(row,col).Range.Font.Bold = 1;
764
                              }
765
                           }
766
                           row++;
767
                        }                     
768
                     }
769
                  }
770
               }
771
            }
772
         }
773
         else
774
         {
775
            MessageBox.Show( "Table Element Serialisation Failed - Table Parameters Incomplete" );
776
         }
777
      }
778
 
779
 
2094 ghuddy 780
 
2088 ghuddy 781
      /// <summary>
2094 ghuddy 782
      /// This function processes a test link element
783
      /// </summary>
784
      /// <param name="theElement"></param>
785
      /// <param name="recurse_level"></param>
786
      private void processTestLink(EA.Element theElement, int recurse_level )
787
      {
788
         string [] EA_DocGenEleLnk = null;
789
         string delimStr = "\r\n";
790
         char [] delim = delimStr.ToCharArray();
791
         EA_DocGenEleLnk = theElement.Notes.ToString().Split(delim,100);
792
         string linkedName = "";
793
 
794
         foreach(string s in EA_DocGenEleLnk)
795
         {
796
            if (s.Length > 0 && s != "\n" && s != "\r")
797
            {
798
               if ( s[0] == '{')
799
               {
800
                  try
801
                  {
802
                     // try to find the GUID as a package
803
                     EA.Package theFoundPackage = EA_Utils.EA_Finder.findPackageInRepositoryByGUID(s);
804
                     if (theFoundPackage != null)
805
                        TextUtils.appendUnitTestSuite(theFoundPackage, recurse_level, ref classesWithUnitTests);
806
                     else 
807
                     {
808
                        // try to find the GUID as an element
809
                        EA.Element theFoundElement = EA_Utils.EA_Finder.findElementInRepositoryByGUID(s);
810
                        if (theFoundElement != null)
811
                           TextUtils.appendUnitTestSuite(theFoundElement, recurse_level, ref classesWithUnitTests);
812
                        else 
813
                           MessageBox.Show("WARNING - Could not find linked element : " + linkedName );
814
                     }
815
                  }
816
                  catch 
817
                  {
818
                     // try to find the GUID as an element
819
                     EA.Element theFoundElement = EA_Utils.EA_Finder.findElementInRepositoryByGUID(s);
820
                     if (theFoundElement != null)
821
                        TextUtils.appendUnitTestSuite(theFoundElement, recurse_level, ref classesWithUnitTests);
822
                     else 
823
                        MessageBox.Show("WARNING - Could not find linked element : " + linkedName );
824
                  }
825
               }
826
               else
827
               {
828
                  linkedName = s;
829
               }            
830
            }
831
         }         
832
      }
833
 
834
 
835
 
836
      /// <summary>
2088 ghuddy 837
      /// This function process a text element. It is a simple wrapper for the 
838
      /// appendAndSelectText()function.
839
      /// </summary>
840
      /// <param name="theElement"></param>
841
      /// <param name="recurse_level"></param>
842
      private void processTextElement(EA.Element theElement, int recurse_level )
843
      {
2094 ghuddy 844
         TextUtils.appendAndSelectText( theElement.Notes.ToString(), EA_Constants.styleName_Body1 );
2088 ghuddy 845
      }
846
 
847
 
2094 ghuddy 848
      /// <summary>
849
      /// This function will insert a relationship matrix table into the document, built from content
850
      /// specified in options that are provided in the notes section of the special element that
851
      /// has led to this function being called.
852
      /// </summary>
853
      /// <param name="theElement"></param>
854
      /// <param name="recurse_level"></param>
855
      private void processRelationshipMatrixElement( EA.Element theElement, int recurse_level )
856
      {
857
         int tableNum = 0;
858
         Word.Table table = null;
859
 
860
         // process the options for the relationship matrix
861
         EA_RelationshipMatrix EA_RelMatrix = new EA_RelationshipMatrix(EA_Utils);
862
         if (!EA_RelMatrix.processRelationshipMatrixOptions( theElement ))
863
         {
864
            return;  // must have been an error
865
         }
866
 
867
         // Scan the fromPackage to find all the "from elements".
868
         ElementAccumulator fromLister = new ElementAccumulator(EA_RelMatrix.fromElementTypes, EA_Utils);
869
         EA_Utils.findAndProcessPackageElements( EA_RelMatrix.fromPackage, fromLister, EA_RelMatrix.fromPackageRecursion );
870
 
871
         // Sort the "from elements"
872
         elementSortByName sorter = new elementSortByName();
873
         fromLister.Elements.Sort( sorter );
874
 
875
         // dictionary to support from-to table construction.
876
         ArrayList fromToDictionary = new ArrayList();
877
 
878
         // dictionary to support to-from table construction.
879
         ArrayList toFromDictionary = new ArrayList();
880
 
881
         bool needFromToTable = false;
882
         if (EA_RelMatrix.fromToTableTitle != null && EA_RelMatrix.fromToTableTitle.Length > 0)
883
            needFromToTable = true;
884
 
885
         bool needToFromTable = false;
886
         if (EA_RelMatrix.toFromTableTitle != null && EA_RelMatrix.toFromTableTitle.Length > 0)
887
            needToFromTable = true;
888
 
889
         // NOTE: this code has to execute even if no from-to table is needed, in order to support the
890
         // generation of a to-from table, assuming the user has requested one.
891
         int numberOfFromToRows = 0;
892
 
893
         foreach(EA.Element fromElement in fromLister.Elements)
894
         {
895
            // look at the elements connection collection to find references to the
896
            // destination elements
897
            bool foundToElement = false;
898
 
899
            EA.Collection conCollection = fromElement.Connectors;
900
 
901
            foreach (EA.Connector thisCon in conCollection)
902
            {
903
               EA.Element destE = EA_Repository.GetElementByID( thisCon.SupplierID );
904
               if (destE == null)
905
                  continue;
906
 
907
               // ignore self-referential connections
908
               if (fromElement.ElementID == thisCon.SupplierID)
909
                  continue;
910
 
911
               // if the destination element is of a type that the user has requested to include...
912
               if (!EA_RelMatrix.toElementTypes.Contains( destE.Type ))
913
                  continue;
914
 
915
               // Capture the from-to relationship in a dictionary where the key is the
916
               // "from element", and the value is the "to element".
917
               DictionaryEntry newFromToEntry = new DictionaryEntry(fromElement, destE);
918
               fromToDictionary.Add( newFromToEntry );
919
               foundToElement = true;
920
 
921
               // Capture the from-to relationship in a dictionary where the key is the
922
               // ID of the destination element, and the value is the from element name.
923
               // This dictionary will enable rapid construction of the to-from table if
924
               // the user has requested it, from the exact same relationship info used
925
               // to construct the from-to table.
926
               if (needToFromTable)
927
               {
928
                  DictionaryEntry newToFromEntry = new DictionaryEntry(destE.ElementID, fromElement.Name);
929
                  toFromDictionary.Add( newToFromEntry );
930
               }
931
            }
932
 
933
            // If we found a from-to relationship that table needs a new row.
934
            if (foundToElement)
935
            {
936
               numberOfFromToRows++;
937
            }
938
               // If we did not find a from-to relationship that table still needs a new row 
939
               // if the user wants all "from elements", even if some have no "to elements".
940
            else if (EA_RelMatrix.fromPackageTrimming == false)
941
            {
942
               DictionaryEntry newFromToEntry = new DictionaryEntry(fromElement, null);
943
               fromToDictionary.Add( newFromToEntry );
944
               numberOfFromToRows++;
945
            }
946
         }
947
 
948
 
949
         if (needFromToTable)
950
         {
951
            // Now we can actually serialise the table
952
 
953
            if (EA_RelMatrix.fromIntroText != null && EA_RelMatrix.fromIntroText.Length > 0)
954
            {
955
               TextUtils.appendAndSelectText( EA_RelMatrix.fromIntroText, EA_Constants.styleName_Body1 );
956
            }
957
 
958
            // create the from-to table in the word doc
959
            tableNum = TableUtils.Table_Create( EA_RelMatrix.fromToTableTitle, numberOfFromToRows + 1, 2 );
960
            table = WordDocument.Tables[tableNum];
961
 
962
            TableUtils.Table_SetTableColumnTitle(table, EA_RelMatrix.fromColumnTitle, 1);
963
            TableUtils.Table_SetTableColumnTitle(table, EA_RelMatrix.toColumnTitle, 2);
964
 
965
            int row = 1;
966
            int lastFromElementId = -1;
967
            bool firstFromToCon = true;
968
            foreach (DictionaryEntry de in fromToDictionary)
969
            {
970
               if ( ((EA.Element)de.Key).ElementID != lastFromElementId )
971
               {
972
                  lastFromElementId = ((EA.Element)de.Key).ElementID;
973
                  row++;
974
                  table.Cell(row,1).Range.Text = ((EA.Element)de.Key).Name;
975
                  firstFromToCon = true;
976
               }
977
 
978
               if (((EA.Element)de.Value) != null)
979
               {
980
                  if (firstFromToCon)
981
                  {
982
                     firstFromToCon = false;
983
                     table.Cell(row,2).Range.Text = ((EA.Element)de.Value).Name;
984
                  }
985
                  else
986
                  {
987
                     table.Cell(row,2).Range.Text += ((EA.Element)de.Value).Name;
988
                  }
989
               }
990
               else
991
               {
992
                  table.Cell(row,2).Range.Text = "Un-allocated relationship!";
993
                  table.Cell(row,2).Range.Font.Color = Word.WdColor.wdColorRed;
994
               }
995
            }
996
         }
997
 
998
         // Does user want a to-from table ?
999
         if (needToFromTable)
1000
         {
1001
            // re-use the fromToDictionary to prepare the to-from table content 
1002
            fromToDictionary.Clear();
1003
 
1004
            // find all elements for the left hand column of the to-from table.
1005
            ElementAccumulator toLister = new ElementAccumulator(EA_RelMatrix.toElementTypes, EA_Utils);
1006
            EA_Utils.findAndProcessPackageElements( EA_RelMatrix.toPackage, toLister, EA_RelMatrix.toPackageRecursion );
1007
 
1008
            // Sort the "to" elements
1009
            toLister.Elements.Sort( sorter );
1010
 
1011
 
1012
            // To make the to-from table, we use the dictionary that was built when making the from-to
1013
            // table. The dictionary will allow rapid determination of what "from" items belong to each
1014
            // "to" item, without us having to go back to EA and enquire on the database.
1015
            // We build a new fromToDictionary from the toFromDictionary, in advance of actually making 
1016
            // the table so that we can figure out how many rows the table needs to have.
1017
            numberOfFromToRows = 0;
1018
 
1019
            foreach(EA.Element toElement in toLister.Elements)
1020
            {
1021
               bool foundToElement = false;
1022
 
1023
               // right-column cell content
1024
               foreach (DictionaryEntry de in toFromDictionary)
1025
               {
1026
                  if ((int)de.Key == toElement.ElementID)
1027
                  {
1028
                     DictionaryEntry newFromToEntry = new DictionaryEntry(toElement, (string)de.Value);
1029
                     fromToDictionary.Add( newFromToEntry );
1030
                     foundToElement = true;
1031
                  }
1032
               }
1033
 
1034
               // If we found a from-to relationship that table needs a new row.
1035
               if (foundToElement)
1036
               {
1037
                  numberOfFromToRows++;
1038
               }
1039
                  // if user wants all "from elements", even if some have no "to elements", then add a dictionary
1040
                  // entry and bump row count.
1041
               else if (EA_RelMatrix.toPackageTrimming == false)
1042
               {
1043
                  DictionaryEntry newFromToEntry = new DictionaryEntry(toElement, "");
1044
                  fromToDictionary.Add( newFromToEntry );
1045
                  numberOfFromToRows++;
1046
               }
1047
            }
1048
 
1049
            // Now begin to add the to-from table to the word document
1050
            if (EA_RelMatrix.toIntroText != null && EA_RelMatrix.toIntroText.Length > 0)
1051
            {
1052
               TextUtils.appendAndSelectText( EA_RelMatrix.toIntroText, EA_Constants.styleName_Body1 );
1053
            }
1054
 
1055
            // create the table in the word doc
1056
            tableNum = TableUtils.Table_Create( EA_RelMatrix.toFromTableTitle, numberOfFromToRows + 1, 2 );
1057
            table = WordDocument.Tables[tableNum];
1058
 
1059
            TableUtils.Table_SetTableColumnTitle(table, EA_RelMatrix.toColumnTitle, 1);
1060
            TableUtils.Table_SetTableColumnTitle(table, EA_RelMatrix.fromColumnTitle, 2);
2088 ghuddy 1061
 
2094 ghuddy 1062
            int lastFromElementId = -1;
1063
            bool firstToFromCon = true;
1064
            int row = 1;
1065
            foreach (DictionaryEntry de in fromToDictionary)
1066
            {
1067
               if ( ((EA.Element)de.Key).ElementID != lastFromElementId )
1068
               {
1069
                  lastFromElementId = ((EA.Element)de.Key).ElementID;
1070
                  row++;
1071
                  table.Cell(row,1).Range.Text = ((EA.Element)de.Key).Name;
1072
                  firstToFromCon = true;
1073
               }
1074
 
1075
               if (((string)de.Value).Length > 0)
1076
               {
1077
                  if (firstToFromCon)
1078
                  {
1079
                     firstToFromCon = false;
1080
                     table.Cell(row,2).Range.Text = (string)de.Value;
1081
                  }
1082
                  else
1083
                  {
1084
                     table.Cell(row,2).Range.Text += (string)de.Value;
1085
                  }
1086
               }
1087
               else
1088
               {
1089
                  table.Cell(row,2).Range.Text = "Un-allocated relationship!";
1090
                  table.Cell(row,2).Range.Font.Color = Word.WdColor.wdColorRed;
1091
               }
1092
            }
1093
         }
1094
      }
2088 ghuddy 1095
 
2094 ghuddy 1096
 
1097
      private void processTestTraceability( EA.Element theElement, int recurse_level )
1098
      {
1099
         if (nonPrivateClasses.Count > 0)
1100
         {
1101
            if (theElement.Notes.Length > 0)
1102
            {
1103
               TextUtils.appendAndSelectText( theElement.Notes, EA_Constants.styleName_Body1);
1104
            }
1105
            int tableNum = TableUtils.Table_Create("Design Element to Unit Test Suite Traceability", 2, 2);
1106
            utTraceabilityTable = WordDocument.Tables[tableNum];
1107
 
1108
            TableUtils.Table_SetTableColumnTitle(utTraceabilityTable, "Design Element (class)", 1);
1109
            TableUtils.Table_SetTableColumnTitle(utTraceabilityTable, "Test Suite", 2);
1110
         }
1111
      }
1112
 
1113
 
1114
      private void completeTestTraceability()
1115
      {
1116
         if (utTraceabilityTable != null)
1117
         {
1118
            int numClassesRemaining = nonPrivateClasses.Count;
1119
            int row = 2;
1120
            foreach(int elementId in nonPrivateClasses)
1121
            {
1122
               EA.Element theElement = EA_Repository.GetElementByID( elementId );
1123
               if (theElement != null)
1124
               {
1125
                  utTraceabilityTable.Cell(row,1).Range.Text = theElement.Name;
1126
 
1127
                  if (classesWithUnitTests.Contains( elementId ))
1128
                  {
1129
                     utTraceabilityTable.Cell(row,2).Range.Text = TextUtils.testSuiteName(theElement);
1130
                  }
1131
                  else
1132
                  {
1133
                     utTraceabilityTable.Cell(row,2).Range.Text = "Missing tests!";
1134
                     utTraceabilityTable.Cell(row,2).Range.Font.Color = Word.WdColor.wdColorRed;
1135
                  }
1136
               }
1137
 
1138
               numClassesRemaining--;
1139
               if (numClassesRemaining > 0)
1140
               {
1141
                  TableUtils.Table_InsertNewRowAfterThisRow(utTraceabilityTable, row);
1142
                  row++;
1143
               }
1144
            }
1145
         }
1146
      }
1147
 
1148
      #endregion
1149
 
1150
      #region special section processing functions (references, terminology, etc)
2088 ghuddy 1151
      /// <summary>
1152
      /// This function processes elements as if they represented document references for
1153
      /// the References section of a document.
1154
      /// </summary>
1155
      /// <param name="thePackage"></param>
1156
      private void createReferencesSection(EA.Package thePackage)
1157
      {
1158
         foreach(EA.Element theElement in thePackage.Elements)
1159
         {
1160
            // Here we want to apply the special ERG template styles for each reference
1161
            // item.
2094 ghuddy 1162
            TextUtils.appendAndSelectText( theElement.Name.ToString(), EA_Constants.styleName_RefListNum );
1163
            TextUtils.appendAndSelectText( theElement.Notes.ToString(), EA_Constants.styleName_RefListText );
2088 ghuddy 1164
         }
1165
      }
1166
 
1167
 
1168
      private void createTerminologySection(EA.Package thePackage)
1169
      {
1170
         // Use local package elements as source of glossary, but if none are present, resort to using
1171
         // the project glossary in the repository 
1172
         int numItems = thePackage.Elements.Count;
1173
         if (numItems == 0)
1174
         {
1175
            numItems = EA_Repository.Terms.Count;
1176
         }
1177
 
1178
         if (numItems > 0)
1179
         {
1180
            // Create a table
2094 ghuddy 1181
            int tableNum = TableUtils.Table_Create("Terminology", numItems+1, 2);
2088 ghuddy 1182
            Word.Table table = WordDocument.Tables[tableNum];
1183
            object center = Word.WdParagraphAlignment.wdAlignParagraphCenter;
2094 ghuddy 1184
 
1185
            TableUtils.Table_SetTableColumnTitle(table, "Term", 1);
1186
            TableUtils.Table_SetTableColumnTitle(table, "Definition", 2);
2088 ghuddy 1187
            table.Columns[1].SetWidth(100, Word.WdRulerStyle.wdAdjustSameWidth );
1188
            int row = 2;
1189
 
1190
            if (thePackage.Elements.Count > 0)
1191
            {
1192
               // The advantage of using the package content is that the elements come out alphabetically
1193
               // sorted already (assuming user has not over-riden the sort order in the project browser).
1194
               // Also, the glossary content can be exactly tailored to what the document requires.
1195
               foreach(EA.Element theElement in thePackage.Elements)
1196
               {
1197
                  table.Cell(row,1).Range.Text = theElement.Name.ToString();
1198
                  table.Cell(row,2).Range.Text = theElement.Notes.ToString();
1199
                  row++;
1200
               }
1201
            }
1202
            else // default to using the project glossary in the repository
1203
            {
1204
               // TODO 
1205
               // 1. Alphabetically Sort the glossary terms before adding them to the table
1206
               //    The Repository glossary seems to be provided in non-sorted order unfortunately.
1207
 
1208
               // inject the glossary into the table
1209
               foreach(EA.Term theTerm in EA_Repository.Terms)
1210
               {
1211
                  table.Cell(row,1).Range.Text = theTerm.Term;
1212
                  table.Cell(row,2).Range.Text = theTerm.Meaning;
1213
                  row++;
1214
               }
1215
            }
1216
         }
1217
      }
1218
 
2094 ghuddy 1219
      #endregion
2088 ghuddy 1220
 
1221
      private bool generatePackageHeadingAndDescription( EA.Package thePackage, int recurse_level )
1222
      {
1223
         // disarm the one-shot package skipping feature if it was armed, and exit the function.
1224
         if (oneShot_skipRootPackage == true)
1225
         {
1226
            oneShot_skipRootPackage = false;
1227
            return false;
1228
         }
1229
 
1230
         // The package name is a heading, and the package notes are paragraphs 
1231
         // directly under that heading
1232
         displayProgress( "PACKAGE: ", thePackage.Name.ToString() );
1233
 
2094 ghuddy 1234
         TextUtils.appendAndSelectHeadingText( thePackage.Name.ToString(), recurse_level );
2088 ghuddy 1235
 
1236
         // Special handling for package called "Terminology" 
1237
         if (thePackage.Name == "Terminology")
1238
         {
2094 ghuddy 1239
            TextUtils.appendAndSelectText( thePackage.Notes.ToString(), EA_Constants.styleName_Body1 );
2088 ghuddy 1240
            createTerminologySection(thePackage);
1241
            return true;
1242
         }
1243
 
1244
         if (thePackage.Name == "References")
1245
         {
2094 ghuddy 1246
            TextUtils.appendAndSelectText( thePackage.Notes.ToString(), EA_Constants.styleName_Body1 );
2088 ghuddy 1247
            createReferencesSection(thePackage);
1248
            return true;
1249
         }
1250
 
1251
         // use the package notes as body text and indicate to caller that package elements 
1252
         // have not been consumed
2094 ghuddy 1253
         TextUtils.appendAndSelectText( thePackage.Notes.ToString(), EA_Constants.styleName_Body1 );      
2088 ghuddy 1254
         return false;
1255
      }
1256
 
1257
 
1258
      private void generatePackageDiagrams( EA.Package thePackage )
1259
      {
1260
         // default handling of diagrams
1261
         foreach(EA.Diagram theDiagram in thePackage.Diagrams)
1262
         {
1263
            displayProgress( "DIAGRAM: ", theDiagram.Name.ToString() );
1264
 
1265
            appendAndSelectDiagramViaClipboard( theDiagram );
1266
         }
1267
      }
1268
 
1269
 
2094 ghuddy 1270
      private void generateMethodContent( EA.Element theElement, int recurse_level )
2088 ghuddy 1271
      {
1272
         recurse_level++;
2098 ghuddy 1273
         if (recurse_level > EA_Constants.MAX_HEADING_LEVEL - 1)  // -1 because this function generates two heading levels 
2094 ghuddy 1274
         {
2098 ghuddy 1275
            throw new System.StackOverflowException(EA_Constants.maxRecursionDepthException );
2094 ghuddy 1276
         }
1277
 
1278
         // Get all the methods into an array list and sort them by their position in the class's
1279
         // method list (ie. sort order is determined by the Pos value in each method).
1280
         ArrayList theMethods = new ArrayList();
1281
         foreach(EA.Method theMethod in theElement.Methods)
1282
            theMethods.Add( theMethod );
1283
         methodSortByPos sorter = new methodSortByPos();
1284
         theMethods.Sort( sorter );
1285
 
1286
         // filter out methods with certain characteristics?
1287
         // eg. Users may only want to document public and protected methods.
1288
         int numMethodsRemaining = 0;
1289
         foreach(EA.Method theMethod in theMethods)
1290
         {
1291
            if (EA_Utils.options.opt_SuppressPrivateMethods == false
1292
               || !theMethod.Visibility.StartsWith("Private"))
1293
               numMethodsRemaining++;
1294
         }
1295
 
1296
         Word.Range wr;
1297
         StringBuilder sb;
1298
 
1299
         if (numMethodsRemaining > 0)
1300
         {
1301
            // Print the "<Class Name> Operations" headings
1302
            sb = new StringBuilder();
1303
            sb.Append( theElement.Name );
1304
            sb.Append( " Operations" );
1305
            TextUtils.appendAndSelectHeadingText(sb.ToString(), recurse_level);
1306
 
1307
            // Iterate through the class's methods
1308
            foreach(EA.Method theMethod in theMethods)
1309
            {
1310
               sb = new StringBuilder();
1311
 
1312
               if (EA_Utils.options.opt_SuppressPrivateMethods == false
1313
                  || !theMethod.Visibility.StartsWith("Private"))
1314
               {
1315
                  // Print the Method name as a sub heading, and its description
1316
                  TextUtils.appendAndSelectHeadingText(theMethod.Name , recurse_level + 1);
1317
                  TextUtils.appendDescription(theMethod.Notes, EA_Utils);
1318
 
1319
                  // Get a list of the method's parameters and sort them by the position field setup 
1320
                  // in EA by the designer
1321
                  ArrayList theParams = new ArrayList();
1322
                  foreach(EA.Parameter theParam in theMethod.Parameters)
1323
                     theParams.Add( theParam );
1324
                  parameterSortByPos paramSorter = new parameterSortByPos();
1325
                  theParams.Sort( paramSorter );
1326
 
1327
                  // Print the prototype heading
2098 ghuddy 1328
                  wr = TextUtils.appendAndSelectText("\nPrototype:", EA_Constants.styleName_Body1_Left_2_5cm_Italic);
2094 ghuddy 1329
 
1330
                  // begin to build the prototype string
1331
                  sb = new StringBuilder();
1332
                  sb.Append( theMethod.ReturnType );
1333
                  sb.Append( " " );
1334
                  sb.Append( theMethod.Name );
1335
                  sb.Append( "(" );
1336
 
1337
                  if (theParams.Count > 0)
1338
                  {
1339
                     int numParamsRemaining = theParams.Count;
1340
 
1341
                     // print what we have so far constructed for the prototype
2098 ghuddy 1342
                     wr = TextUtils.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_3_5cm);
2094 ghuddy 1343
 
1344
                     // Now form a new string for the params
1345
                     sb = new StringBuilder();
1346
                     foreach(EA.Parameter theParam in theParams)
1347
                     {
1348
                        // each parameter is   "[in|out|inout] type name [= default-value]"
1349
                        // where the default value is optional
1350
                        sb.Append( "[" );
1351
                        sb.Append( theParam.Kind );
1352
                        sb.Append( "] " );
1353
                        sb.Append( theParam.Type );
1354
                        sb.Append( " " );
1355
                        sb.Append( theParam.Name );
1356
                        if (theParam.Default.Length > 0)
1357
                        {
1358
                           sb.Append( " = " );
1359
                           sb.Append( theParam.Default );
1360
                        }
1361
 
1362
                        // if there are more parameters after this one, add a comma and newline
1363
                        if (numParamsRemaining > 1)
1364
                           sb.Append( ",\n" );
1365
 
1366
                        numParamsRemaining--;
1367
                     }
1368
 
1369
                     // complete the prototype and print it.
1370
                     sb.Append( ")" );
2098 ghuddy 1371
                     wr = TextUtils.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_4_5cm);
2094 ghuddy 1372
                  }
1373
                  else
1374
                  {
1375
                     // complete the prototype and print it.
1376
                     sb.Append( ")" );
2098 ghuddy 1377
                     wr = TextUtils.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_3_5cm);
2094 ghuddy 1378
                  }
1379
 
1380
 
1381
                  // Prototype Attributes/Characteristics
1382
                  sb = new StringBuilder();
1383
                  sb.Append( theMethod.Visibility );
1384
 
1385
                  if (theMethod.IsStatic)
1386
                     sb.Append("\nStatic");
1387
 
1388
                  if (theMethod.Abstract)
1389
                     sb.Append("\nAbstract");
1390
 
1391
                  if (theMethod.IsPure)
1392
                     sb.Append("\nPure (c++)");
1393
 
1394
                  if (theMethod.IsSynchronized)
1395
                     sb.Append("\nSynchronised");
1396
 
1397
                  if (theMethod.Concurrency != null && theMethod.Concurrency.Length > 0 && !theMethod.Concurrency.StartsWith("Sequential") )
1398
                  {
1399
                     sb.Append("\n");
1400
                     sb.Append(theMethod.Concurrency);
1401
                  }
1402
 
1403
                  if (theMethod.IsConst)
1404
                     sb.Append("\nConst");
1405
 
1406
                  if (theMethod.IsQuery)
1407
                     sb.Append("\nIs Querry (does not alter class variables)");
1408
 
1409
                  if (theMethod.IsLeaf)
1410
                     sb.Append("\nIs Leaf (cannot be overriden)");
1411
 
1412
                  if (theMethod.ReturnIsArray)
1413
                     sb.Append( "\nReturn value is an array" );
1414
 
1415
                  if (theMethod.Throws != null && theMethod.Throws.Length > 0)
1416
                  {
1417
                     sb.Append("\n");
1418
                     sb.Append( theMethod.Throws );
1419
                  }
1420
 
1421
                  if (sb.Length > 0)
1422
                  {
2098 ghuddy 1423
                     wr = TextUtils.appendAndSelectText("Characteristics:", EA_Constants.styleName_Body1_Left_2_5cm_Italic);
2094 ghuddy 1424
 
2098 ghuddy 1425
                     wr = TextUtils.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_3_5cm);
2094 ghuddy 1426
                  }
1427
 
1428
                  // Parameter Descriptions
1429
                  if (theParams.Count > 0)
1430
                  {
2098 ghuddy 1431
                     wr = TextUtils.appendAndSelectText("Parameters:", EA_Constants.styleName_Body1_Left_2_5cm_Italic);
2094 ghuddy 1432
 
1433
                     foreach(EA.Parameter theParam in theParams)
1434
                     {
2098 ghuddy 1435
                        wr = TextUtils.appendAndSelectText( theParam.Name + "\t", EA_Constants.stylename_Parameter_Description);
1436
                        // do notes in seperate step since we want to call the appendDescription() method which 
1437
                        // automatically alerts us to missing descriptions in the generated document.
1438
                        wr = TextUtils.appendDescription( theParam.Notes, EA_Constants.stylename_Parameter_Description, EA_Utils, true);
2094 ghuddy 1439
                     }
1440
                  }
1441
               }
1442
            }
1443
         }
1444
      }
1445
 
1446
 
1447
      /// <summary>
1448
      /// This method serialises a class's attributes to the document. 
1449
      /// </summary>
1450
      /// <param name="theElement"></param>
1451
      /// <param name="recurse_level"></param>
1452
      private void generateAttributeContent( EA.Element theElement, int recurse_level )
1453
      {
1454
         recurse_level++;
2098 ghuddy 1455
         if (recurse_level > EA_Constants.MAX_HEADING_LEVEL)
2088 ghuddy 1456
         {
2098 ghuddy 1457
            throw new System.StackOverflowException(EA_Constants.maxRecursionDepthException );
2088 ghuddy 1458
         }
2094 ghuddy 1459
 
1460
         // Get all the attributes into an array list and sort them by their position in the class's
1461
         // attribute list (ie. sort order is determined by the Pos value in each attribute).
1462
         ArrayList theAttrs = new ArrayList();
1463
         foreach(EA.Attribute theAttr in theElement.Attributes)
1464
            theAttrs.Add( theAttr );
1465
         attributeSortByPos sorter = new attributeSortByPos();
1466
         theAttrs.Sort( sorter );
1467
 
1468
         // TODO
1469
         // filter out attributes with certain characteristics?
1470
         // eg. Users may only want to document public and protected attributes.
1471
 
1472
         int numAttrsRemaining = 0;
1473
         foreach(EA.Attribute theAttr in theAttrs)
1474
         {
1475
            if (EA_Utils.options.opt_SuppressPrivateAttributes == false
1476
               || !theAttr.Visibility.StartsWith("Private"))
1477
               numAttrsRemaining++;
1478
         }
1479
 
1480
         if (numAttrsRemaining > 0)
1481
         {
1482
            StringBuilder sb = new StringBuilder();
1483
 
1484
            sb.Append( theElement.Name );
1485
            sb.Append( " Attributes" );
1486
            TextUtils.appendAndSelectHeadingText(sb.ToString(), recurse_level);
1487
 
1488
            // serialise the attributes to the document.
1489
            foreach(EA.Attribute theAttr in theAttrs)
1490
            {
1491
               if (EA_Utils.options.opt_SuppressPrivateAttributes == false
1492
                  || !theAttr.Visibility.StartsWith("Private"))
1493
               {
1494
                  // Begin to build content string for the "Attribute" table column 
1495
                  sb = new StringBuilder();
1496
 
1497
                  // <type> <name>
1498
                  sb.Append("\n");
1499
                  sb.Append(theAttr.Type);
1500
                  sb.Append(" ");
1501
                  sb.Append(theAttr.Name);
1502
                  Word.Range wr = TextUtils.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1);
1503
                  wr.Font.Bold = 1;
1504
 
1505
                  wr = TextUtils.appendDescription(theAttr.Notes, EA_Utils);
1506
                  wr.ParagraphFormat.LeftIndent = WordApp.CentimetersToPoints((float)3.5);
1507
 
1508
                  // The approach here is to display as much of the attribute as we can but try to keep the output
1509
                  // uncluttered by omitting items the user has not set via the EA GUI.
1510
 
1511
                  // Begin to build content string for the "Other Information" table cell
1512
                  sb = new StringBuilder();
1513
 
1514
                  sb.Append(theAttr.Visibility);
1515
                  sb.Append("\n");
1516
 
1517
                  if (theAttr.IsConst)
1518
                     sb.Append("Constant\n");
1519
 
1520
                  if (theAttr.IsStatic)
1521
                     sb.Append("Static\n");
1522
 
1523
                  if (theAttr.IsDerived)
1524
                     sb.Append("Derived\n");
1525
 
1526
                  if (theAttr.IsOrdered)
1527
                  {
1528
                     sb.Append("Is Ordered\n");
1529
                  }
1530
 
1531
                  if (theAttr.IsCollection)
1532
                  {
1533
                     sb.Append("Is A Collection\n");
1534
                  }
1535
 
1536
                  if (theAttr.Length.Length > 0 && System.Convert.ToInt32(theAttr.Length) > 0)
1537
                  {
1538
                     sb.Append("Length = ");
1539
                     sb.Append(theAttr.Length);
1540
                     sb.Append("\n");
1541
                  }
1542
 
1543
                  if (!theAttr.Containment.StartsWith("Not Specified"))
1544
                  {
1545
                     sb.Append("Containment =");
1546
                     sb.Append(theAttr.Containment);
1547
                     sb.Append("\n");
1548
                  }
1549
 
1550
                  if (theAttr.Container.Length > 0)
1551
                  {
1552
                     sb.Append("Container Type = ");
1553
                     sb.Append(theAttr.Container);
1554
                     sb.Append("\n");
1555
                  }
1556
 
1557
                  if (theAttr.Style.Length > 0)
1558
                  {
1559
                     sb.Append("Style = ");
1560
                     sb.Append(theAttr.Style);
1561
                     sb.Append("\n");
1562
                  }
1563
 
1564
                  if (  System.Convert.ToInt32(theAttr.LowerBound) > 1
1565
                     || System.Convert.ToInt32(theAttr.UpperBound) > 1)
1566
                  {
1567
                     sb.Append("Multiplicity [");
1568
                     sb.Append(theAttr.LowerBound);
1569
                     sb.Append("..");
1570
                     sb.Append(theAttr.UpperBound);
1571
                     sb.Append("]\n");
1572
                  }
1573
 
1574
                  if (theAttr.Scale.Length > 0 && System.Convert.ToInt32(theAttr.Scale) > 0)
1575
                  {
1576
                     sb.Append("Scale = ");
1577
                     sb.Append(theAttr.Scale);
1578
                     sb.Append( "\n" );
1579
                  }
1580
                  if (theAttr.Precision.Length > 0 && System.Convert.ToInt32(theAttr.Precision) > 0)
1581
                  {
1582
                     sb.Append("Precision = ");
1583
                     sb.Append(theAttr.Precision);
1584
                     sb.Append( "\n" );
1585
                  }
1586
 
1587
                  if (theAttr.Default.Length > 0)
1588
                  {
1589
                     sb.Append("Default Value = ");
1590
                     sb.Append(theAttr.Default);
1591
                     sb.Append( "\n" );
1592
                  }
1593
 
1594
                  // Now look at the constraint and tagged value collections and add any found info to the
1595
                  // right hand column
1596
                  short i;
1597
                  for(i=0; i<theAttr.Constraints.Count; i++)
1598
                  {
1599
                     EA.AttributeConstraint theCons = (EA.AttributeConstraint)theAttr.Constraints.GetAt(i);
1600
                     sb.Append( theCons.Type );
1601
                     sb.Append( ": {" );
1602
                     sb.Append( theCons.Name );
1603
                     sb.Append( "}\n" );
1604
                     //sb.Append( theCons.Notes  );
1605
                     //sb.Append( "\n" );
1606
                  }
1607
 
1608
                  for(i=0; i<theAttr.TaggedValues.Count; i++)
1609
                  {
1610
                     EA.AttributeTag theTag = (EA.AttributeTag)theAttr.TaggedValues.GetAt(i);
1611
                     sb.Append( "[" );
1612
                     sb.Append( theTag.Name );
1613
                     sb.Append( "="  );
1614
                     sb.Append( theTag.Value );
1615
                     sb.Append( "]\n" );
1616
                     //sb.Append( theTag.Notes );
1617
                     //sb.Append( "\n" );
1618
                  }
1619
 
1620
                  if (sb.Length > 0)
1621
                  {
1622
                     // remove the trailing "\n"
1623
                     sb.Remove( sb.ToString().Length - 1, 1);
1624
 
2098 ghuddy 1625
                     wr = TextUtils.appendAndSelectText("Characteristics:", EA_Constants.styleName_Body1_Left_3_5cm_Italic);
2094 ghuddy 1626
 
2098 ghuddy 1627
                     wr = TextUtils.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_4_5cm);
2094 ghuddy 1628
                  }
1629
 
1630
                  numAttrsRemaining--;
1631
               }
1632
            }
1633
         }
1634
      }
1635
 
1636
 
1637
      private void generateClassCharacteristics( EA.Element theElement, int recurse_level )
1638
      {
1639
         StringBuilder sb = new StringBuilder();
1640
 
1641
         sb.Append( "Characteristics:" );
2098 ghuddy 1642
         Word.Range wr = TextUtils.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_2_5cm_Italic);
2088 ghuddy 1643
 
2094 ghuddy 1644
         sb = new StringBuilder();
1645
         sb.Append( theElement.Visibility );
1646
 
1647
         if (System.Convert.ToInt32(theElement.Abstract) == 1)
1648
            sb.Append( "\nAbstract" );
1649
 
2098 ghuddy 1650
         wr = TextUtils.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_3_5cm);
2094 ghuddy 1651
 
1652
         sb = new StringBuilder();
1653
         foreach(EA.Element baseClass in theElement.BaseClasses)
2088 ghuddy 1654
         {
2094 ghuddy 1655
            sb.Append( baseClass.Name);
1656
         }
1657
         if (sb.Length > 0)
1658
         {
2098 ghuddy 1659
            wr = TextUtils.appendAndSelectText("Base Class(es):", EA_Constants.styleName_Body1_Left_2_5cm_Italic);
2088 ghuddy 1660
 
2098 ghuddy 1661
            wr = TextUtils.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_3_5cm);
2094 ghuddy 1662
         }
1663
 
1664
         sb = new StringBuilder();
1665
         foreach(EA.Element intf in theElement.Realizes)
1666
         {
1667
            sb.Append( intf.Name);
1668
         }
1669
         if (sb.Length > 0)
1670
         {
2098 ghuddy 1671
            wr = TextUtils.appendAndSelectText("Realises:", EA_Constants.styleName_Body1_Left_2_5cm_Italic);
2094 ghuddy 1672
 
2098 ghuddy 1673
            wr = TextUtils.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_3_5cm);
2094 ghuddy 1674
         }
1675
      }
1676
 
1677
 
1678
      private void generateClassRequirements( EA.Element theElement, int recurse_level )
1679
      {
1680
         StringBuilder sb = new StringBuilder();
1681
 
1682
         sb.Append( "Requirements:" );
2098 ghuddy 1683
         Word.Range wr = TextUtils.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_2_5cm_Italic);
2094 ghuddy 1684
 
1685
         foreach(EA.Requirement theReq in theElement.Requirements)
1686
         {
1687
            sb = new StringBuilder();
1688
            sb.Append( theReq.Name );
2098 ghuddy 1689
            wr = TextUtils.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_3_5cm);
2094 ghuddy 1690
            sb = new StringBuilder();
1691
            sb.Append( theReq.Notes );
1692
            if (sb.Length > 0)
2088 ghuddy 1693
            {
2098 ghuddy 1694
               wr = TextUtils.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_4_5cm);
2088 ghuddy 1695
            }
2094 ghuddy 1696
         }
1697
      }
1698
 
1699
 
1700
      private void generateClassConstraints( EA.Element theElement, int recurse_level )
1701
      {
1702
         StringBuilder sb = new StringBuilder();
1703
 
1704
         sb.Append( "Constraints:" );
2098 ghuddy 1705
         Word.Range wr = TextUtils.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_2_5cm_Italic);
2094 ghuddy 1706
 
1707
         foreach(EA.Constraint theCons in theElement.Constraints)
1708
         {
1709
            sb = new StringBuilder();
1710
            sb.Append( theCons.Type );
1711
            sb.Append( ": {" );
1712
            sb.Append( theCons.Name );
1713
            sb.Append( "}" );
1714
 
2098 ghuddy 1715
            wr = TextUtils.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_3_5cm);
2094 ghuddy 1716
 
1717
            if (theCons.Notes.Length > 0)
2088 ghuddy 1718
            {
2094 ghuddy 1719
               sb = new StringBuilder();
1720
               sb.Append( theCons.Notes );
2098 ghuddy 1721
               wr = TextUtils.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_4_5cm);
2094 ghuddy 1722
            }
1723
         }
1724
      }
1725
 
1726
 
1727
      private void generateElementContent( EA.Element theElement, int recurse_level )
1728
      {
1729
         // track recursion level to control heading style formatting requirements
1730
         if (oneShot_skipRootElementHeading == false)
1731
            recurse_level++;
1732
 
1733
         if (EA_Utils.options.elementTypeFoundInEA_DocGen( theElement.Type ))
1734
         {
1735
            // pass the element to the requirement element serialisation function. It
1736
            // will tell us if it did anything with it. If not, then carry out the default
1737
            // element serialisation.
1738
            if (false == TextUtils.generateRequirementText(theElement, EA_Utils))
1739
            {
1740
               bool isClass = theElement.Type.StartsWith("Class");
1741
 
1742
               if (  true == isClass
1743
                  && true == EA_Utils.options.opt_SuppressPrivateClasses
1744
                  && true == theElement.Visibility.StartsWith("Private") )
2088 ghuddy 1745
               {
2094 ghuddy 1746
                  // do nothing
2088 ghuddy 1747
               }
1748
               else
2094 ghuddy 1749
               {
2098 ghuddy 1750
                  if (recurse_level > EA_Constants.MAX_HEADING_LEVEL)
1751
                  {
1752
                     throw new System.StackOverflowException(EA_Constants.maxRecursionDepthException);
1753
                  }
1754
 
2094 ghuddy 1755
                  trackDocSection(recurse_level);
1756
                  displayProgress( "ELEMENT: ", theElement.Name );
1757
 
2098 ghuddy 1758
                  // Determine if element is filtered out by a NO_DOC tagged value
1759
                  // Having written this code, I realised it might be a bad idea to let users filter out
1760
                  // elements by tagged values. The reason is, if that content is not in a document model
1761
                  // but in a design model, then it might be used by >1 document model made by different
1762
                  // users, so one users choice of filtering might not suit another users. The only way we 
1763
                  // could get this to work is if the tagged values were somehow made specific to a document
1764
                  // model, but how do you do this? GUIDs are the only safe way to key to something but we
1765
                  // dont want every tagged value key to contain a GUID do we?
1766
//                  bool noDocGen = false;
1767
//                  string str_noDocGen = EA_Utils.ReadTag(theElement, "NO_DOC");
1768
//                  if (str_noDocGen.Length > 0)
1769
//                  {
1770
//                     str_noDocGen = str_noDocGen.ToLower();
1771
//                     if (str_noDocGen.CompareTo("true"))
1772
//                     {
1773
//                        noDocGen = true;
1774
//                        displayProgress( "FILTERED: ", theElement.Type );
1775
//                        oneShot_skipRootElementHeading = false;
1776
//                        return;
1777
//                     }
1778
//                  }                     
1779
 
2094 ghuddy 1780
                  // disarm the one-shot element (heading) skipping feature if it was armed, and 
1781
                  // by-pass the code to generate a new heading level for the element
1782
                  if (oneShot_skipRootElementHeading == false)
1783
                  {
1784
                     // Default element serialisation
1785
                     if (  EA_Utils.options.opt_ElementHeadingTransitionLevel > 0
1786
                        && EA_Utils.options.opt_ElementHeadingTransitionLevel <= recurse_level )
1787
                        TextUtils.appendAndSelectNumParaText( theElement.Name, recurse_level );
1788
                     else
1789
                        TextUtils.appendAndSelectHeadingText( theElement.Name, recurse_level );
1790
                  }
1791
                  else
1792
                  {
1793
                     oneShot_skipRootElementHeading = false;
1794
                  }
1795
 
1796
                  TextUtils.appendDescription( theElement.Notes, EA_Utils );
1797
 
1798
                  if (true == isClass)
1799
                  {
1800
                     // If accumulation of non-private classes is enabled, then do so.
1801
                     if (recordingNonPrivateClasses)
1802
                     {
1803
                        if (!theElement.Visibility.StartsWith("Private"))
1804
                        {
1805
                           nonPrivateClasses.Add( theElement.ElementID );
1806
                        }
1807
                     }
1808
 
1809
                     generateClassCharacteristics(theElement, recurse_level);
1810
                  }
1811
 
1812
                  // Requirement collection
1813
                  if (theElement.Requirements.Count > 0)
1814
                  {
1815
                     generateClassRequirements(theElement, recurse_level);
1816
                  }
1817
 
1818
                  // Constraint collection
1819
                  if (theElement.Constraints.Count > 0)
1820
                  {
1821
                     generateClassConstraints(theElement, recurse_level);
1822
                  }
1823
 
1824
                  if (theElement.Issues.Count > 0)
1825
                  {
1826
                  }
1827
 
1828
                  // Attribute collection
1829
                  if (theElement.Attributes.Count > 0)
1830
                  {
1831
                     generateAttributeContent(theElement, recurse_level);
1832
                  }
1833
 
1834
                  // Method collection
1835
                  if (theElement.Methods.Count > 0)
1836
                  {
1837
                     generateMethodContent(theElement, recurse_level);
1838
                  }
1839
               }
2088 ghuddy 1840
            }
2094 ghuddy 1841
            else
1842
            {
1843
               trackDocSection(recurse_level);
1844
               displayProgress( "ELEMENT: ", theElement.Name );
1845
            }
2088 ghuddy 1846
         }
1847
         else
1848
         {
1849
            displayProgress( "FILTERED: ", theElement.Type );
1850
         }
1851
         // TODO
1852
         // We will probably have to put special code in here at some point for attributes
1853
         // of, and collections of things within elements. This will become apparent once
1854
         // someone tries to produce a design document where such things need to be included
1855
         // in the generated document. Lots of work needed here eventually.
1856
 
2094 ghuddy 1857
         // disarm element heading skip control
1858
         oneShot_skipRootElementHeading = false;
2088 ghuddy 1859
      }
1860
 
2094 ghuddy 1861
 
2088 ghuddy 1862
      /// <summary>
1863
      /// This function searches for the old content in the document in order to remove it
1864
      /// prior to adding in the new content from the latest EA model data.
1865
      /// </summary>
1866
      private void removeExistingDocumentContent()
1867
      {
1868
         //WordApp.Visible = true;  // enable this when debugging this horrible function
1869
         Word.Selection aSelection;
2094 ghuddy 1870
         object findStyle = StyleUtils.getStyle( EA_Constants.styleName_Heading1 );
2088 ghuddy 1871
 
1872
         WordApp.Selection.WholeStory();
1873
         aSelection = WordApp.Selection;
1874
 
1875
         aSelection.Find.ClearFormatting();
1876
         aSelection.Find.set_Style( ref findStyle );
1877
         aSelection.Find.Text = "Introduction";
1878
         aSelection.Find.Replacement.Text = "";
1879
         aSelection.Find.Forward = true;
1880
         aSelection.Find.MatchCase = false;
1881
         aSelection.Find.MatchWholeWord = false;
1882
         aSelection.Find.MatchWildcards = false;
1883
         aSelection.Find.MatchSoundsLike = false;
1884
         aSelection.Find.MatchAllWordForms = false;
1885
 
1886
         object missingValue = Type.Missing;
1887
         if (aSelection.Find.Execute(ref missingValue, ref missingValue, 
1888
            ref missingValue, ref missingValue, ref missingValue, 
1889
            ref missingValue, ref missingValue, ref missingValue, 
1890
            ref missingValue, ref missingValue, ref missingValue, 
1891
            ref missingValue, ref missingValue, ref missingValue, 
1892
            ref missingValue)) 
1893
         { 
1894
            // found Introduction with Heading 1 style so we are now at the point in the 
1895
            // document where everything here on must be deleted in readiness for the newly
1896
            // generated content. Extend the range to the end of the document and cut out the
1897
            // old content.
1898
            Word.Range range = aSelection.Range;
1899
            range.End = WordDocument.Content.End;
1900
            range.Cut();
2092 ghuddy 1901
            // try and ensure that no heading style is left in place following the removal
2094 ghuddy 1902
            object style = EA_Constants.styleName_Body1;
2092 ghuddy 1903
            range.set_Style(ref style);
2088 ghuddy 1904
         }
1905
      }
1906
 
1907
 
1908
      /// <summary>
1909
      /// Parses an element (because elements can contain sub-elements).
1910
      /// This is also the function that identifies the occurrences of the special
1911
      /// EA_DocGenXXX elements.
1912
      /// </summary>
1913
      /// <param name="theElement"></param>
1914
      /// <param name="recurse_level"></param>
1915
      private void parse_element(EA.Element theElement, int recurse_level)
1916
      {
1917
         // First look for and handle special elements that control the doc-gen process
1918
 
1919
         // The EA_DocGenPackageLink can contain a list of GUIDs in its notes section
1920
         // that point to model structure outside of the localised structure forming the
1921
         // document. This enables a document to grab content from other external models
1922
         // as long as they are loaded into the repository.
2094 ghuddy 1923
         if (theElement.Name.StartsWith(EA_Constants.EA_DocGenPackageLink))
2088 ghuddy 1924
         {
1925
            processPackageLink( theElement, recurse_level );
1926
         }
1927
 
1928
            // The EA_DocGenDiagramLink can contain a list of GUIDs in its notes section
1929
            // that point to diagram elements anywhere in the repository.
2094 ghuddy 1930
         else if (theElement.Name.StartsWith(EA_Constants.EA_DocGenDiagramLink))
2088 ghuddy 1931
         {
1932
            processDiagramLink( theElement );
1933
         }
1934
 
1935
            // The EA_DocGenDiagramLink can contain a list of GUIDs in its notes section
1936
            // that point to diagram elements anywhere in the repository.
2094 ghuddy 1937
         else if (theElement.Name.StartsWith(EA_Constants.EA_DocGenElementLink))
2088 ghuddy 1938
         {
1939
            processElementLink( theElement, recurse_level );
1940
         }
1941
 
1942
            // The EA_DocGenTable element can contain table content in its notes section
1943
            // and must be dealt with in a special way.
2094 ghuddy 1944
         else if (theElement.Name.StartsWith(EA_Constants.EA_DocGenTable))
2088 ghuddy 1945
         {
1946
            processTableElement( theElement, recurse_level );
1947
         }
1948
 
1949
            // The EA_DocGenText element can contain text content in its notes section
1950
            // that must be appended to the doc in Body 1 style within the current
1951
            // section.
2094 ghuddy 1952
         else if (theElement.Name.StartsWith(EA_Constants.EA_DocGenText))
2088 ghuddy 1953
         {
1954
            processTextElement( theElement, recurse_level );
1955
         }
1956
 
2094 ghuddy 1957
         else if (theElement.Name.StartsWith(EA_Constants.EA_DocGenRelationshipMatrix))
2088 ghuddy 1958
         {
1959
            processRelationshipMatrixElement( theElement, recurse_level );
1960
         }
1961
 
2094 ghuddy 1962
         else if (theElement.Name.StartsWith(EA_Constants.EA_DocGenTestLink))
2088 ghuddy 1963
         {
2094 ghuddy 1964
            processTestLink( theElement, recurse_level );
1965
         }
1966
 
1967
         else if (theElement.Name.StartsWith(EA_Constants.EA_DocGenTestTraceability))
1968
         {
1969
            processTestTraceability( theElement, recurse_level );
1970
         }
1971
 
1972
 
1973
            // we are aware of the other ERG EA add-in, EA_ReqPro! That other add-in creates 
1974
            // ReqProDB stereotyped elements. Never consume them in the document generation process.
1975
         else if ( theElement.Stereotype != EA_Constants.stereotype_ReqProDB )    
1976
         {
2088 ghuddy 1977
            generateElementContent( theElement, recurse_level );
1978
         }      
1979
      }
1980
 
1981
 
1982
      /// <summary>
1983
      /// Parses the package and all of its content, extracting information as needed, and
1984
      /// adding it to the word document. This method is recursive, since recursion is the
1985
      /// easiest way to walk thru' the package levels in the model.
1986
      /// </summary>
1987
      /// <param name="parentPackage"></param>
1988
      /// <param name="recurse_level"></param>
1989
      private void parse_package(EA.Package thePackage, int recurse_level)
1990
      {
1991
         // track recursion level to control heading style formatting requirements
1992
         // The one-shot skiproot feature of the EA_DocGenPackageLink element handling has an effect
1993
         // here, as you can see. 
1994
         bool rootPackageWasSkipped = !oneShot_skipRootPackage;
1995
         if (oneShot_skipRootPackage == false)
1996
         {
1997
            recurse_level++;
1998
            trackDocSection(recurse_level);
1999
         }
2000
 
2098 ghuddy 2001
         if (recurse_level > EA_Constants.MAX_HEADING_LEVEL)
2088 ghuddy 2002
         {
2098 ghuddy 2003
            throw new System.StackOverflowException(EA_Constants.maxRecursionDepthException );
2088 ghuddy 2004
         }
2005
 
2094 ghuddy 2006
         // If we have reached a "Detailed Design" section, we should begin to capture in a list, all public 
2007
         // classes so that we know later on what classes need to be considered in the unit testing section
2008
         // of the document, assuming that this is a s/w design document being generated ofcoarse. 
2009
         bool nameStartedWithDetailedDesign = false;
2010
         if (recordingNonPrivateClasses == false && thePackage.Name.StartsWith("Detailed Design"))
2011
         {
2012
            recordingNonPrivateClasses = true;
2013
            nameStartedWithDetailedDesign = true;
2014
         }
2015
 
2088 ghuddy 2016
         // generate package heading and description. This may, depending on the package name,
2017
         // consume the elements in the package. If it does not, then consume them (and any diagrams)
2018
         // locally here.
2019
         if (false == generatePackageHeadingAndDescription( thePackage, recurse_level ))
2020
         {
2021
            // consume diagrams
2022
            generatePackageDiagrams( thePackage );
2023
 
2024
            // consume elements - we have to use a special sorting class here because of peculiarties
2025
            // in the way EA holds the elements in the collections. 
2026
            EA_ElementSorter elementSorter = new EA_ElementSorter(thePackage);
2027
            EA.Element theElement = null;
2028
            int theElementsRelativeLevel = 0;
2029
            if (true == elementSorter.getFirst(ref theElement, ref theElementsRelativeLevel))
2030
            {
2031
               do
2032
               {
2033
                  int theElementsRecurseLevel = recurse_level + theElementsRelativeLevel;
2034
 
2035
                  parse_element( theElement, theElementsRecurseLevel );
2036
 
2037
               } while (true == elementSorter.getNext(ref theElement, ref theElementsRelativeLevel));
2038
            }
2039
         }
2040
 
2041
         // Scan through the packages within this package.
2042
         foreach(EA.Package lowerLevelPackage in thePackage.Packages)
2043
         {
2044
            // recurse
2045
            parse_package(lowerLevelPackage, recurse_level);
2046
         }
2047
 
2094 ghuddy 2048
         // If appropriate, turn off non-private class accumulation.
2049
         if (nameStartedWithDetailedDesign)
2050
            recordingNonPrivateClasses = false;
2088 ghuddy 2051
      }
2052
 
2053
 
2054
      /// <summary>
2055
      /// This is the overall generate document method. It creates a word document from 
2056
      /// an input template, sets various characteristics of the document, schedules the
2057
      /// EA parsing function, before finally saving the document to the output file name.
2058
      /// </summary>
2059
      private void createTheWordDoc()
2060
      {
2092 ghuddy 2061
         // caputre initial security settings
2062
         MsoAutomationSecurity  securityBefore = WordApp.AutomationSecurity;
2063
 
2088 ghuddy 2064
         try 
2065
         {
2066
            object template       = this.textBox_template.Text;
2067
            object newTemplate    = Type.Missing;
2068
            object outputFilename = this.textBox_output_file.Text;
2069
 
2070
            object docType = Type.Missing;
2071
            object visible = Type.Missing;
2072
            object nothing = Type.Missing;
2073
            object notTrue = false;
2074
 
2075
            EA_Repository.WriteOutput( Main.GUI_OUTPUT_TAB_NAME, "", 0);
2076
            EA_Repository.WriteOutput( Main.GUI_OUTPUT_TAB_NAME, 
2077
                                       String.Format( "Generating Document {0}", this.textBox_output_file.Text), 0 );
2078
 
2092 ghuddy 2079
            // tell word not to show itself unless user has checked the option to say otherwise
2088 ghuddy 2080
            WordApp.Visible = this.checkBox_WordVisibility.Checked;
2092 ghuddy 2081
 
2082
            // disable VB macros from running in the document
2083
            WordApp.AutomationSecurity = MsoAutomationSecurity.msoAutomationSecurityForceDisable;
2084
            WordApp.DisplayAlerts = Word.WdAlertLevel.wdAlertsNone;
2085
 
2088 ghuddy 2086
            // Create a document from the input template
2087
            WordDocument = WordApp.Documents.Add(ref template, ref newTemplate, ref docType, ref visible);
2088
 
2094 ghuddy 2089
            TableUtils.AcceptWordAppAndDoc(WordApp, WordDocument);
2090
            TextUtils.AcceptWordAppAndDoc(WordApp, WordDocument);
2091
            StyleUtils.AcceptWordAppAndDoc(WordApp, WordDocument);
2092
 
2088 ghuddy 2093
            // Remove all old content from the input document/template. Note that this assumes
2094
            // that content will begin at section 1 with the title "Introduction" and it will have
2095
            // "Heading 1" style.
2096
            removeExistingDocumentContent();
2097
 
2098
            // turn off grammar and spell checking
2099
            WordDocument.GrammarChecked = false;
2100
            WordDocument.SpellingChecked = false;
2101
 
2094 ghuddy 2102
            // arm the public class list accumulator.
2103
            recordingNonPrivateClasses = false;
2104
            nonPrivateClasses = new ArrayList();
2105
            classesWithUnitTests = new ArrayList();
2106
 
2092 ghuddy 2107
            // If the input template does not contain the styles needed for requirement documents, 
2108
            // programmatically create them just in case.
2094 ghuddy 2109
            StyleUtils.createRequirementStylesIfNecessary();
2092 ghuddy 2110
 
2098 ghuddy 2111
            StyleUtils.createElementDetailsStyles();
2112
 
2088 ghuddy 2113
            // Parse EA_DocGen Document Model. The parent package is the document model itself
2114
            // and the packages within it are the top level packages only.
2115
            // Question: do we have to parse diagrams and elements at this top level? So far,
2116
            // this has been found to be unecessary, but you never know. For now, dont do it.
2117
            foreach(EA.Package thePackage in EA_ParentPackage.Packages)
2118
            {
2119
               parse_package(thePackage, 0);
2120
            }
2121
 
2094 ghuddy 2122
            // for design docs, a user may have used the test traceability element in their document model,
2123
            // which means that now we are finished with parse 1 of the document, we can complete the traceability
2124
            // table (if any) that was begun when that special element was first encountered.
2125
            completeTestTraceability();
2088 ghuddy 2126
 
2094 ghuddy 2127
            // Save the document to the output file before we try and update the fields. This is because
2128
            // I have seen Fields.Update() fail on a few occasions and it is very annoying
2129
            // to lose what has thus far been generated.
2130
            WordDocument.SaveAs( ref outputFilename, 
2131
               ref nothing, ref nothing, ref nothing, ref nothing, 
2132
               ref nothing, ref nothing, ref nothing, ref nothing,
2133
               ref nothing, ref nothing, ref nothing, ref nothing,
2134
               ref nothing, ref nothing, ref nothing);
2088 ghuddy 2135
 
2094 ghuddy 2136
            object noSave = Word.WdSaveOptions.wdDoNotSaveChanges;
2137
            object format = Word.WdOriginalFormat.wdWordDocument;
2138
            WordDocument.Close(ref noSave, ref format, ref nothing);
2139
 
2140
            // Re-load the document to update the fields. For some as yet unknown reason, doing this 
2141
            // sometimes fails, but by doing it in a re-loaded instance of the word document
2142
            // the failures seem to be reduced.
2143
            WordDocument = WordApp.Documents.Add(ref outputFilename, ref newTemplate, ref docType, ref visible);
2144
            WordDocument.Fields.Update();
2088 ghuddy 2145
            WordDocument.SaveAs( ref outputFilename, 
2146
               ref nothing, ref nothing, ref nothing, ref nothing, 
2147
               ref nothing, ref nothing, ref nothing, ref nothing,
2148
               ref nothing, ref nothing, ref nothing, ref nothing,
2149
               ref nothing, ref nothing, ref nothing);
2150
 
2151
            // Tell user the process completed ok
2152
            textBox_progress.AppendText( "---Completed---" );
2153
            MessageBox.Show("Document Generation Complete");
2098 ghuddy 2154
 
2155
            button_view_output.Enabled = true;
2088 ghuddy 2156
         }
2157
         catch (Exception createTheWordDoc_exception)
2158
         {
2159
            MessageBox.Show("Document Generation Failed\n\n" + createTheWordDoc_exception.Message);
2160
         }
2092 ghuddy 2161
 
2162
         // restore security settings
2163
         WordApp.AutomationSecurity = securityBefore;
2088 ghuddy 2164
      }
2165
 
2092 ghuddy 2166
 
2167
      /// <summary>
2094 ghuddy 2168
      /// Class to sort EA elements alphabetically, in a case insensitive way.
2169
      /// This is used by the processRelationshipMatrixElement method.
2092 ghuddy 2170
      /// </summary>
2094 ghuddy 2171
      public class elementSortByName : IComparer
2092 ghuddy 2172
      {
2094 ghuddy 2173
         int IComparer.Compare( object x, object y)
2092 ghuddy 2174
         {
2094 ghuddy 2175
            if (x!=null & y!= null)
2176
               return (new CaseInsensitiveComparer()).Compare( ((EA.Element)x).Name, ((EA.Element)y).Name );
2177
            else
2178
               return 0;
2092 ghuddy 2179
         }
2180
      }
2181
 
2094 ghuddy 2182
 
2183
      public class attributeSortByPos : IComparer
2092 ghuddy 2184
      {
2094 ghuddy 2185
         int IComparer.Compare( object x, object y)
2092 ghuddy 2186
         {
2094 ghuddy 2187
            if (x!=null & y!= null)
2188
               return ((EA.Attribute)x).Pos - ((EA.Attribute)y).Pos;
2189
            else
2190
               return 0;
2092 ghuddy 2191
         }
2192
      }
2193
 
2088 ghuddy 2194
 
2094 ghuddy 2195
      public class methodSortByPos : IComparer
2088 ghuddy 2196
      {
2197
         int IComparer.Compare( object x, object y)
2198
         {
2199
            if (x!=null & y!= null)
2094 ghuddy 2200
               return ((EA.Method)x).Pos - ((EA.Method)y).Pos;
2088 ghuddy 2201
            else
2202
               return 0;
2203
         }
2204
      }
2094 ghuddy 2205
 
2088 ghuddy 2206
 
2094 ghuddy 2207
      public class parameterSortByPos : IComparer
2088 ghuddy 2208
      {
2094 ghuddy 2209
         int IComparer.Compare( object x, object y)
2088 ghuddy 2210
         {
2094 ghuddy 2211
            if (x!=null & y!= null)
2212
               return ((EA.Parameter)x).Position - ((EA.Parameter)y).Position;
2213
            else
2214
               return 0;
2088 ghuddy 2215
         }
2216
      }
2217
 
2218
 
2219
      #endregion
2220
   }
2221
}