Subversion Repositories DevTools

Rev

Rev 2153 | Rev 2157 | 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
                     ReqProDatabase.close();
141
 
142
                     // Save filter settings to the ReqProDB element if it is available
143
                     if (RQ_Element != null)
144
                     {
145
                        RQ_Element.Notes = rq_filter.saveFilterSettings();
146
                        RQ_Element.Update();
147
                     }
148
 
149
                     return true;
150
                  }
151
                  else
152
                  {
153
                     cancelled = true;
154
                  }
2151 ghuddy 155
               }
2155 ghuddy 156
               else if (mode == ReqProDB_Artifact.MODE.EXPORT)
157
               {
158
                  ExportForm exportForm = new ExportForm();
159
                  exportForm.populate(rq_root_package, EA_TaggedValues.Read(RQ_Element, Constants.TAG_LAST_EXPORT_GUID, ""),
160
                     rq_req_types, rq_req_status_types);
161
                  DialogResult dlgRes = exportForm.ShowDialog();
162
                  if (dlgRes == DialogResult.OK)
163
                  {
164
                     // communicate user selections to the client class that will perform the export.
165
                     string folderName;
166
                     bool createFolder = exportForm.user_create_folder_selection(out folderName);
167
 
168
                     provideExportDecisionsToClient(exportForm.user_selected_object(), 
169
                        createFolder, folderName, 
170
                        exportForm.user_selected_requirement_type(), 
171
                        exportForm.user_selected_export_extent());
172
 
173
 
174
                     // NOTE: Do not close the reqpro database here. The client class will do that 
175
                     // after the export completes.
176
                     return true;
177
                  }
178
                  else
179
                  {
180
                     cancelled = true;
181
                  }
182
               }
183
               ReqProDatabase.close();
2151 ghuddy 184
            }
185
         }
186
         catch (Exception ex)
187
         {
2153 ghuddy 188
            Main.MessageBoxException(ex, "Exception (parse)");
2155 ghuddy 189
         }
190
 
2151 ghuddy 191
         return false;
192
      }
193
 
194
 
2155 ghuddy 195
 
2141 ghuddy 196
      /// <summary>
2155 ghuddy 197
      /// Function that must be overriden in a client class designed to handle the exporting of
198
      /// requirements back to ReqPro. The function gives such a class the details of selections made
199
      /// via the export form.
200
      /// </summary>
201
      /// <param name="selectedObject"></param>
202
      /// <param name="createFolder"></param>
203
      /// <param name="folderName"></param>
204
      /// <param name="requirementType"></param>
205
      /// <param name="requirementStatus"></param>
206
      protected virtual void provideExportDecisionsToClient(ReqPro_object selectedObject,
207
         bool createFolder,
208
         string folderName,
209
         string requirementType,
210
         ExportForm.ExportExtent exportExtent)
211
      {
212
      }
213
 
214
 
215
      /// <summary>
2141 ghuddy 216
      /// This method will be called by the base class parser when it has obtained a ReqPro
217
      /// project object. We capture that object here so we can interrogate the ReqPro database
218
      /// ourselves, if we need to. We wont do that for package/requirement reading, but we may
219
      /// do it for meta-data such as requirement types, etc.
220
      /// </summary>
2151 ghuddy 221
      /// <param name="reqpro_project"></param>
2155 ghuddy 222
      protected override void provideReqProDatabaseInfo(
2145 ghuddy 223
         ReqProDB_Artifact rq_artifact,
224
         EA.Element rq_element)
2141 ghuddy 225
      {
2145 ghuddy 226
         RQ_Artifact = rq_artifact;
227
         RQ_Element = rq_element;
2155 ghuddy 228
 
229
         // Now we have been given a ReqProDB stereotyped element, we use its parent container package
230
         // as our root package. This overrides the default setup during the class constructor.
231
         ea_rootPackage = Main.EA_Repository.GetPackageByID(RQ_Element.PackageID);
2151 ghuddy 232
      }
233
 
2155 ghuddy 234
 
2141 ghuddy 235
      /// <summary>
236
      /// This method will be called by the base class parser whenever a package or requirement object
2155 ghuddy 237
      /// is found in the ReqPro database. The method collects important information from the object
2141 ghuddy 238
      /// into a structure that begins with the ea_rootPackage object. The structure is highly dynamic
239
      /// with each object able to hold a list of other objects. This naturally allows for the ReqPro
240
      /// database hierarchy to be accurately reflected. The hierarchy tracking data maintained within
241
      /// the method allows us to know what object in the structure to hang off any new object derived
242
      /// from info given to us by the base class parser (ie. what object is the parent object at the
243
      /// present time during the parsing).
244
      /// </summary>
245
      /// <param name="level"></param>
246
      /// <param name="ea_repository"></param>
247
      /// <param name="rq_project"></param>
248
      /// <param name="rq_package"></param>
2151 ghuddy 249
      /// <param name="rq_requirement"></param>
250
      protected override void processObject(int level,
2141 ghuddy 251
                                            ReqPro40.Package rq_package,
252
                                            ReqPro40.Requirement rq_requirement)
253
      {
2155 ghuddy 254
         // If we are still at the same level as the previous package, then pop the previous object
2151 ghuddy 255
         // in readiness for pushing the one we are now dealing with.
256
         if (level == lastLevel)
257
         {
258
            rq_objs.Pop();
259
            ea_treePos.Pop();
260
         }
2155 ghuddy 261
         // but if we are beneath the previous level, pop all objects that are above us because
262
         // we no longer need them in our hierarchy reference data.
2151 ghuddy 263
         else if (level < lastLevel)
264
         {
265
            while (lastLevel >= level)
266
            {
267
               rq_objs.Pop();
268
               ea_treePos.Pop();
269
               lastLevel--;
270
            }
271
         }
272
 
273
         // bump the tree position at this level (controls display position in the EA project browser)
274
         int treePos = (int)ea_treePos.Pop();
275
         treePos++;
276
         ea_treePos.Push(treePos);
277
 
278
         // create the new requirement or package
2155 ghuddy 279
         ReqPro_object new_rq_obj = null;
2151 ghuddy 280
         if (rq_requirement != null)
281
         {
2155 ghuddy 282
            new_rq_obj = new ReqPro_object();
283
 
2151 ghuddy 284
            new_rq_obj.isRequirement = true;
285
            new_rq_obj.name   = rq_requirement.Name;
286
            new_rq_obj.text   = rq_requirement.Text;
287
            new_rq_obj.guid   = rq_requirement.GUID;
288
            new_rq_obj.tag    = rq_requirement.get_Tag(ReqPro40.enumTagFormat.eTagFormat_FullTag);
289
 
2155 ghuddy 290
            guid_to_obj_dictionary.Add(rq_requirement.GUID, new_rq_obj);
291
 
2151 ghuddy 292
            bool hasStatus = false;
293
            bool hasDifficulty = false;
294
            bool hasPriority = false;
2153 ghuddy 295
            bool hasSource = false;
296
            bool hasSourceVersion = false;
297
            bool hasSourceSection = false;
2155 ghuddy 298
            bool hasSubsystem = false;
299
            bool hasStability = false;
300
            bool hasType = false;
2153 ghuddy 301
 
2155 ghuddy 302
            // Acquire attributes from ReqPro.
303
            // Note the use of firstTokenOnly() on those attributes that are freeform text. Those
304
            // will most likely be stored in EA tagged values, which have a 256 char size limitation.
305
            // The intention is to limit the attribute to a single line, which hopefully should get it under the
306
            // size limit. If it does not, the addin will truncate the string and issue a warning when
307
            // it writes the tagged value.
308
            if (reqTypeHasOneOrMoreAttrs(new_rq_obj,
2153 ghuddy 309
               ref hasStatus, ref hasDifficulty, ref hasPriority,
2155 ghuddy 310
               ref hasSource, ref hasSourceVersion, ref hasSourceSection,
311
               ref hasSubsystem, ref hasStability, ref hasType))
2151 ghuddy 312
            {
313
               if (hasStatus)
314
               {
315
                  new_rq_obj.status = rq_requirement.AttrValues["Status", ReqPro40.enumAttrValueLookups.eAttrValueLookup_Label].Text;
316
               }
317
               if (hasDifficulty)
318
               {
319
                  new_rq_obj.difficulty = rq_requirement.AttrValues["Difficulty", ReqPro40.enumAttrValueLookups.eAttrValueLookup_Label].Text;
320
               }
321
               if (hasPriority)
322
               {
323
                  new_rq_obj.priority = rq_requirement.AttrValues["Priority", ReqPro40.enumAttrValueLookups.eAttrValueLookup_Label].Text;
324
               }
2153 ghuddy 325
               if (hasSource)
326
               {
2155 ghuddy 327
                  new_rq_obj.source = firstTokenOnly( rq_requirement.AttrValues["Source", ReqPro40.enumAttrValueLookups.eAttrValueLookup_Label].Text );
2153 ghuddy 328
               }
329
               if (hasSourceVersion)
330
               {
2155 ghuddy 331
                  new_rq_obj.sourceVersion = firstTokenOnly( rq_requirement.AttrValues["Source Version", ReqPro40.enumAttrValueLookups.eAttrValueLookup_Label].Text );
2153 ghuddy 332
               }
333
               if (hasSourceSection)
334
               {
2155 ghuddy 335
                  new_rq_obj.sourceSection = firstTokenOnly( rq_requirement.AttrValues["Source Section", ReqPro40.enumAttrValueLookups.eAttrValueLookup_Label].Text );
2153 ghuddy 336
               }
2155 ghuddy 337
               if (hasSubsystem)
338
               {
339
                  new_rq_obj.subsystem = firstTokenOnly( rq_requirement.AttrValues["Subsystem", ReqPro40.enumAttrValueLookups.eAttrValueLookup_Label].Text );
340
               }
341
               if (hasStability)
342
               {
343
                  new_rq_obj.stability = firstTokenOnly( rq_requirement.AttrValues["Stability", ReqPro40.enumAttrValueLookups.eAttrValueLookup_Label].Text );
344
               }
345
               if (hasType)
346
               {
347
                  new_rq_obj.type = firstTokenOnly( rq_requirement.AttrValues["Requirement Type", ReqPro40.enumAttrValueLookups.eAttrValueLookup_Label].Text );
348
               }
2151 ghuddy 349
            }
350
 
2155 ghuddy 351
            new_rq_obj.version = rq_requirement.VersionNumber;
2151 ghuddy 352
            new_rq_obj.versionDateTime = rq_requirement.VersionDateTime;
2155 ghuddy 353
            new_rq_obj.iKey = rq_requirement.Key;
2151 ghuddy 354
 
355
 
356
            // requirements can trace to other requirements, so we have to find those in order to re-construct
2155 ghuddy 357
            // that traceability later on. Currently, we only process TracesTo relationships from ReqPro. This
358
            // seems ok because if a ReqPro user creates a TracesFrom relationship, it shows up as a TracesTo 
359
            // relationship as well - it just depends on which element (src or dest) you are looking at to see 
360
            // which type of relationship.
2151 ghuddy 361
            int limit_numberOfTracesTo = 0;
362
            if (true == rq_requirement.get_HasTracesTo(ref limit_numberOfTracesTo))
363
            {
364
               // scan through the TracesTo relationships
365
               ReqPro40.Relationships theseRelationships = (ReqPro40.Relationships)rq_requirement.TracesTo;
366
 
367
               int i_numberOfTracesTo;
368
               theseRelationships.MoveFirst();
369
               for (i_numberOfTracesTo = 0; i_numberOfTracesTo < limit_numberOfTracesTo; i_numberOfTracesTo++)
370
               {
371
                  // Obtain the traced-to requirement from the relationship, and parse it
372
                  ReqPro40.Relationship thisRelationship = theseRelationships.GetCurrentRelationship();
373
 
2155 ghuddy 374
                  ReqPro40.Requirement tracedToRequirement =
2151 ghuddy 375
                     thisRelationship.get_DestinationRequirement(ReqPro40.enumRequirementsWeights.eReqWeight_Heavy);
376
 
377
                  if (tracedToRequirement != null)
378
                  {
379
                     // Add the GUID of the traced-to requirement to the relevant list within the
380
                     // object representing the traced-from requirement (ie. parent requirement).
381
                     new_rq_obj.ReqPro_traces.Add(tracedToRequirement.GUID);
382
                  }
383
 
384
                  theseRelationships.MoveNext();
385
               }
386
            }
387
         }
388
         else if (rq_package != null)
389
         {
2155 ghuddy 390
 
391
            new_rq_obj = new ReqPro_object();
392
 
2151 ghuddy 393
            new_rq_obj.isPackage = true;
394
 
2141 ghuddy 395
            // Packages in ReqPro may be prefixed by a number to force ReqPro's alphanumeric sorting
2155 ghuddy 396
            // algorithm to order the packages in the way the user wants, as dictated by the actual
2141 ghuddy 397
            // numbers used. EA does not have this problem because it uses a tree position number to
398
            // control a package/element's position in the project browser. So, strip off any leading
399
            // numeric from the ReqPro packages.
400
            string trimstring = " 0123456789";
401
            char[] trimmer = trimstring.ToCharArray();
2151 ghuddy 402
            string filtered_name = rq_package.Name.TrimStart(trimmer);
403
 
404
            new_rq_obj.name = filtered_name;
405
            new_rq_obj.guid = rq_package.GUID;
2155 ghuddy 406
            new_rq_obj.iKey = rq_package.Key;
407
 
408
            guid_to_obj_dictionary.Add(rq_package.GUID, new_rq_obj);
2151 ghuddy 409
         }
410
 
2155 ghuddy 411
         if (new_rq_obj != null)
412
         {
2151 ghuddy 413
 
2155 ghuddy 414
            new_rq_obj.level = level;
415
            new_rq_obj.treePos = treePos;
2151 ghuddy 416
 
2155 ghuddy 417
            // attach it to its parent object
418
            ReqPro_object parent_rq_obj = (ReqPro_object)rq_objs.Peek();
419
            parent_rq_obj.ReqPro_objects.Add( new_rq_obj );
420
            new_rq_obj.parent = parent_rq_obj;
2151 ghuddy 421
 
2155 ghuddy 422
            // keep a count of the number of requirements the object has beneath it
423
            if (true == new_rq_obj.isRequirement)
424
               parent_rq_obj.numberOfRequirements++;
2151 ghuddy 425
 
2155 ghuddy 426
            // push the new object onto the stack, ready for any sub-objects that may belong to it.
427
            // If, the next time we enter this method, the level is the same, this will get popped off.
428
            // If, the next time we enter this method, the level is lower, this and possibly more will
429
            // get popped off.
430
            rq_objs.Push(new_rq_obj);
431
            ea_treePos.Push(0);
432
         }
433
 
2151 ghuddy 434
         // capture what the hierarchy level is for the object just processed.
435
         lastLevel = level;
436
      }
437
 
438
 
2155 ghuddy 439
      private string firstTokenOnly(string s)
2151 ghuddy 440
      {
2155 ghuddy 441
         if (s != null)
2151 ghuddy 442
         {
2155 ghuddy 443
            char [] delim = {'\r'};
444
            string [] tokens = s.Split(delim,2);
445
            return tokens[0];
2151 ghuddy 446
         }
2155 ghuddy 447
         return s;
448
      }
2151 ghuddy 449
 
2155 ghuddy 450
      #endregion
2151 ghuddy 451
 
452
 
453
      protected int write_traces(int totalRequirements)
454
      {
2155 ghuddy 455
         trace_log = new ArrayList();
456
 
457
         Main.WriteSeperator();
458
         Main.WriteOutput(string.Format("Writing Trace Information for {0} requirements", totalRequirements), -1);
2151 ghuddy 459
         int numberWritten = 0;
460
 
461
         // adjust modulo for logging purposes so that the number of output messages is restricted
462
         // for larger and larger numbers of requirements
463
         if (totalRequirements > 1000)
464
            writeTracesModulo = 100;
465
         else if (totalRequirements > 500)
466
            writeTracesModulo = 50;
467
         else if (totalRequirements > 100)
468
            writeTracesModulo = 20;
469
         else if (totalRequirements > 50)
470
            writeTracesModulo = 10;
471
         else if (totalRequirements > 20)
472
            writeTracesModulo = 5;
2155 ghuddy 473
         else // 10 or less
2151 ghuddy 474
            writeTracesModulo = 1;
475
 
476
         foreach( ReqPro_object sub_obj in rq_root_package.ReqPro_objects )
477
         {
478
            if (Main.mustAbort)
479
               return numberWritten;
480
 
481
            numberWritten = write_traces(sub_obj, numberWritten, totalRequirements);
482
         }
483
 
2155 ghuddy 484
         Main.WriteOutput("Traces Completed", -1);
2151 ghuddy 485
 
2155 ghuddy 486
         if (trace_log.Count > 0)
487
         {
488
            DialogResult dlgRes = MessageBoxEx.Show("Display Log of Trace Connection Changes", "Confirm", MessageBoxButtons.YesNo);
489
            if (dlgRes == DialogResult.Yes)
490
            {
491
               foreach (string s in trace_log)
492
               {
493
                  Main.WriteOutput(s, -1);
494
               }
495
            }
496
         }
497
 
498
         Main.WriteSeperator();
499
 
2151 ghuddy 500
         return numberWritten;
501
      }
502
 
2155 ghuddy 503
 
2141 ghuddy 504
      /// <summary>
2155 ghuddy 505
      /// This method examines all of the ReqPro_object trace relationships and mirrors them in
2149 ghuddy 506
      /// the EA requirement elements that have been formed from each un-filtered ReqPro_objects.
507
      /// </summary>
508
      /// <param name="ea_repository"></param>
509
      /// <param name="rq_obj"></param>
2151 ghuddy 510
      private int write_traces(ReqPro_object rq_obj, int numberWritten, int totalRequirements)
2149 ghuddy 511
      {
2151 ghuddy 512
         if (Main.mustAbort)
513
            return numberWritten;
514
 
2149 ghuddy 515
         if (rq_obj.isRequirement)
516
         {
517
            // if this object had an EA element made for it during the write_ea_database() process...
518
            if (rq_obj.ea_element_ID != -1)
519
            {
2155 ghuddy 520
               // trace output
2151 ghuddy 521
               numberWritten++;
522
               if ((numberWritten % writeTracesModulo) == 0)
523
               {
2155 ghuddy 524
                  Main.WriteOutput(string.Format("   {0} of {1}", numberWritten, totalRequirements), -1);
2151 ghuddy 525
               }
526
 
2155 ghuddy 527
               // Get the EA element the object refers to
528
               EA.Element ea_req = Main.EA_Repository.GetElementByID(rq_obj.ea_element_ID);
529
               if (ea_req != null)
2149 ghuddy 530
               {
2155 ghuddy 531
                  if (ea_req.Connectors.Count != 0 || rq_obj.ReqPro_traces.Count != 0)
532
                     create_or_update_connections(ea_req, rq_obj.ReqPro_traces);
2149 ghuddy 533
               }
534
            }
535
         }
536
 
537
         // recurse to ensure we examine the entire hiearchy
538
         foreach(ReqPro_object sub_obj in rq_obj.ReqPro_objects)
539
         {
2151 ghuddy 540
            if (Main.mustAbort)
541
               break;
542
 
543
            numberWritten = write_traces(sub_obj, numberWritten, totalRequirements);
2149 ghuddy 544
         }
2151 ghuddy 545
         return numberWritten;
546
      }
547
 
2155 ghuddy 548
 
2149 ghuddy 549
      /// <summary>
2155 ghuddy 550
      /// This algorithm is intended to create or delete requirement to requirement relationships
551
      /// based upon the view of the relationship captured from ReqPro. This function processes
552
      /// just one element, and so it should be called repeatedly as the facsimile of the ReqPro
553
      /// database captured in memory as a tree structure, is parsed (see write_traces method).
2149 ghuddy 554
      /// </summary>
2155 ghuddy 555
      /// <param name="src_element"></param>
556
      /// <param name="guids"></param>
557
      protected void create_or_update_connections(EA.Element src_element, ArrayList guids)
2151 ghuddy 558
      {
2155 ghuddy 559
         bool connectorCollectionNeedsRefreshing = false;
560
 
561
         string src_tag = EA_TaggedValues.Read(src_element, Constants.TAG_TAG);
562
         string src_guid = EA_TaggedValues.Read(src_element, Constants.TAG_GUID, "");
563
 
564
         // Create a list of booleans that will allow us to track which elements in the guids
565
         // list are validated.
566
         ArrayList traceValidated = null;
567
 
568
         if (guids.Count > 0)
2151 ghuddy 569
         {
2155 ghuddy 570
            traceValidated = new ArrayList();
571
            for (int i = 0; i < guids.Count; i++)
572
            {
573
               traceValidated.Add(0);  // initially, none of the guids are validated.
574
            }
2151 ghuddy 575
         }
2155 ghuddy 576
 
577
         int i_traceValidated = 0;
578
 
579
         int numberOfconnections = src_element.Connectors.Count;
580
         if (numberOfconnections > 10)
581
         {
582
            Main.WriteOutput(string.Format("   ...processing requirement with large number ({0}) of traces", numberOfconnections), src_element.ElementID);
583
         }
584
 
585
         // scan the EA elements connectors
586
         short i_c = 0;
587
         foreach(EA.Connector c in src_element.Connectors)
588
         {
589
            int destId = -1;
590
 
591
            // we dont care about direction of relationship, so test for both
592
            if (c.ClientID == src_element.ElementID)
593
               destId = c.SupplierID;
594
            else if (c.SupplierID == src_element.ElementID)
595
               destId = c.ClientID;
596
 
597
            // and make sure we filter out self-referential connectors
598
            if (destId != src_element.ElementID)
599
            {
600
               // Get the target element and obtain the tagged values that will effectively mark it as
601
               // being a requirement 
602
               EA.Element ea_tgt_req = Main.EA_Repository.GetElementByID(destId);
603
               if (ea_tgt_req != null && ea_tgt_req.Type.Equals("Requirement"))
604
               {
605
                  // Get the GUID from the referenced element
606
                  string rp_tgt_req_guid = EA_TaggedValues.Read(ea_tgt_req, Constants.TAG_GUID, "");
607
                  string rp_tgt_req_tag = EA_TaggedValues.Read(ea_tgt_req, Constants.TAG_TAG, "");
608
 
609
                  if (rp_tgt_req_guid != null && rp_tgt_req_guid.Length > 0 && rp_tgt_req_guid.StartsWith("{")
610
                     && rp_tgt_req_tag != null && rp_tgt_req_tag.Length > 0)
611
                  {
612
                     // looks like an EA element that represents a ReqPro requirement
613
 
614
                     // For this source and destination pair, look for evidence that the relationship
615
                     // is required by examining the guids list passed in as parameter.
616
                     i_traceValidated = 0;
617
                     bool validated = false;
618
                     foreach (string guid in guids)
619
                     {
620
                        // Get the target object of the trace relationship
621
                        ReqPro_object tgt_obj = guid_to_obj_dictionary[guid];
622
                        if (tgt_obj != null)
623
                        {
624
                           if (tgt_obj.ea_element_ID != -1)
625
                           {
626
                              if (destId == tgt_obj.ea_element_ID)
627
                              {
628
                                 validated = true;
629
 
630
                                 traceValidated[i_traceValidated] = (int)traceValidated[i_traceValidated] + 1;
631
 
632
                                 if ((int)traceValidated[i_traceValidated] > 1)
633
                                 {
634
                                    // this is a duplicate trace relationship, so remove it
635
                                    src_element.Connectors.DeleteAt(i_c, false);
636
                                    connectorCollectionNeedsRefreshing = true;
637
 
638
                                    trace_log.Add("Deleted duplicate connection between " + src_tag + " and " + rp_tgt_req_tag);
639
                                 }
640
                                 break;
641
                              }
642
                           }
643
                        }
644
                        i_traceValidated++;
645
                     }
646
 
647
                     if (false == validated)
648
                     {
649
                        // We did not find evidence that the trace was needed, so remove it
650
                        // but we have to check that the object at the other end of the relationship does 
651
                        // not have a trace back to us first. In EA, we dont care about directionality since
652
                        // regardless of direction, all relationships exist in the same collection, but
653
                        // this is not so in ReqPro, which has TracesTo and TracesFrom relationships (and
654
                        // other types too).
655
                        ReqPro_object tgt_obj = guid_to_obj_dictionary[rp_tgt_req_guid];
656
                        if (tgt_obj != null)
657
                        {
658
                           if (false == tgt_obj.ReqPro_traces.Contains(src_guid))
659
                           {
660
                              src_element.Connectors.DeleteAt(i_c, false);
661
                              connectorCollectionNeedsRefreshing = true;
662
 
663
                              trace_log.Add("Deleted connection between " + src_tag + " and " + rp_tgt_req_tag);
664
                           }
665
                        }
666
                     }
667
                  }
668
               }
669
            }
670
            else
671
            {
672
               // Found a self-referential requirement - this is not really allowed, so delete the connection
673
               src_element.Connectors.DeleteAt(i_c, false);
674
               trace_log.Add("Deleted self-referential connection in " + src_tag);
675
               connectorCollectionNeedsRefreshing = true;
676
            }
677
 
678
            i_c++;
679
 
680
            if ((i_c % 10) == 0)
681
            {
682
               Main.WriteOutput(string.Format("   ...{0} of {1}", (int)i_c, numberOfconnections), src_element.ElementID);
683
            }
684
         }
685
 
686
         // Now look for all guids that have not been marked as validated. For these, a new connection
687
         // must be established
688
         i_traceValidated = 0;
689
         foreach (string guid in guids)
690
         {
691
            if ((int)traceValidated[i_traceValidated] == 0)
692
            {
693
               // Get the target object of the trace relationship
694
               ReqPro_object tgt_obj = guid_to_obj_dictionary[guid];
695
               if (tgt_obj != null)
696
               {
697
                  if (tgt_obj.ea_element_ID != -1)
698
                  {
699
                     EA.Element ea_tgt_req = Main.EA_Repository.GetElementByID(tgt_obj.ea_element_ID);
700
                     if (ea_tgt_req != null && ea_tgt_req.Type.Equals("Requirement"))
701
                     {
702
                        string rp_tgt_req_tag = EA_TaggedValues.Read(ea_tgt_req, Constants.TAG_TAG, "");
703
 
704
                        // Add the new connection between the src_element and dest_element
705
                        EA.Connector c = (EA.Connector)src_element.Connectors.AddNew("", "Dependency");
706
                        c.SupplierID = ea_tgt_req.ElementID;
707
                        c.Direction = "Source -> Destination";
708
                        if (false == c.Update())
709
                        {
710
                           Main.WriteOutput("New Connector Error : " + c.GetLastError(), ea_tgt_req.ElementID );
711
                           Main.WriteOutput("...Failed to create connection between " + src_tag + " and " + rp_tgt_req_tag, ea_tgt_req.ElementID);
712
                           connectorCollectionNeedsRefreshing = true;
713
                        }
714
                        else
715
                        {
716
                           trace_log.Add("Created connection between " + src_tag + " and " + rp_tgt_req_tag);
717
                        }
718
                     }
719
                  }
720
               }
721
            }
722
 
723
            i_traceValidated++;
724
         }
725
 
726
         if (connectorCollectionNeedsRefreshing)
727
            src_element.Connectors.Refresh();
2149 ghuddy 728
      }
2155 ghuddy 729
 
730
 
2149 ghuddy 731
      /// <summary>
2141 ghuddy 732
      /// A method to contain common pre-parsing steps.
2151 ghuddy 733
      /// </summary>
734
      private void pre_parsing()
735
      {
736
         // create an object to represent the root of the database so that we can collect
737
         // sub-objects (packages or requirements) underneath it.
738
         rq_root_package = new ReqPro_object();
739
 
2155 ghuddy 740
         rq_root_package.name = "ROOT"; // may be overriden later
741
 
2151 ghuddy 742
         // initialise the ReqPro database hierarchy tracking data
743
         rq_objs.Clear();
744
         rq_objs.Push(rq_root_package);
745
         ea_treePos.Clear();
746
         ea_treePos.Push(0);
747
         lastLevel = 0;
2141 ghuddy 748
      }
2143 ghuddy 749
 
750
 
751
 
2155 ghuddy 752
 
2141 ghuddy 753
	}
2155 ghuddy 754
 
755
 
756
 
757
   public class ReqProObject_Dictionary : DictionaryBase
758
   { 
759
 
760
      public ReqPro_object this[string guid]
761
      {
762
         get {return (ReqPro_object) this.Dictionary[guid]; }
763
 
764
         set { this.Dictionary[guid] = value; } 
765
      }
766
 
767
      public void Add(string guid, ReqPro_object rp_obj) 
768
      { 
769
         this.Dictionary.Add(guid, rp_obj); 
770
      } 
771
 
772
      public bool Contains(string guid)
773
      {
774
         return this.Dictionary.Contains(guid);
775
      }
776
 
777
 
778
      public ICollection Keys
779
      {
780
         get {return this.Dictionary.Keys;}
781
      }
782
   }
2141 ghuddy 783
}