Subversion Repositories DevTools

Rev

Rev 2141 | Rev 2145 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2141 ghuddy 1
using System;
2
using System.Text;
3
using System.Globalization;
4
using System.Collections;
5
using System.Collections.Specialized;
6
using System.Windows.Forms;
7
using ReqPro40;
8
 
9
namespace EA_ReqPro
10
{
11
	/// <summary>
12
	/// Summary description for CopyReqProDatabaseToMemory.
13
	/// </summary>
14
	public class CopyReqProDatabaseToMemory : ReqProParser
15
	{
16
      protected bool allowPackageStructureFragments = false;
17
 
18
      protected EA_Utilities EA_Utils;
19
 
20
      protected ReqPro40.Project RQ_project;
21
 
22
      // Where in an EA database, the copy of the ReqPro database content will be written
23
      protected EA.Package ea_rootPackage;
24
 
25
      // Hierarchy tracking data for the parsing of a ReqPro database
26
      protected Stack rq_objs = new Stack();      // Top of stack indicates current parent package
27
      protected Stack ea_treePos = new Stack();   // Top of stack indicates current tree position reflecting object ordering within the parent package
28
      protected int lastLevel;                    // Allows us to determine if we have gone down/up in the hierarchy
29
 
30
      // Collector for the results of the parsing
31
      protected ReqPro_object rq_root_package;
32
 
33
      protected ArrayList rq_req_types;
34
      protected ArrayList rq_req_status_types;
35
 
36
 
37
      /// <summary>
38
      /// Constructor logic
39
      /// </summary>
40
      /// <param name="ea_repository"></param>
41
		public CopyReqProDatabaseToMemory(EA.Repository ea_repository): base()
42
		{
43
         try
44
         {
45
            // create an EA_Utilities object
46
            EA_Utils = new EA_Utilities(ea_repository);
47
 
48
            // figure out where in the EA database we will place the results of parsing
49
            object o;
50
            EA.ObjectType type;
51
            type = ea_repository.GetTreeSelectedItem(out o);
52
            if (type == EA.ObjectType.otElement)
53
            {
54
               ea_rootPackage = ea_repository.GetPackageByID( ((EA.Element)o).PackageID );
55
            }
56
            else if (type == EA.ObjectType.otPackage)
57
            {
58
               ea_rootPackage = (EA.Package)o;
59
            }
60
            else
61
            {
62
               Exception e = new Exception("No Root Package given");
63
               throw e;
64
            }
65
         }
66
         catch (Exception ex)
67
         {
68
            MessageBox.Show(ex.Message, "Error (CopyReqProDatabaseToMemory::CopyReqProDatabaseToMemory)", MessageBoxButtons.OK);
69
         }    
70
		}
71
 
72
 
73
 
74
      #region Requirement Status Type methods
75
 
76
      /// <summary>
77
      /// Get the requirement status types from the ReqPro database, into a simple list, where each element
78
      /// describes the requirement status type and whether it is filtered or not. This list can be given to 
79
      /// the ReqProFilterForm to capture the users requirement status type filtering decisions. 
80
      /// </summary>
81
      private void get_rq_req_status_types_from_database()
82
      {
83
         StringCollection status_values = new StringCollection();
84
 
85
         // Each requirement type can have its own unique list of status attribute values
86
         // so we have to go through each requirement type and find the set of status values
87
         // that each one has and add them to out string collection, if the collection does
88
         // not already have the strings ofcoarse. So, we are merging together all the status
89
         // values in the ReqPro database, into one set.
90
         ReqPro40.ReqTypes rqtypes = RQ_project.ReqTypes;
91
         foreach (ReqPro40.ReqType rq_type in rqtypes)
92
         {
93
            ReqPro40.Attr attr = rq_type.get_Attr("Status", ReqPro40.enumAttrLookups.eAttrLookups_Label);
94
            foreach (ReqPro40.ListItem listItem in attr.ListItems)
95
            {
96
               if (!status_values.Contains(listItem.Text))
97
               {
98
                  status_values.Add(listItem.Text);
99
               }
100
            }
101
         }
102
 
103
         // With our merged set of status values, create a list of ReqPro_ReqStatus objects.
104
         rq_req_status_types = new ArrayList();
105
         foreach (string s in status_values)
106
         {
107
            ReqPro_ReqStatus new_ReqPro_ReqStatus = new ReqPro_ReqStatus();
108
            new_ReqPro_ReqStatus.filtered = false;
109
            new_ReqPro_ReqStatus.status_value = s;
110
            rq_req_status_types.Add(new_ReqPro_ReqStatus);
111
         }
112
      }
113
 
114
      /// <summary>
115
      /// Examine the requirement status type list to see if the requirement status type of 
116
      /// the specified object has been filtered or not.
117
      /// </summary>
118
      /// <param name="rq_obj"></param>
119
      /// <returns></returns>
120
      protected bool reqStatusTypeIsFiltered(ReqPro_object rq_obj)
121
      {
122
         foreach (ReqPro_ReqStatus rqs in rq_req_status_types)
123
         {
124
            if (0 == rqs.status_value.CompareTo(rq_obj.status))
125
            {
126
               return rqs.filtered;
127
            }
128
         }
129
         return false;
130
      }
131
 
132
      #endregion
133
 
134
      #region Requirement Type methods
135
      /// <summary>
136
      /// Recursively set the requirement type enum in each requirement object read
137
      /// from the ReqPro database. The enum give fast indication of the requirement type.
138
      /// If we didnt do this, each time the requirement type needs to be evaluated, a string 
139
      /// compare needs to be done. Here, we do them all up-front so that down the track a simple
140
      /// integer access is all that is required.
141
      /// </summary>
142
      /// <param name="rq_obj"></param>
143
      private void set_rq_req_types_in_copied_data( ReqPro_object rq_obj )
144
         {
145
            if (rq_obj.isRequirement)
146
            {
147
               int i = 0;
148
               foreach (ReqPro_ReqType req_type in rq_req_types)
149
               {
150
                  if (rq_obj.tag.StartsWith(req_type.prefix))
151
                  {
152
                     rq_obj.tag_enum = i;
153
                  }
154
                  i++;
155
               }
156
            }
157
 
158
            foreach( ReqPro_object sub_obj in rq_obj.ReqPro_objects )
159
            {
160
               // recurse
161
               set_rq_req_types_in_copied_data(sub_obj);
162
            }
163
         }
164
 
165
      /// <summary>
166
      /// Get the requirement types from the ReqPro database, into a simple list, where each element
167
      /// describes the requirement type and whether it is filtered or not. This list can be given to 
168
      /// the ReqProFilterForm to capture the users requirement type filtering decisions. 
169
      /// </summary>
170
      private void get_rq_req_types_from_database()
171
      {
172
         rq_req_types = new ArrayList();
173
 
174
         ReqPro40.ReqTypes rqtypes = RQ_project.ReqTypes;
175
         foreach (ReqPro40.ReqType rq_type in rqtypes)
176
         {
177
            ReqPro_ReqType new_req_type = new ReqPro_ReqType();
178
            new_req_type.name     = rq_type.Name;
179
            new_req_type.prefix   = rq_type.ReqPrefix;
180
            new_req_type.filtered = false;
181
            rq_req_types.Add(new_req_type);
182
         }
183
      }
184
 
185
      /// <summary>
186
      /// Examine the requirement type list to see if the requirement type of the specified object
187
      /// has been filtered or not.
188
      /// </summary>
189
      /// <param name="rq_obj"></param>
190
      /// <returns></returns>
191
      protected bool reqTypeIsFiltered(ReqPro_object rq_obj)
192
      {
193
         return ((ReqPro_ReqType)rq_req_types[rq_obj.tag_enum]).filtered;
194
      }
195
 
196
      #endregion
197
 
198
      #region ReqProParser (base class) overrides
199
      /// <summary>
200
      /// This method is designed to prompt the user to select the ReqPro database file
201
      /// before opening and parsing it. Once parsed, the user is offered a chance to setup
202
      /// the filter controls.
203
      /// </summary>
204
      /// <param name="ea_repository"></param>
205
      /// <returns></returns>
206
      public override bool prompt_and_parse(EA.Repository ea_repository)
207
      {
208
         try
209
         {
210
            pre_parsing();
211
            if (true == base.prompt_and_parse(ea_repository))
212
            {
213
               // obtain the requirement types from the reqpro database (need these for
214
               // the filter dialog)
215
               get_rq_req_types_from_database();
216
               set_rq_req_types_in_copied_data(rq_root_package);
217
 
218
               get_rq_req_status_types_from_database();
219
 
220
               // bring up the filter dialog to allow user to specify exactly what gets copied
221
               ReqProFilterForm rq_filter = new ReqProFilterForm();
222
               rq_filter.populate(rq_root_package, rq_req_types, rq_req_status_types);
223
               DialogResult dlgRes = rq_filter.ShowDialog();
224
               if (dlgRes == DialogResult.OK)
225
               {
226
                  allowPackageStructureFragments = rq_filter.allowPackageStructureFragments;
227
                  RQ_project.CloseProject();
228
                  return true;
229
               }
230
               RQ_project.CloseProject();
231
            }
232
         }
233
         catch (Exception ex)
234
         {
235
            MessageBox.Show(ex.Message, "Error (CopyReqProDatabaseToMemory::parse)", MessageBoxButtons.OK);
236
         }      
237
         return false;
238
      }
239
 
240
 
241
      /// <summary>
242
      /// This method is designed to make use of a ReqProDB artifact to indicate the ReqPro
243
      /// database to open and parse. Once parsed, the user is offered a chance to setup
244
      /// the filter controls.
245
      /// </summary>
246
      /// <param name="ea_repository"></param>
247
      /// <returns></returns>
248
      public override bool parse(EA.Repository ea_repository)
249
      {
250
         try
251
         {
252
            pre_parsing();
253
            if (true == base.parse(ea_repository))
254
            {
255
               // obtain the requirement types from the reqpro database (need these for
256
               // the filter dialog)
257
               get_rq_req_types_from_database();
258
               set_rq_req_types_in_copied_data(rq_root_package);
259
 
260
               get_rq_req_status_types_from_database();
261
 
262
               // bring up the filter dialog to allow user to specify exactly what gets copied
263
               ReqProFilterForm rq_filter = new ReqProFilterForm();
264
               rq_filter.populate(rq_root_package, rq_req_types, rq_req_status_types);
265
               DialogResult dlgRes = rq_filter.ShowDialog();
266
               if (dlgRes == DialogResult.OK)
267
               {
268
                  allowPackageStructureFragments = rq_filter.allowPackageStructureFragments;
269
                  RQ_project.CloseProject();
270
                  return true;
271
               }
272
               RQ_project.CloseProject();
273
            }
274
         }
275
         catch (Exception ex)
276
         {
277
            MessageBox.Show(ex.Message, "Error (CopyReqProDatabaseToMemory::parse)", MessageBoxButtons.OK);
278
         }      
279
         return false;
280
      }
281
 
282
 
283
      /// <summary>
284
      /// This method will be called by the base class parser when it has obtained a ReqPro
285
      /// project object. We capture that object here so we can interrogate the ReqPro database
286
      /// ourselves, if we need to. We wont do that for package/requirement reading, but we may
287
      /// do it for meta-data such as requirement types, etc.
288
      /// </summary>
289
      /// <param name="reqpro_project"></param>
290
      protected override void provideReqProDatabaseInfo(ReqPro40.Project rq_project)
291
      {
292
         RQ_project = rq_project;
293
      }
294
 
295
      /// <summary>
296
      /// This method will be called by the base class parser whenever a package or requirement object
297
      /// is found in the ReqPro database. The method collects important information from the object 
298
      /// into a structure that begins with the ea_rootPackage object. The structure is highly dynamic
299
      /// with each object able to hold a list of other objects. This naturally allows for the ReqPro
300
      /// database hierarchy to be accurately reflected. The hierarchy tracking data maintained within
301
      /// the method allows us to know what object in the structure to hang off any new object derived
302
      /// from info given to us by the base class parser (ie. what object is the parent object at the
303
      /// present time during the parsing).
304
      /// </summary>
305
      /// <param name="level"></param>
306
      /// <param name="ea_repository"></param>
307
      /// <param name="rq_project"></param>
308
      /// <param name="rq_package"></param>
309
      /// <param name="rq_requirement"></param>
310
      protected override void processObject(int level,
311
                                            EA.Repository ea_repository, 
312
                                            ReqPro40.Project rq_project, 
313
                                            ReqPro40.Package rq_package,
314
                                            ReqPro40.Requirement rq_requirement)
315
      {
316
         // If we are still at the same level as the previous package, then pop the previous object 
317
         // in readiness for pushing the one we are now dealing with.
318
         if (level == lastLevel)
319
         {
320
            rq_objs.Pop();
321
            ea_treePos.Pop();
322
         }
323
            // but if we are beneath the previous level, pop all objects that are above us because
324
            // we no longer need them in our hierarchy reference data.
325
         else if (level < lastLevel)
326
         {
327
            while (lastLevel >= level)
328
            {
329
               rq_objs.Pop();
330
               ea_treePos.Pop();
331
               lastLevel--;
332
            }
333
         }
334
 
335
         // bump the tree position at this level (controls display position in the EA project browser)
336
         int treePos = (int)ea_treePos.Pop();
337
         treePos++;
338
         ea_treePos.Push(treePos);
339
 
340
         // create the new requirement or package
341
         ReqPro_object new_rq_obj = new ReqPro_object();
342
         if (rq_requirement != null)
343
         {
344
            new_rq_obj.isRequirement = true;
345
            new_rq_obj.name   = rq_requirement.Name;
346
            new_rq_obj.text   = rq_requirement.Text;
347
            new_rq_obj.guid   = rq_requirement.GUID;
348
            new_rq_obj.tag    = rq_requirement.get_Tag(ReqPro40.enumTagFormat.eTagFormat_FullTag);
349
 
350
            new_rq_obj.status     = rq_requirement.AttrValues["Status", ReqPro40.enumAttrValueLookups.eAttrValueLookup_Label].Text;
351
            new_rq_obj.difficulty = rq_requirement.AttrValues["Difficulty", ReqPro40.enumAttrValueLookups.eAttrValueLookup_Label].Text;
352
            new_rq_obj.priority   = rq_requirement.AttrValues["Priority", ReqPro40.enumAttrValueLookups.eAttrValueLookup_Label].Text;
353
            new_rq_obj.version    = rq_requirement.VersionNumber;
354
            new_rq_obj.versionDateTime = rq_requirement.VersionDateTime;
2143 ghuddy 355
 
356
 
357
            // requirements can trace to other requirements, so we have to find those in order to re-construct
358
            // that traceability later on. Currently, we only process TracesTo relationships from ReqPro.
359
            int limit_numberOfTracesTo = 0;
360
            if (true == rq_requirement.get_HasTracesTo(ref limit_numberOfTracesTo))
361
            {
362
               // scan through the TracesTo relationships
363
               ReqPro40.Relationships theseRelationships = (ReqPro40.Relationships)rq_requirement.TracesTo;
364
 
365
               int i_numberOfTracesTo;
366
               theseRelationships.MoveFirst();
367
               for (i_numberOfTracesTo = 0; i_numberOfTracesTo < limit_numberOfTracesTo; i_numberOfTracesTo++)
368
               {
369
                  // Obtain the traced-to requirement from the relationship, and parse it
370
                  ReqPro40.Relationship thisRelationship = theseRelationships.GetCurrentRelationship();
371
 
372
                  ReqPro40.Requirement tracedToRequirement = 
373
                     thisRelationship.get_DestinationRequirement(ReqPro40.enumRequirementsWeights.eReqWeight_Heavy);
374
 
375
                  if (tracedToRequirement != null)
376
                  {
377
                     // Add the GUID of the traced-to requirement to the relevant list within the
378
                     // object representing the traced-from requirement (ie. parent requirement).
379
                     new_rq_obj.ReqPro_traces.Add(tracedToRequirement.GUID);
380
                  }
381
 
382
                  theseRelationships.MoveNext();
383
               }
384
            }
385
 
2141 ghuddy 386
         }
387
         else if (rq_package != null)
388
         {
389
            new_rq_obj.isPackage = true;
390
 
391
            // Packages in ReqPro may be prefixed by a number to force ReqPro's alphanumeric sorting
392
            // algorithm to order the packages in the way the user wants, as dictated by the actual 
393
            // numbers used. EA does not have this problem because it uses a tree position number to
394
            // control a package/element's position in the project browser. So, strip off any leading
395
            // numeric from the ReqPro packages.
396
            string trimstring = " 0123456789";
397
            char[] trimmer = trimstring.ToCharArray();
398
            string filtered_name = rq_package.Name.TrimStart(trimmer);
399
 
400
            new_rq_obj.name = filtered_name;
401
            new_rq_obj.guid = rq_package.GUID;
402
         }
403
 
404
         new_rq_obj.level = level;
405
         new_rq_obj.treePos = treePos;
406
 
407
         // attach it to its parent object
408
         ReqPro_object parent_rq_obj = (ReqPro_object)rq_objs.Peek();
409
         parent_rq_obj.ReqPro_objects.Add( new_rq_obj );
2143 ghuddy 410
         new_rq_obj.parent = parent_rq_obj;
2141 ghuddy 411
 
412
         // keep a count of the number of requirements the object has beneath it
413
         if (true == new_rq_obj.isRequirement)
414
            parent_rq_obj.numberOfRequirements++;
415
 
416
         // push the new object onto the stack, ready for any sub-objects that may belong to it.
417
         // If, the next time we enter this method, the level is the same, this will get popped off.
418
         // If, the next time we enter this method, the level is lower, this and possibly more will
419
         // get popped off.
420
         rq_objs.Push(new_rq_obj);
421
         ea_treePos.Push(0);
422
 
423
         // capture what the hierarchy level is for the object just processed.
424
         lastLevel = level;
425
      }
426
 
427
      #endregion
428
 
429
 
430
 
431
      /// <summary>
432
      /// A method to contain common pre-parsing steps.
433
      /// </summary>
434
      private void pre_parsing()
435
      {
436
         // create an object to represent the root of the database so that we can collect
437
         // sub-objects (packages or requirements) underneath it.
438
         rq_root_package = new ReqPro_object();
439
         rq_root_package.name = "ROOT";
440
 
441
         // initialise the ReqPro database hierarchy tracking data
442
         rq_objs.Clear();
443
         rq_objs.Push(rq_root_package);
444
         ea_treePos.Clear();
445
         ea_treePos.Push(0);
446
         lastLevel = 0;
447
      }
2143 ghuddy 448
 
449
 
450
 
451
 
2141 ghuddy 452
	}
453
}