Subversion Repositories DevTools

Rev

Rev 2088 | Rev 2092 | 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;
4
using System.ComponentModel;
5
using System.Windows.Forms;
6
using Word;
7
 
8
namespace EA_DocGen
9
{
10
 
11
 
12
   /// <summary>
13
   /// Summary description for createWordDoc.
14
   /// </summary>
15
   public class createWordDoc : System.Windows.Forms.Form
16
   {
17
      // Enterprise Architect Model related data
18
      private EA.Repository EA_Repository = null;
19
      private EA.Package EA_ParentPackage = null;
20
      private EA.Project EA_Project;
21
 
22
      private EA_Utilities EA_Utils = null;
23
 
24
      private bool oneShot_skipRootPackage = false;
25
 
26
      // MS-Office Word related data
27
      private Word.Application WordApp = null;
28
      private Word.Document WordDocument = null;
29
      private Word.Range WordRange;
30
      private object startLocation;
31
      private object endLocation;
32
 
33
      private int[] DocSection = null;
34
      private int   iDocSection = 0;
35
 
36
      private System.Windows.Forms.TextBox textBox_template;
37
      private System.Windows.Forms.Button button_browse_template;
38
      private System.Windows.Forms.TextBox textBox_output_file;
39
      private System.Windows.Forms.Button button_browse_output_file;
40
      private System.Windows.Forms.Button button_cancel;
41
      private System.Windows.Forms.Button button_generate;
42
      private System.Windows.Forms.Button button_view_output;
43
      private System.Windows.Forms.Label label1;
44
      private System.Windows.Forms.Label label2;
45
      private System.Windows.Forms.TextBox textBox_progress;
46
      private System.Windows.Forms.Label label3;
47
      private System.Windows.Forms.CheckBox checkBox_WordVisibility;
48
      /// <summary>
49
      /// Required designer variable.
50
      /// </summary>
51
      private System.ComponentModel.Container components = null;
52
 
53
      public createWordDoc(EA.Repository theRepository, EA.Package theParentPackage, EA_Utilities theEA_Utils)
54
      {
55
         //
56
         // Required for Windows Form Designer support
57
         //
58
         InitializeComponent();
59
 
60
         EA_Repository    = theRepository;
61
         EA_ParentPackage = theParentPackage;
62
         EA_Project       = EA_Repository.GetProjectInterface();
63
 
64
         EA_Utils         = theEA_Utils;
65
 
66
         DocSection = new int[12];
67
         for (int i=0; i<DocSection.Length; i++)
68
         {
69
            DocSection[i] = 0;
70
         }
71
 
72
         WordApp = new Word.Application();
73
      }
74
 
75
      /// <summary>
76
      /// Clean up any resources being used.
77
      /// </summary>
78
      protected override void Dispose( bool disposing )
79
      {
80
         if( disposing )
81
         {
82
            if(components != null)
83
            {
84
               components.Dispose();
85
            }
86
         }
87
         base.Dispose( disposing );
88
      }
89
 
90
 
91
 
92
 
93
      #region Windows Form Designer generated code
94
      /// <summary>
95
      /// Required method for Designer support - do not modify
96
      /// the contents of this method with the code editor.
97
      /// </summary>
98
      private void InitializeComponent()
99
      {
100
         this.textBox_template = new System.Windows.Forms.TextBox();
101
         this.button_browse_template = new System.Windows.Forms.Button();
102
         this.textBox_output_file = new System.Windows.Forms.TextBox();
103
         this.button_browse_output_file = new System.Windows.Forms.Button();
104
         this.button_cancel = new System.Windows.Forms.Button();
105
         this.button_generate = new System.Windows.Forms.Button();
106
         this.button_view_output = new System.Windows.Forms.Button();
107
         this.label1 = new System.Windows.Forms.Label();
108
         this.label2 = new System.Windows.Forms.Label();
109
         this.textBox_progress = new System.Windows.Forms.TextBox();
110
         this.label3 = new System.Windows.Forms.Label();
111
         this.checkBox_WordVisibility = new System.Windows.Forms.CheckBox();
112
         this.SuspendLayout();
113
         // 
114
         // textBox_template
115
         // 
116
         this.textBox_template.Location = new System.Drawing.Point(16, 40);
117
         this.textBox_template.Name = "textBox_template";
118
         this.textBox_template.Size = new System.Drawing.Size(592, 22);
119
         this.textBox_template.TabIndex = 0;
120
         this.textBox_template.Text = "";
121
         this.textBox_template.TextChanged += new System.EventHandler(this.textBox_template_TextChanged);
122
         // 
123
         // button_browse_template
124
         // 
125
         this.button_browse_template.Location = new System.Drawing.Point(616, 40);
126
         this.button_browse_template.Name = "button_browse_template";
127
         this.button_browse_template.Size = new System.Drawing.Size(80, 23);
128
         this.button_browse_template.TabIndex = 1;
129
         this.button_browse_template.Text = "Browse";
130
         this.button_browse_template.Click += new System.EventHandler(this.button_browse_template_Click);
131
         // 
132
         // textBox_output_file
133
         // 
134
         this.textBox_output_file.Location = new System.Drawing.Point(16, 112);
135
         this.textBox_output_file.Name = "textBox_output_file";
136
         this.textBox_output_file.Size = new System.Drawing.Size(592, 22);
137
         this.textBox_output_file.TabIndex = 2;
138
         this.textBox_output_file.Text = "";
139
         this.textBox_output_file.TextChanged += new System.EventHandler(this.textBox_output_file_TextChanged);
140
         // 
141
         // button_browse_output_file
142
         // 
143
         this.button_browse_output_file.Location = new System.Drawing.Point(616, 112);
144
         this.button_browse_output_file.Name = "button_browse_output_file";
145
         this.button_browse_output_file.Size = new System.Drawing.Size(80, 24);
146
         this.button_browse_output_file.TabIndex = 3;
147
         this.button_browse_output_file.Text = "Browse";
148
         this.button_browse_output_file.Click += new System.EventHandler(this.button_browse_output_file_Click);
149
         // 
150
         // button_cancel
151
         // 
152
         this.button_cancel.Location = new System.Drawing.Point(616, 384);
153
         this.button_cancel.Name = "button_cancel";
154
         this.button_cancel.Size = new System.Drawing.Size(80, 23);
155
         this.button_cancel.TabIndex = 4;
156
         this.button_cancel.Text = "Close";
157
         this.button_cancel.Click += new System.EventHandler(this.button_cancel_Click);
158
         // 
159
         // button_generate
160
         // 
161
         this.button_generate.Location = new System.Drawing.Point(496, 384);
162
         this.button_generate.Name = "button_generate";
163
         this.button_generate.Size = new System.Drawing.Size(96, 24);
164
         this.button_generate.TabIndex = 5;
165
         this.button_generate.Text = "Generate";
166
         this.button_generate.Click += new System.EventHandler(this.button_generate_Click);
167
         // 
168
         // button_view_output
169
         // 
170
         this.button_view_output.Location = new System.Drawing.Point(376, 384);
171
         this.button_view_output.Name = "button_view_output";
172
         this.button_view_output.Size = new System.Drawing.Size(96, 23);
173
         this.button_view_output.TabIndex = 6;
174
         this.button_view_output.Text = "View Output";
175
         this.button_view_output.Click += new System.EventHandler(this.button_view_output_Click);
176
         // 
177
         // label1
178
         // 
179
         this.label1.Location = new System.Drawing.Point(16, 16);
180
         this.label1.Name = "label1";
181
         this.label1.Size = new System.Drawing.Size(224, 23);
182
         this.label1.TabIndex = 7;
183
         this.label1.Text = "Input Template or Document Name";
184
         // 
185
         // label2
186
         // 
187
         this.label2.Location = new System.Drawing.Point(16, 88);
188
         this.label2.Name = "label2";
189
         this.label2.Size = new System.Drawing.Size(280, 23);
190
         this.label2.TabIndex = 8;
191
         this.label2.Text = "Output Document Name";
192
         // 
193
         // textBox_progress
194
         // 
195
         this.textBox_progress.Location = new System.Drawing.Point(16, 184);
196
         this.textBox_progress.Multiline = true;
197
         this.textBox_progress.Name = "textBox_progress";
198
         this.textBox_progress.ReadOnly = true;
199
         this.textBox_progress.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
200
         this.textBox_progress.Size = new System.Drawing.Size(680, 168);
201
         this.textBox_progress.TabIndex = 9;
202
         this.textBox_progress.Text = "";
203
         // 
204
         // label3
205
         // 
206
         this.label3.Location = new System.Drawing.Point(16, 152);
207
         this.label3.Name = "label3";
208
         this.label3.TabIndex = 10;
209
         this.label3.Text = "Progress";
210
         // 
211
         // checkBox_WordVisibility
212
         // 
213
         this.checkBox_WordVisibility.Location = new System.Drawing.Point(16, 384);
214
         this.checkBox_WordVisibility.Name = "checkBox_WordVisibility";
215
         this.checkBox_WordVisibility.Size = new System.Drawing.Size(256, 24);
216
         this.checkBox_WordVisibility.TabIndex = 17;
217
         this.checkBox_WordVisibility.Text = "Show MS-WORD During Construction";
218
         // 
219
         // createWordDoc
220
         // 
221
         this.AutoScaleBaseSize = new System.Drawing.Size(6, 15);
222
         this.ClientSize = new System.Drawing.Size(712, 432);
223
         this.Controls.Add(this.checkBox_WordVisibility);
224
         this.Controls.Add(this.label3);
225
         this.Controls.Add(this.textBox_progress);
226
         this.Controls.Add(this.textBox_output_file);
227
         this.Controls.Add(this.textBox_template);
228
         this.Controls.Add(this.label2);
229
         this.Controls.Add(this.label1);
230
         this.Controls.Add(this.button_view_output);
231
         this.Controls.Add(this.button_generate);
232
         this.Controls.Add(this.button_cancel);
233
         this.Controls.Add(this.button_browse_output_file);
234
         this.Controls.Add(this.button_browse_template);
235
         this.Name = "createWordDoc";
236
         this.Text = "createWordDoc";
237
         this.Closing += new System.ComponentModel.CancelEventHandler(this.createWordDoc_Closing);
238
         this.ResumeLayout(false);
239
 
240
      }
241
      #endregion
242
 
243
 
244
      #region Message handlers
245
      private void button_view_output_Click(object sender, System.EventArgs e)
246
      {
247
         if (WordApp != null)
248
         {
249
            WordApp.Visible = true;
250
         }
251
      }
252
 
253
 
254
 
255
 
256
      private void button_generate_Click(object sender, System.EventArgs e)
257
      {
258
         if (this.textBox_template.Text.Length > 0)
259
         {
260
            if (this.textBox_output_file.Text.Length > 0)
261
            {
262
               createTheWordDoc();
263
            }
264
            else
265
            {
266
               MessageBox.Show("Error - must specify an output file");
267
            }
268
         }
269
         else
270
         {
271
            MessageBox.Show("Error - must specify an input template file");
272
         }
273
      }
274
 
275
      private void button_cancel_Click(object sender, System.EventArgs e)
276
      {
277
         this.Close();   
278
      }
279
 
280
      private void button_browse_template_Click(object sender, System.EventArgs e)
281
      {
282
         OpenFileDialog dialog = new OpenFileDialog();
283
         dialog.Filter = "Word Files (*.doc;*.dot)|*.doc;*.dot|All files(*.*)|*.*";
284
         dialog.FilterIndex = 1;
285
         dialog.ShowDialog();
286
         this.textBox_template.Text = dialog.FileName;
287
 
288
      }
289
 
290
      private void button_browse_output_file_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;
295
         dialog.CheckFileExists = false;
296
         dialog.ShowDialog();
297
         this.textBox_output_file.Text = dialog.FileName;
298
      }
299
 
300
      private void textBox_template_TextChanged(object sender, System.EventArgs e)
301
      {
302
 
303
      }
304
 
305
      private void textBox_output_file_TextChanged(object sender, System.EventArgs e)
306
      {
307
 
308
      }
309
 
310
      private void createWordDoc_Closing(object sender, System.ComponentModel.CancelEventArgs e)
311
      {
312
         if (WordApp != null)
313
         {
314
            // try-catch just in case user closed the application themselves whilst viewing the
315
            // generated output document
316
            try 
317
            {
318
               object nothing = Type.Missing;
319
               object notTrue = false;
320
 
321
               WordApp.Application.Quit( ref notTrue, ref nothing, ref nothing);
322
            }
323
            catch (Exception createWordDoc_Closing_exception)
324
            {
325
               // dummy statement
326
               String s = createWordDoc_Closing_exception.Message;
327
            }
328
         }
329
      }
330
 
331
      #endregion
332
 
333
 
334
      #region word document generation code
335
 
336
      /// <summary>
337
      /// This class is one derived from the EA_UtilitiesRecursionWorker base class so that
338
      /// an instance of it can be used as a parameter in the EA_Utilities.findAndProcessPackageElements
339
      /// method which recursively parses a given package. Thus, clients can parse EA model structure but
340
      /// specify their own functionality to be carried out on packages and elements found in the 
341
      /// parsing.
342
      /// This particular derived class is designed to collect a list of element names from the
343
      /// package, from elements that have a type that is acceptable.
344
      /// </summary>
345
      public class ElementAccumulator : EA_UtilitiesRecursionWorker
346
      {
347
         public ArrayList Elements = null;
348
 
349
         private ArrayList validElementTypes = null;
350
 
351
         public ElementAccumulator(ArrayList elementTypeList): base()
352
         {
353
            validElementTypes = elementTypeList;
354
            Elements = new ArrayList();
355
         }
356
 
357
         public override void processElement( EA.Element theElement )
358
         {
359
            if (validElementTypes.Contains( theElement.Type ))
360
            {
361
               if ( (theElement.Type == "Requirement") && (theElement.Status == "Rejected") )
362
                  return;
363
 
364
               Elements.Add( theElement );
365
            }
366
         }
367
      }
368
 
369
 
370
      private void trackDocSection(int recurse_level)
371
      {
372
         iDocSection = recurse_level;
373
         DocSection[iDocSection]++;     
374
         for (int i=iDocSection+1; i<DocSection.Length; i++)
375
            DocSection[i] = 0;
376
      }
377
 
378
 
379
      /// <summary>
380
      /// Displays progress of the document generation in the createWordDocument dialog
381
      /// </summary>
382
      /// <param name="prefix"></param>
383
      /// <param name="EA_string"></param>
384
      private void displayProgress(string prefix, string EA_string)
385
      {
386
         textBox_progress.AppendText( prefix + EA_string + "\r\n" );
387
 
388
         // Display to the output tab as well - as a longer term record of what happened
389
         string s = "";
390
         for (int i = 1; i<=iDocSection; i++)
391
         {
392
            if (i!=1)
393
               s = s + ".";
394
            s = s + DocSection[i].ToString();
395
         }
396
         while (s.Length < 30)
397
            s += " ";
398
 
399
         EA_Repository.WriteOutput( Main.GUI_OUTPUT_TAB_NAME, s + prefix + EA_string, 0);
400
      }
401
 
402
 
403
      /// <summary>
404
      /// This method takes the specified EA diagram element and puts the diagram image
405
      /// into the clipboard from where it can be pasted into the word document. After
406
      /// pasting it into the document, it sets the style and other aspects of the image.
407
      /// </summary>
408
      /// <param name="theDiagram"></param>
409
      private void appendAndSelectDiagramViaClipboard(EA.Diagram theDiagram)
410
      {
411
         // open the diagram in EA and copy it's image to the clipboard
412
         if (EA_Project.PutDiagramImageOnClipboard(theDiagram.DiagramGUID,0))
413
         {
414
            // create a range at the end of the document
415
            startLocation = WordDocument.Content.End;
416
            WordDocument.Content.InsertParagraphAfter();
417
            endLocation = WordDocument.Content.End;
418
            WordRange = WordDocument.Range(ref startLocation, ref endLocation);
419
            object direction = Word.WdCollapseDirection.wdCollapseEnd;
420
            WordRange.Collapse(ref direction);  // collapse prevents existing content being replaced
421
 
422
            // Get ready for the diagram paste and the formatting we want to do on it with the
423
            // selection object.
424
            SelectInsertionPointAtEndOfDocument();
425
 
426
            // Paste the diagram into the document
427
            WordRange.Paste();           
428
 
429
            // Set style of the diagram to "Normal" so that it can occupy space all the way to the left margin
430
            object l_style = "Normal";
431
            endLocation = WordDocument.Content.End;
432
            WordRange = WordDocument.Range(ref startLocation, ref endLocation);
433
            WordRange.set_Style(ref l_style);
434
 
435
            // Center the diagram on the page
436
            object unit = Word.WdUnits.wdLine;
437
            object missing = Type.Missing;
438
            object count = 1;
439
            WordApp.Selection.MoveDown( ref unit, ref count, ref missing);
440
            WordApp.Selection.ParagraphFormat.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter;
441
 
442
            // Add a caption
443
            WordDocument.Content.InsertParagraphAfter();
444
            SelectInsertionPointAtEndOfDocument();         
445
            object Label = "Figure";
446
            object Title = Type.Missing;
447
            object TitleAutoText = Type.Missing;
448
            object Position = Word.WdCaptionPosition.wdCaptionPositionAbove;
449
            object ExcludeLabel = 0;
450
            WordApp.Selection.InsertCaption( ref Label, ref Title, ref TitleAutoText, ref Position, ref ExcludeLabel);
451
            WordApp.Selection.TypeText( ": " + theDiagram.Name.ToString());
452
            WordApp.Selection.ParagraphFormat.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter;
453
 
454
            // experimental code to create a bookmark for the figure caption
455
            //WordDocument.Paragraphs[ WordDocument.Paragraphs.Count ].Range.Select();
456
            //object lastParaRange = WordDocument.Paragraphs[ WordDocument.Paragraphs.Count ].Range;
457
            //string bookmarkName = theDiagram.Name;
458
            //bookmarkName = bookmarkName.Replace(' ', '_');
459
            //WordDocument.Bookmarks.Add( bookmarkName, ref lastParaRange );
460
 
461
            // Close the diagram in EA
462
            EA_Repository.CloseDiagram(theDiagram.DiagramID);
463
         }
464
      }
465
 
466
 
467
      /// <summary>
468
      /// Appends a specified text string to the word document, selects the new text, and applies
469
      /// the specified style formatting to it.
470
      /// </summary>
471
      /// <param name="wordText"></param>
472
      /// <param name="styleText"></param>
473
      /// <param name="continuation"></param>
474
      private void appendAndSelectText(string wordText, string styleText) 
475
      { 
476
         appendAndSelectText(wordText, styleText, false );
477
      }
478
 
479
      private void appendAndSelectText(string wordText, string styleText, bool continuation )
480
      {
481
         if (wordText.Length > 0)
482
         {
483
            object style = styleText;
484
            int i;
485
            startLocation = 0;
486
            endLocation = i = WordDocument.Content.End;
487
 
488
            WordRange = WordDocument.Range(ref startLocation, ref endLocation);
489
 
490
            if (!continuation)
491
               WordRange.InsertAfter( "\n" );
492
 
493
            WordRange.InsertAfter( wordText );
494
 
495
            // Make a range out of the pasted text
496
            startLocation = i;
497
            endLocation = WordDocument.Content.End;
498
            WordRange = WordDocument.Range(ref startLocation, ref endLocation);
499
 
500
            // and set the pasted text style
501
            WordRange.set_Style(ref style);
502
         }
503
      }
504
 
505
 
506
      /// <summary>
507
      /// Appends a specified text string to the word document, selects the new text, and applies
508
      /// a heading level style to it. 
509
      /// </summary>
510
      /// <param name="wordText"></param>
511
      /// <param name="level"></param>
512
      private void appendAndSelectHeadingText(string wordText, int level)
513
      {
514
         // Convert level to heading style
515
         String styleText;
516
         switch(level)
517
         {
518
            case 1: styleText = "Heading 1"; break;
519
            case 2: styleText = "Heading 2"; break;
520
            case 3: styleText = "Heading 3"; break;
521
            case 4: styleText = "Heading 4"; break;
522
            case 5: styleText = "Heading 5"; break;
523
            case 6: styleText = "Heading 6"; break;
524
            case 7: styleText = "Heading 7"; break;
525
            case 8: styleText = "Heading 8"; break;
526
            case 9: styleText = "Heading 9"; break;
527
            default: styleText = "Body 1"; break;
528
         }
529
         // append the text as a heading
530
         appendAndSelectText(wordText, styleText);
531
      }
532
 
533
 
534
      /// <summary>
535
      /// Appends a specified text string to the word document, selects the new text, and applies
536
      /// a num para heading level style to it. 
537
      /// </summary>
538
      /// <param name="wordText"></param>
539
      /// <param name="level"></param>
540
      private void appendAndSelectNumParaText(string wordText, int level)
541
      {
542
         // Convert level to heading style
543
         String styleText;
544
         switch(level)
545
         {
546
            case 1: styleText = "NumPara 1"; break;
547
            case 2: styleText = "NumPara 2"; break;
548
            case 3: styleText = "NumPara 3"; break;
549
            case 4: styleText = "NumPara 4"; break;
550
            case 5: styleText = "NumPara 5"; break;
551
            case 6: styleText = "NumPara 6"; break;
552
            case 7: styleText = "NumPara 7"; break;
553
            case 8: styleText = "NumPara 8"; break;
554
            case 9: styleText = "NumPara 9"; break;
555
            default: styleText = "Body 1"; break;
556
         }
557
         // append the text as a heading
558
         appendAndSelectText(wordText, styleText);
559
      }
560
 
561
 
562
      private void SelectInsertionPointAtEndOfDocument()
563
      {
564
         object unit; 
565
         object extend;
566
 
567
         unit = Word.WdUnits.wdStory; 
568
         extend = Word.WdMovementType.wdMove;
569
         WordApp.Selection.EndKey(ref unit, ref extend);
570
      }
571
 
572
 
573
      /// <summary>
574
      /// This is an attempt to create a table similar in style to those made by the ERG doc template macros.
575
      /// It is not exaclty that same though, and further work could be done to align it more precisely.
576
      /// </summary>
577
      /// <param name="tableTitle"></param>
578
      /// <param name="numRows"></param>
579
      /// <param name="numCols"></param>
580
      /// <returns></returns>
581
      private int createTable(string tableTitle, int numRows, int numCols)
582
      {
583
         WordDocument.Content.InsertParagraphAfter();
584
         SelectInsertionPointAtEndOfDocument();
585
 
586
         object Label = "Table";
587
         object Title = Type.Missing;
588
         object TitleAutoText = Type.Missing;
589
         object Position = Word.WdCaptionPosition.wdCaptionPositionAbove;
590
         object ExcludeLabel = 0;
591
         WordApp.Selection.InsertCaption( ref Label, ref Title, ref TitleAutoText, ref Position, ref ExcludeLabel);
592
         WordApp.Selection.TypeText( ": " + tableTitle);
593
         WordApp.Selection.ParagraphFormat.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter;
594
 
595
         startLocation = WordDocument.Content.End;
596
         WordDocument.Content.InsertParagraphAfter();
597
         endLocation = WordDocument.Content.End;
598
         WordRange = WordDocument.Range(ref startLocation, ref endLocation);
599
 
600
         object defaultTableBehaviour = Type.Missing;
601
         object autofitBehaviour = Type.Missing;
602
         Word.Table Table = WordDocument.Tables.Add( WordRange, numRows, numCols, ref defaultTableBehaviour, ref autofitBehaviour );
603
 
604
         Table.Rows[1].Shading.BackgroundPatternColor = Word.WdColor.wdColorGray10;
605
         Table.Borders.OutsideLineStyle = Word.WdLineStyle.wdLineStyleSingle;
606
         Table.Borders.InsideLineStyle = Word.WdLineStyle.wdLineStyleSingle;
607
 
608
         Table.Select();
609
         object tableTextStyle = "Table Text";
610
         Table.Range.set_Style( ref tableTextStyle );
611
 
612
         return WordDocument.Tables.Count;
613
      }
614
 
615
 
616
 
617
      /// <summary>
618
      /// This function process a package link element, parsing each linked package by the
619
      /// parse_package() recursive function.
620
      /// </summary>
621
      /// <param name="theElement"></param>
622
      /// <param name="recurse_level"></param>
623
      private void processPackageLink(EA.Element theElement, int recurse_level)
624
      {
625
         string [] EA_DocGenPkgLnk = null;
626
         string delimStr = "\r\n";
627
         char [] delim = delimStr.ToCharArray();
628
         EA_DocGenPkgLnk = theElement.Notes.ToString().Split(delim,100);
629
         string linkedName = "";
630
 
631
         foreach(string s in EA_DocGenPkgLnk)
632
         {
633
            if (s.Length > 0 && s != "\n" && s != "\r")
634
            {
635
               if (s == "skiproot")
636
               {
637
                  oneShot_skipRootPackage = true;
638
               }
639
               else if (s[0] == '{')
640
               {
641
                  EA.Package theFoundPackage = EA_Utils.EA_Finder.findPackageInRepositoryByGUID(s);
642
                  if (theFoundPackage != null)
643
                  {
644
                     parse_package(theFoundPackage, recurse_level);
645
                  }
646
                  else
647
                  {
648
                     MessageBox.Show("WARNING - Could not find linked package : " + linkedName );
649
                  }
650
               }
651
               else
652
               {
653
                  linkedName = s;
654
               }            
655
            }
656
         }
657
      }
658
 
659
 
660
      /// <summary>
661
      /// This function process a diagram link element, using the appendAndSelectDiagramViaClipboard()
662
      /// for each linked diagram.
663
      /// </summary>
664
      /// <param name="theElement"></param>
665
      private void processDiagramLink(EA.Element theElement)
666
      {
667
         string [] EA_DocGenDiagLnk = null;
668
         string delimStr = "\r\n";
669
         char [] delim = delimStr.ToCharArray();
670
         EA_DocGenDiagLnk = theElement.Notes.ToString().Split(delim,100);
671
         string linkedName = "";
672
 
673
         foreach(string s in EA_DocGenDiagLnk)
674
         {
675
            if (s.Length > 0 && s != "\n" && s != "\r" )
676
            {
677
               if (s[0] == '{')
678
               {
679
                  EA.Diagram theFoundDiagram = EA_Utils.EA_Finder.findDiagramInRepositoryByGUID(s);
680
                  if (theFoundDiagram != null)
681
                  {
682
                     displayProgress( "DIAGRAM: ", theFoundDiagram.Name.ToString() );
683
                     appendAndSelectDiagramViaClipboard( theFoundDiagram );
684
                  }
685
                  else 
686
                  {
687
                     MessageBox.Show("WARNING - Could not find linked diagram : " + linkedName );
688
                  }
689
               }
690
               else
691
               {
692
                  linkedName = s;
693
               }            
694
            }
695
         }         
696
      }
697
 
698
 
699
      /// <summary>
700
      /// This function process an element link element, parsing each linked element by the
701
      /// parse_element() recursive function.
702
      /// </summary>
703
      /// <param name="theElement"></param>
704
      /// <param name="recurse_level"></param>
705
      private void processElementLink(EA.Element theElement, int recurse_level )
706
      {
707
         string [] EA_DocGenEleLnk = null;
708
         string delimStr = "\r\n";
709
         char [] delim = delimStr.ToCharArray();
710
         EA_DocGenEleLnk = theElement.Notes.ToString().Split(delim,100);
711
         string linkedName = "";
712
 
713
         foreach(string s in EA_DocGenEleLnk)
714
         {
715
            if (s.Length > 0 && s != "\n" && s != "\r")
716
            {
717
               if ( s[0] == '{')
718
               {
719
                  EA.Element theFoundElement = EA_Utils.EA_Finder.findElementInRepositoryByGUID(s);
720
                  if (theFoundElement != null)
721
                  {
722
                     parse_element( theFoundElement, recurse_level );
723
                  }
724
                  else 
725
                  {
726
                     MessageBox.Show("WARNING - Could not find linked element : " + linkedName );
727
                  }
728
               }
729
               else
730
               {
731
                  linkedName = s;
732
               }            
733
            }
734
         }         
735
      }
736
 
737
 
738
      /// <summary>
739
      /// This method creates a table from the content of an EA_DocGenTable element in the model.
740
      /// The elements notes section contains the table parameters and cell content.
741
      /// See the EA_Utilities::AddTableElement() method for the layout of this content.
742
      /// </summary>
743
      /// <param name="theElement"></param>
744
      /// <param name="recurse_level"></param>
745
      private void processTableElement(EA.Element theElement, int recurse_level )
746
      {
747
         string [] EA_DocGenTable = null;
748
         string [] cells = null;
749
 
750
         string delimStr = "\r\n";
751
         char [] delim = delimStr.ToCharArray();
752
 
753
         string trimStr = " ";
754
         char [] trimChars = trimStr.ToCharArray();
755
 
756
         EA_DocGenTable = theElement.Notes.ToString().Split(delim,200);
757
 
758
         int columnCount = 0;
759
         int rowCount = 0;
760
         char seperator = ',';
761
         string tableTitle = "";
762
         bool gotSeperator = false;
763
         bool gotTitle = false;
764
 
765
         // Scan the notes content line by line looking for table parameters and counting
766
         // the number of table rows (which is not specified as an explicit table parameter).
767
         int s_ElementsConsumedByTableParams = 0;
768
         foreach(string s in EA_DocGenTable)
769
         {
770
            if (s.Length > 0 && s != "\n" && s != "\r" )
771
            {
772
               if (gotTitle == false && s.StartsWith("title"))
773
               {
774
                  s_ElementsConsumedByTableParams++;
775
                  tableTitle = EA_Utils.options.getOptionValue(s, tableTitle);
776
                  gotTitle = true;
777
                  if (tableTitle == "")
778
                  {
779
                     MessageBox.Show( "Table Element Serialisation Failed - Bad Title" );
780
                     break;
781
                  }
782
               }
783
 
784
               else if (columnCount == 0 && s.StartsWith("columns"))
785
               {
786
                  s_ElementsConsumedByTableParams++;
787
                  columnCount = EA_Utils.options.getOptionValue(s, columnCount);
788
                  if (columnCount == 0)
789
                  {
790
                     MessageBox.Show( "Table Element Serialisation Failed - bad column count" );
791
                     break;
792
                  }
793
               }
794
               else if (gotSeperator == false && s.StartsWith("seperator"))
795
               {
796
                  s_ElementsConsumedByTableParams++;
797
                  seperator = EA_Utils.options.getOptionValue(s, seperator);
798
                  gotSeperator = true;
799
               }
800
               else
801
               {
802
                  rowCount++;
803
               }
804
            }
805
         }
806
 
807
         if (gotTitle == true && gotSeperator == true && columnCount != 0)
808
         {
809
            if (rowCount < 2)
810
            {
811
               MessageBox.Show( "Table Element Serialisation Failed - Insufficient Rows" );
812
            }
813
            else
814
            {
815
               // create the table in the word doc
816
               int tableNum = createTable( tableTitle, rowCount, columnCount );
817
               Word.Table table = WordDocument.Tables[tableNum];
818
               object center = Word.WdParagraphAlignment.wdAlignParagraphCenter;
819
 
820
               // scan the element notes again to extract the cell content and add it to the
821
               // table we just created.
822
               int row = 1;
823
               int col = 1;
824
               foreach(string s in EA_DocGenTable)
825
               {
826
                  if (s.Length > 0 && s != "\n" && s != "\r" )
827
                  {
828
                     if (s_ElementsConsumedByTableParams > 0)
829
                     {
830
                        s_ElementsConsumedByTableParams--;
831
                     }
832
                     else
833
                     {
834
                        delimStr = seperator.ToString();
835
                        delim = delimStr.ToCharArray();
836
                        cells = s.Split(delim,columnCount);
837
 
838
                        if (cells.Length != columnCount)
839
                        {
840
                           MessageBox.Show( "Table Element Serialisation Failed - Bad Row" );
841
                           break;
842
                        }
843
                        else
844
                        {
845
                           // serialise table row
846
                           for(col=1; col<=columnCount; col++)
847
                           {
848
                              cells[col-1].TrimStart( trimChars );
849
                              cells[col-1].TrimEnd( trimChars );
850
 
851
                              table.Cell(row,col).Range.Text = cells[col-1];
852
 
853
                              // special handling for heading row
854
                              if (row == 1)
855
                              {
856
                                 table.Cell(row,col).Range.ParagraphFormat.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter;
857
                                 table.Cell(row,col).Range.Font.Bold = 1;
858
                              }
859
                           }
860
                           row++;
861
                        }                     
862
                     }
863
                  }
864
               }
865
            }
866
         }
867
         else
868
         {
869
            MessageBox.Show( "Table Element Serialisation Failed - Table Parameters Incomplete" );
870
         }
871
      }
872
 
873
 
874
      /// <summary>
875
      /// This function process a text element. It is a simple wrapper for the 
876
      /// appendAndSelectText()function.
877
      /// </summary>
878
      /// <param name="theElement"></param>
879
      /// <param name="recurse_level"></param>
880
      private void processTextElement(EA.Element theElement, int recurse_level )
881
      {
882
         appendAndSelectText( theElement.Notes.ToString(), "Body 1" );
883
      }
884
 
885
 
886
 
887
 
888
      /// <summary>
889
      /// This function processes elements as if they represented document references for
890
      /// the References section of a document.
891
      /// </summary>
892
      /// <param name="thePackage"></param>
893
      private void createReferencesSection(EA.Package thePackage)
894
      {
895
         foreach(EA.Element theElement in thePackage.Elements)
896
         {
897
            // Here we want to apply the special ERG template styles for each reference
898
            // item.
899
            appendAndSelectText( theElement.Name.ToString(), "Reference List Number" );
900
            appendAndSelectText( theElement.Notes.ToString(), "Reference List Text" );
901
         }
902
      }
903
 
904
 
905
      private void createTerminologySection(EA.Package thePackage)
906
      {
907
         // Use local package elements as source of glossary, but if none are present, resort to using
908
         // the project glossary in the repository 
909
         int numItems = thePackage.Elements.Count;
910
         if (numItems == 0)
911
         {
912
            numItems = EA_Repository.Terms.Count;
913
         }
914
 
915
         if (numItems > 0)
916
         {
917
            // Create a table
918
            int tableNum = createTable("Terminology", numItems+1, 2);
919
            Word.Table table = WordDocument.Tables[tableNum];
920
            object center = Word.WdParagraphAlignment.wdAlignParagraphCenter;
921
            table.Cell(1,1).Range.Text = "Term";
922
            table.Cell(1,1).Range.ParagraphFormat.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter;
923
            table.Cell(1,1).Range.Font.Bold = 1;
924
            table.Cell(1,2).Range.Text = "Definition";
925
            table.Cell(1,2).Range.ParagraphFormat.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter;
926
            table.Cell(1,2).Range.Font.Bold = 1;
927
            table.Columns[1].SetWidth(100, Word.WdRulerStyle.wdAdjustSameWidth );
928
            int row = 2;
929
 
930
            if (thePackage.Elements.Count > 0)
931
            {
932
               // The advantage of using the package content is that the elements come out alphabetically
933
               // sorted already (assuming user has not over-riden the sort order in the project browser).
934
               // Also, the glossary content can be exactly tailored to what the document requires.
935
               foreach(EA.Element theElement in thePackage.Elements)
936
               {
937
                  table.Cell(row,1).Range.Text = theElement.Name.ToString();
938
                  table.Cell(row,2).Range.Text = theElement.Notes.ToString();
939
                  row++;
940
               }
941
            }
942
            else // default to using the project glossary in the repository
943
            {
944
               // TODO 
945
               // 1. Alphabetically Sort the glossary terms before adding them to the table
946
               //    The Repository glossary seems to be provided in non-sorted order unfortunately.
947
 
948
               // inject the glossary into the table
949
               foreach(EA.Term theTerm in EA_Repository.Terms)
950
               {
951
                  table.Cell(row,1).Range.Text = theTerm.Term;
952
                  table.Cell(row,2).Range.Text = theTerm.Meaning;
953
                  row++;
954
               }
955
            }
956
         }
957
      }
958
 
959
 
960
      private bool generatePackageHeadingAndDescription( EA.Package thePackage, int recurse_level )
961
      {
962
         // disarm the one-shot package skipping feature if it was armed, and exit the function.
963
         if (oneShot_skipRootPackage == true)
964
         {
965
            oneShot_skipRootPackage = false;
966
            return false;
967
         }
968
 
969
         // The package name is a heading, and the package notes are paragraphs 
970
         // directly under that heading
971
         displayProgress( "PACKAGE: ", thePackage.Name.ToString() );
972
 
973
         appendAndSelectHeadingText( thePackage.Name.ToString(), recurse_level );
974
 
975
         // Special handling for package called "Terminology" 
976
         if (thePackage.Name == "Terminology")
977
         {
978
            appendAndSelectText( thePackage.Notes.ToString(), "Body 1" );
979
            createTerminologySection(thePackage);
980
            return true;
981
         }
982
 
983
         if (thePackage.Name == "References")
984
         {
985
            appendAndSelectText( thePackage.Notes.ToString(), "Body 1" );
986
            createReferencesSection(thePackage);
987
            return true;
988
         }
989
 
990
         // use the package notes as body text and indicate to caller that package elements 
991
         // have not been consumed
992
         appendAndSelectText( thePackage.Notes.ToString(), "Body 1" );      
993
         return false;
994
      }
995
 
996
 
997
      private void generatePackageDiagrams( EA.Package thePackage )
998
      {
999
         // default handling of diagrams
1000
         foreach(EA.Diagram theDiagram in thePackage.Diagrams)
1001
         {
1002
            displayProgress( "DIAGRAM: ", theDiagram.Name.ToString() );
1003
 
1004
            appendAndSelectDiagramViaClipboard( theDiagram );
1005
         }
1006
      }
1007
 
1008
 
1009
      private void generateElementContent( EA.Element theElement, int recurse_level )
1010
      {
1011
         recurse_level++;
1012
         if (recurse_level > 9)
1013
         {
1014
            throw new System.StackOverflowException("Max Recursion Depth (9) Exceeded" );
1015
         }
1016
         trackDocSection(recurse_level);
1017
 
1018
         if (EA_Utils.options.elementTypeFoundInEA_DocGen( theElement.Type ))
1019
         {
1020
            displayProgress( "ELEMENT: ", theElement.Name.ToString() );
1021
 
1022
            if ( theElement.Type.StartsWith("Requirement")
1023
               && EA_Utils.options.opt_DisplayRequirementsWithStatus == true )
1024
            {
1025
               generateRequirementText( theElement );
1026
            }
1027
            else
1028
            {
1029
               if (theElement.Type.StartsWith("Requirement")
1030
                  && EA_Utils.options.opt_DisplayRequirementElementsAsSections == false )
1031
               {
1032
                  string s;
1033
                  s = EA_Utils.options.opt_RequirementElementDisplayFormat;
1034
                  s = s.Replace(@"%s",@"{0}");
1035
                  appendAndSelectText( String.Format( s, theElement.Name ), "Body 1");
1036
                  WordRange.Font.Bold = 1;
1037
               }
1038
               else if ( EA_Utils.options.opt_ElementHeadingTransitionLevel > 0
1039
                  && EA_Utils.options.opt_ElementHeadingTransitionLevel <= recurse_level )
1040
                  appendAndSelectNumParaText( theElement.Name.ToString(), recurse_level );
1041
               else
1042
                  appendAndSelectHeadingText( theElement.Name.ToString(), recurse_level );
1043
 
1044
               appendAndSelectText( theElement.Notes.ToString(), "Body 1" );
1045
            }
1046
         }
1047
         else
1048
         {
1049
            displayProgress( "FILTERED: ", theElement.Type );
1050
 
1051
         }
1052
         // TODO
1053
         // We will probably have to put special code in here at some point for attributes
1054
         // of, and collections of things within elements. This will become apparent once
1055
         // someone tries to produce a design document where such things need to be included
1056
         // in the generated document. Lots of work needed here eventually.
1057
 
1058
      }
1059
 
1060
 
1061
      /// <summary>
1062
      /// This function was the only way I could figure out how to obtain a style object for
1063
      /// the style name given. Everything else I tried, didn't work, even code from Visual Basic
1064
      /// examples failed to work or even compile (once converted) in C#.
1065
      /// </summary>
1066
      /// <param name="styleText"></param>
1067
      /// <returns></returns>
1068
      private Word.Style getStyle(string styleText)
1069
      {
1070
         foreach(Word.Style aStyle in WordDocument.Styles)
1071
         {
1072
            //MessageBox.Show( aStyle.NameLocal );
1073
            if (aStyle.NameLocal.StartsWith(styleText))
1074
            {
1075
               return aStyle;
1076
            }
1077
         }
1078
         return null;
1079
      }
1080
 
1081
 
1082
      /// <summary>
1083
      /// This function searches for the old content in the document in order to remove it
1084
      /// prior to adding in the new content from the latest EA model data.
1085
      /// </summary>
1086
      private void removeExistingDocumentContent()
1087
      {
1088
         //WordApp.Visible = true;  // enable this when debugging this horrible function
1089
         Word.Selection aSelection;
1090
         object findStyle = getStyle("Heading 1");
1091
 
1092
         WordApp.Selection.WholeStory();
1093
         aSelection = WordApp.Selection;
1094
 
1095
         aSelection.Find.ClearFormatting();
1096
         aSelection.Find.set_Style( ref findStyle );
1097
         aSelection.Find.Text = "Introduction";
1098
         aSelection.Find.Replacement.Text = "";
1099
         aSelection.Find.Forward = true;
1100
         aSelection.Find.MatchCase = false;
1101
         aSelection.Find.MatchWholeWord = false;
1102
         aSelection.Find.MatchWildcards = false;
1103
         aSelection.Find.MatchSoundsLike = false;
1104
         aSelection.Find.MatchAllWordForms = false;
1105
 
1106
         object missingValue = Type.Missing;
1107
         if (aSelection.Find.Execute(ref missingValue, ref missingValue, 
1108
            ref missingValue, ref missingValue, ref missingValue, 
1109
            ref missingValue, ref missingValue, ref missingValue, 
1110
            ref missingValue, ref missingValue, ref missingValue, 
1111
            ref missingValue, ref missingValue, ref missingValue, 
1112
            ref missingValue)) 
1113
         { 
1114
            // found Introduction with Heading 1 style so we are now at the point in the 
1115
            // document where everything here on must be deleted in readiness for the newly
1116
            // generated content. Extend the range to the end of the document and cut out the
1117
            // old content.
1118
            Word.Range range = aSelection.Range;
1119
            range.End = WordDocument.Content.End;
1120
            range.Cut();
1121
         }
1122
      }
1123
 
1124
 
1125
      /// <summary>
1126
      /// Parses an element (because elements can contain sub-elements).
1127
      /// This is also the function that identifies the occurrences of the special
1128
      /// EA_DocGenXXX elements.
1129
      /// </summary>
1130
      /// <param name="theElement"></param>
1131
      /// <param name="recurse_level"></param>
1132
      private void parse_element(EA.Element theElement, int recurse_level)
1133
      {
1134
         // First look for and handle special elements that control the doc-gen process
1135
 
1136
         // The EA_DocGenPackageLink can contain a list of GUIDs in its notes section
1137
         // that point to model structure outside of the localised structure forming the
1138
         // document. This enables a document to grab content from other external models
1139
         // as long as they are loaded into the repository.
1140
         if (theElement.Name.StartsWith("EA_DocGenPackageLink"))
1141
         {
1142
            processPackageLink( theElement, recurse_level );
1143
         }
1144
 
1145
            // The EA_DocGenDiagramLink can contain a list of GUIDs in its notes section
1146
            // that point to diagram elements anywhere in the repository.
1147
         else if (theElement.Name.StartsWith("EA_DocGenDiagramLink"))
1148
         {
1149
            processDiagramLink( theElement );
1150
         }
1151
 
1152
            // The EA_DocGenDiagramLink can contain a list of GUIDs in its notes section
1153
            // that point to diagram elements anywhere in the repository.
1154
         else if (theElement.Name.StartsWith("EA_DocGenElementLink"))
1155
         {
1156
            processElementLink( theElement, recurse_level );
1157
         }
1158
 
1159
            // The EA_DocGenTable element can contain table content in its notes section
1160
            // and must be dealt with in a special way.
1161
         else if (theElement.Name.StartsWith("EA_DocGenTable"))
1162
         {
1163
            processTableElement( theElement, recurse_level );
1164
         }
1165
 
1166
            // The EA_DocGenText element can contain text content in its notes section
1167
            // that must be appended to the doc in Body 1 style within the current
1168
            // section.
1169
         else if (theElement.Name.StartsWith("EA_DocGenText"))
1170
         {
1171
            processTextElement( theElement, recurse_level );
1172
         }
1173
 
1174
         else if (theElement.Name.StartsWith("EA_DocGenRelationshipMatrix"))
1175
         {
1176
            processRelationshipMatrixElement( theElement, recurse_level );
1177
         }
1178
 
1179
         else
1180
         {
1181
            generateElementContent( theElement, recurse_level );
1182
         }      
1183
      }
1184
 
1185
 
1186
      /// <summary>
1187
      /// Parses the package and all of its content, extracting information as needed, and
1188
      /// adding it to the word document. This method is recursive, since recursion is the
1189
      /// easiest way to walk thru' the package levels in the model.
1190
      /// </summary>
1191
      /// <param name="parentPackage"></param>
1192
      /// <param name="recurse_level"></param>
1193
      private void parse_package(EA.Package thePackage, int recurse_level)
1194
      {
1195
         // track recursion level to control heading style formatting requirements
1196
         // The one-shot skiproot feature of the EA_DocGenPackageLink element handling has an effect
1197
         // here, as you can see. 
1198
         bool rootPackageWasSkipped = !oneShot_skipRootPackage;
1199
         if (oneShot_skipRootPackage == false)
1200
         {
1201
            recurse_level++;
1202
            trackDocSection(recurse_level);
1203
         }
1204
 
1205
         if (recurse_level > 9)
1206
         {
1207
            throw new System.StackOverflowException("Max Recursion Depth (9) Exceeded" );
1208
         }
1209
 
1210
         // generate package heading and description. This may, depending on the package name,
1211
         // consume the elements in the package. If it does not, then consume them (and any diagrams)
1212
         // locally here.
1213
         if (false == generatePackageHeadingAndDescription( thePackage, recurse_level ))
1214
         {
1215
            // consume diagrams
1216
            generatePackageDiagrams( thePackage );
1217
 
1218
            // consume elements - we have to use a special sorting class here because of peculiarties
1219
            // in the way EA holds the elements in the collections. 
1220
            EA_ElementSorter elementSorter = new EA_ElementSorter(thePackage);
1221
            EA.Element theElement = null;
1222
            int theElementsRelativeLevel = 0;
1223
            if (true == elementSorter.getFirst(ref theElement, ref theElementsRelativeLevel))
1224
            {
1225
               do
1226
               {
1227
                  int theElementsRecurseLevel = recurse_level + theElementsRelativeLevel;
1228
 
1229
                  parse_element( theElement, theElementsRecurseLevel );
1230
 
1231
               } while (true == elementSorter.getNext(ref theElement, ref theElementsRelativeLevel));
1232
            }
1233
         }
1234
 
1235
         // Scan through the packages within this package.
1236
         foreach(EA.Package lowerLevelPackage in thePackage.Packages)
1237
         {
1238
            // recurse
1239
            parse_package(lowerLevelPackage, recurse_level);
1240
         }
1241
 
1242
 
1243
         if (rootPackageWasSkipped == false)
1244
            recurse_level--;
1245
      }
1246
 
1247
 
1248
      /// <summary>
1249
      /// This is the overall generate document method. It creates a word document from 
1250
      /// an input template, sets various characteristics of the document, schedules the
1251
      /// EA parsing function, before finally saving the document to the output file name.
1252
      /// </summary>
1253
      private void createTheWordDoc()
1254
      {
1255
         try 
1256
         {
1257
            object template       = this.textBox_template.Text;
1258
            object newTemplate    = Type.Missing;
1259
            object outputFilename = this.textBox_output_file.Text;
1260
 
1261
            object docType = Type.Missing;
1262
            object visible = Type.Missing;
1263
            object nothing = Type.Missing;
1264
            object notTrue = false;
1265
 
1266
            EA_Repository.WriteOutput( Main.GUI_OUTPUT_TAB_NAME, "", 0);
1267
            EA_Repository.WriteOutput( Main.GUI_OUTPUT_TAB_NAME, 
1268
                                       String.Format( "Generating Document {0}", this.textBox_output_file.Text), 0 );
1269
 
1270
            // tell word not to show itself
1271
            WordApp.Visible = this.checkBox_WordVisibility.Checked;
1272
 
1273
            // Create a document from the input template
1274
            WordDocument = WordApp.Documents.Add(ref template, ref newTemplate, ref docType, ref visible);
1275
 
1276
            // Remove all old content from the input document/template. Note that this assumes
1277
            // that content will begin at section 1 with the title "Introduction" and it will have
1278
            // "Heading 1" style.
1279
            removeExistingDocumentContent();
1280
 
1281
            // turn off grammar and spell checking
1282
            WordDocument.GrammarChecked = false;
1283
            WordDocument.SpellingChecked = false;
1284
 
1285
            // Parse EA_DocGen Document Model. The parent package is the document model itself
1286
            // and the packages within it are the top level packages only.
1287
            // Question: do we have to parse diagrams and elements at this top level? So far,
1288
            // this has been found to be unecessary, but you never know. For now, dont do it.
1289
            foreach(EA.Package thePackage in EA_ParentPackage.Packages)
1290
            {
1291
               parse_package(thePackage, 0);
1292
            }
1293
 
1294
            // TODO
1295
            // Can we run a word macro from this addin? If so, we should open the doc properties
1296
            // dialog to let user enter/update the properties.
1297
            // We could emulate the UpdateAllDocumentFields subroutine written in VB within the
1298
            // ERG standard template. For now though, do some basic stuff only.
1299
 
1300
            // Select the entire document, and Update all fields, including Table of Contents
1301
            // and then collapse the selection in case user wants to view the document, because
1302
            // they wont want to see the inverse video of the selection.
1303
            WordApp.Selection.WholeStory();
1304
            WordApp.Selection.Fields.Update();
1305
            object direction = Word.WdCollapseDirection.wdCollapseEnd;
1306
            WordApp.Selection.Collapse(ref direction);
1307
 
1308
            // Save the document to the output file
1309
            WordDocument.SaveAs( ref outputFilename, 
1310
               ref nothing, ref nothing, ref nothing, ref nothing, 
1311
               ref nothing, ref nothing, ref nothing, ref nothing,
1312
               ref nothing, ref nothing, ref nothing, ref nothing,
1313
               ref nothing, ref nothing, ref nothing);
1314
 
1315
            // Tell user the process completed ok
1316
            textBox_progress.AppendText( "---Completed---" );
1317
            MessageBox.Show("Document Generation Complete");
1318
 
1319
 
1320
         }
1321
         catch (Exception createTheWordDoc_exception)
1322
         {
1323
            MessageBox.Show("Document Generation Failed\n\n" + createTheWordDoc_exception.Message);
1324
         }
1325
      }
1326
 
1327
      /// <summary>
1328
      /// Generates the text for requirements.  This uses custom styles to format the text 
1329
      /// rather than formatting it in code.
1330
      /// </summary>
1331
      private void generateRequirementText( EA.Element theElement )
1332
      {
1333
         string reqID = "";
1334
         string reqShortDesc = "";
1335
         string reqNotes = "";
1336
         string reqStatusText = "";
1337
         string reqHeadingStyle ="";
1338
         string reqParaStyle = "";
1339
         object reqNameStyle = "Requirements Name";
1340
         Word.Range shortDescRange;
1341
 
1342
         // Set the style depending on the status
1343
         switch ( theElement.Status )
1344
         {
1345
            case "Proposed":
1346
               reqStatusText = "(Proposed)";
1347
               reqHeadingStyle = "Requirements Proposed Heading";
1348
               reqParaStyle = "Requirements Proposed Body";
1349
               break;
1350
 
1351
            case "Rejected":
1352
               reqHeadingStyle = "Requirements Rejected Heading";
1353
               reqParaStyle = "Requirements Rejected Body";
1354
               break;
1355
 
1356
            case "Approved":
1357
               reqStatusText = "(Phase " + theElement.Phase + ")";
1358
               reqHeadingStyle = "Requirements Approved Heading";
1359
               reqParaStyle = "Requirements Approved Body";
1360
               break;
1361
 
1362
            default:
1363
               reqStatusText = "(" + theElement.Status + ")(Phase " + theElement.Phase + ")";
1364
               reqHeadingStyle = "Requirements Approved Heading";
1365
               reqParaStyle = "Requirements Approved Body";
1366
               break;
1367
         }
1368
 
1369
         // Pull out the ID from the name
1370
         int pos = theElement.Name.IndexOf( " ", 0, theElement.Name.Length );
1371
         reqID = theElement.Name.Substring( 0, pos );
1372
 
1373
         // Pull out the short description from the rest of the name
1374
         reqShortDesc = theElement.Name.Substring( pos, theElement.Name.Length-pos );
1375
         reqShortDesc = reqShortDesc.Trim();
1376
 
1377
         // Pull out the notes
1378
         reqNotes = theElement.Notes.ToString();
1379
 
1380
         // Add the text
1381
         appendAndSelectText( reqID + '\t', reqHeadingStyle );
1382
         appendAndSelectText( reqShortDesc, reqHeadingStyle, true );
1383
         shortDescRange = WordRange;
1384
         appendAndSelectText( '\t' + reqStatusText, reqHeadingStyle, true );
1385
 
1386
         //reapply the name char style to the short desc.
1387
         shortDescRange.Start = shortDescRange.Start-1;
1388
         shortDescRange.End = WordRange.Start-1;
1389
         shortDescRange.set_Style( ref reqNameStyle );
1390
 
1391
         appendAndSelectText( reqNotes, reqParaStyle );
1392
 
1393
      }
1394
 
1395
 
1396
      public class elementSortByName : IComparer
1397
      {
1398
         int IComparer.Compare( object x, object y)
1399
         {
1400
            if (x!=null & y!= null)
1401
               return (new CaseInsensitiveComparer()).Compare( ((EA.Element)x).Name, ((EA.Element)y).Name );
1402
            else
1403
               return 0;
1404
         }
1405
      }
1406
 
1407
      /// <summary>
1408
      /// This function will insert a relationship matrix table into the document, built from content
1409
      /// specified in options that are provided in the notes section of the special element that
1410
      /// has led to this function being called.
1411
      /// </summary>
1412
      /// <param name="theElement"></param>
1413
      /// <param name="recurse_level"></param>
1414
      private void processRelationshipMatrixElement( EA.Element theElement, int recurse_level )
1415
      {
1416
         int tableNum = 0;
1417
         Word.Table table = null;
1418
 
1419
         // process the options for the relationship matrix
1420
         EA_RelationshipMatrix EA_RelMatrix = new EA_RelationshipMatrix(EA_Utils);
1421
         if (!EA_RelMatrix.processRelationshipMatrixOptions( theElement ))
1422
         {
1423
            return;  // must have been an error
1424
         }
1425
 
1426
         // Scan the fromPackage to find out how many elements are present and so how many
1427
         // rows the matrix table will need
1428
         ElementAccumulator fromLister = new ElementAccumulator(EA_RelMatrix.fromElementTypes);
1429
         EA_Utils.findAndProcessPackageElements( EA_RelMatrix.fromPackage, fromLister, EA_RelMatrix.fromPackageRecursion );
1430
 
1431
         // Sort the "from" elements
1432
         elementSortByName sorter = new elementSortByName();
1433
         fromLister.Elements.Sort( sorter );
1434
 
1435
         // dictionary to support to-from table construction.
1436
         ArrayList fromToDictionary = new ArrayList();
1437
 
2090 ghuddy 1438
 
1439
         bool needFromToTable = false;
1440
         if (EA_RelMatrix.fromToTableTitle != null && EA_RelMatrix.fromToTableTitle.Length > 0)
1441
            needFromToTable = true;
1442
 
1443
         bool needToFromTable = false;
1444
         if (EA_RelMatrix.toFromTableTitle != null && EA_RelMatrix.toFromTableTitle.Length > 0)
1445
            needToFromTable = true;
1446
 
1447
         if (needFromToTable)
2088 ghuddy 1448
         {
2090 ghuddy 1449
            if (EA_RelMatrix.fromIntroText != null && EA_RelMatrix.fromIntroText.Length > 0)
2088 ghuddy 1450
            {
1451
               appendAndSelectText( EA_RelMatrix.fromIntroText, "Body 1" );
1452
            }
1453
 
2090 ghuddy 1454
            // create the from-to table in the word doc
2088 ghuddy 1455
            tableNum = createTable( EA_RelMatrix.fromToTableTitle, fromLister.Elements.Count + 1, 2 );
1456
            table = WordDocument.Tables[tableNum];
1457
 
1458
            table.Cell(1,1).Range.Text = EA_RelMatrix.fromColumnTitle;
1459
            table.Cell(1,1).Range.ParagraphFormat.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter;
1460
            table.Cell(1,1).Range.Font.Bold = 1;
1461
            table.Cell(1,2).Range.Text = EA_RelMatrix.toColumnTitle;
1462
            table.Cell(1,2).Range.ParagraphFormat.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter;
1463
            table.Cell(1,2).Range.Font.Bold = 1;
1464
         }
1465
 
2090 ghuddy 1466
         // Add from-to content to the from-to table. 
1467
         // NOTE: this code has to execute even if no from-to table is needed, in order to support the
1468
         // generation of a to-from table, assuming the user has requested one.
2088 ghuddy 1469
         int row = 2;
1470
         foreach(EA.Element fromElement in fromLister.Elements)
1471
         {
2090 ghuddy 1472
            // Output the left hand column text to the from-to table, if one has been requested
1473
            if (needFromToTable)
2088 ghuddy 1474
               table.Cell(row,1).Range.Text = fromElement.Name;
1475
 
1476
            // look at the elements connection collection to find references to the
1477
            // destination elements
1478
            EA.Collection conCollection = fromElement.Connectors;
1479
            bool firstCon = true;
1480
            foreach (EA.Connector thisCon in conCollection)
1481
            {
1482
               EA.Element destE = EA_Repository.GetElementByID( thisCon.SupplierID );
1483
               if (destE == null)
1484
                  continue;
1485
 
2090 ghuddy 1486
               // ignore self-referential connections
1487
               if (fromElement.ElementID == thisCon.SupplierID)
1488
                  continue;
1489
 
2088 ghuddy 1490
               // if the destination element is of a type that the user has requested to include...
1491
               if (!EA_RelMatrix.toElementTypes.Contains( destE.Type ))
1492
                  continue;
1493
 
2090 ghuddy 1494
               // Output the right hand column text to the from-to table, if one has been requested
1495
               if (needFromToTable)
2088 ghuddy 1496
               {
2090 ghuddy 1497
                  if (firstCon)
1498
                  {
1499
                     firstCon = false;
2088 ghuddy 1500
                     table.Cell(row,2).Range.Text = destE.Name;
2090 ghuddy 1501
                  }
1502
                  else
1503
                  {
2088 ghuddy 1504
                     table.Cell(row,2).Range.Text += destE.Name;
2090 ghuddy 1505
                  }
2088 ghuddy 1506
               }
1507
 
1508
               // Capture the from-to relationship in a dictionary where the key is the
1509
               // ID of the destination element, and the value is the from element name.
1510
               // This dictionary will enable rapid construction of the to-from table if
1511
               // the user has requested it, from the exact same relationship info used
2090 ghuddy 1512
               // to construct the from-to table.
1513
               if (needToFromTable)
2088 ghuddy 1514
               {
1515
                  DictionaryEntry newEntry = new DictionaryEntry(destE.ElementID, fromElement.Name);
1516
                  fromToDictionary.Add( newEntry );
1517
               }
1518
            }
1519
            row++;
1520
         }
1521
 
1522
         // Does user want a to-from table ?
2090 ghuddy 1523
         if (needToFromTable)
2088 ghuddy 1524
         {
1525
            ElementAccumulator toLister = new ElementAccumulator(EA_RelMatrix.toElementTypes);
1526
            EA_Utils.findAndProcessPackageElements( EA_RelMatrix.toPackage, toLister, EA_RelMatrix.toPackageRecursion );
1527
 
1528
            // Sort the "to" elements
1529
            toLister.Elements.Sort( sorter );
1530
 
2090 ghuddy 1531
            if (EA_RelMatrix.toIntroText != null && EA_RelMatrix.toIntroText.Length > 0)
2088 ghuddy 1532
            {
1533
               appendAndSelectText( EA_RelMatrix.toIntroText, "Body 1" );
1534
            }
1535
 
1536
            // create the table in the word doc
1537
            tableNum = createTable( EA_RelMatrix.toFromTableTitle, toLister.Elements.Count + 1, 2 );
1538
            table = WordDocument.Tables[tableNum];
1539
 
1540
            table.Cell(1,1).Range.Text = EA_RelMatrix.toColumnTitle;
1541
            table.Cell(1,1).Range.ParagraphFormat.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter;
1542
            table.Cell(1,1).Range.Font.Bold = 1;
1543
            table.Cell(1,2).Range.Text = EA_RelMatrix.fromColumnTitle;
1544
            table.Cell(1,2).Range.ParagraphFormat.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter;
1545
            table.Cell(1,2).Range.Font.Bold = 1;
1546
 
1547
            // To make the to-from table, we use the dictionary that was built when making the from-to
1548
            // table. The dictionary will allow rapid determination of what "from" items belong to each
1549
            // "to" item, without us having to go back to EA and enquire on the database.
1550
            row = 2;
2090 ghuddy 1551
            foreach(EA.Element toElement in toLister.Elements)
2088 ghuddy 1552
            {
2090 ghuddy 1553
               // left-column cell content
1554
               table.Cell(row,1).Range.Text = toElement.Name;
2088 ghuddy 1555
 
2090 ghuddy 1556
               // right-column cell content
2088 ghuddy 1557
               bool firstCon = true;
1558
               foreach (DictionaryEntry de in fromToDictionary)
1559
               {
2090 ghuddy 1560
                  if ((int)de.Key == toElement.ElementID)
2088 ghuddy 1561
                  {
1562
                     if (firstCon)
1563
                     {
1564
                        firstCon = false;
1565
                        table.Cell(row,2).Range.Text = (string)de.Value;
1566
                     }
1567
                     else
1568
                     {
1569
                        table.Cell(row,2).Range.Text += (string)de.Value;
1570
                     }
1571
                  }
1572
               }
1573
               row++;
1574
            }
1575
         }
1576
      }
1577
 
1578
 
1579
 
1580
      #endregion
1581
   }
1582
}