Subversion Repositories DevTools

Rev

Rev 2161 | 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>
2155 ghuddy 12
	/// This class is responsible for constructing a facsimile of the reqpro database, from objects given to it 
13
	/// by the ReqProParser base class. It then enables the user to select particular filter settings applied
14
	/// to that data, to control a subsequent import into EA (not performed in this class or it's base class ).
2141 ghuddy 15
	/// </summary>
16
	public class CopyReqProDatabaseToMemory : ReqProParser
17
	{
2155 ghuddy 18
      // Flag to allow a client to configure this class to allow package structure fragments to be 
19
      // captured during an import, ie. package structures that are ticked in the filter form but whose
20
      // parental structur is not ticked.
2141 ghuddy 21
      protected bool allowPackageStructureFragments = false;
22
 
2145 ghuddy 23
      // items setup by base class calling into provideReqProDatabaseInfo()
24
      protected ReqProDB_Artifact RQ_Artifact;
25
      protected EA.Element RQ_Element;
2141 ghuddy 26
 
27
      // Where in an EA database, the copy of the ReqPro database content will be written
28
      protected EA.Package ea_rootPackage;
2155 ghuddy 29
 
2141 ghuddy 30
      // Hierarchy tracking data for the parsing of a ReqPro database
31
      protected Stack rq_objs = new Stack();      // Top of stack indicates current parent package
32
      protected Stack ea_treePos = new Stack();   // Top of stack indicates current tree position reflecting object ordering within the parent package
33
      protected int lastLevel;                    // Allows us to determine if we have gone down/up in the hierarchy
34
 
2155 ghuddy 35
      private ReqProObject_Dictionary guid_to_obj_dictionary;
36
 
37
      private ArrayList trace_log;
38
 
2141 ghuddy 39
      // Collector for the results of the parsing
40
      protected ReqPro_object rq_root_package;
41
 
2151 ghuddy 42
      private int writeTracesModulo = 100;
2141 ghuddy 43
 
44
      /// <summary>
45
      /// Constructor logic
46
      /// </summary>
47
      /// <param name="ea_repository"></param>
2151 ghuddy 48
		public CopyReqProDatabaseToMemory(): base()
2141 ghuddy 49
		{
2155 ghuddy 50
         // figure out where in the EA database we will place the results of parsing
51
         // NOTE: This just attempts to find a default value for ea_rootPackage.
52
         // Its final value may be overriden later in the parsing process, when the 
53
         // ReqProDB element is acquired (see in provideReqProDatabaseInfo() method).
54
         ea_rootPackage = EA_Utilities.get_selected_package();
2141 ghuddy 55
		}
56
 
57
 
2151 ghuddy 58
 
59
      #region Requirement Type methods
2141 ghuddy 60
      /// <summary>
61
      /// Recursively set the requirement type enum in each requirement object read
62
      /// from the ReqPro database. The enum give fast indication of the requirement type.
2155 ghuddy 63
      /// If we didnt do this, each time the requirement type needs to be evaluated, a string
2141 ghuddy 64
      /// compare needs to be done. Here, we do them all up-front so that down the track a simple
65
      /// integer access is all that is required.
66
      /// </summary>
2151 ghuddy 67
      /// <param name="rq_obj"></param>
2141 ghuddy 68
      private void set_rq_req_types_in_copied_data( ReqPro_object rq_obj )
69
         {
70
            if (rq_obj.isRequirement)
71
            {
72
               int i = 0;
2151 ghuddy 73
               foreach (ReqPro_ReqType req_type in rq_req_types)
74
               {
75
                  if (rq_obj.tag.StartsWith(req_type.prefix))
76
                  {
77
                     rq_obj.tag_enum = i;
78
                  }
79
                  i++;
2141 ghuddy 80
               }
81
            }
82
 
83
            foreach( ReqPro_object sub_obj in rq_obj.ReqPro_objects )
84
            {
85
               // recurse
86
               set_rq_req_types_in_copied_data(sub_obj);
87
            }
2151 ghuddy 88
         }
89
 
90
 
91
      #endregion
92
 
93
      #region ReqProParser (base class) overrides
2141 ghuddy 94
      /// <summary>
95
      /// This method is designed to prompt the user to select the ReqPro database file
96
      /// before opening and parsing it. Once parsed, the user is offered a chance to setup
97
      /// the filter controls.
98
      /// </summary>
99
      /// <param name="ea_repository"></param>
100
      /// <returns></returns>
2155 ghuddy 101
      public override bool prompt_and_parse(ReqProDB_Artifact.MODE mode, out bool cancelled)
2151 ghuddy 102
      {
2155 ghuddy 103
         cancelled = false;
104
 
105
         guid_to_obj_dictionary = new ReqProObject_Dictionary();
106
 
2151 ghuddy 107
         try
108
         {
109
            pre_parsing();
2155 ghuddy 110
            if (true == base.prompt_and_parse(mode, out cancelled))
2151 ghuddy 111
            {
2155 ghuddy 112
               // update the reqpro root package name from the actual reqpro project that has now been opened
113
               // and parsed. This may or may not be used depending upon the higher level function being carried 
114
               // out. For imports, the name is never used. For exports, it may appear as the root name in 
115
               // a folder view of the reqpro database package content.
116
               rq_root_package.name = ReqProDatabase.name();
117
 
2151 ghuddy 118
               // make sure all imported requirements have the correct requirement type enumeration
119
               // (converted from the string name of the tag)
120
               set_rq_req_types_in_copied_data(rq_root_package);
121
 
2155 ghuddy 122
               // Do one thing for imports, and another for exports.
123
               if (  mode == ReqProDB_Artifact.MODE.DOC_MODEL
124
                  || mode == ReqProDB_Artifact.MODE.TRACEABILITY )
2151 ghuddy 125
               {
2155 ghuddy 126
                  // bring up the import filter dialog to allow user to specify exactly what gets copied
127
                  ReqProFilterForm rq_filter = new ReqProFilterForm(mode == ReqProDB_Artifact.MODE.TRACEABILITY);
128
                  rq_filter.populate(rq_root_package, rq_req_types, rq_req_status_types);
2151 ghuddy 129
 
2155 ghuddy 130
                  // Setup the filter based on the saved filter settings in the ReqProDB element (if any)
2151 ghuddy 131
                  if (RQ_Element != null)
132
                  {
2155 ghuddy 133
                     rq_filter.loadFilterSettings(RQ_Element.Notes);
2151 ghuddy 134
                  }
135
 
2155 ghuddy 136
                  DialogResult dlgRes = rq_filter.ShowDialog();
137
                  if (dlgRes == DialogResult.OK)
138
                  {
139
                     allowPackageStructureFragments = rq_filter.allowPackageStructureFragments;
140
 
141
                     // Save filter settings to the ReqProDB element if it is available
142
                     if (RQ_Element != null)
143
                     {
144
                        RQ_Element.Notes = rq_filter.saveFilterSettings();
145
                        RQ_Element.Update();
146
                     }
147
 
148
                     return true;
149
                  }
150
                  else
151
                  {
152
                     cancelled = true;
153
                  }
2151 ghuddy 154
               }
2155 ghuddy 155
               else if (mode == ReqProDB_Artifact.MODE.EXPORT)
156
               {
157
                  ExportForm exportForm = new ExportForm();
158
                  exportForm.populate(rq_root_package, EA_TaggedValues.Read(RQ_Element, Constants.TAG_LAST_EXPORT_GUID, ""),
159
                     rq_req_types, rq_req_status_types);
160
                  DialogResult dlgRes = exportForm.ShowDialog();
161
                  if (dlgRes == DialogResult.OK)
162
                  {
163
                     // communicate user selections to the client class that will perform the export.
164
                     string folderName;
165
                     bool createFolder = exportForm.user_create_folder_selection(out folderName);
166
 
167
                     provideExportDecisionsToClient(exportForm.user_selected_object(), 
168
                        createFolder, folderName, 
169
                        exportForm.user_selected_requirement_type(), 
170
                        exportForm.user_selected_export_extent());
171
 
172
 
173
                     // NOTE: Do not close the reqpro database here. The client class will do that 
174
                     // after the export completes.
175
                     return true;
176
                  }
177
                  else
178
                  {
179
                     cancelled = true;
180
                  }
181
               }
2151 ghuddy 182
            }
183
         }
184
         catch (Exception ex)
185
         {
2153 ghuddy 186
            Main.MessageBoxException(ex, "Exception (parse)");
2155 ghuddy 187
         }
188
 
2151 ghuddy 189
         return false;
190
      }
191
 
192
 
2155 ghuddy 193
 
2141 ghuddy 194
      /// <summary>
2155 ghuddy 195
      /// Function that must be overriden in a client class designed to handle the exporting of
196
      /// requirements back to ReqPro. The function gives such a class the details of selections made
197
      /// via the export form.
198
      /// </summary>
199
      /// <param name="selectedObject"></param>
200
      /// <param name="createFolder"></param>
201
      /// <param name="folderName"></param>
202
      /// <param name="requirementType"></param>
203
      /// <param name="requirementStatus"></param>
204
      protected virtual void provideExportDecisionsToClient(ReqPro_object selectedObject,
205
         bool createFolder,
206
         string folderName,
207
         string requirementType,
208
         ExportForm.ExportExtent exportExtent)
209
      {
210
      }
211
 
212
 
213
      /// <summary>
2141 ghuddy 214
      /// This method will be called by the base class parser when it has obtained a ReqPro
215
      /// project object. We capture that object here so we can interrogate the ReqPro database
216
      /// ourselves, if we need to. We wont do that for package/requirement reading, but we may
217
      /// do it for meta-data such as requirement types, etc.
218
      /// </summary>
2151 ghuddy 219
      /// <param name="reqpro_project"></param>
2155 ghuddy 220
      protected override void provideReqProDatabaseInfo(
2145 ghuddy 221
         ReqProDB_Artifact rq_artifact,
222
         EA.Element rq_element)
2141 ghuddy 223
      {
2145 ghuddy 224
         RQ_Artifact = rq_artifact;
225
         RQ_Element = rq_element;
2155 ghuddy 226
 
227
         // Now we have been given a ReqProDB stereotyped element, we use its parent container package
228
         // as our root package. This overrides the default setup during the class constructor.
229
         ea_rootPackage = Main.EA_Repository.GetPackageByID(RQ_Element.PackageID);
2151 ghuddy 230
      }
231
 
2155 ghuddy 232
 
2141 ghuddy 233
      /// <summary>
234
      /// This method will be called by the base class parser whenever a package or requirement object
2155 ghuddy 235
      /// is found in the ReqPro database. The method collects important information from the object
2141 ghuddy 236
      /// into a structure that begins with the ea_rootPackage object. The structure is highly dynamic
237
      /// with each object able to hold a list of other objects. This naturally allows for the ReqPro
238
      /// database hierarchy to be accurately reflected. The hierarchy tracking data maintained within
239
      /// the method allows us to know what object in the structure to hang off any new object derived
240
      /// from info given to us by the base class parser (ie. what object is the parent object at the
241
      /// present time during the parsing).
242
      /// </summary>
243
      /// <param name="level"></param>
244
      /// <param name="ea_repository"></param>
245
      /// <param name="rq_project"></param>
246
      /// <param name="rq_package"></param>
2151 ghuddy 247
      /// <param name="rq_requirement"></param>
248
      protected override void processObject(int level,
2141 ghuddy 249
                                            ReqPro40.Package rq_package,
250
                                            ReqPro40.Requirement rq_requirement)
251
      {
2155 ghuddy 252
         // If we are still at the same level as the previous package, then pop the previous object
2151 ghuddy 253
         // in readiness for pushing the one we are now dealing with.
254
         if (level == lastLevel)
255
         {
256
            rq_objs.Pop();
257
            ea_treePos.Pop();
258
         }
2155 ghuddy 259
         // but if we are beneath the previous level, pop all objects that are above us because
260
         // we no longer need them in our hierarchy reference data.
2151 ghuddy 261
         else if (level < lastLevel)
262
         {
263
            while (lastLevel >= level)
264
            {
265
               rq_objs.Pop();
266
               ea_treePos.Pop();
267
               lastLevel--;
268
            }
269
         }
270
 
271
         // bump the tree position at this level (controls display position in the EA project browser)
272
         int treePos = (int)ea_treePos.Pop();
273
         treePos++;
274
         ea_treePos.Push(treePos);
275
 
276
         // create the new requirement or package
2155 ghuddy 277
         ReqPro_object new_rq_obj = null;
2151 ghuddy 278
         if (rq_requirement != null)
279
         {
2155 ghuddy 280
            new_rq_obj = new ReqPro_object();
281
 
2151 ghuddy 282
            new_rq_obj.isRequirement = true;
283
            new_rq_obj.name   = rq_requirement.Name;
284
            new_rq_obj.text   = rq_requirement.Text;
285
            new_rq_obj.guid   = rq_requirement.GUID;
286
            new_rq_obj.tag    = rq_requirement.get_Tag(ReqPro40.enumTagFormat.eTagFormat_FullTag);
287
 
2155 ghuddy 288
            guid_to_obj_dictionary.Add(rq_requirement.GUID, new_rq_obj);
289
 
2151 ghuddy 290
            bool hasStatus = false;
291
            bool hasDifficulty = false;
292
            bool hasPriority = false;
2153 ghuddy 293
            bool hasSource = false;
294
            bool hasSourceVersion = false;
295
            bool hasSourceSection = false;
2155 ghuddy 296
            bool hasSubsystem = false;
297
            bool hasStability = false;
298
            bool hasType = false;
2153 ghuddy 299
 
2155 ghuddy 300
            // Acquire attributes from ReqPro.
301
            // Note the use of firstTokenOnly() on those attributes that are freeform text. Those
302
            // will most likely be stored in EA tagged values, which have a 256 char size limitation.
303
            // The intention is to limit the attribute to a single line, which hopefully should get it under the
304
            // size limit. If it does not, the addin will truncate the string and issue a warning when
305
            // it writes the tagged value.
306
            if (reqTypeHasOneOrMoreAttrs(new_rq_obj,
2153 ghuddy 307
               ref hasStatus, ref hasDifficulty, ref hasPriority,
2155 ghuddy 308
               ref hasSource, ref hasSourceVersion, ref hasSourceSection,
309
               ref hasSubsystem, ref hasStability, ref hasType))
2151 ghuddy 310
            {
311
               if (hasStatus)
312
               {
2161 ghuddy 313
                  new_rq_obj.status = rq_requirement.AttrValues[Constants.RP_ATTR_STATUS, ReqPro40.enumAttrValueLookups.eAttrValueLookup_Label].Text;
2151 ghuddy 314
               }
315
               if (hasDifficulty)
316
               {
2161 ghuddy 317
                  new_rq_obj.difficulty = rq_requirement.AttrValues[Constants.RP_ATTR_DIFFICULTY, ReqPro40.enumAttrValueLookups.eAttrValueLookup_Label].Text;
2151 ghuddy 318
               }
319
               if (hasPriority)
320
               {
2161 ghuddy 321
                  new_rq_obj.priority = rq_requirement.AttrValues[Constants.RP_ATTR_PRIORITY, ReqPro40.enumAttrValueLookups.eAttrValueLookup_Label].Text;
2151 ghuddy 322
               }
2153 ghuddy 323
               if (hasSource)
324
               {
2161 ghuddy 325
                  new_rq_obj.source = firstTokenOnly( rq_requirement.AttrValues[Constants.RP_ATTR_SOURCE, ReqPro40.enumAttrValueLookups.eAttrValueLookup_Label].Text );
2153 ghuddy 326
               }
327
               if (hasSourceVersion)
328
               {
2161 ghuddy 329
                  new_rq_obj.sourceVersion = firstTokenOnly( rq_requirement.AttrValues[Constants.RP_ATTR_SOURCE_VERSION, ReqPro40.enumAttrValueLookups.eAttrValueLookup_Label].Text );
2153 ghuddy 330
               }
331
               if (hasSourceSection)
332
               {
2161 ghuddy 333
                  new_rq_obj.sourceSection = firstTokenOnly( rq_requirement.AttrValues[Constants.RP_ATTR_SOURCE_SECTION, ReqPro40.enumAttrValueLookups.eAttrValueLookup_Label].Text );
2153 ghuddy 334
               }
2155 ghuddy 335
               if (hasSubsystem)
336
               {
2161 ghuddy 337
                  new_rq_obj.subsystem = firstTokenOnly( rq_requirement.AttrValues[Constants.RP_ATTR_SUBSYSTEM_TYPE, ReqPro40.enumAttrValueLookups.eAttrValueLookup_Label].Text );
2155 ghuddy 338
               }
339
               if (hasStability)
340
               {
2161 ghuddy 341
                  new_rq_obj.stability = firstTokenOnly( rq_requirement.AttrValues[Constants.RP_ATTR_STABILITY, ReqPro40.enumAttrValueLookups.eAttrValueLookup_Label].Text );
2155 ghuddy 342
               }
343
               if (hasType)
344
               {
2161 ghuddy 345
                  new_rq_obj.type = firstTokenOnly( rq_requirement.AttrValues[Constants.RP_ATTR_REQ_TYPE, ReqPro40.enumAttrValueLookups.eAttrValueLookup_Label].Text );
2155 ghuddy 346
               }
2151 ghuddy 347
            }
348
 
2155 ghuddy 349
            new_rq_obj.version = rq_requirement.VersionNumber;
2151 ghuddy 350
            new_rq_obj.versionDateTime = rq_requirement.VersionDateTime;
2155 ghuddy 351
            new_rq_obj.iKey = rq_requirement.Key;
2151 ghuddy 352
 
353
 
354
            // requirements can trace to other requirements, so we have to find those in order to re-construct
2155 ghuddy 355
            // that traceability later on. Currently, we only process TracesTo relationships from ReqPro. This
356
            // seems ok because if a ReqPro user creates a TracesFrom relationship, it shows up as a TracesTo 
357
            // relationship as well - it just depends on which element (src or dest) you are looking at to see 
358
            // which type of relationship.
2151 ghuddy 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
 
2155 ghuddy 372
                  ReqPro40.Requirement tracedToRequirement =
2151 ghuddy 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
         }
386
         else if (rq_package != null)
387
         {
2155 ghuddy 388
 
389
            new_rq_obj = new ReqPro_object();
390
 
2151 ghuddy 391
            new_rq_obj.isPackage = true;
392
 
2141 ghuddy 393
            // Packages in ReqPro may be prefixed by a number to force ReqPro's alphanumeric sorting
2155 ghuddy 394
            // algorithm to order the packages in the way the user wants, as dictated by the actual
2141 ghuddy 395
            // numbers used. EA does not have this problem because it uses a tree position number to
396
            // control a package/element's position in the project browser. So, strip off any leading
397
            // numeric from the ReqPro packages.
398
            string trimstring = " 0123456789";
399
            char[] trimmer = trimstring.ToCharArray();
2151 ghuddy 400
            string filtered_name = rq_package.Name.TrimStart(trimmer);
401
 
402
            new_rq_obj.name = filtered_name;
403
            new_rq_obj.guid = rq_package.GUID;
2155 ghuddy 404
            new_rq_obj.iKey = rq_package.Key;
405
 
406
            guid_to_obj_dictionary.Add(rq_package.GUID, new_rq_obj);
2151 ghuddy 407
         }
408
 
2155 ghuddy 409
         if (new_rq_obj != null)
410
         {
2151 ghuddy 411
 
2155 ghuddy 412
            new_rq_obj.level = level;
413
            new_rq_obj.treePos = treePos;
2151 ghuddy 414
 
2155 ghuddy 415
            // attach it to its parent object
416
            ReqPro_object parent_rq_obj = (ReqPro_object)rq_objs.Peek();
417
            parent_rq_obj.ReqPro_objects.Add( new_rq_obj );
418
            new_rq_obj.parent = parent_rq_obj;
2151 ghuddy 419
 
2155 ghuddy 420
            // keep a count of the number of requirements the object has beneath it
421
            if (true == new_rq_obj.isRequirement)
422
               parent_rq_obj.numberOfRequirements++;
2151 ghuddy 423
 
2155 ghuddy 424
            // push the new object onto the stack, ready for any sub-objects that may belong to it.
425
            // If, the next time we enter this method, the level is the same, this will get popped off.
426
            // If, the next time we enter this method, the level is lower, this and possibly more will
427
            // get popped off.
428
            rq_objs.Push(new_rq_obj);
429
            ea_treePos.Push(0);
430
         }
431
 
2151 ghuddy 432
         // capture what the hierarchy level is for the object just processed.
433
         lastLevel = level;
434
      }
435
 
436
 
2155 ghuddy 437
      private string firstTokenOnly(string s)
2151 ghuddy 438
      {
2155 ghuddy 439
         if (s != null)
2151 ghuddy 440
         {
2155 ghuddy 441
            char [] delim = {'\r'};
442
            string [] tokens = s.Split(delim,2);
443
            return tokens[0];
2151 ghuddy 444
         }
2155 ghuddy 445
         return s;
446
      }
2151 ghuddy 447
 
2155 ghuddy 448
      #endregion
2151 ghuddy 449
 
2157 ghuddy 450
      #region Trace Relationship Methods
2151 ghuddy 451
 
452
      protected int write_traces(int totalRequirements)
453
      {
2155 ghuddy 454
         trace_log = new ArrayList();
455
 
456
         Main.WriteSeperator();
457
         Main.WriteOutput(string.Format("Writing Trace Information for {0} requirements", totalRequirements), -1);
2151 ghuddy 458
         int numberWritten = 0;
459
 
460
         // adjust modulo for logging purposes so that the number of output messages is restricted
461
         // for larger and larger numbers of requirements
462
         if (totalRequirements > 1000)
463
            writeTracesModulo = 100;
464
         else if (totalRequirements > 500)
465
            writeTracesModulo = 50;
466
         else if (totalRequirements > 100)
467
            writeTracesModulo = 20;
468
         else if (totalRequirements > 50)
469
            writeTracesModulo = 10;
470
         else if (totalRequirements > 20)
471
            writeTracesModulo = 5;
2155 ghuddy 472
         else // 10 or less
2151 ghuddy 473
            writeTracesModulo = 1;
474
 
475
         foreach( ReqPro_object sub_obj in rq_root_package.ReqPro_objects )
476
         {
477
            if (Main.mustAbort)
478
               return numberWritten;
479
 
480
            numberWritten = write_traces(sub_obj, numberWritten, totalRequirements);
481
         }
482
 
2155 ghuddy 483
         Main.WriteOutput("Traces Completed", -1);
2151 ghuddy 484
 
2155 ghuddy 485
         if (trace_log.Count > 0)
486
         {
487
            DialogResult dlgRes = MessageBoxEx.Show("Display Log of Trace Connection Changes", "Confirm", MessageBoxButtons.YesNo);
488
            if (dlgRes == DialogResult.Yes)
489
            {
490
               foreach (string s in trace_log)
491
               {
492
                  Main.WriteOutput(s, -1);
493
               }
494
            }
495
         }
496
 
497
         Main.WriteSeperator();
498
 
2151 ghuddy 499
         return numberWritten;
500
      }
501
 
2155 ghuddy 502
 
2141 ghuddy 503
      /// <summary>
2155 ghuddy 504
      /// This method examines all of the ReqPro_object trace relationships and mirrors them in
2149 ghuddy 505
      /// the EA requirement elements that have been formed from each un-filtered ReqPro_objects.
506
      /// </summary>
507
      /// <param name="ea_repository"></param>
508
      /// <param name="rq_obj"></param>
2151 ghuddy 509
      private int write_traces(ReqPro_object rq_obj, int numberWritten, int totalRequirements)
2149 ghuddy 510
      {
2151 ghuddy 511
         if (Main.mustAbort)
512
            return numberWritten;
513
 
2149 ghuddy 514
         if (rq_obj.isRequirement)
515
         {
516
            // if this object had an EA element made for it during the write_ea_database() process...
517
            if (rq_obj.ea_element_ID != -1)
518
            {
2155 ghuddy 519
               // trace output
2151 ghuddy 520
               numberWritten++;
521
               if ((numberWritten % writeTracesModulo) == 0)
522
               {
2155 ghuddy 523
                  Main.WriteOutput(string.Format("   {0} of {1}", numberWritten, totalRequirements), -1);
2151 ghuddy 524
               }
525
 
2155 ghuddy 526
               // Get the EA element the object refers to
527
               EA.Element ea_req = Main.EA_Repository.GetElementByID(rq_obj.ea_element_ID);
528
               if (ea_req != null)
2149 ghuddy 529
               {
2155 ghuddy 530
                  if (ea_req.Connectors.Count != 0 || rq_obj.ReqPro_traces.Count != 0)
531
                     create_or_update_connections(ea_req, rq_obj.ReqPro_traces);
2149 ghuddy 532
               }
533
            }
534
         }
535
 
536
         // recurse to ensure we examine the entire hiearchy
537
         foreach(ReqPro_object sub_obj in rq_obj.ReqPro_objects)
538
         {
2151 ghuddy 539
            if (Main.mustAbort)
540
               break;
541
 
542
            numberWritten = write_traces(sub_obj, numberWritten, totalRequirements);
2149 ghuddy 543
         }
2151 ghuddy 544
         return numberWritten;
545
      }
546
 
2155 ghuddy 547
 
2149 ghuddy 548
      /// <summary>
2155 ghuddy 549
      /// This algorithm is intended to create or delete requirement to requirement relationships
550
      /// based upon the view of the relationship captured from ReqPro. This function processes
551
      /// just one element, and so it should be called repeatedly as the facsimile of the ReqPro
552
      /// database captured in memory as a tree structure, is parsed (see write_traces method).
2149 ghuddy 553
      /// </summary>
2155 ghuddy 554
      /// <param name="src_element"></param>
555
      /// <param name="guids"></param>
556
      protected void create_or_update_connections(EA.Element src_element, ArrayList guids)
2151 ghuddy 557
      {
2155 ghuddy 558
         bool connectorCollectionNeedsRefreshing = false;
559
 
560
         string src_tag = EA_TaggedValues.Read(src_element, Constants.TAG_TAG);
561
         string src_guid = EA_TaggedValues.Read(src_element, Constants.TAG_GUID, "");
562
 
2165 ghuddy 563
         ReqPro40.Requirement rp_req = null;
564
 
2155 ghuddy 565
         // Create a list of booleans that will allow us to track which elements in the guids
566
         // list are validated.
567
         ArrayList traceValidated = null;
568
 
569
         if (guids.Count > 0)
2151 ghuddy 570
         {
2155 ghuddy 571
            traceValidated = new ArrayList();
572
            for (int i = 0; i < guids.Count; i++)
573
            {
574
               traceValidated.Add(0);  // initially, none of the guids are validated.
575
            }
2151 ghuddy 576
         }
2155 ghuddy 577
 
578
         int i_traceValidated = 0;
579
 
580
         int numberOfconnections = src_element.Connectors.Count;
581
         if (numberOfconnections > 10)
582
         {
583
            Main.WriteOutput(string.Format("   ...processing requirement with large number ({0}) of traces", numberOfconnections), src_element.ElementID);
584
         }
585
 
586
         // scan the EA elements connectors
587
         short i_c = 0;
588
         foreach(EA.Connector c in src_element.Connectors)
589
         {
590
            int destId = -1;
591
 
592
            // we dont care about direction of relationship, so test for both
593
            if (c.ClientID == src_element.ElementID)
594
               destId = c.SupplierID;
595
            else if (c.SupplierID == src_element.ElementID)
596
               destId = c.ClientID;
597
 
598
            // and make sure we filter out self-referential connectors
599
            if (destId != src_element.ElementID)
600
            {
601
               // Get the target element and obtain the tagged values that will effectively mark it as
602
               // being a requirement 
603
               EA.Element ea_tgt_req = Main.EA_Repository.GetElementByID(destId);
604
               if (ea_tgt_req != null && ea_tgt_req.Type.Equals("Requirement"))
605
               {
606
                  // Get the GUID from the referenced element
607
                  string rp_tgt_req_guid = EA_TaggedValues.Read(ea_tgt_req, Constants.TAG_GUID, "");
608
                  string rp_tgt_req_tag = EA_TaggedValues.Read(ea_tgt_req, Constants.TAG_TAG, "");
609
 
610
                  if (rp_tgt_req_guid != null && rp_tgt_req_guid.Length > 0 && rp_tgt_req_guid.StartsWith("{")
611
                     && rp_tgt_req_tag != null && rp_tgt_req_tag.Length > 0)
612
                  {
613
                     // looks like an EA element that represents a ReqPro requirement
614
 
615
                     // For this source and destination pair, look for evidence that the relationship
616
                     // is required by examining the guids list passed in as parameter.
617
                     i_traceValidated = 0;
618
                     bool validated = false;
619
                     foreach (string guid in guids)
620
                     {
621
                        // Get the target object of the trace relationship
622
                        ReqPro_object tgt_obj = guid_to_obj_dictionary[guid];
623
                        if (tgt_obj != null)
624
                        {
625
                           if (tgt_obj.ea_element_ID != -1)
626
                           {
627
                              if (destId == tgt_obj.ea_element_ID)
628
                              {
629
                                 validated = true;
630
 
631
                                 traceValidated[i_traceValidated] = (int)traceValidated[i_traceValidated] + 1;
632
 
633
                                 if ((int)traceValidated[i_traceValidated] > 1)
634
                                 {
635
                                    // this is a duplicate trace relationship, so remove it
636
                                    src_element.Connectors.DeleteAt(i_c, false);
637
                                    connectorCollectionNeedsRefreshing = true;
638
 
639
                                    trace_log.Add("Deleted duplicate connection between " + src_tag + " and " + rp_tgt_req_tag);
640
                                 }
641
                                 break;
642
                              }
643
                           }
644
                        }
645
                        i_traceValidated++;
646
                     }
647
 
648
                     if (false == validated)
649
                     {
650
                        // We did not find evidence that the trace was needed, so remove it
651
                        // but we have to check that the object at the other end of the relationship does 
652
                        // not have a trace back to us first. In EA, we dont care about directionality since
653
                        // regardless of direction, all relationships exist in the same collection, but
654
                        // this is not so in ReqPro, which has TracesTo and TracesFrom relationships (and
655
                        // other types too).
2165 ghuddy 656
                        // Also, if the target is not a reqpro requirement then we should probably leave the relationship
657
                        // in place since the target may be an element an EA user is preparing to be a ReqPro requirement
658
                        // but they have yet to export it.
2155 ghuddy 659
                        ReqPro_object tgt_obj = guid_to_obj_dictionary[rp_tgt_req_guid];
660
                        if (tgt_obj != null)
661
                        {
662
                           if (false == tgt_obj.ReqPro_traces.Contains(src_guid))
663
                           {
2165 ghuddy 664
                              // Does the current requirement we are dealing with have a relationship with another
665
                              // requirement with the GUID indicated by the tgt_obj ? If is does, then we cannot
666
                              // delete the relationship in EA. We have to go to the ReqPro database to ascertain this
667
                              // since the filter dialog may have filtered out the target object and so our local
668
                              // structure cannot tell us much in this regard.
669
                              if (rp_req == null)
670
                                 rp_req = ReqProDatabase.get_requirement_by_guid(src_guid);
2155 ghuddy 671
 
2165 ghuddy 672
                              if (rp_req != null && false == ReqProDatabase.any_relationship_exists(rp_req, tgt_obj.guid))
673
                              {
674
                                 src_element.Connectors.DeleteAt(i_c, false);
675
                                 connectorCollectionNeedsRefreshing = true;
676
 
677
                                 trace_log.Add("Deleted connection between " + src_tag + " and " + rp_tgt_req_tag);
678
                              }
2155 ghuddy 679
                           }
680
                        }
681
                     }
682
                  }
683
               }
684
            }
685
            else
686
            {
687
               // Found a self-referential requirement - this is not really allowed, so delete the connection
688
               src_element.Connectors.DeleteAt(i_c, false);
689
               trace_log.Add("Deleted self-referential connection in " + src_tag);
690
               connectorCollectionNeedsRefreshing = true;
691
            }
692
 
693
            i_c++;
694
 
695
            if ((i_c % 10) == 0)
696
            {
697
               Main.WriteOutput(string.Format("   ...{0} of {1}", (int)i_c, numberOfconnections), src_element.ElementID);
698
            }
699
         }
700
 
701
         // Now look for all guids that have not been marked as validated. For these, a new connection
702
         // must be established
703
         i_traceValidated = 0;
704
         foreach (string guid in guids)
705
         {
706
            if ((int)traceValidated[i_traceValidated] == 0)
707
            {
708
               // Get the target object of the trace relationship
709
               ReqPro_object tgt_obj = guid_to_obj_dictionary[guid];
710
               if (tgt_obj != null)
711
               {
712
                  if (tgt_obj.ea_element_ID != -1)
713
                  {
714
                     EA.Element ea_tgt_req = Main.EA_Repository.GetElementByID(tgt_obj.ea_element_ID);
715
                     if (ea_tgt_req != null && ea_tgt_req.Type.Equals("Requirement"))
716
                     {
717
                        string rp_tgt_req_tag = EA_TaggedValues.Read(ea_tgt_req, Constants.TAG_TAG, "");
718
 
719
                        // Add the new connection between the src_element and dest_element
720
                        EA.Connector c = (EA.Connector)src_element.Connectors.AddNew("", "Dependency");
721
                        c.SupplierID = ea_tgt_req.ElementID;
722
                        c.Direction = "Source -> Destination";
723
                        if (false == c.Update())
724
                        {
725
                           Main.WriteOutput("New Connector Error : " + c.GetLastError(), ea_tgt_req.ElementID );
726
                           Main.WriteOutput("...Failed to create connection between " + src_tag + " and " + rp_tgt_req_tag, ea_tgt_req.ElementID);
727
                           connectorCollectionNeedsRefreshing = true;
728
                        }
729
                        else
730
                        {
731
                           trace_log.Add("Created connection between " + src_tag + " and " + rp_tgt_req_tag);
732
                        }
733
                     }
734
                  }
735
               }
736
            }
737
 
738
            i_traceValidated++;
739
         }
740
 
741
         if (connectorCollectionNeedsRefreshing)
742
            src_element.Connectors.Refresh();
2149 ghuddy 743
      }
2155 ghuddy 744
 
745
 
2157 ghuddy 746
      #endregion
747
 
748
 
2149 ghuddy 749
      /// <summary>
2141 ghuddy 750
      /// A method to contain common pre-parsing steps.
2151 ghuddy 751
      /// </summary>
752
      private void pre_parsing()
753
      {
754
         // create an object to represent the root of the database so that we can collect
755
         // sub-objects (packages or requirements) underneath it.
756
         rq_root_package = new ReqPro_object();
757
 
2155 ghuddy 758
         rq_root_package.name = "ROOT"; // may be overriden later
759
 
2151 ghuddy 760
         // initialise the ReqPro database hierarchy tracking data
761
         rq_objs.Clear();
762
         rq_objs.Push(rq_root_package);
763
         ea_treePos.Clear();
764
         ea_treePos.Push(0);
765
         lastLevel = 0;
2141 ghuddy 766
      }
2143 ghuddy 767
 
768
 
2141 ghuddy 769
	}
2155 ghuddy 770
 
771
 
772
 
773
   public class ReqProObject_Dictionary : DictionaryBase
774
   { 
775
 
776
      public ReqPro_object this[string guid]
777
      {
778
         get {return (ReqPro_object) this.Dictionary[guid]; }
779
 
780
         set { this.Dictionary[guid] = value; } 
781
      }
782
 
783
      public void Add(string guid, ReqPro_object rp_obj) 
784
      { 
785
         this.Dictionary.Add(guid, rp_obj); 
786
      } 
787
 
788
      public bool Contains(string guid)
789
      {
790
         return this.Dictionary.Contains(guid);
791
      }
792
 
793
 
794
      public ICollection Keys
795
      {
796
         get {return this.Dictionary.Keys;}
797
      }
798
   }
2141 ghuddy 799
}