Rev 2128 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
using System;using System.Drawing;using System.Collections;using System.Text;using System.ComponentModel;using System.Windows.Forms;using Word;using Microsoft.Office.Core;using System.Threading;namespace EA_DocGen{/// <summary>/// Summary description for createWordDoc./// </summary>public class createWordDoc : System.Windows.Forms.Form{// Enterprise Architect Model related dataprivate EA.Package EA_ParentPackage = null;private EA.Project EA_Project;private Thread creationThread = null; // Document generation threadpublic static bool abortCreationThread; // Used to abort the document generation threadprivate bool mustClose = false; // Used to signal closure required for doc generation dialogprivate bool docGenCompletedNormally = false; // Used to indicate if success message is made just prior to thread exitprivate bool oneShot_skipRootPackage = false;private bool oneShot_skipRootElementHeading = false;private int processingLink = 0;private ArrayList processedElements = null;// This data is designed to support unit test traceability. As such, it is only of real use// when making s/w design documents. It allows all non-private classes to be collected into// a list in order to generate a design-to-unit-test traceability table.private ArrayList classesNeedingUnitTests = null;private ArrayList classesWithUnitTests = null;private Word.Table utTraceabilityTable = null;// MS-Office Word related datapublic static Word.Application WordApp = null;public static Word.Document WordDocument = null;// Form datapublic System.Windows.Forms.TextBox textBox_template;private System.Windows.Forms.Button button_browse_template;public System.Windows.Forms.TextBox textBox_output_file;private System.Windows.Forms.Button button_browse_output_file;private System.Windows.Forms.Button button_cancel;private System.Windows.Forms.Button button_generate;private System.Windows.Forms.Button button_view_output;private System.Windows.Forms.Label label1;private System.Windows.Forms.Label label2;private System.Windows.Forms.CheckBox checkBox_WordVisibility;private System.Windows.Forms.CheckBox checkBox_keep_on_top;/// <summary>/// Required designer variable./// </summary>private System.ComponentModel.Container components = null;public createWordDoc(EA.Package theParentPackage){//// Required for Windows Form Designer support//InitializeComponent();EA_ParentPackage = theParentPackage;EA_Project = Main.EA_Repository.GetProjectInterface();DocSectionTracking.initialise();TabularContent.initialise();TextualContent.initialise();StyleContent.initialise();TextParser.initialise();WordApp = new Word.Application();}/// <summary>/// Clean up any resources being used./// </summary>protected override void Dispose( bool disposing ){if( disposing ){if(components != null){components.Dispose();}}base.Dispose( disposing );}#region Windows Form Designer generated code/// <summary>/// Required method for Designer support - do not modify/// the contents of this method with the code editor./// </summary>private void InitializeComponent(){this.textBox_template = new System.Windows.Forms.TextBox();this.button_browse_template = new System.Windows.Forms.Button();this.textBox_output_file = new System.Windows.Forms.TextBox();this.button_browse_output_file = new System.Windows.Forms.Button();this.button_cancel = new System.Windows.Forms.Button();this.button_generate = new System.Windows.Forms.Button();this.button_view_output = new System.Windows.Forms.Button();this.label1 = new System.Windows.Forms.Label();this.label2 = new System.Windows.Forms.Label();this.checkBox_WordVisibility = new System.Windows.Forms.CheckBox();this.checkBox_keep_on_top = new System.Windows.Forms.CheckBox();this.SuspendLayout();//// textBox_template//this.textBox_template.Location = new System.Drawing.Point(8, 32);this.textBox_template.Name = "textBox_template";this.textBox_template.Size = new System.Drawing.Size(696, 22);this.textBox_template.TabIndex = 0;this.textBox_template.Text = "";this.textBox_template.TextChanged += new System.EventHandler(this.textBox_template_TextChanged);//// button_browse_template//this.button_browse_template.Location = new System.Drawing.Point(712, 32);this.button_browse_template.Name = "button_browse_template";this.button_browse_template.Size = new System.Drawing.Size(64, 23);this.button_browse_template.TabIndex = 4;this.button_browse_template.Text = "Browse";this.button_browse_template.Click += new System.EventHandler(this.button_browse_template_Click);//// textBox_output_file//this.textBox_output_file.Location = new System.Drawing.Point(8, 96);this.textBox_output_file.Name = "textBox_output_file";this.textBox_output_file.Size = new System.Drawing.Size(696, 22);this.textBox_output_file.TabIndex = 1;this.textBox_output_file.Text = "";this.textBox_output_file.TextChanged += new System.EventHandler(this.textBox_output_file_TextChanged);//// button_browse_output_file//this.button_browse_output_file.Location = new System.Drawing.Point(712, 96);this.button_browse_output_file.Name = "button_browse_output_file";this.button_browse_output_file.Size = new System.Drawing.Size(64, 24);this.button_browse_output_file.TabIndex = 5;this.button_browse_output_file.Text = "Browse";this.button_browse_output_file.Click += new System.EventHandler(this.button_browse_output_file_Click);//// button_cancel//this.button_cancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;this.button_cancel.Location = new System.Drawing.Point(648, 152);this.button_cancel.Name = "button_cancel";this.button_cancel.Size = new System.Drawing.Size(128, 32);this.button_cancel.TabIndex = 3;this.button_cancel.Text = "Close / Abort";this.button_cancel.Click += new System.EventHandler(this.button_cancel_Click);//// button_generate//this.button_generate.Location = new System.Drawing.Point(496, 152);this.button_generate.Name = "button_generate";this.button_generate.Size = new System.Drawing.Size(128, 32);this.button_generate.TabIndex = 2;this.button_generate.Text = "Generate";this.button_generate.Click += new System.EventHandler(this.button_generate_Click);//// button_view_output//this.button_view_output.Enabled = false;this.button_view_output.Location = new System.Drawing.Point(336, 152);this.button_view_output.Name = "button_view_output";this.button_view_output.Size = new System.Drawing.Size(128, 32);this.button_view_output.TabIndex = 6;this.button_view_output.Text = "View Output";this.button_view_output.Click += new System.EventHandler(this.button_view_output_Click);//// label1//this.label1.Location = new System.Drawing.Point(8, 8);this.label1.Name = "label1";this.label1.Size = new System.Drawing.Size(224, 23);this.label1.TabIndex = 7;this.label1.Text = "Input Template or Document Name";//// label2//this.label2.Location = new System.Drawing.Point(8, 72);this.label2.Name = "label2";this.label2.Size = new System.Drawing.Size(280, 23);this.label2.TabIndex = 8;this.label2.Text = "Output Document Name";//// checkBox_WordVisibility//this.checkBox_WordVisibility.Checked = true;this.checkBox_WordVisibility.CheckState = System.Windows.Forms.CheckState.Checked;this.checkBox_WordVisibility.Location = new System.Drawing.Point(8, 168);this.checkBox_WordVisibility.Name = "checkBox_WordVisibility";this.checkBox_WordVisibility.Size = new System.Drawing.Size(256, 24);this.checkBox_WordVisibility.TabIndex = 7;this.checkBox_WordVisibility.Text = "Show MS-WORD During Construction";//// checkBox_keep_on_top//this.checkBox_keep_on_top.Checked = true;this.checkBox_keep_on_top.CheckState = System.Windows.Forms.CheckState.Checked;this.checkBox_keep_on_top.Location = new System.Drawing.Point(8, 136);this.checkBox_keep_on_top.Name = "checkBox_keep_on_top";this.checkBox_keep_on_top.Size = new System.Drawing.Size(224, 24);this.checkBox_keep_on_top.TabIndex = 9;this.checkBox_keep_on_top.Text = "Keep dialog on top";this.checkBox_keep_on_top.CheckedChanged += new System.EventHandler(this.checkBox_keep_on_top_CheckedChanged);//// createWordDoc//this.AcceptButton = this.button_generate;this.AutoScaleBaseSize = new System.Drawing.Size(6, 15);this.CancelButton = this.button_cancel;this.ClientSize = new System.Drawing.Size(784, 202);this.Controls.Add(this.checkBox_keep_on_top);this.Controls.Add(this.textBox_output_file);this.Controls.Add(this.textBox_template);this.Controls.Add(this.checkBox_WordVisibility);this.Controls.Add(this.label2);this.Controls.Add(this.label1);this.Controls.Add(this.button_view_output);this.Controls.Add(this.button_generate);this.Controls.Add(this.button_cancel);this.Controls.Add(this.button_browse_output_file);this.Controls.Add(this.button_browse_template);this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;this.Name = "createWordDoc";this.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide;this.Text = "Generate Document From Document Model";this.TopMost = true;this.Closing += new System.ComponentModel.CancelEventHandler(this.createWordDoc_Closing);this.ResumeLayout(false);}#endregion#region Message handlersprivate void button_view_output_Click(object sender, System.EventArgs e){if (WordApp != null){WordApp.Visible = true;}button_view_output.Enabled = false;}private void button_generate_Click(object sender, System.EventArgs e){if (this.textBox_template.Text.Length > 0){if (this.textBox_output_file.Text.Length > 0){creationThread = new Thread(new ThreadStart(createTheWordDoc));creationThread.ApartmentState = ApartmentState.STA;creationThread.Priority = ThreadPriority.Highest;creationThread.Start();}else{MessageBox.Show("Error - must specify an output file");}}else{MessageBox.Show("Error - must specify an input template file");}}private void button_cancel_Click(object sender, System.EventArgs e){}private void button_browse_template_Click(object sender, System.EventArgs e){OpenFileDialog dialog = new OpenFileDialog();dialog.Filter = "Word Files (*.doc;*.dot)|*.doc;*.dot|All files(*.*)|*.*";dialog.FilterIndex = 1;if (DialogResult.OK == dialog.ShowDialog()){this.textBox_template.Text = dialog.FileName;}}private void button_browse_output_file_Click(object sender, System.EventArgs e){OpenFileDialog dialog = new OpenFileDialog();dialog.Filter = "Word Files (*.doc;*.dot)|*.doc;*.dot|All files(*.*)|*.*";dialog.FilterIndex = 1;dialog.CheckFileExists = false;if (DialogResult.OK == dialog.ShowDialog()){this.textBox_output_file.Text = dialog.FileName;}}private void textBox_template_TextChanged(object sender, System.EventArgs e){}private void checkBox_keep_on_top_CheckedChanged(object sender, System.EventArgs e){this.TopMost = this.checkBox_keep_on_top.Checked;}private void textBox_output_file_TextChanged(object sender, System.EventArgs e){}private void createWordDoc_Closing(object sender, System.ComponentModel.CancelEventArgs e){if (creationThread != null && creationThread.IsAlive && !mustClose && Main.threadCreateDocProcessRunning){e.Cancel = true;DialogResult dlgRes = MessageBox.Show("Cancel Document Generation?", "Cancel", MessageBoxButtons.YesNo);if (dlgRes == DialogResult.Yes){abortCreationThread = true;mustClose = true;Main.EA_Repository.WriteOutput(Main.GUI_OUTPUT_TAB_NAME, "Document Generation Aborting...Please Wait", -1);}}else if (WordApp != null){// try-catch just in case user closed the application themselves whilst viewing the// generated output documenttry{object nothing = Type.Missing;object notTrue = false;WordApp.Application.Quit( ref notTrue, ref nothing, ref nothing);}catch (Exception createWordDoc_Closing_exception){// dummy statementString s = createWordDoc_Closing_exception.Message;}}}#endregion#region word document generation code/// <summary>/// Displays progress of the document generation in the createWordDocument dialog/// </summary>/// <param name="prefix"></param>/// <param name="EA_string"></param>private void displayProgress(string prefix, string EA_string){//textBox_progress.AppendText( prefix + EA_string + "\r\n" );// Display to the output tab as well - as a longer term record of what happenedStringBuilder sb = new StringBuilder("");DocSectionTracking.appendHeadingNumber(ref sb);while (sb.Length < 30)sb.Append(" ");sb.Append(prefix);sb.Append(EA_string);Main.EA_Repository.WriteOutput( Main.GUI_OUTPUT_TAB_NAME, sb.ToString(), 0);}/// <summary>/// This method takes the specified EA diagram element and puts the diagram image/// into the clipboard from where it can be pasted into the word document. After/// pasting it into the document, it sets the style and other aspects of the image./// </summary>/// <param name="theDiagram"></param>private void appendAndSelectDiagramViaClipboard(EA.Diagram theDiagram){// NOTE: diagrams only use one stereotype, not a list of them, so dont use StereotypeEx fieldif ( EA_DocGenOptions.optionValue(EA_DocGenOptions.boolean_options_e.CONSIDER_API_DIAGRAMS_ONLY)&& !theDiagram.Stereotype.Equals("API") ){displayProgress( "SKIPPED DIAGRAM: ", theDiagram.Name );}else if (theDiagram.StyleEx != null && theDiagram.StyleEx.IndexOf("ExcludeRTF=1") >= 0){displayProgress( "EXCLUDED DIAGRAM: ", theDiagram.Name );}// open the diagram in EA and copy it's image to the clipboardelse if (EA_Project.PutDiagramImageOnClipboard(theDiagram.DiagramGUID,0)){object startLocation;object endLocation;if (theDiagram.Notes != null && theDiagram.Notes.Length > 0){//@@@@//TextualContent.appendDescription( TextualContent.trimTrailingReturns(theDiagram.Notes) );TextParser.parse( TextualContent.trimTrailingReturns(theDiagram.Notes), theDiagram.DiagramID, EA_Constants.styleName_Body1, 0, false);}// create a range at the end of the documentstartLocation = WordDocument.Content.End;WordDocument.Content.InsertParagraphAfter();endLocation = WordDocument.Content.End;Word.Range WordRange = WordDocument.Range(ref startLocation, ref endLocation);object direction = Word.WdCollapseDirection.wdCollapseEnd;WordRange.Collapse(ref direction); // collapse prevents existing content being replaced// Get ready for the diagram paste and the formatting we want to do on it with the// selection object.TextualContent.SelectInsertionPointAtEndOfDocument();// Paste the diagram into the documentWordRange.Paste();// Set style of the diagram to "Normal" so that it can occupy space all the way to the left marginobject l_style = EA_Constants.styleName_Normal;endLocation = WordDocument.Content.End;WordRange = WordDocument.Range(ref startLocation, ref endLocation);WordRange.set_Style(ref l_style);// Center the diagram on the pageobject unit = Word.WdUnits.wdLine;object missing = Type.Missing;object count = 1;WordApp.Selection.MoveDown( ref unit, ref count, ref missing);WordApp.Selection.ParagraphFormat.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter;// Add a captionWordDocument.Content.InsertParagraphAfter();TextualContent.SelectInsertionPointAtEndOfDocument();object Label = "Figure";object Title = Type.Missing;object TitleAutoText = Type.Missing;object Position = Word.WdCaptionPosition.wdCaptionPositionAbove;object ExcludeLabel = 0;WordApp.Selection.InsertCaption( ref Label, ref Title, ref TitleAutoText, ref Position, ref ExcludeLabel);WordApp.Selection.TypeText( ": " + theDiagram.Name);WordApp.Selection.ParagraphFormat.Alignment = Word.WdParagraphAlignment.wdAlignParagraphCenter;// experimental code to create a bookmark for the figure caption//WordDocument.Paragraphs[ WordDocument.Paragraphs.Count ].Range.Select();//object lastParaRange = WordDocument.Paragraphs[ WordDocument.Paragraphs.Count ].Range;//string bookmarkName = theDiagram.Name;//bookmarkName = bookmarkName.Replace(' ', '_');//WordDocument.Bookmarks.Add( bookmarkName, ref lastParaRange );// Close the diagram in EAMain.EA_Repository.CloseDiagram(theDiagram.DiagramID);displayProgress( "DIAGRAM: ", theDiagram.Name );}}#region special element processing functions (link elements, table and text elements, etc)/// <summary>/// This function process a package link element, parsing each linked package by the/// parse_package() recursive function./// </summary>/// <param name="theElement"></param>/// <param name="recurse_level"></param>private void processPackageLink(EA.Element theElement, int recurse_level){if (theElement.Notes != null && theElement.Notes.Length > 0){string [] EA_DocGenPkgLnk = null;string delimStr = "\r\n";char [] delim = delimStr.ToCharArray();EA_DocGenPkgLnk = theElement.Notes.Split(delim,100);string linkedName = "";foreach(string s in EA_DocGenPkgLnk){if (s.Length > 0 && s != "\n" && s != "\r"){if (s == "skiproot"){oneShot_skipRootPackage = true;}else if (s[0] == '{'){EA.Package theFoundPackage = Main.EA_Repository.GetPackageByGuid(s);if (theFoundPackage != null){parse_package(theFoundPackage, recurse_level);}else{MessageBox.Show("WARNING - Could not find linked package : " + linkedName );}}else{linkedName = s;}}}}}/// <summary>/// This function process a diagram link element, using the appendAndSelectDiagramViaClipboard()/// for each linked diagram./// </summary>/// <param name="theElement"></param>private void processDiagramLink(EA.Element theElement){if (theElement.Notes != null && theElement.Notes.Length > 0){string [] EA_DocGenDiagLnk = null;string delimStr = "\r\n";char [] delim = delimStr.ToCharArray();EA_DocGenDiagLnk = theElement.Notes.Split(delim,100);string linkedName = "";foreach(string s in EA_DocGenDiagLnk){if (s.Length > 0 && s != "\n" && s != "\r" ){if (s[0] == '{'){EA.Diagram theFoundDiagram = (EA.Diagram)Main.EA_Repository.GetDiagramByGuid(s);if (theFoundDiagram != null){appendAndSelectDiagramViaClipboard( theFoundDiagram );}else{MessageBox.Show("WARNING - Could not find linked diagram : " + linkedName );}}else{linkedName = s;}}}}}/// <summary>/// This function process an element link element, parsing each linked element by the/// parse_element() recursive function./// </summary>/// <param name="theElement"></param>/// <param name="recurse_level"></param>private void processElementLink(EA.Element theElement, int recurse_level ){if (theElement.Notes != null && theElement.Notes.Length > 0){string [] EA_DocGenEleLnk = null;string delimStr = "\r\n";char [] delim = delimStr.ToCharArray();EA_DocGenEleLnk = theElement.Notes.Split(delim,100);string linkedName = "";foreach(string s in EA_DocGenEleLnk){if (s.Length > 0 && s != "\n" && s != "\r"){if (s == "skiproot"){oneShot_skipRootElementHeading = true;}else if ( s[0] == '{'){EA.Element theFoundElement = Main.EA_Repository.GetElementByGuid(s);if (theFoundElement != null){parse_element( theFoundElement, recurse_level );}else{MessageBox.Show("WARNING - Could not find linked element : " + linkedName );}}else{linkedName = s;}}}}}/// <summary>/// This method is recursive and searches a model structure to find a match to any/// of the names given in a list. Matched package structure is then parsed for/// document content generation./// </summary>/// <param name="parentPackage"></param>/// <param name="thePackage"></param>/// <param name="recurse_level"></param>/// <param name="skipRoots"></param>/// <param name="names"></param>private void processNameLinkPackage(EA.Package parentPackage, EA.Package thePackage, int recurse_level, bool skipRoots, ref ArrayList names){// search for the package name in the names[] listint i = 0;bool found = false;foreach (string name in names){// users can specify parent\child in a name to help narrow down exactly what package they// are looking for so deal with that, but the parent\ part is optional.int splitpos = name.IndexOf('\\',0);if (splitpos >= 0){if (parentPackage != null){if (name.Substring(0,splitpos).Equals(parentPackage.Name)){if (name.Substring(splitpos+1).Equals(thePackage.Name)){found = true;break;}}}else{if (name.Substring(splitpos+1).Equals(thePackage.Name)){found = true;break;}}}else{if (name.Equals(thePackage.Name)){found = true;break;}}i++;}if (found){// remove the found name, arm the skiproot mechanism if needed, and parse the packagenames.RemoveAt(i);if (skipRoots == true)oneShot_skipRootPackage = true;parse_package(thePackage, recurse_level);}else if (names.Count > 0) // any names left to process?{// recurse for each of this packages sub-packagesforeach(EA.Package subPackage in thePackage.Packages){processNameLinkPackage(thePackage, subPackage, recurse_level, skipRoots, ref names);}}}private void processNameLink(EA.Element theElement, int recurse_level ){if (theElement.Notes != null && theElement.Notes.Length > 0){string delimStr = "\r\n";char [] delim = delimStr.ToCharArray();string [] EA_DocGenNameLnk = theElement.Notes.Split(delim,100);string linkedName = "";bool gotLinkedName = false;ArrayList names = new ArrayList();EA.Package theFoundPackage = null;bool skipRoots = false;// search through the option stringsforeach(string s in EA_DocGenNameLnk){if (s.Length > 0 && s != "\n" && s != "\r"){if (s == "skiproot"){skipRoots = true;}else if (s[0] == '{') // is it a GUID?{// find the package by its GUIDtheFoundPackage = Main.EA_Repository.GetPackageByGuid(s);}else if (s.StartsWith("package=")){// add the users named package to our list of namesnames.Add( s.Substring(8, s.Length - 8) );}else if (gotLinkedName == false){// capture name of package refered to by the GUID - this is only for diagnostic purposesgotLinkedName = true;linkedName = s;}}}// If the GUID was resolved...if (theFoundPackage != null){processNameLinkPackage(null, theFoundPackage, recurse_level, skipRoots, ref names);if (names.Count > 0){StringBuilder sb = new StringBuilder();sb.Append("WARNING - Could not find named package(s)\n");sb.Append("within name link: ");sb.Append(linkedName);sb.Append("\n\nProblem package= directives are:\n");foreach(String s in names){sb.Append("\n");sb.Append(s);}MessageBox.Show(sb.ToString());}}else{MessageBox.Show("WARNING - Could not find linked package : " + linkedName );}}}/// <summary>/// This function processes a name link element. These are elements that point/// (using a GUID) to a package, and the user has specified text names of sub-packages/// within the package that they wish to have processed for document generation./// This is a useful way of getting content when you cannot be sure that the GUIDs/// of the packages you want will remain constant (eg. when re-using content from/// a reqpro import (for doc gen purposes))./// </summary>/// <param name="theElement"></param>/// <param name="recurse_level"></param>private void processTestLink(EA.Element theElement, int recurse_level ){if (theElement.Notes != null && theElement.Notes.Length > 0){string [] EA_DocGenEleLnk = null;string delimStr = "\r\n";char [] delim = delimStr.ToCharArray();EA_DocGenEleLnk = theElement.Notes.Split(delim,100);string linkedName = "";foreach(string s in EA_DocGenEleLnk){if (s.Length > 0 && s != "\n" && s != "\r"){if ( s[0] == '{'){try{// try to find the GUID as a packageEA.Package theFoundPackage = Main.EA_Repository.GetPackageByGuid(s);if (theFoundPackage != null)TextualContent.appendUnitTestSuite(theFoundPackage, recurse_level, ref classesWithUnitTests);else{// try to find the GUID as an elementEA.Element theFoundElement = Main.EA_Repository.GetElementByGuid(s);if (theFoundElement != null)TextualContent.appendUnitTestSuite(theFoundElement, recurse_level, ref classesWithUnitTests);elseMessageBox.Show("WARNING - Could not find linked element : " + linkedName );}}catch{// try to find the GUID as an elementEA.Element theFoundElement = Main.EA_Repository.GetElementByGuid(s);if (theFoundElement != null)TextualContent.appendUnitTestSuite(theFoundElement, recurse_level, ref classesWithUnitTests);elseMessageBox.Show("WARNING - Could not find linked element : " + linkedName );}}else{linkedName = s;}}}}}private void processTestTraceability( EA.Element theElement, int recurse_level ){if (classesNeedingUnitTests.Count > 0){TextualContent.appendAndSelectText( theElement.Notes, EA_Constants.styleName_Body1);int tableNum = TabularContent.Table_Create("Design Element to Unit Test Suite Traceability", true, 2, 2);utTraceabilityTable = WordDocument.Tables[tableNum];TabularContent.Table_SetTableColumnTitle(utTraceabilityTable, "Design Element (class)", 1);TabularContent.Table_SetTableColumnTitle(utTraceabilityTable, "Test Suite", 2);}}private void completeTestTraceability(){if (utTraceabilityTable != null){int numClassesRemaining = classesNeedingUnitTests.Count;int row = 2;foreach(int elementId in classesNeedingUnitTests){EA.Element theElement = Main.EA_Repository.GetElementByID( elementId );if (theElement != null){utTraceabilityTable.Cell(row,1).Range.Text = theElement.Name;if (classesWithUnitTests.Contains( elementId )){utTraceabilityTable.Cell(row,2).Range.Text = TextualContent.testSuiteName(theElement);}else{utTraceabilityTable.Cell(row,2).Range.Text = "Missing tests!";utTraceabilityTable.Cell(row,2).Range.Font.Color = Word.WdColor.wdColorRed;}}numClassesRemaining--;if (numClassesRemaining > 0){TabularContent.Table_InsertNewRowAfterThisRow(utTraceabilityTable, row);row++;}if (abortCreationThread)break;}}}#endregion#region special section processing functions (references, terminology, etc)/// <summary>/// This function processes elements as if they represented document references for/// the References section of a document./// </summary>/// <param name="thePackage"></param>private void createReferencesSection(EA.Package thePackage){foreach(EA.Element theElement in thePackage.Elements){if (abortCreationThread)return;// Here we want to apply the special ERG template styles for each reference// item.TextualContent.appendAndSelectText( theElement.Name, EA_Constants.styleName_RefListNum );TextualContent.appendAndSelectText( theElement.Notes, EA_Constants.styleName_RefListText );}}private void createTerminologySection(EA.Package thePackage, int recurse_level){// Use local package elements as source of glossary, but if none are present, resort to using// the project glossary in the repositoryint numItems = thePackage.Elements.Count;if (numItems == 0){numItems = Main.EA_Repository.Terms.Count;// For some wierd reason, I have seen exceptions occur here when trying to get a sorted list of glossary// items, so I put a trap and retry loop in until such time as the exact cause can be determined.ArrayList glossary = null;bool done = false;int retries = 3;do{if (abortCreationThread)return;try{glossary = new ArrayList();foreach(EA.Term theTerm in Main.EA_Repository.Terms)glossary.Add(theTerm);glossarySort sorter = new glossarySort();glossary.Sort( sorter );done = true;}catch (Exception e){Main.EA_Repository.WriteOutput(Main.GUI_OUTPUT_TAB_NAME, "Sorting Glossary, Exception" + e.Message, -1);retries--;}} while (!done && retries > 0);if (done && glossary.Count > 0){// Create a tableint tableNum = TabularContent.Table_Create("Terminology", true, numItems+1, 2);Word.Table table = WordDocument.Tables[tableNum];object center = Word.WdParagraphAlignment.wdAlignParagraphCenter;TabularContent.Table_SetTableColumnTitle(table, "Term", 1);TabularContent.Table_SetTableColumnTitle(table, "Definition", 2);table.Columns[1].SetWidth(100, Word.WdRulerStyle.wdAdjustSameWidth );int row = 2;// inject the glossary into the tableforeach(EA.Term theTerm in glossary){if (abortCreationThread)return;table.Cell(row,1).Range.Text = theTerm.Term;table.Cell(row,2).Range.Text = theTerm.Meaning;row++;}}}else{// scan content of terminology package - allow user to specify tables, text, package links,// and diagram links.ArrayList infoItems = new ArrayList();foreach(EA.Element theElement in thePackage.Elements){if (abortCreationThread)return;if (theElement.Name.StartsWith(EA_Constants.EA_DocGenTable)){TabularContent.processTableElement( theElement, recurse_level);}else if (theElement.Name.StartsWith(EA_Constants.EA_DocGenPackageLink)){processingLink++;processPackageLink( theElement, recurse_level );processingLink--;}else if (theElement.Name.StartsWith(EA_Constants.EA_DocGenText)){TextualContent.appendAndSelectText( TextualContent.trimTrailingReturns(theElement.Notes), EA_Constants.styleName_Body1 );}else if (theElement.Name.StartsWith(EA_Constants.EA_DocGenDiagramLink)){processingLink++;processDiagramLink( theElement );processingLink--;}else if (theElement.Name.StartsWith(EA_Constants.EA_DocGenElementLink)){processingLink++;processElementLink( theElement, recurse_level );processingLink--;}else if (!theElement.Name.StartsWith(EA_Constants.EA_DocGenBaseName) // ignore all other special EA_DocGen elements|| theElement.Name.Length == EA_Constants.EA_DocGenBaseName.Length) // allow EA_DocGen to be used as a term/acronym{infoItems.Add( theElement );}}if (infoItems.Count > 0){// Create a tableint tableNum = TabularContent.Table_Create("Terminology", true, infoItems.Count+1, 2);Word.Table table = WordDocument.Tables[tableNum];object center = Word.WdParagraphAlignment.wdAlignParagraphCenter;TabularContent.Table_SetTableColumnTitle(table, "Term", 1);TabularContent.Table_SetTableColumnTitle(table, "Definition", 2);table.Columns[1].SetWidth(100, Word.WdRulerStyle.wdAdjustSameWidth );int row = 2;elementSortByName sorter = new elementSortByName();infoItems.Sort(sorter);foreach(EA.Element theElement in infoItems){if (abortCreationThread)return;table.Cell(row,1).Range.Text = theElement.Name;if (theElement.Notes != null && theElement.Notes.Length > 0)table.Cell(row,2).Range.Text = theElement.Notes;row++;}}}}#endregionprivate bool generatePackageHeadingAndDescription( EA.Package thePackage, int recurse_level ){bool processLowerLevelContent = true; // return value for this function// The package name is a heading, and the package notes are paragraphs// directly under that headingTextualContent.appendAndSelectHeadingText( thePackage.Name, recurse_level );displayProgress( "PACKAGE: ", thePackage.Name );// Special handling for package called "Terminology"if (thePackage.Name == "Terminology"){TextualContent.appendAndSelectText( TextualContent.trimTrailingReturns(thePackage.Notes), EA_Constants.styleName_Body1 );createTerminologySection(thePackage, recurse_level);processLowerLevelContent = false;}else if (thePackage.Name == "References"){TextualContent.appendAndSelectText( TextualContent.trimTrailingReturns(thePackage.Notes), EA_Constants.styleName_Body1 );createReferencesSection(thePackage);processLowerLevelContent = false;}else{if (thePackage.Notes != null && thePackage.Notes.Length > 0){// use the package notes as body text and indicate to caller that package elements// have not been consumed// @@@@//TextualContent.appendAndSelectText( TextualContent.trimTrailingReturns(thePackage.Notes), EA_Constants.styleName_Body1 );TextParser.parse( TextualContent.trimTrailingReturns(thePackage.Notes), thePackage.PackageID, EA_Constants.styleName_Body1, 0, false);}}return processLowerLevelContent;}private void generatePackageDiagrams( EA.Package thePackage ){// default handling of diagramsforeach(EA.Diagram theDiagram in thePackage.Diagrams){if (abortCreationThread)return;if (theDiagram.ParentID == 0 || thePackage.PackageID == theDiagram.ParentID){appendAndSelectDiagramViaClipboard( theDiagram );}}}private void generateElementDiagrams( EA.Element theElement ){// default handling of diagramsforeach(EA.Diagram theDiagram in theElement.Diagrams){if (abortCreationThread)return;if (theDiagram.ParentID == 0 || theElement.ElementID == theDiagram.ParentID){appendAndSelectDiagramViaClipboard( theDiagram );}}}private void generateMethodContent( EA.Element theElement, int recurse_level ){recurse_level++;// Get all the methods into an array list and sort them by their position in the class's// method list (ie. sort order is determined by the Pos value in each method).ArrayList theMethods = new ArrayList();foreach(EA.Method theMethod in theElement.Methods)theMethods.Add( theMethod );methodSortByPos sorter = new methodSortByPos();theMethods.Sort( sorter );// filter out methods with certain characteristics?// eg. Users may only want to document public and protected methods.int numMethodsRemaining = 0;foreach(EA.Method theMethod in theMethods){if (abortCreationThread)return;if (EA_DocGenOptions.optionValue(EA_DocGenOptions.boolean_options_e.SUPPRESS_PRIVATE_METHODS) == false|| !theMethod.Visibility.StartsWith("Private"))numMethodsRemaining++;}Word.Range wr;StringBuilder sb;if (numMethodsRemaining > 0){// Print the "<Class Name> Operations" headingssb = new StringBuilder();sb.Append( theElement.Name );sb.Append( " Operations" );TextualContent.appendAndSelectHeadingText(sb.ToString(), recurse_level);// Iterate through the class's methodsforeach(EA.Method theMethod in theMethods){if (abortCreationThread)return;sb = new StringBuilder();if (EA_DocGenOptions.optionValue(EA_DocGenOptions.boolean_options_e.SUPPRESS_PRIVATE_METHODS) == false|| !theMethod.Visibility.StartsWith("Private")){// Print the Method name as a sub heading, and its descriptionTextualContent.appendAndSelectHeadingText(theMethod.Name , recurse_level + 1);TextualContent.appendDescription(TextualContent.trimTrailingReturns(theMethod.Notes));// Get a list of the method's parameters and sort them by the position field setup// in EA by the designerArrayList theParams = new ArrayList();foreach(EA.Parameter theParam in theMethod.Parameters)theParams.Add( theParam );parameterSortByPos paramSorter = new parameterSortByPos();theParams.Sort( paramSorter );// Print the prototype headingwr = TextualContent.appendAndSelectText("\nPrototype:", EA_Constants.styleName_Body1_Left_2_5cm_Italic);// begin to build the prototype stringsb = new StringBuilder();sb.Append( theMethod.ReturnType );sb.Append( " " );sb.Append( theMethod.Name );sb.Append( "(" );if (theParams.Count > 0){int numParamsRemaining = theParams.Count;// print what we have so far constructed for the prototypewr = TextualContent.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_3_5cm);// Now form a new string for the paramssb = new StringBuilder();foreach(EA.Parameter theParam in theParams){if (abortCreationThread)return;// each parameter is "[in|out|inout] type name [= default-value]"// where the default value is optionalsb.Append( "[" );sb.Append( theParam.Kind );sb.Append( "] " );sb.Append( theParam.Type );sb.Append( " " );sb.Append( theParam.Name );if (theParam.Default.Length > 0){sb.Append( " = " );sb.Append( theParam.Default );}// if there are more parameters after this one, add a comma and newlineif (numParamsRemaining > 1)sb.Append( ",\n" );numParamsRemaining--;}// complete the prototype and print it.sb.Append( ")" );wr = TextualContent.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_4_5cm);}else{// complete the prototype and print it.sb.Append( ")" );wr = TextualContent.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_3_5cm);}if (EA_DocGenOptions.optionValue(EA_DocGenOptions.boolean_options_e.SUPPRESS_METHOD_CHARACTERISTICS) == false){// Prototype Attributes/Characteristicssb = new StringBuilder();sb.Append( theMethod.Visibility );if (theMethod.IsStatic)sb.Append("\nStatic");if (theMethod.Abstract)sb.Append("\nAbstract");if (theMethod.IsPure)sb.Append("\nPure (c++)");if (theMethod.IsSynchronized)sb.Append("\nSynchronised");if (theMethod.Concurrency != null && theMethod.Concurrency.Length > 0 && !theMethod.Concurrency.StartsWith("Sequential") ){sb.Append("\n");sb.Append(theMethod.Concurrency);}if (theMethod.IsConst)sb.Append("\nConst");if (theMethod.IsQuery)sb.Append("\nIs Querry (does not alter class variables)");if (theMethod.IsLeaf)sb.Append("\nIs Leaf (cannot be overriden)");if (theMethod.ReturnIsArray)sb.Append( "\nReturn value is an array" );if (theMethod.Throws != null && theMethod.Throws.Length > 0){sb.Append("\n");sb.Append( theMethod.Throws );}if (sb.Length > 0){wr = TextualContent.appendAndSelectText("Characteristics:", EA_Constants.styleName_Body1_Left_2_5cm_Italic);wr = TextualContent.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_3_5cm);}}// Parameter Descriptionsif (theParams.Count > 0){wr = TextualContent.appendAndSelectText("Parameters:", EA_Constants.styleName_Body1_Left_2_5cm_Italic);foreach(EA.Parameter theParam in theParams){wr = TextualContent.appendAndSelectText( theParam.Name + "\t", EA_Constants.stylename_Parameter_Description);// do notes in seperate step since we want to call the appendDescription() method which// automatically alerts us to missing descriptions in the generated document.wr = TextualContent.appendDescription( TextualContent.trimTrailingReturns(theParam.Notes), EA_Constants.stylename_Parameter_Description, true);if (abortCreationThread)return;}}}}}}/// <summary>/// This method serialises a class's attributes to the document./// </summary>/// <param name="theElement"></param>/// <param name="recurse_level"></param>private void generateAttributeContent( EA.Element theElement, int recurse_level ){recurse_level++;// Get all the attributes into an array list and sort them by their position in the class's// attribute list (ie. sort order is determined by the Pos value in each attribute).ArrayList theAttrs = new ArrayList();foreach(EA.Attribute theAttr in theElement.Attributes)theAttrs.Add( theAttr );attributeSortByPos sorter = new attributeSortByPos();theAttrs.Sort( sorter );// TODO// filter out attributes with certain characteristics?// eg. Users may only want to document public and protected attributes.int numAttrsRemaining = 0;foreach(EA.Attribute theAttr in theAttrs){if (abortCreationThread)return;if (EA_DocGenOptions.optionValue(EA_DocGenOptions.boolean_options_e.SUPPRESS_PRIVATE_ATTRIBUTES) == false|| !theAttr.Visibility.StartsWith("Private"))numAttrsRemaining++;}if (numAttrsRemaining > 0){StringBuilder sb = new StringBuilder();sb.Append( theElement.Name );sb.Append( " Attributes" );TextualContent.appendAndSelectHeadingText(sb.ToString(), recurse_level);// serialise the attributes to the document.foreach(EA.Attribute theAttr in theAttrs){if (abortCreationThread)return;if (EA_DocGenOptions.optionValue(EA_DocGenOptions.boolean_options_e.SUPPRESS_PRIVATE_ATTRIBUTES) == false|| !theAttr.Visibility.StartsWith("Private")){// Begin to build content string for the "Attribute" table columnsb = new StringBuilder();// <type> <name>sb.Append("\n");sb.Append(theAttr.Type);sb.Append(" ");sb.Append(theAttr.Name);Word.Range wr = TextualContent.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1);if (wr.Characters.Last.Text.Equals("\r"))wr.End = wr.End - 1; // Dont boldise the \r paragraph markerwr.Font.Bold = 1;wr = TextualContent.appendDescription(TextualContent.trimTrailingReturns(theAttr.Notes));wr.ParagraphFormat.LeftIndent = WordApp.CentimetersToPoints((float)3.5);if (EA_DocGenOptions.optionValue(EA_DocGenOptions.boolean_options_e.SUPPRESS_ATTRIBUTE_CHARACTERISTICS) == false){// The approach here is to display as much of the attribute as we can but try to keep the output// uncluttered by omitting items the user has not set via the EA GUI.// Begin to build content string for the attribute characteristicssb = new StringBuilder();sb.Append(theAttr.Visibility);sb.Append("\n");if (theAttr.IsConst)sb.Append("Constant\n");if (theAttr.IsStatic)sb.Append("Static\n");if (theAttr.IsDerived)sb.Append("Derived\n");if (theAttr.IsOrdered){sb.Append("Is Ordered\n");}if (theAttr.IsCollection){sb.Append("Is A Collection\n");}if (theAttr.Length.Length > 0 && System.Convert.ToInt32(theAttr.Length) > 0){sb.Append("Length = ");sb.Append(theAttr.Length);sb.Append("\n");}if (!theAttr.Containment.StartsWith("Not Specified")){sb.Append("Containment =");sb.Append(theAttr.Containment);sb.Append("\n");}if (theAttr.Container.Length > 0){sb.Append("Container Type = ");sb.Append(theAttr.Container);sb.Append("\n");}if (theAttr.Style.Length > 0){sb.Append("Style = ");sb.Append(theAttr.Style);sb.Append("\n");}if ( System.Convert.ToInt32(theAttr.LowerBound) > 1|| System.Convert.ToInt32(theAttr.UpperBound) > 1){sb.Append("Multiplicity [");sb.Append(theAttr.LowerBound);sb.Append("..");sb.Append(theAttr.UpperBound);sb.Append("]\n");}if (theAttr.Scale.Length > 0 && System.Convert.ToInt32(theAttr.Scale) > 0){sb.Append("Scale = ");sb.Append(theAttr.Scale);sb.Append( "\n" );}if (theAttr.Precision.Length > 0 && System.Convert.ToInt32(theAttr.Precision) > 0){sb.Append("Precision = ");sb.Append(theAttr.Precision);sb.Append( "\n" );}if (theAttr.Default.Length > 0){sb.Append("Default Value = ");sb.Append(theAttr.Default);sb.Append( "\n" );}// Now look at the constraint and tagged value collections and add any found info to the// right hand columnshort i;for(i=0; i<theAttr.Constraints.Count; i++){if (abortCreationThread)return;EA.AttributeConstraint theCons = (EA.AttributeConstraint)theAttr.Constraints.GetAt(i);sb.Append( theCons.Type );sb.Append( ": {" );sb.Append( theCons.Name );sb.Append( "}\n" );//if (theCons.Notes != null && theCons.Notes.Length > 0)//{// sb.Append( theCons.Notes );// sb.Append( "\n" );//}}for(i=0; i<theAttr.TaggedValues.Count; i++){if (abortCreationThread)return;EA.AttributeTag theTag = (EA.AttributeTag)theAttr.TaggedValues.GetAt(i);sb.Append( "[" );sb.Append( theTag.Name );sb.Append( "=" );sb.Append( theTag.Value );sb.Append( "]\n" );//if (theTag.Notes != null && theTag.Notes.Length > 0)// sb.Append( theTag.Notes );// sb.Append( "\n" );//}}if (sb.Length > 0){// remove the trailing "\n"sb.Remove( sb.ToString().Length - 1, 1);wr = TextualContent.appendAndSelectText("Characteristics:", EA_Constants.styleName_Body1_Left_3_5cm_Italic);wr = TextualContent.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_4_5cm);}}numAttrsRemaining--;}}}}private void generateClassCharacteristics( EA.Element theElement, int recurse_level ){StringBuilder sb = null;Word.Range wr = null;// CHARACTERISTICSif (EA_DocGenOptions.optionValue(EA_DocGenOptions.boolean_options_e.SUPPRESS_CLASS_CHARACTERISTICS) == false){sb = new StringBuilder();sb.Append( "Characteristics:" );wr = TextualContent.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_2_5cm_Italic);sb = new StringBuilder();// VISIBILITYsb.Append( theElement.Visibility );// ABSTRACTif (System.Convert.ToInt32(theElement.Abstract) == 1)sb.Append( "\nAbstract" );// STEREOTYPESif (theElement.StereotypeEx.Length > 0){sb.Append("\nStereotypes: ");sb.Append(theElement.StereotypeEx);}// MULTIPLICITYif (theElement.Multiplicity.Length > 0){sb.Append("\nMultiplicity: ");sb.Append(theElement.Multiplicity);}// IS ACTIVEif (theElement.IsActive)sb.Append("\nClass is active (has its own thread of control)\n");// IS SPECif (theElement.IsSpec)sb.Append("\nClass is a specification\n");wr = TextualContent.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_3_5cm);}// BASE CLASSESif (EA_DocGenOptions.optionValue(EA_DocGenOptions.boolean_options_e.SUPPRESS_CLASS_BASE_CLASSES) == false){sb = new StringBuilder();foreach(EA.Element baseClass in theElement.BaseClasses){sb.Append( baseClass.Name);}if (sb.Length > 0){wr = TextualContent.appendAndSelectText("Base Class(es):", EA_Constants.styleName_Body1_Left_2_5cm_Italic);wr = TextualContent.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_3_5cm);}}// REALISESif (EA_DocGenOptions.optionValue(EA_DocGenOptions.boolean_options_e.SUPPRESS_CLASS_REALISES) == false){sb = new StringBuilder();foreach(EA.Element intf in theElement.Realizes){sb.Append( intf.Name);}if (sb.Length > 0){wr = TextualContent.appendAndSelectText("Realises:", EA_Constants.styleName_Body1_Left_2_5cm_Italic);wr = TextualContent.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_3_5cm);}}}private void generateClassRequirements( EA.Element theElement, int recurse_level ){if (EA_DocGenOptions.optionValue(EA_DocGenOptions.boolean_options_e.SUPPRESS_CLASS_REQUIREMENTS) == false){StringBuilder sb = new StringBuilder();sb.Append( "Requirements:" );Word.Range wr = TextualContent.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_2_5cm_Italic);foreach(EA.Requirement theReq in theElement.Requirements){if (abortCreationThread)return;sb = new StringBuilder();sb.Append( theReq.Name );wr = TextualContent.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_3_5cm);if (theReq.Notes != null && theReq.Notes.Length > 0){sb = new StringBuilder();sb.Append( theReq.Notes );wr = TextualContent.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_4_5cm);}}}}private void generateClassConstraints( EA.Element theElement, int recurse_level ){if (EA_DocGenOptions.optionValue(EA_DocGenOptions.boolean_options_e.SUPPRESS_CLASS_CONSTRAINTS) == false){StringBuilder sb = new StringBuilder();sb.Append( "Constraints:" );Word.Range wr = TextualContent.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_2_5cm_Italic);foreach(EA.Constraint theCons in theElement.Constraints){if (abortCreationThread)return;sb = new StringBuilder();sb.Append( theCons.Type );sb.Append( ": {" );sb.Append( theCons.Name );sb.Append( "}" );wr = TextualContent.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_3_5cm);if (theCons.Notes != null && theCons.Notes.Length > 0){sb = new StringBuilder();sb.Append( theCons.Notes );wr = TextualContent.appendAndSelectText(sb.ToString(), EA_Constants.styleName_Body1_Left_4_5cm);}}}}private bool generateElementContent( EA.Element theElement, int recurse_level ){bool allowSubElementParsing = true; // return value for the function// track recursion level to control heading style formatting requirementsif (oneShot_skipRootElementHeading == false)recurse_level++;if (EA_DocGenOptions.elementTypeFoundInEA_DocGen( theElement.Type )){// pass the element to the requirement element serialisation function. It// will tell us if it did anything with it. If not, then carry out the default// element serialisation.if (false == TextualContent.generateRequirementText(theElement)){bool isClass = theElement.Type.StartsWith("Class");if ( ( true == isClass&& true == EA_DocGenOptions.optionValue(EA_DocGenOptions.boolean_options_e.SUPPRESS_PRIVATE_CLASSES)&& true == theElement.Visibility.StartsWith("Private"))|| ( true == EA_DocGenOptions.optionValue(EA_DocGenOptions.boolean_options_e.CONSIDER_API_ELEMENTS_ONLY)&& 0 > theElement.StereotypeEx.IndexOf("API"))){// do nothingDocSectionTracking.trackDocSection(recurse_level);displayProgress( "SKIPPED: ", theElement.Name );allowSubElementParsing = false;}else{// disarm the one-shot element (heading) skipping feature if it was armed, and// by-pass the code to generate a new heading level for the elementif (oneShot_skipRootElementHeading == false){// Default element serialisationTextualContent.appendAndSelectHeadingText( theElement.Name, recurse_level );}else{oneShot_skipRootElementHeading = false;}processedElements.Add(theElement.ElementID);displayProgress( "ELEMENT: ", theElement.Name );if (theElement.Notes != null && theElement.Notes.Length > 0){// @@@@//TextualContent.appendDescription( TextualContent.trimTrailingReturns(theElement.Notes) );TextParser.parse( TextualContent.trimTrailingReturns(theElement.Notes), theElement.ElementID, EA_Constants.styleName_Body1, 0, false);}generateElementDiagrams(theElement);if (true == isClass){// accumulate unit testable classes.if ( theElement.StereotypeEx.IndexOf("API") >= 0&& !theElement.Visibility.StartsWith("Private")){classesNeedingUnitTests.Add( theElement.ElementID );}if (!abortCreationThread)generateClassCharacteristics(theElement, recurse_level);}// Requirement collectionif (!abortCreationThread && theElement.Requirements.Count > 0){generateClassRequirements(theElement, recurse_level);}// Constraint collectionif (!abortCreationThread && theElement.Constraints.Count > 0){generateClassConstraints(theElement, recurse_level);}if (!abortCreationThread && theElement.Issues.Count > 0){}// Attribute collectionif (!abortCreationThread && theElement.Attributes.Count > 0){generateAttributeContent(theElement, recurse_level);}// Method collectionif (!abortCreationThread && theElement.Methods.Count > 0){generateMethodContent(theElement, recurse_level);}}}else{processedElements.Add(theElement.ElementID);DocSectionTracking.trackDocSection(recurse_level);displayProgress( "ELEMENT: ", theElement.Name );}}else{DocSectionTracking.trackDocSection(recurse_level);displayProgress( "FILTERED: ", theElement.Type );}// TODO// We will probably have to put special code in here at some point for attributes// of, and collections of things within elements. This will become apparent once// someone tries to produce a design document where such things need to be included// in the generated document. Lots of work needed here eventually.// disarm element heading skip controloneShot_skipRootElementHeading = false;return allowSubElementParsing;}/// <summary>/// This function searches for the old content in the document in order to remove it/// prior to adding in the new content from the latest EA model data./// </summary>private void removeExistingDocumentContent(){//WordApp.Visible = true; // enable this when debugging this horrible functionWord.Selection aSelection;object findStyle = StyleContent.getStyle( EA_Constants.styleName_Heading1 );WordApp.Selection.WholeStory();aSelection = WordApp.Selection;aSelection.Find.ClearFormatting();aSelection.Find.set_Style( ref findStyle );aSelection.Find.Text = "Introduction";aSelection.Find.Replacement.Text = "";aSelection.Find.Forward = true;aSelection.Find.MatchCase = false;aSelection.Find.MatchWholeWord = false;aSelection.Find.MatchWildcards = false;aSelection.Find.MatchSoundsLike = false;aSelection.Find.MatchAllWordForms = false;object missingValue = Type.Missing;if (aSelection.Find.Execute(ref missingValue, ref missingValue,ref missingValue, ref missingValue, ref missingValue,ref missingValue, ref missingValue, ref missingValue,ref missingValue, ref missingValue, ref missingValue,ref missingValue, ref missingValue, ref missingValue,ref missingValue)){// found Introduction with Heading 1 style so we are now at the point in the// document where everything here on must be deleted in readiness for the newly// generated content. Extend the range to the end of the document and cut out the// old content.Word.Range range = aSelection.Range;range.End = WordDocument.Content.End;range.Cut();// try and ensure that no heading style is left in place following the removalobject style = EA_Constants.styleName_Body1;range.set_Style(ref style);}}/// <summary>/// Parses an element (because elements can contain sub-elements)./// This is also the function that identifies the occurrences of the special/// EA_DocGenXXX elements./// </summary>/// <param name="theElement"></param>/// <param name="recurse_level"></param>private void parse_element(EA.Element theElement, int recurse_level){if (abortCreationThread)return;// First look for and handle special elements that control the doc-gen process// The EA_DocGenPackageLink can contain a list of GUIDs in its notes section// that point to model structure outside of the localised structure forming the// document. This enables a document to grab content from other external models// as long as they are loaded into the repository.if (theElement.Name.StartsWith(EA_Constants.EA_DocGenPackageLink)){processingLink++;processPackageLink( theElement, recurse_level );processingLink--;}// The EA_DocGenDiagramLink can contain a list of GUIDs in its notes section// that point to diagram elements anywhere in the repository.else if (theElement.Name.StartsWith(EA_Constants.EA_DocGenDiagramLink)){processingLink++;processDiagramLink( theElement );processingLink--;}// The EA_DocGenDiagramLink can contain a list of GUIDs in its notes section// that point to diagram elements anywhere in the repository.else if (theElement.Name.StartsWith(EA_Constants.EA_DocGenElementLink)){processingLink++;processElementLink( theElement, recurse_level );processingLink--;}// The EA_DocGenTable element can contain table content in its notes section// and must be dealt with in a special way.else if (theElement.Name.StartsWith(EA_Constants.EA_DocGenTable)){TabularContent.processTableElement(theElement, recurse_level);}// The EA_DocGenText element can contain text content in its notes section// that must be appended to the doc in Body 1 style within the current// section.else if (theElement.Name.StartsWith(EA_Constants.EA_DocGenText)){if (theElement.Notes != null && theElement.Notes.Length > 0){//@@@@//TextualContent.appendAndSelectText( TextualContent.trimTrailingReturns(theElement.Notes), EA_Constants.styleName_Body1 );TextParser.parse( TextualContent.trimTrailingReturns(theElement.Notes), theElement.ElementID, EA_Constants.styleName_Body1, 0, false);}}else if (theElement.Name.StartsWith(EA_Constants.EA_DocGenRelationshipMatrix)){EA_RelationshipMatrix.initialise(processedElements);if (EA_RelationshipMatrix.processRelationshipMatrixOptions( theElement )){EA_RelationshipMatrix.processRelationshipMatrixElement( theElement, recurse_level );}}else if (theElement.Name.StartsWith(EA_Constants.EA_DocGenTestLink)){processingLink++;processTestLink( theElement, recurse_level );processingLink--;}else if (theElement.Name.StartsWith(EA_Constants.EA_DocGenTestTraceability)){processTestTraceability( theElement, recurse_level );}else if (theElement.Name.StartsWith(EA_Constants.EA_DocGenNameLink)){processingLink++;processNameLink( theElement, recurse_level );processingLink--;}// we are aware of the other ERG EA add-in, EA_ReqPro! That add-in creates// ReqProDB stereotyped elements. Never consume them in the document generation process.else if (0 > theElement.StereotypeEx.IndexOf(EA_Constants.stereotype_ReqProDB)){bool allowSubElementParsing = generateElementContent( theElement, recurse_level );if (allowSubElementParsing){// Look at this elements sub-elementsforeach(EA.Element subElement in theElement.Elements){if (abortCreationThread)return;parse_element(subElement, recurse_level+1);}}}}/// <summary>/// Parses the package and all of its content, extracting information as needed, and/// adding it to the word document. This method is recursive, since recursion is the/// easiest way to walk thru' the package levels in the model./// </summary>/// <param name="parentPackage"></param>/// <param name="recurse_level"></param>private void parse_package(EA.Package thePackage, int recurse_level){if (abortCreationThread)return;// track recursion level to control heading style formatting requirements// The one-shot skiproot feature of the EA_DocGenPackageLink element handling has an effect// here, as you can see.bool rootPackageWasSkipped = !oneShot_skipRootPackage;if (oneShot_skipRootPackage == false){recurse_level++;}// determine if the package has an API stereotypebool packageHasAPIStereotype = false;if (0 <= thePackage.StereotypeEx.IndexOf("API") )packageHasAPIStereotype = true;// only process the package if it the stereotype allows, or sensitivity to the stereotype is disabledif ( !EA_DocGenOptions.optionValue(EA_DocGenOptions.boolean_options_e.CONSIDER_API_PACKAGES_ONLY)|| ( EA_DocGenOptions.optionValue(EA_DocGenOptions.boolean_options_e.CONSIDER_API_PACKAGES_ONLY)&& EA_DocGenOptions.optionValue(EA_DocGenOptions.boolean_options_e.RESTRICT_FOR_LINKED_PACKAGES_ONLY) && processingLink == 0)|| (EA_DocGenOptions.optionValue(EA_DocGenOptions.boolean_options_e.CONSIDER_API_PACKAGES_ONLY)&& packageHasAPIStereotype)){bool processLowerLevelContent = true;// disarm the one-shot package skipping feature if it was armedif (oneShot_skipRootPackage == true){oneShot_skipRootPackage = false;}else{// Generate heading and description for the package. This function also takes care of some// specially handled packages (terminology, references).processLowerLevelContent = generatePackageHeadingAndDescription( thePackage, recurse_level );}// generate package heading and description. This may, depending on the package name,// consume the elements in the package. If it does not, then consume them (and any diagrams)// locally here.if (true == processLowerLevelContent){// consume diagramsgeneratePackageDiagrams( thePackage );foreach(EA.Element subElement in thePackage.Elements){if (abortCreationThread)return;if (subElement.ParentID == 0 || thePackage.PackageID == subElement.ParentID)parse_element(subElement, recurse_level);}// Scan through the sub-packages within this package.foreach(EA.Package subPackage in thePackage.Packages){if (abortCreationThread)return;// recurseparse_package(subPackage, recurse_level);}}}else{// disarm the one-shot package skipping feature if it was armedif (oneShot_skipRootPackage == true){oneShot_skipRootPackage = false;}}}/// <summary>/// This is the overall generate document method. It creates a word document from/// an input template, sets various characteristics of the document, schedules the/// EA parsing function, before finally saving the document to the output file name./// </summary>private void createTheWordDoc(){docGenCompletedNormally = false;abortCreationThread = false;Main.threadCreateDocProcessRunning = true;// capture initial security settingsMsoAutomationSecurity securityBefore = WordApp.AutomationSecurity;button_generate.Enabled = false;button_browse_output_file.Enabled = false;button_browse_template.Enabled = false;textBox_output_file.Enabled = false;textBox_template.Enabled = false;checkBox_WordVisibility.Enabled = false;try{object template = this.textBox_template.Text;object newTemplate = Type.Missing;object outputFilename = this.textBox_output_file.Text;object docType = Type.Missing;object visible = Type.Missing;object nothing = Type.Missing;object notTrue = false;Main.EA_Repository.WriteOutput( Main.GUI_OUTPUT_TAB_NAME, "", 0);Main.EA_Repository.WriteOutput( Main.GUI_OUTPUT_TAB_NAME,String.Format( "Generating Document {0}", this.textBox_output_file.Text), 0 );// control word visibility based on checkbox user can modifyWordApp.Visible = this.checkBox_WordVisibility.Checked;// disable VB macros from running in the documentWordApp.AutomationSecurity = MsoAutomationSecurity.msoAutomationSecurityForceDisable;WordApp.DisplayAlerts = Word.WdAlertLevel.wdAlertsNone;// Create a document from the input templateMain.EA_Repository.WriteOutput(Main.GUI_OUTPUT_TAB_NAME, "Creating new document based on template", -1);WordDocument = WordApp.Documents.Add(ref template, ref newTemplate, ref docType, ref visible);// Remove all old content from the input document/template. Note that this assumes// that content will begin at section 1 with the title "Introduction" and it will have// "Heading 1" style.if (!abortCreationThread){Main.EA_Repository.WriteOutput(Main.GUI_OUTPUT_TAB_NAME, "Removing existing content (if any)", -1);removeExistingDocumentContent();}// turn off grammar and spell checkingWordDocument.GrammarChecked = false;WordDocument.SpellingChecked = false;// arm the public class list accumulator.classesNeedingUnitTests = new ArrayList();classesWithUnitTests = new ArrayList();processingLink = 0;processedElements = new ArrayList();// If the input template does not contain the styles needed for requirement documents,// programmatically create them just in case.if (!abortCreationThread){Main.EA_Repository.WriteOutput(Main.GUI_OUTPUT_TAB_NAME, "Creating Requirement Styles", -1);StyleContent.createRequirementStyles();}if (!abortCreationThread){Main.EA_Repository.WriteOutput(Main.GUI_OUTPUT_TAB_NAME, "Creating Additional Heading Styles", -1);StyleContent.createAdditionalHeadingLevelStyles();}if (!abortCreationThread){Main.EA_Repository.WriteOutput(Main.GUI_OUTPUT_TAB_NAME, "Creating Element Detail Styles", -1);StyleContent.createElementDetailsStyles();}if (!abortCreationThread){Main.EA_Repository.WriteOutput(Main.GUI_OUTPUT_TAB_NAME, "Correcting known problems in ERG template styles", -1);StyleContent.correctErrorsInTemplateStyles();}if (EA_DocGenOptions.optionValue(EA_DocGenOptions.boolean_options_e.FORCE_HEADING_TABS_TO_2_5_CM)){Main.EA_Repository.WriteOutput(Main.GUI_OUTPUT_TAB_NAME, "Forcing Heading styles to use tab stop at 2.5cm only", -1);StyleContent.forceHeadingsToUse2_5cmTabStops();}// Parse EA_DocGen Document Model. The parent package is the document model itself// and the packages within it are the top level packages only.// Question: do we have to parse diagrams and elements at this top level? So far,// this has been found to be unecessary, but you never know. For now, dont do it.if (!abortCreationThread){Main.EA_Repository.WriteOutput(Main.GUI_OUTPUT_TAB_NAME, "Generating new content", -1);foreach(EA.Package thePackage in EA_ParentPackage.Packages){parse_package(thePackage, 0);if (abortCreationThread)break;}}// for design docs, a user may have used the test traceability element in their document model,// which means that now we are finished with parse 1 of the document, we can complete the traceability// table (if any) that was begun when that special element was first encountered.if (!abortCreationThread){completeTestTraceability();// Save the document to the output file before we try and update the fields. This is because// I have seen Fields.Update() fail on a few occasions and it is very annoying// to lose what has thus far been generated.WordDocument.SaveAs( ref outputFilename,ref nothing, ref nothing, ref nothing, ref nothing,ref nothing, ref nothing, ref nothing, ref nothing,ref nothing, ref nothing, ref nothing, ref nothing,ref nothing, ref nothing, ref nothing);object noSave = Word.WdSaveOptions.wdDoNotSaveChanges;object format = Word.WdOriginalFormat.wdWordDocument;WordDocument.Close(ref noSave, ref format, ref nothing);if (!abortCreationThread){Main.EA_Repository.WriteOutput(Main.GUI_OUTPUT_TAB_NAME, "Updating Fields and Saving Document", -1);// Re-load the document to update the fields. For some as yet unknown reason, doing this// sometimes fails, but by doing it in a re-loaded instance of the word document// the failures seem to be reduced.WordDocument = WordApp.Documents.Add(ref outputFilename, ref newTemplate, ref docType, ref visible);WordDocument.Fields.Update();WordDocument.SaveAs( ref outputFilename,ref nothing, ref nothing, ref nothing, ref nothing,ref nothing, ref nothing, ref nothing, ref nothing,ref nothing, ref nothing, ref nothing, ref nothing,ref nothing, ref nothing, ref nothing);// Tell user the process completed okMain.EA_Repository.WriteOutput(Main.GUI_OUTPUT_TAB_NAME, "Document Generation Complete", -1);docGenCompletedNormally = true;button_view_output.Enabled = true;}}else{Main.EA_Repository.WriteOutput(Main.GUI_OUTPUT_TAB_NAME, "Document Generation Aborted", -1);MessageBox.Show("Document Generation Aborted");}}catch (Exception createTheWordDoc_exception){Main.ShowException(createTheWordDoc_exception, "Document Generation Failed");}// restore security settingsWordApp.AutomationSecurity = securityBefore;// issue the generation complete message box as close to the end of the thread as possible so that// there is less of a chance that a user pressing the close button will see a "cancel generation"// warning box.if (docGenCompletedNormally)MessageBox.Show("Document Generation Complete");// we can mark the thread as not running since from now on we do not want to do anything with the// WordApp or WordDocument objects and their destruction wont cause any ill effects.Main.threadCreateDocProcessRunning = false;if (mustClose)this.Close();}#endregion}}