Subversion Repositories DevTools

Rev

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