Subversion Repositories DevTools

Rev

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

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