Subversion Repositories DevTools

Rev

Rev 2151 | Rev 2155 | 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
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
 
2153 ghuddy 18
      //protected EA_Utilities EA_Utils;
2141 ghuddy 19
 
2145 ghuddy 20
      // items setup by base class calling into provideReqProDatabaseInfo()
2141 ghuddy 21
      protected ReqPro40.Project RQ_project;
2145 ghuddy 22
      protected ReqPro40.Application RQ_app;
23
      protected ReqProDB_Artifact RQ_Artifact;
24
      protected EA.Element RQ_Element;
2141 ghuddy 25
 
26
      // Where in an EA database, the copy of the ReqPro database content will be written
27
      protected EA.Package ea_rootPackage;
28
 
29
      // Hierarchy tracking data for the parsing of a ReqPro database
30
      protected Stack rq_objs = new Stack();      // Top of stack indicates current parent package
31
      protected Stack ea_treePos = new Stack();   // Top of stack indicates current tree position reflecting object ordering within the parent package
32
      protected int lastLevel;                    // Allows us to determine if we have gone down/up in the hierarchy
33
 
34
      // Collector for the results of the parsing
35
      protected ReqPro_object rq_root_package;
36
 
2151 ghuddy 37
      private int writeTracesModulo = 100;
2141 ghuddy 38
 
39
      /// <summary>
40
      /// Constructor logic
41
      /// </summary>
42
      /// <param name="ea_repository"></param>
2151 ghuddy 43
		public CopyReqProDatabaseToMemory(): base()
2141 ghuddy 44
		{
45
         try
46
         {
47
            // figure out where in the EA database we will place the results of parsing
2151 ghuddy 48
            object o;
49
            EA.ObjectType type;
50
            type = Main.EA_Repository.GetTreeSelectedItem(out o);
51
            if (type == EA.ObjectType.otElement)
52
            {
53
               ea_rootPackage = Main.EA_Repository.GetPackageByID( ((EA.Element)o).PackageID );
54
            }
55
            else if (type == EA.ObjectType.otPackage)
56
            {
57
               ea_rootPackage = (EA.Package)o;
58
            }
59
            else
60
            {
61
               Exception e = new Exception("No Root Package given");
62
               throw e;
63
            }
2141 ghuddy 64
         }
2151 ghuddy 65
         catch (Exception ex)
66
         {
2153 ghuddy 67
            Main.MessageBoxException(ex, "Exception (CopyReqProDatabaseToMemory)");
2141 ghuddy 68
         }    
69
		}
70
 
71
 
2151 ghuddy 72
 
73
      #region Requirement Type methods
2141 ghuddy 74
      /// <summary>
75
      /// Recursively set the requirement type enum in each requirement object read
76
      /// from the ReqPro database. The enum give fast indication of the requirement type.
77
      /// If we didnt do this, each time the requirement type needs to be evaluated, a string 
78
      /// compare needs to be done. Here, we do them all up-front so that down the track a simple
79
      /// integer access is all that is required.
80
      /// </summary>
2151 ghuddy 81
      /// <param name="rq_obj"></param>
2141 ghuddy 82
      private void set_rq_req_types_in_copied_data( ReqPro_object rq_obj )
83
         {
84
            if (rq_obj.isRequirement)
85
            {
86
               int i = 0;
2151 ghuddy 87
               foreach (ReqPro_ReqType req_type in rq_req_types)
88
               {
89
                  if (rq_obj.tag.StartsWith(req_type.prefix))
90
                  {
91
                     rq_obj.tag_enum = i;
92
                  }
93
                  i++;
2141 ghuddy 94
               }
95
            }
96
 
97
            foreach( ReqPro_object sub_obj in rq_obj.ReqPro_objects )
98
            {
99
               // recurse
100
               set_rq_req_types_in_copied_data(sub_obj);
101
            }
2151 ghuddy 102
         }
103
 
104
 
105
      #endregion
106
 
107
      #region ReqProParser (base class) overrides
2141 ghuddy 108
      /// <summary>
109
      /// This method is designed to prompt the user to select the ReqPro database file
110
      /// before opening and parsing it. Once parsed, the user is offered a chance to setup
111
      /// the filter controls.
112
      /// </summary>
113
      /// <param name="ea_repository"></param>
114
      /// <returns></returns>
2151 ghuddy 115
      public override bool prompt_and_parse(ReqProDB_Artifact.MODE mode)
116
      {
117
         try
118
         {
119
 
120
            pre_parsing();
121
            if (true == base.prompt_and_parse(mode))
122
            {
123
               // make sure all imported requirements have the correct requirement type enumeration
124
               // (converted from the string name of the tag)
125
               set_rq_req_types_in_copied_data(rq_root_package);
126
 
127
               // bring up the filter dialog to allow user to specify exactly what gets copied
128
               ReqProFilterForm rq_filter = new ReqProFilterForm(mode == ReqProDB_Artifact.MODE.TRACEABILITY);
129
               rq_filter.populate(rq_root_package, rq_req_types, rq_req_status_types);
130
 
131
               // Setup the filter based on the saved filter settings in the ReqProDB element (if any)
132
               if (RQ_Element != null)
133
               {
134
                  rq_filter.loadFilterSettings(RQ_Element.Notes);
135
               }
136
 
137
               DialogResult dlgRes = rq_filter.ShowDialog();
138
               if (dlgRes == DialogResult.OK)
139
               {
140
                  allowPackageStructureFragments = rq_filter.allowPackageStructureFragments;
141
                  RQ_project.CloseProject();
142
 
143
                  // Save filter settings to the ReqProDB element if it is available
144
                  if (RQ_Element != null)
145
                  {
146
                     RQ_Element.Notes = rq_filter.saveFilterSettings();
147
                     RQ_Element.Update();
148
                  }
149
 
150
                  return true;
151
               }
152
               RQ_project.CloseProject();
153
            }
154
         }
155
         catch (Exception ex)
156
         {
2153 ghuddy 157
            Main.MessageBoxException(ex, "Exception (parse)");
2151 ghuddy 158
         }      
159
         return false;
160
      }
161
 
162
 
163
 
2141 ghuddy 164
      /// <summary>
165
      /// This method will be called by the base class parser when it has obtained a ReqPro
166
      /// project object. We capture that object here so we can interrogate the ReqPro database
167
      /// ourselves, if we need to. We wont do that for package/requirement reading, but we may
168
      /// do it for meta-data such as requirement types, etc.
169
      /// </summary>
2151 ghuddy 170
      /// <param name="reqpro_project"></param>
2145 ghuddy 171
      protected override void provideReqProDatabaseInfo(ReqPro40.Application rq_app, 
172
         ReqPro40.Project rq_project, 
173
         ReqProDB_Artifact rq_artifact,
174
         EA.Element rq_element)
2141 ghuddy 175
      {
2145 ghuddy 176
         RQ_app = rq_app;
2141 ghuddy 177
         RQ_project = rq_project;
2145 ghuddy 178
         RQ_Artifact = rq_artifact;
179
         RQ_Element = rq_element;
2151 ghuddy 180
      }
181
 
2141 ghuddy 182
      /// <summary>
183
      /// This method will be called by the base class parser whenever a package or requirement object
184
      /// is found in the ReqPro database. The method collects important information from the object 
185
      /// into a structure that begins with the ea_rootPackage object. The structure is highly dynamic
186
      /// with each object able to hold a list of other objects. This naturally allows for the ReqPro
187
      /// database hierarchy to be accurately reflected. The hierarchy tracking data maintained within
188
      /// the method allows us to know what object in the structure to hang off any new object derived
189
      /// from info given to us by the base class parser (ie. what object is the parent object at the
190
      /// present time during the parsing).
191
      /// </summary>
192
      /// <param name="level"></param>
193
      /// <param name="ea_repository"></param>
194
      /// <param name="rq_project"></param>
195
      /// <param name="rq_package"></param>
2151 ghuddy 196
      /// <param name="rq_requirement"></param>
197
      protected override void processObject(int level,
198
                                            ReqPro40.Project rq_project, 
2141 ghuddy 199
                                            ReqPro40.Package rq_package,
200
                                            ReqPro40.Requirement rq_requirement)
201
      {
2151 ghuddy 202
         // If we are still at the same level as the previous package, then pop the previous object 
203
         // in readiness for pushing the one we are now dealing with.
204
         if (level == lastLevel)
205
         {
206
            rq_objs.Pop();
207
            ea_treePos.Pop();
208
         }
209
            // but if we are beneath the previous level, pop all objects that are above us because
210
            // we no longer need them in our hierarchy reference data.
211
         else if (level < lastLevel)
212
         {
213
            while (lastLevel >= level)
214
            {
215
               rq_objs.Pop();
216
               ea_treePos.Pop();
217
               lastLevel--;
218
            }
219
         }
220
 
221
         // bump the tree position at this level (controls display position in the EA project browser)
222
         int treePos = (int)ea_treePos.Pop();
223
         treePos++;
224
         ea_treePos.Push(treePos);
225
 
226
         // create the new requirement or package
227
         ReqPro_object new_rq_obj = new ReqPro_object();
228
         if (rq_requirement != null)
229
         {
230
            new_rq_obj.isRequirement = true;
231
            new_rq_obj.name   = rq_requirement.Name;
232
            new_rq_obj.text   = rq_requirement.Text;
233
            new_rq_obj.guid   = rq_requirement.GUID;
234
            new_rq_obj.tag    = rq_requirement.get_Tag(ReqPro40.enumTagFormat.eTagFormat_FullTag);
235
 
236
            bool hasStatus = false;
237
            bool hasDifficulty = false;
238
            bool hasPriority = false;
2153 ghuddy 239
            bool hasSource = false;
240
            bool hasSourceVersion = false;
241
            bool hasSourceSection = false;
242
 
243
            if (reqTypeHasOneOrMoreAttrs(new_rq_obj, 
244
               ref hasStatus, ref hasDifficulty, ref hasPriority,
245
               ref hasSource, ref hasSourceVersion, ref hasSourceSection))
2151 ghuddy 246
            {
247
               if (hasStatus)
248
               {
249
                  new_rq_obj.status = rq_requirement.AttrValues["Status", ReqPro40.enumAttrValueLookups.eAttrValueLookup_Label].Text;
250
               }
251
               if (hasDifficulty)
252
               {
253
                  new_rq_obj.difficulty = rq_requirement.AttrValues["Difficulty", ReqPro40.enumAttrValueLookups.eAttrValueLookup_Label].Text;
254
               }
255
               if (hasPriority)
256
               {
257
                  new_rq_obj.priority = rq_requirement.AttrValues["Priority", ReqPro40.enumAttrValueLookups.eAttrValueLookup_Label].Text;
258
               }
2153 ghuddy 259
               if (hasSource)
260
               {
261
                  new_rq_obj.source = rq_requirement.AttrValues["Source", ReqPro40.enumAttrValueLookups.eAttrValueLookup_Label].Text;
262
               }
263
               if (hasSourceVersion)
264
               {
265
                  new_rq_obj.sourceVersion = rq_requirement.AttrValues["Source Version", ReqPro40.enumAttrValueLookups.eAttrValueLookup_Label].Text;
266
               }
267
               if (hasSourceSection)
268
               {
269
                  new_rq_obj.sourceSection = rq_requirement.AttrValues["Source Section", ReqPro40.enumAttrValueLookups.eAttrValueLookup_Label].Text;
270
               }
2151 ghuddy 271
            }
272
 
273
            new_rq_obj.version    = rq_requirement.VersionNumber;
274
            new_rq_obj.versionDateTime = rq_requirement.VersionDateTime;
275
 
276
 
277
            // requirements can trace to other requirements, so we have to find those in order to re-construct
278
            // that traceability later on. Currently, we only process TracesTo relationships from ReqPro.
279
            int limit_numberOfTracesTo = 0;
280
            if (true == rq_requirement.get_HasTracesTo(ref limit_numberOfTracesTo))
281
            {
282
               // scan through the TracesTo relationships
283
               ReqPro40.Relationships theseRelationships = (ReqPro40.Relationships)rq_requirement.TracesTo;
284
 
285
               int i_numberOfTracesTo;
286
               theseRelationships.MoveFirst();
287
               for (i_numberOfTracesTo = 0; i_numberOfTracesTo < limit_numberOfTracesTo; i_numberOfTracesTo++)
288
               {
289
                  // Obtain the traced-to requirement from the relationship, and parse it
290
                  ReqPro40.Relationship thisRelationship = theseRelationships.GetCurrentRelationship();
291
 
292
                  ReqPro40.Requirement tracedToRequirement = 
293
                     thisRelationship.get_DestinationRequirement(ReqPro40.enumRequirementsWeights.eReqWeight_Heavy);
294
 
295
                  if (tracedToRequirement != null)
296
                  {
297
                     // Add the GUID of the traced-to requirement to the relevant list within the
298
                     // object representing the traced-from requirement (ie. parent requirement).
299
                     new_rq_obj.ReqPro_traces.Add(tracedToRequirement.GUID);
300
                  }
301
 
302
                  theseRelationships.MoveNext();
303
               }
304
            }
305
 
306
         }
307
         else if (rq_package != null)
308
         {
309
            new_rq_obj.isPackage = true;
310
 
2141 ghuddy 311
            // Packages in ReqPro may be prefixed by a number to force ReqPro's alphanumeric sorting
312
            // algorithm to order the packages in the way the user wants, as dictated by the actual 
313
            // numbers used. EA does not have this problem because it uses a tree position number to
314
            // control a package/element's position in the project browser. So, strip off any leading
315
            // numeric from the ReqPro packages.
316
            string trimstring = " 0123456789";
317
            char[] trimmer = trimstring.ToCharArray();
2151 ghuddy 318
            string filtered_name = rq_package.Name.TrimStart(trimmer);
319
 
320
            new_rq_obj.name = filtered_name;
321
            new_rq_obj.guid = rq_package.GUID;
322
         }
323
 
324
         new_rq_obj.level = level;
325
         new_rq_obj.treePos = treePos;
326
 
327
         // attach it to its parent object
328
         ReqPro_object parent_rq_obj = (ReqPro_object)rq_objs.Peek();
329
         parent_rq_obj.ReqPro_objects.Add( new_rq_obj );
330
         new_rq_obj.parent = parent_rq_obj;
331
 
332
         // keep a count of the number of requirements the object has beneath it
333
         if (true == new_rq_obj.isRequirement)
334
            parent_rq_obj.numberOfRequirements++;
335
 
336
         // push the new object onto the stack, ready for any sub-objects that may belong to it.
337
         // If, the next time we enter this method, the level is the same, this will get popped off.
338
         // If, the next time we enter this method, the level is lower, this and possibly more will
339
         // get popped off.
340
         rq_objs.Push(new_rq_obj);
341
         ea_treePos.Push(0);
342
 
343
         // capture what the hierarchy level is for the object just processed.
344
         lastLevel = level;
345
      }
346
 
347
      #endregion
348
 
349
 
2149 ghuddy 350
      /// <summary>
351
      /// Finds and returns the ReqPro_object instance that contains the specified GUID. The
352
      /// GUID is that of the originating ReqPro requirement, which is copied into a ReqPro_object
353
      /// instance when it is created. This find operation supports the ability to resolve object to
354
      /// object trace relationships mirrored from the ReqPro database during the construction
355
      /// of the ReqPro_object hierarchy.
356
      /// </summary>
357
      /// <param name="rq_obj"></param>
358
      /// <param name="ReqProGUID"></param>
2151 ghuddy 359
      /// <returns></returns>
360
      protected ReqPro_object findReqPro_object_byReqProGUID(ReqPro_object rq_obj, string ReqProGUID)
361
      {
362
         if (rq_obj.guid.CompareTo(ReqProGUID) == 0)
363
         {
364
            return rq_obj;
365
         }
366
 
367
         foreach (ReqPro_object sub_rq_obj in rq_obj.ReqPro_objects)
368
         {
369
            ReqPro_object tgt_obj = findReqPro_object_byReqProGUID(sub_rq_obj, ReqProGUID);
370
            if (tgt_obj != null)
371
               return tgt_obj;
372
         }
373
 
374
         return null;
375
      }
376
 
377
      protected int write_traces(int totalRequirements)
378
      {
379
         Main.EA_Repository.WriteOutput( Main.GUI_OUTPUT_TAB_NAME, "Writing Trace Information", -1);
380
         int numberWritten = 0;
381
 
382
         // adjust modulo for logging purposes so that the number of output messages is restricted
383
         // for larger and larger numbers of requirements
384
         if (totalRequirements > 1000)
385
            writeTracesModulo = 100;
386
         else if (totalRequirements > 500)
387
            writeTracesModulo = 50;
388
         else if (totalRequirements > 100)
389
            writeTracesModulo = 20;
390
         else if (totalRequirements > 50)
391
            writeTracesModulo = 10;
392
         else if (totalRequirements > 20)
393
            writeTracesModulo = 5;
394
         else // 10 or less 
395
            writeTracesModulo = 1;
396
 
397
         foreach( ReqPro_object sub_obj in rq_root_package.ReqPro_objects )
398
         {
399
            if (Main.mustAbort)
400
               return numberWritten;
401
 
402
            numberWritten = write_traces(sub_obj, numberWritten, totalRequirements);
403
         }
404
 
405
         Main.EA_Repository.WriteOutput(Main.GUI_OUTPUT_TAB_NAME, "Traces Completed", -1);
406
 
407
         return numberWritten;
408
      }
409
 
2141 ghuddy 410
      /// <summary>
2149 ghuddy 411
      /// This method examines all of the ReqPro_object trace relationships and mirrors them in 
412
      /// the EA requirement elements that have been formed from each un-filtered ReqPro_objects.
413
      /// </summary>
414
      /// <param name="ea_repository"></param>
415
      /// <param name="rq_obj"></param>
2151 ghuddy 416
      private int write_traces(ReqPro_object rq_obj, int numberWritten, int totalRequirements)
2149 ghuddy 417
      {
2151 ghuddy 418
         if (Main.mustAbort)
419
            return numberWritten;
420
 
2149 ghuddy 421
         if (rq_obj.isRequirement)
422
         {
423
            // if this object had an EA element made for it during the write_ea_database() process...
424
            if (rq_obj.ea_element_ID != -1)
425
            {
2151 ghuddy 426
               numberWritten++;
427
               if ((numberWritten % writeTracesModulo) == 0)
428
               {
429
                  Main.EA_Repository.WriteOutput(Main.GUI_OUTPUT_TAB_NAME, string.Format("   {0} of {1}", numberWritten, totalRequirements), -1);
430
               }
431
 
432
               EA.Element ea_rq_obj = Main.EA_Repository.GetElementByID(rq_obj.ea_element_ID);
2149 ghuddy 433
               if (ea_rq_obj != null)
434
               {
435
                  foreach(string s in rq_obj.ReqPro_traces)
436
                  {
437
                     ReqPro_object tgt_obj = findReqPro_object_byReqProGUID(rq_root_package,s);
438
                     if (tgt_obj != null)
439
                     {
440
                        if (tgt_obj.ea_element_ID != -1)
441
                        {
2151 ghuddy 442
                           EA.Element ea_tgt_obj = Main.EA_Repository.GetElementByID(tgt_obj.ea_element_ID);
2149 ghuddy 443
                           if (ea_tgt_obj != null)
444
                           {
2151 ghuddy 445
                              add_connection(ea_rq_obj, ea_tgt_obj);
2149 ghuddy 446
                           }
447
                        }
448
                     }
449
                  }
450
               }
451
            }
452
         }
453
 
454
         // recurse to ensure we examine the entire hiearchy
455
         foreach(ReqPro_object sub_obj in rq_obj.ReqPro_objects)
456
         {
2151 ghuddy 457
            if (Main.mustAbort)
458
               break;
459
 
460
            numberWritten = write_traces(sub_obj, numberWritten, totalRequirements);
2149 ghuddy 461
         }
2151 ghuddy 462
         return numberWritten;
463
      }
464
 
2149 ghuddy 465
      /// <summary>
466
      /// Adds a connection between one EA element and another
467
      /// </summary>
468
      /// <param name="repository"></param>
469
      /// <param name="rq_artifact"></param>
2151 ghuddy 470
      /// <param name="ea_req"></param>
471
      protected void add_connection(EA.Element src_element, EA.Element dest_element)
472
      {
473
         // Add the new requirement to the src_element
474
         EA.Connector c = (EA.Connector)src_element.Connectors.AddNew("", "Dependency");
475
         c.SupplierID = dest_element.ElementID;
476
         //c.Stereotype = "trace";
477
         c.Direction = "Source -> Destination";
478
         if (false == c.Update())
479
         {
480
            Main.EA_Repository.WriteOutput( Main.GUI_OUTPUT_TAB_NAME, "New Connector Error : " + c.GetLastError(), dest_element.ElementID );
481
         }
482
         src_element.Connectors.Refresh();
2149 ghuddy 483
      }
484
 
485
      /// <summary>
2141 ghuddy 486
      /// A method to contain common pre-parsing steps.
2151 ghuddy 487
      /// </summary>
488
      private void pre_parsing()
489
      {
490
         // create an object to represent the root of the database so that we can collect
491
         // sub-objects (packages or requirements) underneath it.
492
         rq_root_package = new ReqPro_object();
493
         rq_root_package.name = "ROOT";
494
 
495
         // initialise the ReqPro database hierarchy tracking data
496
         rq_objs.Clear();
497
         rq_objs.Push(rq_root_package);
498
         ea_treePos.Clear();
499
         ea_treePos.Push(0);
500
         lastLevel = 0;
2141 ghuddy 501
      }
2143 ghuddy 502
 
503
 
504
 
505
 
2141 ghuddy 506
	}
507
}