Subversion Repositories DevTools

Rev

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