/// <summary> /// Called when an FCO or folder changes /// </summary> /// <param name="subject">the object the event(s) happened to</param> /// <param name="eventMask">objectevent_enum values ORed together</param> /// <param name="param">extra information provided for cetertain event types</param> public void ObjectEvent(MgaObject subject, uint eventMask, object param) { if (!componentEnabled) { return; } if (!handleEvents) { return; } uint uOBJEVENT_CREATED = 0; unchecked { uOBJEVENT_CREATED = (uint)objectevent_enum.OBJEVENT_CREATED; } bool objectCreatedAndNotLibObject = (eventMask & uOBJEVENT_CREATED) != 0 && (eventMask & (uint)objectevent_enum.OBJEVENT_DESTROYED) == 0 && subject.IsLibObject == false; if (xmeImportInProgress) { if (objectCreatedAndNotLibObject && subject.MetaBase.MetaRef == componentAssemblyMetaRef && componentAssemblyPathMetaRef != 0) { string path = ((IMgaFCO)subject).StrAttrByName["Path"]; if (path == "") { ((IMgaFCO)subject).StrAttrByName["Path"] = GetRandomComponentAssemblyDir(); } } return; } // TODO: Handle object events (OR eventMask with the members of objectevent_enum) // Warning: Only those events are received that you have subscribed for by setting ComponentConfig.eventMask // If the event is OBJEVENT_DESTROYED, most operations on subject will fail // Safe operations: getting Project, ObjType, ID, MetaRole, Meta, MetaBase, Name, AbsPath // Operations that will fail: all others, including attribute access and graph navigation // Try handling OBJEVENT_PRE_DESTROYED if these operations are necessary // Be careful not to modify Library objects (check subject.IsLibObject) // MessageBox.Show(eventMask.ToString()); // GMEConsole.Out.WriteLine(subject.Name); // attribute was changed and object was neither created nor destroyed bool attributeChanged = (eventMask & (uint)objectevent_enum.OBJEVENT_ATTR) != 0 && (eventMask & uOBJEVENT_CREATED) == 0 && (eventMask & (uint)objectevent_enum.OBJEVENT_DESTROYED) == 0; if (objectCreatedAndNotLibObject) { MgaObject parent; GME.MGA.Meta.objtype_enum objType; subject.GetParent(out parent, out objType); // Object was created if (subject.MetaBase.Name == "Component") { // Check that parent is a Components folder if (objType == GME.MGA.Meta.objtype_enum.OBJTYPE_FOLDER && parent.MetaBase.Name == "Components") { Process(CyPhyClasses.Component.Cast(subject)); } } else if (subject.MetaBase.Name == "ComponentAssembly") { Process(CyPhyClasses.ComponentAssembly.Cast(subject)); } } else if (attributeChanged && subject.IsLibObject == false) { MgaObject parent; GME.MGA.Meta.objtype_enum objType; subject.GetParent(out parent, out objType); if (subject.MetaBase.Name == "Component") { string oldPath = null; // Check that parent is a Components folder if (objType == GME.MGA.Meta.objtype_enum.OBJTYPE_FOLDER && parent.MetaBase.Name == "Components") { if (param != null) { var parameters = ((object[])param).ToList(); int pathAttr = parameters.IndexOf("ATTR:Path"); if (pathAttr != -1) { oldPath = (string)parameters[pathAttr + 1]; RenameComponentDirectory(CyPhyClasses.Component.Cast(subject), oldPath); } } } } } }
/// <summary> /// Elaborates a DesignContainer object. /// </summary> public override void Elaborate() { MgaFilter filter = this.Subject.Project.CreateFilter(); var allObjects = this.Subject.GetDescendantFCOs(filter); foreach (MgaFCO obj in allObjects) { if (obj.IsPrimaryDerived) { obj.DetachFromArcheType(); } } foreach (MgaFCO obj in allObjects) { if (this.Traceability.ContainsKey(obj.ID) == false) { // add to traceability this.Traceability.Add(obj.ID, obj.ID); } if (obj is MgaReference) { var reference = obj as MgaReference; if (reference.Referred == null) { if (reference.MetaBase.MetaRef == this.Factory.ComponentRefMeta) { this.Logger.WriteWarning(string.Format("Null {0} [{1}] was ignored and skipped.", reference.Name, reference.MetaBase.Name)); } continue; } var referred = reference.Referred; MgaObject parent = null; GME.MGA.Meta.objtype_enum type; reference.GetParent(out parent, out type); if (IsConfigurationType(parent)) { continue; } if (parent.MetaBase.MetaRef == Factory.DecisionGroupMeta || parent.MetaBase.MetaRef == Factory.VisualConstraintMeta || parent.MetaBase.MetaRef == Factory.And_operatorMeta || parent.MetaBase.MetaRef == Factory.Or_operatorMeta || parent.MetaBase.MetaRef == Factory.Not_operatorMeta) { // DecisionGroup can hold only ComponentRefs, so we can't do anything with its children (META-3595) continue; } if (referred.MetaBase.MetaRef == this.Factory.ComponentMeta) { var copied = this.SwitchReferenceToModel(parent as MgaModel, reference, true); // delete reference reference.DestroyObject(); } else if (referred.MetaBase.MetaRef == this.Factory.ComponentAssemblyMeta) { MgaObject parent2 = parent; GME.MGA.Meta.objtype_enum type2; // worst case this will terminate at the root folder level while (parent2 != null && parent2 is MgaModel) { // FIXME: is this safe? should we compare IDs? if (parent2 == reference.Referred) { string message = string.Format("Circular dependency: {0} --> {1}", parent2.Name, reference.Referred.Name); throw new ElaboratorCircularReferenceException(message); } parent2.GetParent(out parent2, out type2); } if (this.ComponentAssemblyReferences.Any(x => x.ID == reference.Referred.ID)) { string message = string.Format("Circular dependency: {0} --> {1}", string.Join(" -> ", this.ComponentAssemblyReferences.Select(x => x.Name)), reference.Referred.Name); throw new ElaboratorCircularReferenceException(message); } var copied = this.SwitchReferenceToModel(parent as MgaModel, reference, false); // prevent circular dependency var innerElaborator = Elaborator.GetElaborator(copied, this.Logger, UnrollConnectors) as ComponentAssemblyElaborator; // use only one map innerElaborator.Traceability = this.Traceability; innerElaborator.ComponentGUIDs = this.ComponentGUIDs; innerElaborator.ComponentCopyMap = this.ComponentCopyMap; // hold only one queue foreach (var item in this.ComponentAssemblyReferences) { innerElaborator.ComponentAssemblyReferences.Enqueue(item); } innerElaborator.ComponentAssemblyReferences.Enqueue(reference.Referred); this.InnerElaborators.Add(innerElaborator); innerElaborator.Elaborate(); // delete reference reference.DestroyObject(); } else if (referred.MetaBase.MetaRef == this.Factory.DesignContainerMeta) { MgaObject parent2 = parent; GME.MGA.Meta.objtype_enum type2; // worst case this will terminate at the root folder level while (parent2 != null && parent2 is MgaModel) { // FIXME: is this safe? should we compare IDs? if (parent2 == reference.Referred) { string message = string.Format("Circular dependency: {0} --> {1}", parent2.Name, reference.Referred.Name); throw new ElaboratorCircularReferenceException(message); } parent2.GetParent(out parent2, out type2); } if (this.DesignSpaceReferences.Any(x => x.ID == reference.Referred.ID)) { string message = string.Format("Circular dependency: {0} --> {1}", string.Join(" -> ", this.DesignSpaceReferences.Select(x => x.Name)), reference.Referred.Name); throw new ElaboratorCircularReferenceException(message); } var copied = this.SwitchReferenceToModel(parent as MgaModel, reference, false); var innerElaborator = Elaborator.GetElaborator(copied, this.Logger, UnrollConnectors) as DesignContainerElaborator; // use only one map innerElaborator.Traceability = this.Traceability; innerElaborator.ComponentGUIDs = this.ComponentGUIDs; innerElaborator.ComponentCopyMap = this.ComponentCopyMap; // hold only one queue foreach (var item in this.DesignSpaceReferences) { innerElaborator.DesignSpaceReferences.Enqueue(item); } innerElaborator.DesignSpaceReferences.Enqueue(reference.Referred); this.InnerElaborators.Add(innerElaborator); innerElaborator.Elaborate(); // delete reference reference.DestroyObject(); } } } }
/// <summary> /// Elaborates the given context recursively. /// </summary> public override void Elaborate() { SortedDictionary <string, MgaModel> parentsWithDupComponentGuids = new SortedDictionary <string, MgaModel>(); MgaFilter filter = this.Subject.Project.CreateFilter(); var allObjects = this.Subject.GetDescendantFCOs(filter); foreach (MgaFCO obj in allObjects) { if (obj.IsPrimaryDerived) { obj.DetachFromArcheType(); } } foreach (MgaFCO obj in allObjects) { if (this.Traceability.ContainsKey(obj.ID) == false) { // add to traceability this.Traceability.Add(obj.ID, obj.ID); } if (obj is MgaModel) { var model = obj as MgaModel; if (model.MetaBase.MetaRef == this.Factory.ComponentAssemblyMeta) { var managedGuid = model.StrAttrByName["ManagedGUID"]; if (string.IsNullOrEmpty(managedGuid) == false) { // copiedObj.StrAttrByName["ManagedGUID"] = managedGuid; // model.RegistryValue[RegistryNameInstanceGuidChain] = model.RegistryValue[RegistryNameInstanceGuidChain] + managedGuid; } } } else if (obj is MgaReference) { var reference = obj as MgaReference; if (reference.Referred == null) { if (reference.MetaBase.MetaRef == this.Factory.ComponentRefMeta) { this.Logger.WriteWarning(string.Format("Null {0} [{1}] was ignored and skipped.", reference.Name, reference.MetaBase.Name)); } continue; } var referred = reference.Referred; if (referred.MetaBase.MetaRef == this.Factory.ComponentMeta) { MgaObject parent = null; GME.MGA.Meta.objtype_enum type; reference.GetParent(out parent, out type); var instanceGuid = reference.GetStrAttrByNameDisp("InstanceGUID"); if (string.IsNullOrWhiteSpace(instanceGuid)) { instanceGuid = new Guid(reference.GetGuidDisp()).ToString("D"); reference.SetStrAttrByNameDisp("InstanceGUID", instanceGuid); } if (parent is MgaModel) { instanceGuid = ((MgaModel)parent).RegistryValue[RegistryNameInstanceGuidChain] + instanceGuid; bool dupComponentGuid = !this.ComponentGUIDs.Add(instanceGuid); if (dupComponentGuid) { LogDebug("Duplicate ID " + instanceGuid, reference); parentsWithDupComponentGuids[parent.AbsPath] = parent as MgaModel; } } var copied = this.SwitchReferenceToModel(parent as MgaModel, reference, createInstance: true); // delete reference reference.DestroyObject(); } else if (referred.MetaBase.MetaRef == this.Factory.ComponentAssemblyMeta) { MgaObject parent = null; GME.MGA.Meta.objtype_enum type; reference.GetParent(out parent, out type); MgaObject parent2 = parent; GME.MGA.Meta.objtype_enum type2; // worst case this will terminate at the root folder level while (parent2 != null && parent2 is MgaModel) { // FIXME: is this safe? should we compare IDs? if (parent2 == reference.Referred) { string message = string.Format("Circular dependency: {0} --> {1}", parent2.Name, reference.Referred.Name); throw new ElaboratorCircularReferenceException(message); } parent2.GetParent(out parent2, out type2); } if (this.ComponentAssemblyReferences.Any(x => x.ID == reference.Referred.ID)) { string message = string.Format("Circular dependency: {0} --> {1}", string.Join(" -> ", this.ComponentAssemblyReferences.Select(x => x.Name)), reference.Referred.Name); throw new ElaboratorCircularReferenceException(message); } var copied = this.SwitchReferenceToModel(parent as MgaModel, reference, false); // prevent circular dependency var innerElaborator = Elaborator.GetElaborator(copied, this.Logger, UnrollConnectors) as ComponentAssemblyElaborator; // use only one map innerElaborator.Traceability = this.Traceability; innerElaborator.ComponentGUIDs = this.ComponentGUIDs; innerElaborator.ComponentCopyMap = this.ComponentCopyMap; // hold only one queue foreach (var item in this.ComponentAssemblyReferences) { innerElaborator.ComponentAssemblyReferences.Enqueue(item); } innerElaborator.ComponentAssemblyReferences.Enqueue(reference.Referred); this.InnerElaborators.Add(innerElaborator); innerElaborator.Elaborate(); // delete reference reference.DestroyObject(); } } } // FIXME: it is possible for a parentWithDupComponentGuid to contain child CAs that need to be deduped also string lastPath = null; foreach (var ent in parentsWithDupComponentGuids) { if (lastPath != null) { if (ent.Key.StartsWith(lastPath)) { continue; } } lastPath = ent.Key; var model = ent.Value; allObjects = model.GetDescendantFCOs(filter); var parentGuid = model.ParentModel != null ? model.ParentModel.RegistryValue[RegistryNameInstanceGuidChain] : null; // parent model should contain the concatenated InstanceGUID string guidConcat = (parentGuid ?? "") + new Guid(model.GetGuidDisp()).ToString("D"); foreach (MgaFCO obj in allObjects) { if (obj.MetaBase.MetaRef == this.Factory.ComponentMeta) { obj.SetStrAttrByNameDisp("InstanceGUID", guidConcat + obj.GetStrAttrByNameDisp("InstanceGUID")); } if (obj.MetaBase.MetaRef == this.Factory.ComponentAssemblyMeta) { obj.RegistryValue[RegistryNameInstanceGuidChain] = guidConcat; } } } this.IsElaborated = true; }