Blame | Last modification | View Log | RSS feed
using System;using System.Windows.Forms;using System.Collections;using System.IO;namespace EA_ReqPro{/// <summary>/// The EA_ElementSorter class has been created to allow an element collection belonging to a/// package to be sorted and traversed in the order implied by the view of those elements/// in the project browser. This is needed since the ordering of elements in the collections/// does not seem to match that of the project browser. Furthermore, an element can be in more/// than one collection, because elements themselves can have sub-elements and associated/// collections yet such sub-elements also appear in the parent package collection. Confusing?/// Until Sparx Systems changes the way it organises elements, we need to use this class to/// sort them and traverse them, unfortunately./// </summary>public class EA_ElementSorter{private ArrayList sorted_elements;private ArrayList sorted_element_levels;private int i_sorted_elements;public EA_ElementSorter(EA.Package thePackage){i_sorted_elements = 0;sorted_elements = new ArrayList();sorted_element_levels = new ArrayList();sortElements(thePackage); // this is where most of the work is done}/// <summary>/// Return the first element in the sorted and flattened list of EA elements/// </summary>/// <param name="theElement"></param>/// <param name="recurse_level"></param>/// <returns></returns>public bool getFirst(ref EA.Element theElement, ref int recurse_level){i_sorted_elements = 0;if (i_sorted_elements < sorted_elements.Count){theElement = (EA.Element)sorted_elements[i_sorted_elements];recurse_level = (int)sorted_element_levels[i_sorted_elements];return true;}return false;}/// <summary>/// Return the next element in the sorted and flattened list of EA elements/// </summary>/// <param name="theElement"></param>/// <param name="recurse_level"></param>/// <returns></returns>public bool getNext(ref EA.Element theElement, ref int recurse_level){i_sorted_elements++;if (i_sorted_elements < sorted_elements.Count){theElement = (EA.Element)sorted_elements[i_sorted_elements];recurse_level = (int)sorted_element_levels[i_sorted_elements];return true;}return false;}/// <summary>/// This function sorts elements that belong to a package so that they can be traversed/// in the order in which they appear in the project browser. This is necessary because/// the order in which the elements are encountered when parsing the database, bears little/// relationship to the order seen in the browser, and things get considerably more/// complicated if elements have sub-elements in the browser, because it seems that due to/// EA's internal organisation of collections, the sub-elements can be encountered more/// than once./// This method creates an object hierarchy using the EA_ElementWrapper class and then/// traverses it to flatten it out into a sorted array list of elements./// </summary>/// <param name="thePackage"></param>/// <returns></returns>private void sortElements(EA.Package thePackage){// Grab a hold of all the elements under this package. This will include sub-elements to elements// because even those sub-elements still belong to this package and its element collection.ArrayList unsorted_elements = new ArrayList();foreach(EA.Element theElement in thePackage.Elements){unsorted_elements.Add(theElement);}// Begin to build a hierarchical representation of the elements, first by getting all the elements// that do not have a ParentID (ie. elements that are not themselves sub-elements of other elements).ArrayList element_wrappers = new ArrayList();int i;for (i = 0; i < unsorted_elements.Count; ){object obj = unsorted_elements[i];if ( ((EA.Element)obj).ParentID == 0 ){EA_ElementWrapper element_wrapper = new EA_ElementWrapper( (EA.Element)obj );element_wrappers.Add( element_wrapper );unsorted_elements.RemoveAt(i);continue;}i++;}// Now go through the remaining elements (if any), which will all be sub-elements of other elements// in order to pull them out of the unsorted list and place them at the correct place in the// element hierarchy. Multiple passes of this will ensure that the unsorted element list is// eventually exhausted, but nevertheless, we protect against an infinite loop condition anyway.int lastCount = -1; // variable to ensure loop is not infinitewhile (unsorted_elements.Count > 0 && lastCount != unsorted_elements.Count){lastCount = unsorted_elements.Count;// Attempt to extract more unsorted elements and add them to the hiearchically sorted datafor (i = 0; i < unsorted_elements.Count; ){object obj = unsorted_elements[i];// Try and find the correct place in the hiearchy where this unsorted element can be appended.EA_ElementWrapper found_element_wrapper = null;foreach(EA_ElementWrapper element_wrapper in element_wrappers){found_element_wrapper = findElementWrapper(element_wrapper, ((EA.Element)obj).ParentID );if (found_element_wrapper != null)break;}// If we found the correct place in the hierarchy, append it, and remove it from the// unsorted element list.if (found_element_wrapper != null){EA_ElementWrapper element_wrapper = new EA_ElementWrapper( (EA.Element)obj );found_element_wrapper.sub_elements.Add( element_wrapper );unsorted_elements.RemoveAt(i);continue;}i++;}}// TODO// What should we do if unsorted_elements.Count is still > 0?// Now flatten the hierarchically sorted results into a simple ArrayList.foreach(EA_ElementWrapper element_wrapper in element_wrappers){parseElementWrapperForFlattening( element_wrapper, 0 );}}/// <summary>/// A recursive EA_ElementWrapper parser that builds a flattened list of EA elements/// </summary>/// <param name="element_wrapper"></param>/// <param name="recurse_level"></param>private void parseElementWrapperForFlattening(EA_ElementWrapper element_wrapper, int recurse_level){sorted_elements.Add(element_wrapper.m_element);sorted_element_levels.Add(recurse_level);foreach(object obj in element_wrapper.sub_elements){parseElementWrapperForFlattening( (EA_ElementWrapper)obj, recurse_level+1 );}}/// <summary>/// A recursive EA_ElementWrapper parser, that matches an object to a specified elementId/// </summary>/// <param name="thisElementWrapper"></param>/// <param name="elementId"></param>/// <returns></returns>private EA_ElementWrapper findElementWrapper(EA_ElementWrapper thisElementWrapper, int elementId){// If this element wrapper itself is the target, then return itif (thisElementWrapper.m_element.ElementID == elementId){return thisElementWrapper;}// otherwise, look through all this element's sub-elements, and each sub-element's sub-elements, etc, etcforeach (object obj in thisElementWrapper.sub_elements){EA_ElementWrapper found = findElementWrapper( (EA_ElementWrapper)obj, elementId );if (found != null)return found;}return null;}}/// <summary>/// A wrapper class for an EA element that allows that element to be the holder of a collection/// of sub-elements. This allows us to build a hierarchical structure of elements that mirrors/// the structure (aka. indentation) of elements as seen in the project browser, where elements/// are implied to be sub-elements to other elements etc./// </summary>public class EA_ElementWrapper{public EA.Element m_element;public ArrayList sub_elements;public EA_ElementWrapper(EA.Element element){m_element = element;sub_elements = new ArrayList();}}}