| 2088 |
ghuddy |
1 |
using System;
|
|
|
2 |
using System.Windows.Forms;
|
|
|
3 |
using System.Collections;
|
|
|
4 |
using System.IO;
|
|
|
5 |
|
|
|
6 |
namespace EA_DocGen
|
|
|
7 |
{
|
|
|
8 |
/// <summary>
|
|
|
9 |
/// The EA_ElementSorter class has been created to allow an element collection belonging to a
|
|
|
10 |
/// package to be sorted and traversed in the order implied by the view of those elements
|
|
|
11 |
/// in the project browser. This is needed since the ordering of elements in the collections
|
|
|
12 |
/// does not seem to match that of the project browser. Furthermore, an element can be in more
|
|
|
13 |
/// than one collection, because elements themselves can have sub-elements and associated
|
|
|
14 |
/// collections yet such sub-elements also appear in the parent package collection. Confusing?
|
|
|
15 |
/// Until Sparx Systems changes the way it organises elements, we need to use this class to
|
|
|
16 |
/// sort them and traverse them, unfortunately.
|
|
|
17 |
/// </summary>
|
|
|
18 |
public class EA_ElementSorter
|
|
|
19 |
{
|
|
|
20 |
private ArrayList sorted_elements;
|
|
|
21 |
private ArrayList sorted_element_levels;
|
|
|
22 |
private int i_sorted_elements;
|
|
|
23 |
|
|
|
24 |
public EA_ElementSorter(EA.Package thePackage)
|
|
|
25 |
{
|
|
|
26 |
i_sorted_elements = 0;
|
|
|
27 |
sorted_elements = new ArrayList();
|
|
|
28 |
sorted_element_levels = new ArrayList();
|
|
|
29 |
|
|
|
30 |
sortElements(thePackage); // this is where most of the work is done
|
|
|
31 |
}
|
|
|
32 |
|
|
|
33 |
/// <summary>
|
|
|
34 |
/// Return the first element in the sorted and flattened list of EA elements
|
|
|
35 |
/// </summary>
|
|
|
36 |
/// <param name="theElement"></param>
|
|
|
37 |
/// <param name="recurse_level"></param>
|
|
|
38 |
/// <returns></returns>
|
|
|
39 |
public bool getFirst(ref EA.Element theElement, ref int recurse_level)
|
|
|
40 |
{
|
|
|
41 |
i_sorted_elements = 0;
|
|
|
42 |
if (i_sorted_elements < sorted_elements.Count)
|
|
|
43 |
{
|
|
|
44 |
theElement = (EA.Element)sorted_elements[i_sorted_elements];
|
|
|
45 |
recurse_level = (int)sorted_element_levels[i_sorted_elements];
|
|
|
46 |
return true;
|
|
|
47 |
}
|
|
|
48 |
return false;
|
|
|
49 |
}
|
|
|
50 |
|
|
|
51 |
/// <summary>
|
|
|
52 |
/// Return the next element in the sorted and flattened list of EA elements
|
|
|
53 |
/// </summary>
|
|
|
54 |
/// <param name="theElement"></param>
|
|
|
55 |
/// <param name="recurse_level"></param>
|
|
|
56 |
/// <returns></returns>
|
|
|
57 |
public bool getNext(ref EA.Element theElement, ref int recurse_level)
|
|
|
58 |
{
|
|
|
59 |
i_sorted_elements++;
|
|
|
60 |
if (i_sorted_elements < sorted_elements.Count)
|
|
|
61 |
{
|
|
|
62 |
theElement = (EA.Element)sorted_elements[i_sorted_elements];
|
|
|
63 |
recurse_level = (int)sorted_element_levels[i_sorted_elements];
|
|
|
64 |
return true;
|
|
|
65 |
}
|
|
|
66 |
return false;
|
|
|
67 |
}
|
|
|
68 |
|
|
|
69 |
|
|
|
70 |
/// <summary>
|
|
|
71 |
/// This function sorts elements that belong to a package so that they can be traversed
|
|
|
72 |
/// in the order in which they appear in the project browser. This is necessary because
|
|
|
73 |
/// the order in which the elements are encountered when parsing the database, bears little
|
|
|
74 |
/// relationship to the order seen in the browser, and things get considerably more
|
|
|
75 |
/// complicated if elements have sub-elements in the browser, because it seems that due to
|
|
|
76 |
/// EA's internal organisation of collections, the sub-elements can be encountered more
|
|
|
77 |
/// than once.
|
|
|
78 |
/// This method creates an object hierarchy using the EA_ElementWrapper class and then
|
|
|
79 |
/// traverses it to flatten it out into a sorted array list of elements.
|
|
|
80 |
/// </summary>
|
|
|
81 |
/// <param name="thePackage"></param>
|
|
|
82 |
/// <returns></returns>
|
|
|
83 |
private void sortElements(EA.Package thePackage)
|
|
|
84 |
{
|
|
|
85 |
// Grab a hold of all the elements under this package. This will include sub-elements to elements
|
|
|
86 |
// because even those sub-elements still belong to this package and its element collection.
|
|
|
87 |
ArrayList unsorted_elements = new ArrayList();
|
|
|
88 |
foreach(EA.Element theElement in thePackage.Elements)
|
|
|
89 |
{
|
|
|
90 |
unsorted_elements.Add(theElement);
|
|
|
91 |
}
|
|
|
92 |
|
|
|
93 |
// Begin to build a hierarchical representation of the elements, first by getting all the elements
|
|
|
94 |
// that do not have a ParentID (ie. elements that are not themselves sub-elements of other elements).
|
|
|
95 |
ArrayList element_wrappers = new ArrayList();
|
|
|
96 |
|
|
|
97 |
int i;
|
|
|
98 |
for (i = 0; i < unsorted_elements.Count; )
|
|
|
99 |
{
|
|
|
100 |
object obj = unsorted_elements[i];
|
|
|
101 |
|
|
|
102 |
if ( ((EA.Element)obj).ParentID == 0 )
|
|
|
103 |
{
|
|
|
104 |
EA_ElementWrapper element_wrapper = new EA_ElementWrapper( (EA.Element)obj );
|
|
|
105 |
element_wrappers.Add( element_wrapper );
|
|
|
106 |
unsorted_elements.RemoveAt(i);
|
|
|
107 |
continue;
|
|
|
108 |
}
|
|
|
109 |
i++;
|
|
|
110 |
}
|
|
|
111 |
|
|
|
112 |
// Now go through the remaining elements (if any), which will all be sub-elements of other elements
|
|
|
113 |
// in order to pull them out of the unsorted list and place them at the correct place in the
|
|
|
114 |
// element hierarchy. Multiple passes of this will ensure that the unsorted element list is
|
|
|
115 |
// eventually exhausted, but nevertheless, we protect against an infinite loop condition anyway.
|
|
|
116 |
int lastCount = -1; // variable to ensure loop is not infinite
|
|
|
117 |
while (unsorted_elements.Count > 0 && lastCount != unsorted_elements.Count)
|
|
|
118 |
{
|
|
|
119 |
lastCount = unsorted_elements.Count;
|
|
|
120 |
|
|
|
121 |
// Attempt to extract more unsorted elements and add them to the hiearchically sorted data
|
|
|
122 |
for (i = 0; i < unsorted_elements.Count; )
|
|
|
123 |
{
|
|
|
124 |
object obj = unsorted_elements[i];
|
|
|
125 |
|
|
|
126 |
// Try and find the correct place in the hiearchy where this unsorted element can be appended.
|
|
|
127 |
EA_ElementWrapper found_element_wrapper = null;
|
|
|
128 |
foreach(EA_ElementWrapper element_wrapper in element_wrappers)
|
|
|
129 |
{
|
|
|
130 |
found_element_wrapper = findElementWrapper(element_wrapper, ((EA.Element)obj).ParentID );
|
|
|
131 |
if (found_element_wrapper != null)
|
|
|
132 |
break;
|
|
|
133 |
}
|
|
|
134 |
|
|
|
135 |
// If we found the correct place in the hierarchy, append it, and remove it from the
|
|
|
136 |
// unsorted element list.
|
|
|
137 |
if (found_element_wrapper != null)
|
|
|
138 |
{
|
|
|
139 |
EA_ElementWrapper element_wrapper = new EA_ElementWrapper( (EA.Element)obj );
|
|
|
140 |
found_element_wrapper.sub_elements.Add( element_wrapper );
|
|
|
141 |
unsorted_elements.RemoveAt(i);
|
|
|
142 |
continue;
|
|
|
143 |
}
|
|
|
144 |
|
|
|
145 |
i++;
|
|
|
146 |
}
|
|
|
147 |
}
|
|
|
148 |
// TODO
|
|
|
149 |
// What should we do if unsorted_elements.Count is still > 0?
|
|
|
150 |
|
|
|
151 |
// Now flatten the hierarchically sorted results into a simple ArrayList.
|
|
|
152 |
foreach(EA_ElementWrapper element_wrapper in element_wrappers)
|
|
|
153 |
{
|
|
|
154 |
parseElementWrapperForFlattening( element_wrapper, 0 );
|
|
|
155 |
}
|
|
|
156 |
}
|
|
|
157 |
|
|
|
158 |
/// <summary>
|
|
|
159 |
/// A recursive EA_ElementWrapper parser that builds a flattened list of EA elements
|
|
|
160 |
/// </summary>
|
|
|
161 |
/// <param name="element_wrapper"></param>
|
|
|
162 |
/// <param name="recurse_level"></param>
|
|
|
163 |
private void parseElementWrapperForFlattening(EA_ElementWrapper element_wrapper, int recurse_level)
|
|
|
164 |
{
|
|
|
165 |
sorted_elements.Add(element_wrapper.m_element);
|
|
|
166 |
sorted_element_levels.Add(recurse_level);
|
|
|
167 |
|
|
|
168 |
foreach(object obj in element_wrapper.sub_elements)
|
|
|
169 |
{
|
|
|
170 |
parseElementWrapperForFlattening( (EA_ElementWrapper)obj, recurse_level+1 );
|
|
|
171 |
}
|
|
|
172 |
}
|
|
|
173 |
|
|
|
174 |
/// <summary>
|
|
|
175 |
/// A recursive EA_ElementWrapper parser, that matches an object to a specified elementId
|
|
|
176 |
/// </summary>
|
|
|
177 |
/// <param name="thisElementWrapper"></param>
|
|
|
178 |
/// <param name="elementId"></param>
|
|
|
179 |
/// <returns></returns>
|
|
|
180 |
private EA_ElementWrapper findElementWrapper(EA_ElementWrapper thisElementWrapper, int elementId)
|
|
|
181 |
{
|
|
|
182 |
// If this element wrapper itself is the target, then return it
|
|
|
183 |
if (thisElementWrapper.m_element.ElementID == elementId)
|
|
|
184 |
{
|
|
|
185 |
return thisElementWrapper;
|
|
|
186 |
}
|
|
|
187 |
|
|
|
188 |
// otherwise, look through all this element's sub-elements, and each sub-element's sub-elements, etc, etc
|
|
|
189 |
foreach (object obj in thisElementWrapper.sub_elements)
|
|
|
190 |
{
|
|
|
191 |
EA_ElementWrapper found = findElementWrapper( (EA_ElementWrapper)obj, elementId );
|
|
|
192 |
if (found != null)
|
|
|
193 |
return found;
|
|
|
194 |
}
|
|
|
195 |
return null;
|
|
|
196 |
}
|
|
|
197 |
|
|
|
198 |
}
|
|
|
199 |
|
|
|
200 |
/// <summary>
|
|
|
201 |
/// A wrapper class for an EA element that allows that element to be the holder of a collection
|
|
|
202 |
/// of sub-elements. This allows us to build a hierarchical structure of elements that mirrors
|
|
|
203 |
/// the structure (aka. indentation) of elements as seen in the project browser, where elements
|
|
|
204 |
/// are implied to be sub-elements to other elements etc.
|
|
|
205 |
/// </summary>
|
|
|
206 |
public class EA_ElementWrapper
|
|
|
207 |
{
|
|
|
208 |
public EA.Element m_element;
|
|
|
209 |
public ArrayList sub_elements;
|
|
|
210 |
|
|
|
211 |
public EA_ElementWrapper(EA.Element element)
|
|
|
212 |
{
|
|
|
213 |
m_element = element;
|
|
|
214 |
sub_elements = new ArrayList();
|
|
|
215 |
}
|
|
|
216 |
}
|
|
|
217 |
}
|