Subversion Repositories DevTools

Rev

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