Subversion Repositories DevTools

Rev

Rev 2141 | Rev 2151 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

using System;
using System.Text;
using System.Globalization;
using System.Collections;
using System.Windows.Forms;
using ReqPro40;


namespace EA_ReqPro
{
        /// <summary>
        /// The ReqProParser class encapsulates a parsing algorithm for a ReqPro database
        /// designed to pick out packages and requirement elements and to provide that information
        /// to a client with sufficient information to allow it to build a model of that ReqPro
        /// database content in memory, maintaining the hierarchy and ordering of objects found.
        /// </summary>
        public class ReqProParser
        {
                public ReqProParser()
                {
                }

      /// <summary>
      /// The parser will call this virtual method when it has opened a ReqPro project
      /// </summary>
      /// <param name="rq_project"></param>
      protected virtual void provideReqProDatabaseInfo(ReqPro40.Application rq_app, 
         ReqPro40.Project rq_project, 
         ReqProDB_Artifact rq_artifact,
         EA.Element rq_element)
      {
      }

      /// <summary>
      /// The parser will call this virtual method for every package it finds
      /// in the ReqPro database.
      /// </summary>
      /// <param name="level"></param>
      /// <param name="ea_repository"></param>
      /// <param name="rq_project"></param>
      /// <param name="rq_Package"></param>
      protected virtual void processPackage(int level,
                                            EA.Repository ea_repository, 
                                            ReqPro40.Project rq_project, 
                                            ReqPro40.Package rq_package)
      {
      }

      /// <summary>
      /// The parser will call this virtual method for every requirement it
      /// finds in the ReqPro database.
      /// </summary>
      /// <param name="level"></param>
      /// <param name="ea_repository"></param>
      /// <param name="rq_project"></param>
      /// <param name="rq_Package"></param>
      /// <param name="rq_Requirement"></param>
      protected virtual void processRequirement(int level,
                                                EA.Repository ea_repository, 
                                                ReqPro40.Project rq_project, 
                                                ReqPro40.Package rq_package,
                                                ReqPro40.Requirement rq_requirement)
      {
      }

      /// <summary>
      /// The parser will call this virtual method for every package or requirement it
      /// finds in the ReqPro database.
      /// </summary>
      /// <param name="level"></param>
      /// <param name="ea_repository"></param>
      /// <param name="rq_project"></param>
      /// <param name="rq_Package"></param>
      /// <param name="rq_Requirement"></param>
      protected virtual void processObject(int level,
                                           EA.Repository ea_repository, 
                                           ReqPro40.Project rq_project, 
                                           ReqPro40.Package rq_package,
                                           ReqPro40.Requirement rq_requirement)
      {
      }




      /// <summary>
      /// Initiates a ReqPro database parsing operation using a prompted reqpro database open operation
      /// </summary>
      /// <param name="ea_repository"></param>
      /// <returns></returns>
      public virtual bool prompt_and_parse(EA.Repository ea_repository, ReqProDB_Artifact.MODE mode)
      {
         ReqPro40.Application rq_app = null;
         ReqPro40.Project rq_project = null;

         try
         {
            // If we can find a ReqProDB artifact in the package, use it to logon to the ReqPro database
            ReqProDB_Artifact RQ_Artifact = new ReqProDB_Artifact();
            EA.Element RQ_Element = RQ_Artifact.get_rq_artifact(ea_repository);
            if (RQ_Element != null)
            {
               // check to see if the ReqProDB element has the same mode as that specified by parameter
               ReqProDB_Artifact.MODE rq_art_mode = RQ_Artifact.get_mode(ea_repository, RQ_Element);
               if (rq_art_mode != ReqProDB_Artifact.MODE.UNDEFINED)
               {
                  if (rq_art_mode != mode)
                  {
                     DialogResult dlgRes = MessageBox.Show("You are attempting to use a ReqProDB element\n" +
                        "for a different purpose than that which was\n" +
                        "specified when the element was first created.\n" +
                        "Continue Anyway?", "Confirm", MessageBoxButtons.YesNo);
                     if (dlgRes != DialogResult.Yes)
                     {
                        return false;
                     }
                  }
               }

               rq_project = RQ_Artifact.OpenReqProProject(ea_repository, RQ_Element);
               if (rq_project != null)
                  rq_app = RQ_Artifact.RQ_app;
            }
            
            // If no ReqProDB artifact found, prompt user to logon to the ReqPro database
            if (rq_project == null)
            {
               // let user select the ReqPro database file name
               OpenFileDialog ofd = new OpenFileDialog();
               ofd.Title = "Select Requisite Pro project file";
               ofd.Filter = "ReqPro files (*.rqs)|*.rqs|All files (*.*)|*.*";
               DialogResult dlgRes = ofd.ShowDialog();
               if (dlgRes != DialogResult.OK)
                  return false;

               // let user specifiy username/password
               Logon logon = new Logon("");
               dlgRes = logon.ShowDialog();
               if (dlgRes != DialogResult.OK)
                  return false;

               string username = logon.ebUserName.Text;
               string password = logon.ebPassword.Text;

               // Connect to the ReqPro database using the ReqPro extensibility mechanism
               rq_app = new ReqPro40.ApplicationClass();

               rq_project = 
                  rq_app.OpenProject(ofd.FileName,
                  ReqPro40.enumOpenProjectOptions.eOpenProjOpt_RQSFile,
                  username,
                  password, 
                  enumProjectFlags.eProjFlag_Normal,
                  enumRelatedProjectOptions.eRelatedProjOption_ConnectAsSpecified);

               // if we do not currently have a ReqProDB artifact, create one
               if (RQ_Element == null)
               {
                  EA_Utilities EA_Utils = new EA_Utilities(ea_repository);

                  RQ_Element = RQ_Artifact.create_rq_artifact( ea_repository, 
                     EA_Utils.get_selected_package(), 
                     rq_project.Name, 
                     rq_project.Description, 
                     logon.ebUserName.Text, 
                     ofd.FileName, 
                     rq_project.GUID);
               }
            }



            // Now do the parsing of the ReqPro database
            if (rq_project != null)
            {
               // give req pro project object to user of this class
               provideReqProDatabaseInfo(rq_app, rq_project, RQ_Artifact, RQ_Element);

               // Get the ReqPro root package and parse it
               ReqPro40.RootPackage rq_rootPackage = rq_project.GetRootPackage(true);

               parseRootPackage(0, ea_repository, rq_project, rq_rootPackage);
               return true;
            }
         }
         catch (Exception ex)
         {
            MessageBox.Show(ex.Message, "Error (ReqProParser::prompt_and_parse)", MessageBoxButtons.OK);
            if (rq_project != null)
               rq_project.CloseProject();
         }  
         return false;
      }

      /// <summary>
      /// This method handles the parsing of the root package in the ReqPro database.
      /// The method is almost identical to the parsePackage method, except that this
      /// deals with a ReqPro40.RootPackage object, whereas the latter deals with a
      /// ReqPro40.Package object. Perhaps the two functions could be combined into 
      /// one if we move to .NET 2 where c# has some support for generic (template)
      /// programming.
      /// </summary>
      /// <param name="repository"></param>
      /// <param name="rq_project"></param>
      /// <param name="thisPackage"></param>
      private void parseRootPackage(int level,
                                    EA.Repository ea_repository, 
                                    ReqPro40.Project rq_project, 
                                    ReqPro40.RootPackage thisPackage)
      {
         // Scan through the sub-packages of the root package
         int limit_packageCount = thisPackage.get_Count(ReqPro40.enumElementTypes.eElemType_Package);
         if (limit_packageCount > 0)
         {
            int i_packageCount;
            thisPackage.MoveFirst();
            for (i_packageCount = 0; i_packageCount < limit_packageCount; i_packageCount++)
            {
               // Read the sub-package and parse it
               ReqPro40.Package subPackage = (ReqPro40.Package)thisPackage.GetCurrentElement();
               parsePackage(level+1, ea_repository, rq_project, subPackage);
               thisPackage.MoveNext();
            }
         }

         // Scan through the requirements directly beneath the root package
         int limit_reqCount = thisPackage.get_Count(ReqPro40.enumElementTypes.eElemType_Requirement);
         if (limit_reqCount > 0)
         {
            // Obtain the requirement element key list from the root package and scan through each entry
            int i_reqCount;
            System.Object[,] keyList = (System.Object[,])thisPackage.KeyList(ReqPro40.enumElementTypes.eElemType_Requirement);
            for (i_reqCount = 0; i_reqCount < limit_reqCount; i_reqCount++)
            {
               // Obtain the ReqPro requirement from its key, and parse it
               ReqPro40.Requirement thisRequirement = 
                  rq_project.GetRequirement(keyList[0,i_reqCount],
                                            ReqPro40.enumRequirementLookups.eReqLookup_Key,
                                            ReqPro40.enumRequirementsWeights.eReqWeight_Heavy,
                                            ReqPro40.enumRequirementFlags.eReqFlag_RetainHierarchy);

               if (thisRequirement != null)
               {
                  parseRequirement(level+1, ea_repository, rq_project, null, thisRequirement);                  
               }
            }
         }
      }

      /// <summary>
      /// This method handles the parsing of each package beneath the root package
      /// in the ReqPro database.
      /// The method is almost identical to the parseRootPackage method, except that 
      /// this deals with a ReqPro40.Package object, whereas the latter deals with a
      /// ReqPro40.RootPackage object. Perhaps the two functions could be combined into 
      /// one if we move to .NET 2 where c# has some support for generic (template)
      /// programming.      
      /// </summary>
      /// <param name="repository"></param>
      /// <param name="rq_project"></param>
      /// <param name="thisPackage"></param>
      private void parsePackage(int level,
                                EA.Repository ea_repository, 
                                ReqPro40.Project rq_project, 
                                ReqPro40.Package thisPackage)
      {
         // call user defined functions
         processPackage(level, ea_repository, rq_project, thisPackage);
         processObject(level, ea_repository, rq_project, thisPackage, null);

         // Scan through the sub-packages of this package
         int limit_packageCount = thisPackage.get_Count(ReqPro40.enumElementTypes.eElemType_Package);
         if (limit_packageCount > 0)
         {
            int i_packageCount;
            thisPackage.MoveFirst();
            for (i_packageCount = 0; i_packageCount < limit_packageCount; i_packageCount++)
            {
               // Read the sub-package and parse it
               ReqPro40.Package subPackage = (ReqPro40.Package)thisPackage.GetCurrentElement();
               parsePackage(level+1, ea_repository, rq_project, subPackage);
               thisPackage.MoveNext();
            }
         }

         // Scan through the requirements directly beneath this package
         int limit_reqCount = thisPackage.get_Count(ReqPro40.enumElementTypes.eElemType_Requirement);
         if (limit_reqCount > 0)
         {
            // Obtain the requirement element key list from this package and scan through each entry
            int i_reqCount;
            System.Object[,] keyList = (System.Object[,])thisPackage.KeyList(ReqPro40.enumElementTypes.eElemType_Requirement);
            for (i_reqCount = 0; i_reqCount < limit_reqCount; i_reqCount++)
            {
               // Obtain the ReqPro requirement from its key, and parse it
               ReqPro40.Requirement thisRequirement = 
                  rq_project.GetRequirement(keyList[0,i_reqCount],
                                            ReqPro40.enumRequirementLookups.eReqLookup_Key,
                                            ReqPro40.enumRequirementsWeights.eReqWeight_Heavy,
                                            ReqPro40.enumRequirementFlags.eReqFlag_RetainHierarchy);
               if (thisRequirement != null)
               {
                  parseRequirement(level+1, ea_repository, rq_project, thisPackage, thisRequirement);                  
               }
            }
         }
      }



      /// <summary>
      /// This method parses a requirement and any sub-requirements found in the 
      /// ReqPro database by the package/root package parsers.
      /// NOTE that when called from the parseRootPackage method, the thisPackage
      /// parameter will be null.
      /// </summary>
      /// <param name="repository"></param>
      /// <param name="rq_project"></param>
      /// <param name="thisPackage"></param>
      /// <param name="thisRequirement"></param>
      private void parseRequirement(int level,
                                    EA.Repository ea_repository, 
                                    ReqPro40.Project rq_project, 
                                    ReqPro40.Package thisPackage, 
                                    ReqPro40.Requirement thisRequirement)
      {
         // call user defined functions
         processRequirement(level, ea_repository, rq_project, thisPackage, thisRequirement);
         processObject(level, ea_repository, rq_project, thisPackage, thisRequirement);

         // requirements can have children that are requirements, so we have to find those
         int limit_numberOfChildren = 0;
         if (true == thisRequirement.get_HasChildren(ref limit_numberOfChildren))
         {
            // scan through the child relationships
            ReqPro40.Relationships theseRelationships = (ReqPro40.Relationships)thisRequirement.Children;

            int i_numberOfChildren;
            theseRelationships.MoveFirst();
            for (i_numberOfChildren = 0; i_numberOfChildren < limit_numberOfChildren; i_numberOfChildren++)
            {
               // Obtain the sub-requirement from the relationship, and parse it
               ReqPro40.Relationship thisRelationship = theseRelationships.GetCurrentRelationship();

               ReqPro40.Requirement subRequirement = 
                  thisRelationship.get_DestinationRequirement(ReqPro40.enumRequirementsWeights.eReqWeight_Heavy);

               if (subRequirement != null)
               {
                  parseRequirement(level+1, ea_repository, rq_project, thisPackage, subRequirement);
               }

               theseRelationships.MoveNext();
            }
         }
      }

        }
}