Subversion Repositories DevTools

Rev

Rev 2132 | Blame | Compare with Previous | Last modification | View Log | RSS feed

using System;
using System.Collections;
using System.Text;
using System.ComponentModel;
using System.Windows.Forms;
using Microsoft.Office.Interop.Word;

namespace EA_DocGen
{
        /// <summary>
        /// Summary description for EA_RelationshipMatrix.
        /// </summary>
        public class EA_RelationshipMatrix
        {

      public struct RM_ColumnType
      {
         public string columnTitle;

         public string packageGUID;
         public string packageName;

         public ArrayList elementTypes;

         public bool packageRecursion;
         public bool packageTrimming;
         public bool elementNotes;
         public bool reqTagSort;
      };

      public struct RM_TableType
      {
         public string introText;
         public string title;
      };

      public struct RM_MatrixType
      {
         public int style;
         public RM_TableType fromToTable;
         public RM_TableType toFromTable;
         public RM_ColumnType from;
         public RM_ColumnType to;
      };

      // DATA
      private static RM_MatrixType RM_Matrix;

      private static EA.Element RM_Element = null;

      private static EA.Package fromPackage = null;
      private static EA.Package toPackage = null;

      private static ArrayList processedElements = null;

      private static string [] options_string = null;

      private enum DictionaryValueType
      {
         DVT_EA_ELEMENT,
         DVT_STRING
      };

                public static void initialise(ArrayList processedElementsRef)
                {
         processedElements = processedElementsRef;

         RM_Matrix.from.elementTypes = new ArrayList();
         RM_Matrix.to.elementTypes = new ArrayList();
                }

      private static void reset()
      {
         RM_Matrix.style = 1;

         RM_Matrix.fromToTable.introText = null;
         RM_Matrix.fromToTable.title = null;

         RM_Matrix.from.columnTitle = null;
         RM_Matrix.from.packageGUID = null;
         RM_Matrix.from.elementTypes.Clear();
         RM_Matrix.from.packageRecursion = true;
         RM_Matrix.from.packageTrimming = false;
         RM_Matrix.from.elementNotes = false;
         RM_Matrix.from.packageName = null;
         RM_Matrix.from.reqTagSort = true;

         fromPackage = null;
        
         RM_Matrix.toFromTable.introText = null;
         RM_Matrix.toFromTable.title = null;

         RM_Matrix.to.columnTitle = null;
         RM_Matrix.to.packageGUID = null;
         RM_Matrix.to.elementTypes.Clear();
         RM_Matrix.to.packageRecursion = true;
         RM_Matrix.to.packageTrimming = false;
         RM_Matrix.to.elementNotes = false;
         RM_Matrix.to.packageName = null;
         RM_Matrix.to.reqTagSort = true;

         toPackage = null;
      }


      public static bool processRelationshipMatrixOptions(EA.Element theElement)
      {
         RM_Element = theElement;

         reset();

         // Extract the control options from the notes of the element
         
         string delimStr = "\n";
         char [] delim = delimStr.ToCharArray();
         options_string = theElement.Notes.Split(delim,100);
         int i = 0;
         foreach(string s in options_string)
         {
            options_string[i] = s.Trim();
            i++;
         }

         // scan the options string and assign values into the options variables as required
         foreach(string s in options_string)
         {
            if (s.Length > 0 && s != "\n" && s != "\r" && s[0] != '\\')
            {
               if (s.StartsWith("style="))
               {
                  RM_Matrix.style = EA_DocGenOptions.getOptionValue(s, RM_Matrix.style);
               }
                  // FROM items
               else if (s.StartsWith("fromIntroText="))
               {
                  RM_Matrix.fromToTable.introText = EA_DocGenOptions.getOptionValue(s, null);
               }
               else if (s.StartsWith("fromToTableTitle=")) 
               {
                  RM_Matrix.fromToTable.title = EA_DocGenOptions.getOptionValue(s, null);
               }
               else if (s.StartsWith("fromColumnTitle=")) 
               {
                  RM_Matrix.from.columnTitle = EA_DocGenOptions.getOptionValue(s, RM_Matrix.from.columnTitle);
               }
               else if (s.StartsWith("fromPackageRecursion=")) 
               {
                  RM_Matrix.from.packageRecursion = EA_DocGenOptions.getOptionValue(s, RM_Matrix.from.packageRecursion);
               }
               else if (s.StartsWith("fromPackageTrimming="))
               {
                  RM_Matrix.from.packageTrimming = EA_DocGenOptions.getOptionValue(s, RM_Matrix.from.packageTrimming);
               }
               else if (s.StartsWith("fromPackage=")) 
               {
                  RM_Matrix.from.packageGUID = EA_DocGenOptions.getOptionValue(s, RM_Matrix.from.packageGUID);
               }
               else if (s.StartsWith("fromElementNotes="))
               {
                  RM_Matrix.from.elementNotes = EA_DocGenOptions.getOptionValue(s, RM_Matrix.from.elementNotes);
               }
               else if (s.StartsWith("fromPackageName="))
               {
                  RM_Matrix.from.packageName = EA_DocGenOptions.getOptionValue(s, RM_Matrix.from.packageName);
               }
               else if (s.StartsWith("fromElementType=")) 
               {
                  string et = EA_DocGenOptions.getOptionValue(s,null);
                  if (et != null) 
                  {
                     RM_Matrix.from.elementTypes.Add( et );
                  }
               }
               else if (s.StartsWith("fromUsesTagSort="))
               {
                  RM_Matrix.from.reqTagSort = EA_DocGenOptions.getOptionValue(s, RM_Matrix.from.reqTagSort);
               }

                  // TO items
               else if (s.StartsWith("toIntroText="))
               {
                  RM_Matrix.toFromTable.introText = EA_DocGenOptions.getOptionValue(s, null);
               }
               else if (s.StartsWith("toFromTableTitle=")) 
               {
                  RM_Matrix.toFromTable.title = EA_DocGenOptions.getOptionValue(s, null);
               }
               else if (s.StartsWith("toColumnTitle=")) 
               {
                  RM_Matrix.to.columnTitle = EA_DocGenOptions.getOptionValue(s, RM_Matrix.to.columnTitle);
               }
               else if (s.StartsWith("toPackageRecursion=")) 
               {
                  RM_Matrix.to.packageRecursion = EA_DocGenOptions.getOptionValue(s, RM_Matrix.to.packageRecursion);
               }
               else if (s.StartsWith("toPackageTrimming=")) 
               {
                  RM_Matrix.to.packageTrimming = EA_DocGenOptions.getOptionValue(s, RM_Matrix.to.packageTrimming);
               }               
               else if (s.StartsWith("toPackage=")) 
               {
                  RM_Matrix.to.packageGUID = EA_DocGenOptions.getOptionValue(s, RM_Matrix.to.packageGUID);
               }
               else if (s.StartsWith("toElementNotes="))
               {
                  RM_Matrix.to.elementNotes = EA_DocGenOptions.getOptionValue(s, RM_Matrix.to.elementNotes);
               }
               else if (s.StartsWith("toPackageName="))
               {
                  RM_Matrix.to.packageName = EA_DocGenOptions.getOptionValue(s, RM_Matrix.to.packageName);
               }               
               else if (s.StartsWith("toElementType=")) 
               {
                  string et = EA_DocGenOptions.getOptionValue(s,null);
                  if (et != null) 
                  {
                     RM_Matrix.to.elementTypes.Add( et );
                  }
               }
               else if (s.StartsWith("toUsesTagSort="))
               {
                  RM_Matrix.to.reqTagSort = EA_DocGenOptions.getOptionValue(s, RM_Matrix.to.reqTagSort);
               }
            }
         }

         // Verify that we have all the necessary compulsory options
         if (RM_Matrix.fromToTable.title == null && RM_Matrix.toFromTable.title == null)
         {
            MessageBox.Show("Error in EA_DocGenRelationshipMatrix options list\n\n" +
               "Missing option: Must specify at least one table title");
            return false;
         }

         // FROM items
         if (RM_Matrix.from.columnTitle == null)
         {
            MessageBox.Show("Error in EA_DocGenRelationshipMatrix options list\n\n" +
               "Missing option: fromColumnTitle");
            return false;
         }
         if (RM_Matrix.from.packageGUID == null)
         {
            MessageBox.Show("Error in EA_DocGenRelationshipMatrix options list\n\n" +
               "Missing option: fromPackageGUID");
            return false;
         }
         if (RM_Matrix.from.elementTypes.Count == 0)
         {
            MessageBox.Show("Error in EA_DocGenRelationshipMatrix options list\n\n" +
               "Missing option(s): fromElementTypes");
            return false;
         }      

         // TO items
         if (RM_Matrix.to.columnTitle == null)
         {
            MessageBox.Show("Error in EA_DocGenRelationshipMatrix options list\n\n" +
               "Missing option: toColumnTitle");
            return false;
         }
         if (RM_Matrix.to.packageGUID == null)
         {
            MessageBox.Show("Error in EA_DocGenRelationshipMatrix options list\n\n" +
               "Missing option: toPackageGUID");
            return false;
         }
         if (RM_Matrix.to.elementTypes.Count == 0)
         {
            MessageBox.Show("Error in EA_DocGenRelationshipMatrix options list\n\n" +
               "Missing option(s): toElementTypes");
            return false;
         }   

         // Find GUID linked packages in the repository
         fromPackage = Main.EA_Repository.GetPackageByGuid( RM_Matrix.from.packageGUID );
         if (fromPackage == null)
         {
            MessageBox.Show("Error processing EA_DocGenRelationshipMatrix\n\n" +
               "could not locate fromPackage in Repository");
            return false;
         }

         toPackage = Main.EA_Repository.GetPackageByGuid( RM_Matrix.to.packageGUID );
         if (toPackage == null)
         {
            MessageBox.Show("Error processing EA_DocGenRelationshipMatrix\n\n" +
               "could not locate toPackage in Repository");
            return false;
         }

         return true;
      }


      public static string optionTemplateForRelationshipMatrix(int style)
      {
         switch (style)
         {
            case 1:
               return
               "style=1\r\n"
               + "fromToTableTitle=\r\n"
               + "fromIntroText=\r\n"
               + "fromColumnTitle=\r\n"
               + "fromPackage=\r\n"
               + "fromElementType=\r\n"
               + "fromElementType=\r\n"
               + "fromPackageRecursion=true\r\n"
               + "fromPackageTrimming=false\r\n"
               + "fromElementNotes=false\r\n"
               + "fromUsesTagSort=true\r\n"

               + "toFromTableTitle=\r\n"
               + "toIntroText=\r\n"
               + "toColumnTitle=\r\n"
               + "toPackage=\r\n"
               + "toElementType=\r\n"
               + "toPackageRecursion=true\r\n"
               + "toPackageTrimming=false\r\n"
               + "toElementNotes=false\r\n"
               + "toUsesTagSort=true\r\n";
            case 2:
               return
               "style=2\r\n"
               + "fromToTableTitle=Requirement Dependencies\r\n"
               + "fromIntroText=The following table identifies the source requirements (if any) for each requirement stated in this document.\r\n"
               + "fromColumnTitle=Requirement\r\n"
               + "fromPackage=\r\n"
               + "fromElementType=Requirement\r\n"
               + "fromPackageRecursion=true\r\n"
               + "fromPackageTrimming=false\r\n"
               + "fromElementNotes=false\r\n"
               + "fromUsesTagSort=true\r\n"

               + "toPackageRecursion=true\r\n"
               + "toPackage=\r\n"
               + "toColumnTitle=Source Requirements\r\n"
               + "toElementType=Requirement\r\n";
            default:
               return "";
         }
      }


      /// <summary>
      /// This function will insert one or more relationship matrix tables into the document, 
      /// built from content specified in options that are provided in the notes section of 
      /// the special element that has led to this function being called.
      /// </summary>
      /// <param name="theElement"></param>
      /// <param name="recurse_level"></param>
      public static void processRelationshipMatrixElement( EA.Element theElement, int recurse_level )
      {
         RM_Element = theElement;

         if (RM_Matrix.from.packageName != null && fromPackage != null)
         {
            EA.Package newFromPackage = EA_Utilities.findNamedPackage(fromPackage, RM_Matrix.from.packageName);
            if (newFromPackage != null)
            {
               fromPackage = newFromPackage;
            }
            else
            {
               MessageBox.Show("Error processing EA_DocGenRelationshipMatrix\n\n" +
                  "could not locate fromPackageName in Repository");
               return;
            }
         }

         if (RM_Matrix.to.packageName != null && toPackage != null)
         {
            EA.Package newToPackage = EA_Utilities.findNamedPackage(toPackage, RM_Matrix.to.packageName);
            if (newToPackage != null)
            {
               toPackage = newToPackage;
            }
            else
            {
               MessageBox.Show("Error processing EA_DocGenRelationshipMatrix\n\n" +
                  "could not locate toPackageName in Repository");
               return;
            }
         }

         switch (RM_Matrix.style)
         {
            case 1:
               processRelationshipMatrixElementStyle1();
               break;

            case 2:
               processRelationshipMatrixElementStyle2();
               break;
         }
      }


      /// <summary>
      /// This function will insert a relationship matrix table into the document, built from content
      /// specified in options that are provided in the notes section of the special element that
      /// has led to this function being called.
      /// 
      /// The style of these tables is that required for requirement to design traceability.
      /// </summary>
      /// <param name="EA_RelMatrix"></param>
      private static void processRelationshipMatrixElementStyle1()
      {
         int tableNum = 0;
         Table table = null;

         // Scan the fromPackage to find all the "from elements".
         Main.WriteOutput("   Finding elements in fromPackage", -1);
         ElementAccumulator fromLister = new ElementAccumulator(RM_Matrix.from.elementTypes);
         EA_Utilities.findAndProcessPackageElements( fromPackage, fromLister, RM_Matrix.from.packageRecursion );

         if (createWordDoc.abortCreationThread)
            return;

         // Scan the toPackage to find all the "to elements".
         Main.WriteOutput("   Finding elements in toPackage", -1);
         ElementAccumulator toLister = new ElementAccumulator(RM_Matrix.to.elementTypes);
         EA_Utilities.findAndProcessPackageElements( toPackage, toLister, RM_Matrix.to.packageRecursion );

         if (createWordDoc.abortCreationThread)
            return;

         // Sort the "from elements"
         Main.WriteOutput("   Sorting elements in fromPackage", -1);
         if (RM_Matrix.from.reqTagSort)
         {
            elementSortByTAG sorter = new elementSortByTAG();
            fromLister.Elements.Sort( sorter );
         }
         else
         {
            elementSortByName sorter = new elementSortByName();
            fromLister.Elements.Sort( sorter );
         }

         // Sort the "to" elements
         Main.WriteOutput("   Sorting elements in toPackage", -1);
         if (RM_Matrix.to.reqTagSort)
         {
            elementSortByTAG sorter = new elementSortByTAG();
            toLister.Elements.Sort( sorter );
         }
         else
         {
            elementSortByName sorter = new elementSortByName();
            toLister.Elements.Sort( sorter );
         }

         if (createWordDoc.abortCreationThread)
            return;

         // dictionary to support from-to table construction.
         ArrayList fromToDictionary = new ArrayList();

         // dictionary to support to-from table construction.
         ArrayList toFromDictionary = new ArrayList();
         
         bool needFromToTable = false;
         if (RM_Matrix.fromToTable.title != null && RM_Matrix.fromToTable.title.Length > 0)
            needFromToTable = true;

         bool needToFromTable = false;
         if (RM_Matrix.toFromTable.title != null && RM_Matrix.toFromTable.title.Length > 0)
            needToFromTable = true;

         // NOTE: this code has to execute even if no from-to table is needed, in order to support the
         // generation of a to-from table, assuming the user has requested one.
         int numberOfFromToRows = 0;

         Main.WriteOutput("   Creating from-to Dictionary", -1);
         
         foreach(EA.Element fromElement in fromLister.Elements)
         {
            if (createWordDoc.abortCreationThread)
               return;

            // look at the elements connection collection to find references to the
            // destination elements
            bool foundToElement = false;

            EA.Collection conCollection = fromElement.Connectors;
            
            foreach (EA.Connector thisCon in conCollection)
            {
               if (createWordDoc.abortCreationThread)
                  return;

               EA.Element destE = Main.EA_Repository.GetElementByID( thisCon.SupplierID );
               if (destE == null)
                  continue;

               // ignore self-referential connections
               if (fromElement.ElementID == thisCon.SupplierID)
                  continue;

               // if the destination element is of a type that the user has requested to include...
               if (!RM_Matrix.to.elementTypes.Contains( destE.Type ))
                  continue;

               // if the destination element is in the "to list"...
               if ( !toLister.ElementIds.Contains(destE.ElementID) )
                  continue;

               // Capture the from-to relationship in a dictionary where the key is the
               // "from element", and the value is the "to element".
               DictionaryEntry newFromToEntry = new DictionaryEntry(fromElement, destE);
               fromToDictionary.Add( newFromToEntry );
               foundToElement = true;

               // Capture the from-to relationship in a dictionary where the key is the
               // ID of the destination element, and the value is the from element name.
               // This dictionary will enable rapid construction of the to-from table if
               // the user has requested it, from the exact same relationship info used
               // to construct the from-to table.
               if (needToFromTable)
               {
                  DictionaryEntry newToFromEntry = new DictionaryEntry(destE.ElementID, fromElement.Name);
                  toFromDictionary.Add( newToFromEntry );
               }
            }

            // If we found a from-to relationship that table needs a new row.
            if (foundToElement)
            {
               numberOfFromToRows++;
            }
               // If we did not find a from-to relationship that table still needs a new row 
               // if the user wants all "from elements", even if some have no "to elements".
            else if (RM_Matrix.from.packageTrimming == false)
            {
               DictionaryEntry newFromToEntry = new DictionaryEntry(fromElement, null);
               fromToDictionary.Add( newFromToEntry );
               numberOfFromToRows++;
            }
         }
         
         if (createWordDoc.abortCreationThread)
            return;

         if (needFromToTable)
         {
            // Now we can actually serialise the table

            Main.WriteOutput("   Creating from-to table", -1);

            if (RM_Matrix.fromToTable.introText != null && RM_Matrix.fromToTable.introText.Length > 0)
            {
               Range wr = TextualContent.appendAndSelectText( RM_Matrix.fromToTable.introText, EA_Constants.styleName_Body1 );
               object obj = string.Format("EA_DocGen Informational Comment - This table has been produced using the following options:\n\n{0}", RM_Element.Notes);
               createWordDoc.WordDocument.Comments.Add(wr, ref obj);
            }

            // create the from-to table in the word doc
            tableNum = TabularContent.Table_Create( RM_Matrix.fromToTable.title, true, numberOfFromToRows + 1, 2 );
            table = createWordDoc.WordDocument.Tables[tableNum];
            
            TabularContent.Table_SetTableColumnTitle(table, RM_Matrix.from.columnTitle, 1);
            TabularContent.Table_SetTableColumnTitle(table, RM_Matrix.to.columnTitle, 2);

            fillInTable(fromToDictionary, table, DictionaryValueType.DVT_EA_ELEMENT);
         }

         if (createWordDoc.abortCreationThread)
            return;

         // Does user want a to-from table ?
         if (needToFromTable)
         {
            Main.WriteOutput("   Creating to-from Dictionary", -1);

            // update fromElementNotes with toElementNotes setting
            RM_Matrix.from.elementNotes = RM_Matrix.to.elementNotes;

            // re-use the fromToDictionary to prepare the to-from table content 
            fromToDictionary.Clear();

            // We've already found all elements for the left hand column of the to-from table.
            // They are stored in the toLister

            if (createWordDoc.abortCreationThread)
               return;

            // To make the to-from table, we use the dictionary that was built when making the from-to
            // table. The dictionary will allow rapid determination of what "from" items belong to each
            // "to" item, without us having to go back to EA and enquire on the database.
            // We build a new fromToDictionary from the toFromDictionary, in advance of actually making 
            // the table so that we can figure out how many rows the table needs to have.
            numberOfFromToRows = 0;
            
            foreach(EA.Element toElement in toLister.Elements)
            {
               if (createWordDoc.abortCreationThread)
                  return;

               bool foundToElement = false;

               // right-column cell content
               foreach (DictionaryEntry de in toFromDictionary)
               {
                  if ((int)de.Key == toElement.ElementID)
                  {
                     DictionaryEntry newFromToEntry = new DictionaryEntry(toElement, (string)de.Value);
                     fromToDictionary.Add( newFromToEntry );
                     foundToElement = true;
                  }
               }

               if (createWordDoc.abortCreationThread)
                  return;

               // If we found a from-to relationship that table needs a new row.
               if (foundToElement)
               {
                  numberOfFromToRows++;
               }
                  // if user wants all "from elements", even if some have no "to elements", then add a dictionary
                  // entry and bump row count.
               else if (RM_Matrix.to.packageTrimming == false)
               {
                  DictionaryEntry newFromToEntry = new DictionaryEntry(toElement, "");
                  fromToDictionary.Add( newFromToEntry );
                  numberOfFromToRows++;
               }
            }

            if (createWordDoc.abortCreationThread)
               return;

            // Now begin to add the to-from table to the word document
            Main.WriteOutput("   Creating to-from table", -1);

            if (RM_Matrix.toFromTable.introText != null && RM_Matrix.toFromTable.introText.Length > 0)
            {
               Range wr = TextualContent.appendAndSelectText( RM_Matrix.toFromTable.introText, EA_Constants.styleName_Body1 );

               // add options comment only if user did not generate a from-to table, since there is no point in repeating
               // the options comment which applies to both from-to and to-from table pair.
               if (!needFromToTable)
               {
                  object obj = string.Format("EA_DocGen Informational Comment - This table has been produced using the following options:\n\n{0}", RM_Element.Notes);
                  createWordDoc.WordDocument.Comments.Add(wr, ref obj);
               }
            }

            // create the table in the word doc
            tableNum = TabularContent.Table_Create( RM_Matrix.toFromTable.title, true, numberOfFromToRows + 1, 2 );
            table = createWordDoc.WordDocument.Tables[tableNum];
            
            TabularContent.Table_SetTableColumnTitle(table, RM_Matrix.to.columnTitle, 1);
            TabularContent.Table_SetTableColumnTitle(table, RM_Matrix.from.columnTitle, 2);
 
            fillInTable(fromToDictionary, table, DictionaryValueType.DVT_STRING);
         }
      }


        private static void fillInTable(ArrayList fromToDictionary, Table table, DictionaryValueType valueType)
      {
         int lastFromElementId = -1;
         bool firstCellContent = true;
         int row = 1;
         foreach (DictionaryEntry de in fromToDictionary)
         {
            if (createWordDoc.abortCreationThread)
               return;

            if ( ((EA.Element)de.Key).ElementID != lastFromElementId )
            {
               lastFromElementId = ((EA.Element)de.Key).ElementID;
               row++;
               table.Cell(row,1).Range.Text = ((EA.Element)de.Key).Name;
               firstCellContent = true;

               if (RM_Matrix.from.elementNotes)
               {
                  if (((EA.Element)de.Key).Notes != null && ((EA.Element)de.Key).Notes.Length > 0)
                  {
                     table.Cell(row,1).Range.Text += ((EA.Element)de.Key).Notes;
                  }
                  // Because we are including both the short description and the notes of the requirement
                  // in the cell, we need to discriminate them. We do this by bolding the short description,
                  // and reducing the font size of the notes to 8.
                  Range wr = table.Cell(row,1).Range;
                  wr.Sentences[1].Font.Bold = 1;
                  for(int i=2; i<=wr.Sentences.Count; i++)
                     wr.Sentences[i].Font.Size = 8;
               }
            }

            if ((valueType == DictionaryValueType.DVT_EA_ELEMENT) && (((EA.Element)de.Value) != null))
            {
               if (firstCellContent)
               {
                  firstCellContent = false;
                  table.Cell(row,2).Range.Text = ((EA.Element)de.Value).Name;
               }
               else
               {
                  table.Cell(row,2).Range.Text += ((EA.Element)de.Value).Name;
               }
            }
            else if ((valueType == DictionaryValueType.DVT_STRING) && (((string)de.Value).Length > 0))
            {
               if (firstCellContent)
               {
                  firstCellContent = false;
                  table.Cell(row,2).Range.Text = (string)de.Value;
               }
               else
               {
                  table.Cell(row,2).Range.Text += (string)de.Value;
               }
            }
            else
            {
               if (EA_DocGenOptions.optionValue(EA_DocGenOptions.boolean_options_e.SUPPRESS_UN_ALLOCATED_RELATIONSHIP_WARNINGS) == false)
               {
                  table.Cell(row,2).Range.Text = "Un-allocated relationship!";
                  table.Cell(row,2).Range.Font.Color = WdColor.wdColorRed;
               }
            }
         }
      }
 

      /// <summary>
      /// This function will insert a relationship matrix table into the document, built from content
      /// specified in options that are provided in the notes section of the special element that
      /// has led to this function being called.
      /// 
      /// The style of this single table is that required for requirement to requirement traceability.
      /// Here, only a single table is generated, and the only elements in the left hand column will
      /// be those serialised to the document earlier on, and the content of the right hand column
      /// will be the parental requirements (all the way up to root requirements).
      /// </summary>
      /// <param name="EA_RelMatrix"></param>
      private static void processRelationshipMatrixElementStyle2()
      {
         int i;
         int tableNum = 0;
         Table table = null;

         // Scan the fromPackage to find all the "from elements".
         Main.WriteOutput("   Finding elements in fromPackage", -1);

         ElementAccumulator fromLister = new ElementAccumulator(RM_Matrix.from.elementTypes);
         EA_Utilities.findAndProcessPackageElements( fromPackage, fromLister, RM_Matrix.from.packageRecursion );

         if (createWordDoc.abortCreationThread)
            return;

         // Remove all elements from the list that did not go to form content in the document
         // prior to this point in the document generation process.
         for (i=0; i<fromLister.Elements.Count; )
         {
            if (createWordDoc.abortCreationThread)
               return;

            if ( !processedElements.Contains( ((EA.Element)fromLister.Elements[i]).ElementID ) )
            {
               fromLister.Elements.RemoveAt(i);
               continue;
            }
            i++;
         }

         if (createWordDoc.abortCreationThread)
            return;

         // Sort the remaining "from elements"
         Main.WriteOutput("   Sorting elements in fromPackage", -1);

         if (RM_Matrix.from.reqTagSort)
         {
            elementSortByTAG sorter = new elementSortByTAG();
            fromLister.Elements.Sort( sorter );
         }
         else
         {
            elementSortByName sorter = new elementSortByName();
            fromLister.Elements.Sort( sorter );
         }

         if (createWordDoc.abortCreationThread)
            return;

         // Scan the toPackage to find all the "to elements".
         // Extract their element IDs into a new list.
         Main.WriteOutput("   Finding elements in toPackage", -1);

         ElementAccumulator toLister = new ElementAccumulator(RM_Matrix.to.elementTypes);
         EA_Utilities.findAndProcessPackageElements( toPackage, toLister, RM_Matrix.to.packageRecursion );
         ArrayList acceptableParents = new ArrayList();
         foreach(EA.Element ele in toLister.Elements)
         {
            if (createWordDoc.abortCreationThread)
               return;

            acceptableParents.Add( ele.ElementID);
         }

         if (createWordDoc.abortCreationThread)
            return;

         // The list of from elements dictates the number of rows in our table.
         int numberOfFromToRows = fromLister.Elements.Count;
         
         Main.WriteOutput("   Creating from-to table", -1);

         if (RM_Matrix.fromToTable.introText != null && RM_Matrix.fromToTable.introText.Length > 0)
         {
            Range wr = TextualContent.appendAndSelectText( RM_Matrix.fromToTable.introText, EA_Constants.styleName_Body1 );
            object obj = string.Format("EA_DocGen Informational Comment - This table has been produced using the following options:\n\n{0}", RM_Element.Notes);
            createWordDoc.WordDocument.Comments.Add(wr, ref obj);
         }

         // create the from-to table in the word doc
         tableNum = TabularContent.Table_Create( RM_Matrix.fromToTable.title, true, numberOfFromToRows + 1, 2 );
         table = createWordDoc.WordDocument.Tables[tableNum];
            
         TabularContent.Table_SetTableColumnTitle(table, RM_Matrix.from.columnTitle, 1);
         TabularContent.Table_SetTableColumnTitle(table, RM_Matrix.to.columnTitle, 2);

         int row = 2;
         foreach(EA.Element ele in fromLister.Elements)
         {
            if (createWordDoc.abortCreationThread)
               return;

            table.Cell(row,1).Range.Text = ele.Name;

            if (RM_Matrix.from.elementNotes && ele.Notes != null && ele.Notes.Length > 0)
            {
               table.Cell(row,1).Range.Text += ele.Notes;
            }

            StringBuilder sb = new StringBuilder();

            ArrayList parentsDiscovered = new ArrayList();

            // Find this requirement's parent (source) requirements
            elementParenthood(ele, ref acceptableParents, ref parentsDiscovered, ref sb);

            // if no source requirements found and user has opted for trimming, delete the table row
            if (RM_Matrix.from.packageTrimming == true && sb.Length == 0)
            {
               TabularContent.Table_DeleteThisRow(table, row);
               continue;
            }
            
            // fill in the right hand cell on this row of the table with the source requirement list
            table.Cell(row,2).Range.Text = sb.ToString();
            row++;
         }

      }


      private static void elementParenthood(EA.Element ele, ref ArrayList acceptableParents, ref ArrayList parentsDiscovered, ref StringBuilder sb)
      {
         foreach(EA.Connector con in ele.Connectors)
         {
            if (createWordDoc.abortCreationThread)
               return;

            // ignore downwards direction, indicated by the client ID being equal to the element ID
            if (con.ClientID != ele.ElementID)
            {
               // if we have not already come across this upward path before...
               if (!parentsDiscovered.Contains(con.ClientID))
               {
                  parentsDiscovered.Add(con.ClientID);

                  // if this parent is in the list of acceptable parents...
                  if (acceptableParents.Contains(con.ClientID))
                  {
                     // get the parent element, add its name to our list, and ascend through the element
                     // using recursion.
                     EA.Element client = Main.EA_Repository.GetElementByID(con.ClientID);
                     if (client != null)
                     {
                        if (sb.Length > 0)
                           sb.Append("\n");
                        sb.Append(client.Name);

                        elementParenthood(client, ref acceptableParents, ref parentsDiscovered, ref sb);
                     }
                  }
               }
            }
         }
      }

        }
}