Subversion Repositories DevTools

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2141 ghuddy 1
using System;
2
using System.Windows.Forms;
3
using System.Collections;
4
using System.IO;
5
 
6
namespace EA_ReqPro
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
}