Subversion Repositories DevTools

Rev

Rev 2145 | Rev 2153 | 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;
2151 ghuddy 2
using System.Text;
3
using System.Globalization;
4
using System.Collections;
5
using System.Collections.Specialized;
6
using System.Windows.Forms;
2141 ghuddy 7
using ReqPro40;
8
 
9
 
10
namespace EA_ReqPro
11
{
12
	/// <summary>
13
	/// The ReqProParser class encapsulates a parsing algorithm for a ReqPro database
14
	/// designed to pick out packages and requirement elements and to provide that information
15
	/// to a client with sufficient information to allow it to build a model of that ReqPro
16
	/// database content in memory, maintaining the hierarchy and ordering of objects found.
17
	/// </summary>
18
	public class ReqProParser
19
	{
2151 ghuddy 20
      // lists of meta-data in the ReqPro database
21
      protected ArrayList rq_req_types;
22
      protected ArrayList rq_req_status_types;
23
      protected ArrayList delayedMessages;
24
 
25
      // constructor
2141 ghuddy 26
		public ReqProParser()
27
		{
2151 ghuddy 28
         delayedMessages = new ArrayList();
2141 ghuddy 29
		}
30
 
31
      /// <summary>
32
      /// The parser will call this virtual method when it has opened a ReqPro project
33
      /// </summary>
34
      /// <param name="rq_project"></param>
2145 ghuddy 35
      protected virtual void provideReqProDatabaseInfo(ReqPro40.Application rq_app, 
36
         ReqPro40.Project rq_project, 
37
         ReqProDB_Artifact rq_artifact,
38
         EA.Element rq_element)
2141 ghuddy 39
      {
40
      }
41
 
42
      /// <summary>
43
      /// The parser will call this virtual method for every package it finds
44
      /// in the ReqPro database.
45
      /// </summary>
46
      /// <param name="level"></param>
47
      /// <param name="ea_repository"></param>
48
      /// <param name="rq_project"></param>
49
      /// <param name="rq_Package"></param>
2151 ghuddy 50
      protected virtual void processPackage(int level,
51
                                            ReqPro40.Project rq_project, 
2141 ghuddy 52
                                            ReqPro40.Package rq_package)
53
      {
54
      }
55
 
56
      /// <summary>
57
      /// The parser will call this virtual method for every requirement it
58
      /// finds in the ReqPro database.
59
      /// </summary>
60
      /// <param name="level"></param>
61
      /// <param name="ea_repository"></param>
62
      /// <param name="rq_project"></param>
63
      /// <param name="rq_Package"></param>
64
      /// <param name="rq_Requirement"></param>
2151 ghuddy 65
      protected virtual void processRequirement(int level,
66
                                                ReqPro40.Project rq_project, 
2141 ghuddy 67
                                                ReqPro40.Package rq_package,
68
                                                ReqPro40.Requirement rq_requirement)
69
      {
70
      }
71
 
72
      /// <summary>
73
      /// The parser will call this virtual method for every package or requirement it
74
      /// finds in the ReqPro database.
75
      /// </summary>
76
      /// <param name="level"></param>
77
      /// <param name="ea_repository"></param>
78
      /// <param name="rq_project"></param>
79
      /// <param name="rq_Package"></param>
80
      /// <param name="rq_Requirement"></param>
2151 ghuddy 81
      protected virtual void processObject(int level,
82
                                           ReqPro40.Project rq_project, 
2141 ghuddy 83
                                           ReqPro40.Package rq_package,
84
                                           ReqPro40.Requirement rq_requirement)
85
      {
86
      }
87
 
2151 ghuddy 88
      protected void writeDelayedMessages()
89
      {
90
         foreach(string s in delayedMessages)
91
         {
92
            Main.EA_Repository.WriteOutput( Main.GUI_OUTPUT_TAB_NAME, s, -1);
93
         }
94
      }
2141 ghuddy 95
 
2151 ghuddy 96
      #region Requirement Type methods
2141 ghuddy 97
 
98
      /// <summary>
2151 ghuddy 99
      /// Get the requirement types from the ReqPro database, into a simple list, where each element
100
      /// describes the requirement type and whether it is filtered or not. This list can be given to 
101
      /// the ReqProFilterForm to capture the users requirement type filtering decisions. 
102
      /// </summary>
103
      protected void get_rq_req_types_from_database(ReqPro40.Project RQ_project)
104
      {
105
         rq_req_types = new ArrayList();
106
 
107
         ReqPro40.ReqTypes rqtypes = RQ_project.ReqTypes;
108
         foreach (ReqPro40.ReqType rq_type in rqtypes)
109
         {
110
            ReqPro_ReqType new_req_type = new ReqPro_ReqType(rq_type);
111
            new_req_type.name     = rq_type.Name;
112
            new_req_type.prefix   = rq_type.ReqPrefix;
113
            rq_req_types.Add(new_req_type);
114
         }
115
      }
116
 
117
      /// <summary>
118
      /// Examine the requirement type list to see if the requirement type of the specified object
119
      /// has been filtered or not.
120
      /// </summary>
121
      /// <param name="rq_obj"></param>
122
      /// <returns></returns>
123
      protected bool reqTypeIsFiltered(ReqPro_object rq_obj)
124
      {
125
         return ((ReqPro_ReqType)rq_req_types[rq_obj.tag_enum]).filtered;
126
      }
127
 
128
      protected bool reqTypeHasOneOrMoreAttrs(ReqPro_object rq_obj, ref bool hasStatus, ref bool hasDiff, ref bool hasPrio)
129
      {
130
         foreach (ReqPro_ReqType rp_rt in rq_req_types)
131
         {
132
            if (rq_obj.tag.StartsWith(rp_rt.prefix))
133
            {
134
               hasStatus = rp_rt.hasStatus;
135
               hasDiff = rp_rt.hasDifficulty;
136
               hasPrio = rp_rt.hasPriority;
137
               return hasStatus | hasDiff | hasPrio;
138
            }
139
         }
140
 
141
         return false;
142
      }
143
 
144
      #endregion
145
 
146
      #region Requirement Status Type methods
147
 
148
      /// <summary>
149
      /// Get the requirement status types from the ReqPro database, into a simple list, where each element
150
      /// describes the requirement status type and whether it is filtered or not. This list can be given to 
151
      /// the ReqProFilterForm to capture the users requirement status type filtering decisions. 
152
      /// </summary>
153
      protected void get_rq_req_status_types_from_database(ReqPro40.Project RQ_project)
154
      {
155
         StringCollection status_values = new StringCollection();
156
 
157
         // Each requirement type can have its own unique list of status attribute values
158
         // so we have to go through each requirement type and find the set of status values
159
         // that each one has and add them to out string collection, if the collection does
160
         // not already have the strings ofcoarse. So, we are merging together all the status
161
         // values in the ReqPro database, into one set.
162
         foreach (ReqPro_ReqType rp_rt in rq_req_types)
163
         {
164
            try 
165
            {
166
               ReqPro40.Attr attr = rp_rt.rq_type.get_Attr("Status", ReqPro40.enumAttrLookups.eAttrLookups_Label);
167
               rp_rt.hasStatus = true;
168
 
169
               foreach (ReqPro40.ListItem listItem in attr.ListItems)
170
               {
171
                  if (!status_values.Contains(listItem.Text))
172
                  {
173
                     status_values.Add(listItem.Text);
174
                  }
175
               }
176
            }
177
            catch 
178
            {
179
               delayedMessages.Add( string.Format("WARNING, ReqPro requirement type ({0}) has no Status attribute", rp_rt.prefix) );
180
            }
181
            // Also check if this requirement type has any of the other attributes we might import. This is
182
            // a little off topic for this function but this is a convenient place to do this until another
183
            // function is written.
184
            try 
185
            {
186
               ReqPro40.Attr attr = rp_rt.rq_type.get_Attr("Difficulty", ReqPro40.enumAttrLookups.eAttrLookups_Label);
187
               rp_rt.hasDifficulty = true;
188
            }
189
            catch 
190
            {
191
               delayedMessages.Add( string.Format("WARNING, ReqPro requirement type ({0}) has no Difficulty attribute", rp_rt.prefix) );
192
            };
193
 
194
            try 
195
            {
196
               ReqPro40.Attr attr = rp_rt.rq_type.get_Attr("Priority", ReqPro40.enumAttrLookups.eAttrLookups_Label);
197
               rp_rt.hasPriority = true;
198
            }
199
            catch 
200
            {
201
               delayedMessages.Add( string.Format("WARNING, ReqPro requirement type ({0}) has no Priority attribute", rp_rt.prefix) );
202
            };
203
         }
204
 
205
         // if reqpro had no status values, then add a dummy one
206
         if (status_values.Count == 0)
207
         {
208
            status_values.Add("Approved");
209
         }
210
 
211
         // With our merged set of status values, create a list of ReqPro_ReqStatus objects.
212
         rq_req_status_types = new ArrayList();
213
         foreach (string s in status_values)
214
         {
215
            ReqPro_ReqStatus new_ReqPro_ReqStatus = new ReqPro_ReqStatus();
216
            new_ReqPro_ReqStatus.filtered = false;
217
            new_ReqPro_ReqStatus.status_value = s;
218
            rq_req_status_types.Add(new_ReqPro_ReqStatus);
219
         }
220
      }
221
 
222
      /// <summary>
223
      /// Examine the requirement status type list to see if the requirement status type of 
224
      /// the specified object has been filtered or not.
225
      /// </summary>
226
      /// <param name="rq_obj"></param>
227
      /// <returns></returns>
228
      protected bool reqStatusTypeIsFiltered(ReqPro_object rq_obj)
229
      {
230
         foreach (ReqPro_ReqStatus rqs in rq_req_status_types)
231
         {
232
            if (0 == rqs.status_value.CompareTo(rq_obj.status))
233
            {
234
               return rqs.filtered;
235
            }
236
         }
237
         return false;
238
      }
239
 
240
      #endregion
241
 
242
 
243
      /// <summary>
2141 ghuddy 244
      /// Initiates a ReqPro database parsing operation using a prompted reqpro database open operation
245
      /// </summary>
246
      /// <param name="ea_repository"></param>
2151 ghuddy 247
      /// <returns></returns>
248
      public virtual bool prompt_and_parse(ReqProDB_Artifact.MODE mode)
2141 ghuddy 249
      {
2145 ghuddy 250
         ReqPro40.Application rq_app = null;
2141 ghuddy 251
         ReqPro40.Project rq_project = null;
252
 
2151 ghuddy 253
         try
254
         {
255
            // If we can find a ReqProDB artifact in the package, use it to logon to the ReqPro database
256
            ReqProDB_Artifact RQ_Artifact = new ReqProDB_Artifact();
257
            EA.Element RQ_Element = RQ_Artifact.get_rq_artifact();
258
            if (RQ_Element != null)
259
            {
260
               // check to see if the ReqProDB element has the same mode as that specified by parameter
261
               ReqProDB_Artifact.MODE rq_art_mode = RQ_Artifact.get_mode(RQ_Element);
262
               if (rq_art_mode != ReqProDB_Artifact.MODE.UNDEFINED)
263
               {
264
                  if (rq_art_mode != mode)
265
                  {
266
                     DialogResult dlgRes = MessageBoxEx.Show("You are attempting to use a ReqProDB element " +
267
                        "for a different purpose than that which was " +
268
                        "specified when the element was first created. " +
269
                        "Continue Anyway?", "Confirm", MessageBoxButtons.YesNo);
270
                     if (dlgRes != DialogResult.Yes)
271
                     {
272
                        return false;
273
                     }
274
                  }
275
               }
276
 
277
               if (Main.mustAbort)
278
                  return false;
279
 
280
               rq_project = RQ_Artifact.OpenReqProProject(RQ_Element);
281
               if (rq_project != null)
282
                  rq_app = RQ_Artifact.RQ_app;
283
            }
284
 
285
            if (Main.mustAbort)
286
               return false;
287
 
288
            // If no ReqProDB artifact found, prompt user to logon to the ReqPro database
289
            if (rq_project == null)
290
            {
291
               // let user select the ReqPro database file name
292
               OpenFileDialog ofd = new OpenFileDialog();
293
               ofd.Title = "Select Requisite Pro project file";
294
               ofd.Filter = "ReqPro files (*.rqs)|*.rqs|All files (*.*)|*.*";
295
               DialogResult dlgRes = ofd.ShowDialog();
296
               if (dlgRes != DialogResult.OK)
297
                  return false;
298
 
299
               if (Main.mustAbort)
300
                  return false;
301
 
302
               // let user specifiy username/password
303
               Logon logon = new Logon("");
304
               dlgRes = logon.ShowDialog();
305
               if (dlgRes != DialogResult.OK)
306
                  return false;
307
 
308
               if (Main.mustAbort)
309
                  return false;
310
 
311
               string username = logon.ebUserName.Text;
312
               string password = logon.ebPassword.Text;
313
 
314
               // Connect to the ReqPro database using the ReqPro extensibility mechanism
315
               rq_app = new ReqPro40.ApplicationClass();
316
 
317
               rq_project = 
318
                  rq_app.OpenProject(ofd.FileName,
319
                  ReqPro40.enumOpenProjectOptions.eOpenProjOpt_RQSFile,
320
                  username,
321
                  password, 
322
                  enumProjectFlags.eProjFlag_Normal,
323
                  enumRelatedProjectOptions.eRelatedProjOption_ConnectAsSpecified);
324
 
325
               if (Main.mustAbort)
326
                  return false;
327
 
328
               // if we do not currently have a ReqProDB artifact, create one
329
               if (RQ_Element == null)
330
               {
331
                  EA_Utilities EA_Utils = new EA_Utilities();
332
 
333
                  RQ_Element = RQ_Artifact.create_rq_artifact(
334
                     EA_Utils.get_selected_package(), 
335
                     rq_project.Name, 
336
                     rq_project.Description, 
337
                     logon.ebUserName.Text, 
338
                     ofd.FileName, 
339
                     rq_project.GUID);
340
               }
341
               if (Main.mustAbort)
342
                  return false;
343
            }
344
 
345
            if (Main.mustAbort)
346
               return false;
347
 
348
            // Now do the parsing of the ReqPro database
349
            if (rq_project != null)
350
            {
2145 ghuddy 351
               // give req pro project object to user of this class
2151 ghuddy 352
               provideReqProDatabaseInfo(rq_app, rq_project, RQ_Artifact, RQ_Element);
353
 
354
               // get the requirement types from the req pro project
355
               get_rq_req_types_from_database(rq_project);
356
 
357
               get_rq_req_status_types_from_database(rq_project);
358
 
359
               // Get the ReqPro root package and parse it
360
               Main.EA_Repository.WriteOutput(Main.GUI_OUTPUT_TAB_NAME, "Acquiring ReqPro Database", -1);
361
               ReqPro40.RootPackage rq_rootPackage = rq_project.GetRootPackage(true);
362
 
363
               parseRootPackage(0, rq_project, rq_rootPackage);
364
 
365
               if (Main.mustAbort)
366
                  return false;
367
 
368
               return true;
369
            }
370
         }
371
         catch (Exception ex)
372
         {
373
            MessageBoxEx.Show(ex.Message, "Error (prompt_and_parse)", MessageBoxButtons.OK);
374
            if (rq_project != null)
375
               rq_project.CloseProject();
2141 ghuddy 376
         }  
377
         return false;
2151 ghuddy 378
      }
379
 
2141 ghuddy 380
      /// <summary>
381
      /// This method handles the parsing of the root package in the ReqPro database.
382
      /// The method is almost identical to the parsePackage method, except that this
383
      /// deals with a ReqPro40.RootPackage object, whereas the latter deals with a
384
      /// ReqPro40.Package object. Perhaps the two functions could be combined into 
385
      /// one if we move to .NET 2 where c# has some support for generic (template)
386
      /// programming.
387
      /// </summary>
388
      /// <param name="repository"></param>
389
      /// <param name="rq_project"></param>
2151 ghuddy 390
      /// <param name="thisPackage"></param>
391
      private void parseRootPackage(int level,
392
                                    ReqPro40.Project rq_project, 
393
                                    ReqPro40.RootPackage thisPackage)
394
      {
395
         // Scan through the sub-packages of the root package
396
         int limit_packageCount = thisPackage.get_Count(ReqPro40.enumElementTypes.eElemType_Package);
397
         if (limit_packageCount > 0)
398
         {
399
            int i_packageCount;
400
            thisPackage.MoveFirst();
401
            for (i_packageCount = 0; i_packageCount < limit_packageCount; i_packageCount++)
402
            {
403
               if (Main.mustAbort)
404
                  break;
405
 
406
               // Read the sub-package and parse it
407
               ReqPro40.Package subPackage = (ReqPro40.Package)thisPackage.GetCurrentElement();
408
               parsePackage(level+1, "", rq_project, subPackage);
409
               thisPackage.MoveNext();
410
            }
411
         }
412
 
413
         if (Main.mustAbort)
414
            return;
415
 
416
         // Scan through the requirements directly beneath the root package
417
         int limit_reqCount = thisPackage.get_Count(ReqPro40.enumElementTypes.eElemType_Requirement);
418
         if (limit_reqCount > 0)
419
         {
420
            // Obtain the requirement element key list from the root package and scan through each entry
421
            int i_reqCount;
422
            System.Object[,] keyList = (System.Object[,])thisPackage.KeyList(ReqPro40.enumElementTypes.eElemType_Requirement);
423
            for (i_reqCount = 0; i_reqCount < limit_reqCount; i_reqCount++)
424
            {
425
               if (Main.mustAbort)
426
                  break;
427
 
428
               // Obtain the ReqPro requirement from its key, and parse it
429
               ReqPro40.Requirement thisRequirement = 
430
                  rq_project.GetRequirement(keyList[0,i_reqCount],
431
                                            ReqPro40.enumRequirementLookups.eReqLookup_Key,
432
                                            ReqPro40.enumRequirementsWeights.eReqWeight_Heavy,
433
                                            ReqPro40.enumRequirementFlags.eReqFlag_RetainHierarchy);
434
 
435
               if (thisRequirement != null)
436
               {
437
                  parseRequirement(level+1, rq_project, null, thisRequirement);                  
438
               }
439
            }
440
         }
441
      }
442
 
2141 ghuddy 443
      /// <summary>
444
      /// This method handles the parsing of each package beneath the root package
445
      /// in the ReqPro database.
446
      /// The method is almost identical to the parseRootPackage method, except that 
447
      /// this deals with a ReqPro40.Package object, whereas the latter deals with a
448
      /// ReqPro40.RootPackage object. Perhaps the two functions could be combined into 
449
      /// one if we move to .NET 2 where c# has some support for generic (template)
450
      /// programming.      
451
      /// </summary>
452
      /// <param name="repository"></param>
453
      /// <param name="rq_project"></param>
2151 ghuddy 454
      /// <param name="thisPackage"></param>
455
      private void parsePackage(int level,
456
                                string prefix,
457
                                ReqPro40.Project rq_project, 
458
                                ReqPro40.Package thisPackage)
459
      {
460
         if (Main.mustAbort)
461
            return;
462
 
463
         Main.EA_Repository.WriteOutput(Main.GUI_OUTPUT_TAB_NAME, prefix + thisPackage.Name, -1);
464
 
465
         // call user defined functions
466
         processPackage(level, rq_project, thisPackage);
467
         processObject(level, rq_project, thisPackage, null);
468
 
469
         // Scan through the sub-packages of this package
470
         int limit_packageCount = thisPackage.get_Count(ReqPro40.enumElementTypes.eElemType_Package);
471
         if (limit_packageCount > 0)
472
         {
473
            int i_packageCount;
474
            thisPackage.MoveFirst();
475
            for (i_packageCount = 0; i_packageCount < limit_packageCount; i_packageCount++)
476
            {
477
               if (Main.mustAbort)
478
                  break;
479
 
480
               // Read the sub-package and parse it
481
               ReqPro40.Package subPackage = (ReqPro40.Package)thisPackage.GetCurrentElement();
482
               parsePackage(level+1, prefix + "    ", rq_project, subPackage);
483
               thisPackage.MoveNext();
484
            }
485
         }
486
 
487
         if (Main.mustAbort)
488
            return;
489
 
490
         // Scan through the requirements directly beneath this package
491
         int limit_reqCount = thisPackage.get_Count(ReqPro40.enumElementTypes.eElemType_Requirement);
492
         if (limit_reqCount > 0)
493
         {
494
            // Obtain the requirement element key list from this package and scan through each entry
495
            int i_reqCount;
496
            System.Object[,] keyList = (System.Object[,])thisPackage.KeyList(ReqPro40.enumElementTypes.eElemType_Requirement);
497
            for (i_reqCount = 0; i_reqCount < limit_reqCount; i_reqCount++)
498
            {
499
               if (Main.mustAbort)
500
                  break;
501
 
502
               // Obtain the ReqPro requirement from its key, and parse it
503
               ReqPro40.Requirement thisRequirement = 
504
                  rq_project.GetRequirement(keyList[0,i_reqCount],
505
                                            ReqPro40.enumRequirementLookups.eReqLookup_Key,
506
                                            ReqPro40.enumRequirementsWeights.eReqWeight_Heavy,
507
                                            ReqPro40.enumRequirementFlags.eReqFlag_RetainHierarchy);
508
               if (thisRequirement != null)
509
               {
510
                  parseRequirement(level+1, rq_project, thisPackage, thisRequirement);                  
511
               }
512
            }
513
         }
514
      }
515
 
516
 
517
 
2141 ghuddy 518
      /// <summary>
519
      /// This method parses a requirement and any sub-requirements found in the 
520
      /// ReqPro database by the package/root package parsers.
521
      /// NOTE that when called from the parseRootPackage method, the thisPackage
522
      /// parameter will be null.
523
      /// </summary>
524
      /// <param name="repository"></param>
525
      /// <param name="rq_project"></param>
526
      /// <param name="thisPackage"></param>
2151 ghuddy 527
      /// <param name="thisRequirement"></param>
528
      private void parseRequirement(int level,
529
                                    ReqPro40.Project rq_project, 
530
                                    ReqPro40.Package thisPackage, 
531
                                    ReqPro40.Requirement thisRequirement)
532
      {
533
         if (Main.mustAbort)
534
            return;
2141 ghuddy 535
 
2151 ghuddy 536
         // call user defined functions
537
         processRequirement(level, rq_project, thisPackage, thisRequirement);
538
         processObject(level, rq_project, thisPackage, thisRequirement);
539
 
540
         // requirements can have children that are requirements, so we have to find those
541
         int limit_numberOfChildren = 0;
542
         if (true == thisRequirement.get_HasChildren(ref limit_numberOfChildren))
543
         {
544
            // scan through the child relationships
545
            ReqPro40.Relationships theseRelationships = (ReqPro40.Relationships)thisRequirement.Children;
546
 
547
            int i_numberOfChildren;
548
            theseRelationships.MoveFirst();
549
            for (i_numberOfChildren = 0; i_numberOfChildren < limit_numberOfChildren; i_numberOfChildren++)
550
            {
551
               if (Main.mustAbort)
552
                  break;
553
 
554
               // Obtain the sub-requirement from the relationship, and parse it
555
               ReqPro40.Relationship thisRelationship = theseRelationships.GetCurrentRelationship();
556
 
557
               ReqPro40.Requirement subRequirement = 
558
                  thisRelationship.get_DestinationRequirement(ReqPro40.enumRequirementsWeights.eReqWeight_Heavy);
559
 
560
               if (subRequirement != null)
561
               {
562
                  parseRequirement(level+1, rq_project, thisPackage, subRequirement);
563
               }
564
 
565
               theseRelationships.MoveNext();
566
            }
567
         }
568
      }
569
 
2141 ghuddy 570
	}
2151 ghuddy 571
 
2141 ghuddy 572
}