Hey @A.Acheson thanks for your help. Between your code, and a few other samples that I found online I managed to put together a working program.
An interesting aspect to this "ETM" system is that it apparently does NOT look at the BOM when moving the data over to the ERP database. Instead it looks at the information in the Model Browser (at least this is how it was described to me by the people at Genius ERP). Dealing with the BOM directly wouldn't have been a good solution, and I needed to exclude and/or suppress the various components. The code accomplishes this by first iterating through, creating the ModelStates where it must & can. It then iterates through, suppressing Content Center Files where it can. If it's an iAssembly it cannot create model states or suppress, so instead it opens the iassembly Factory & excludes the Content Center. If you watch the demonstration, you'll see where this breaks down a bit when the table gets involved, but it works in 99% of our applications, so that'll have to do. I know we weren't using this feature for what it was originally intended (reduce processor load), but Autodesk getting rid of it really screwed us!
Here's a link to a demo of it in action, make sure you chage the res to 1080p if it's too grainy:
https://drive.google.com/file/d/127fuYy3q6inEDC8BRAKChO1XY7AGUnh2/view?usp=sharing
And here's the code:
-Please note there's a sub in there SelectModelState(). I used some source code which displayed a drop down list and allowed the user to create their own model state, or select from existing ones. It then allowed the user to click on individual occurrences to suppress. I only needed this "All CC Suppressed" Model State, so some of that stuff is vestigial and commented out.
Sub Main
Dim oName As String
oName = SelectModelState()
If oName = "!!Leave The Rule!!12345" Then Return
TraverseAssemblyMS(oName)
TraverseAssemblySuppress(oName)
InventorVb.DocumentUpdate()
End Sub
Function SelectModelState()
Dim oDoc As AssemblyDocument
oDoc = ThisApplication.ActiveDocument
'Get Active Document Component Definition
Dim oAsmCompDef As AssemblyComponentDefinition
oAsmCompDef = oDoc.ComponentDefinition
'Get the current Model State
oCurrrent = oDoc.ModelStateName
'Create a list and add "create New State" as the first member of the list
Dim oList As New ArrayList
oList.Add("*** Create New State ***")
'Get all Model States in the active document and add each of them to the list
Dim oModelState As ModelState
For Each oModelState In oDoc.ComponentDefinition.ModelStates
oList.Add(oModelState.Name)
Next
If Not oList.Contains("All CC Suppressed") Then
oList.Add("All CC Suppressed")
End If
'Display the list in a box and allow the user to select one.
'oName = InputListBox("Select one to use", oList, oCurrrent, "States")
oName = "All CC Suppressed"
If oName = "*** Create New State ***" Then
oName = InputBox("Enter name for new model state: ", "Create Model State", "New Model State")
End If
'I had to do this because a Function can't return a null, and attempting to do so crashed inventor.
If oName = "" Then 'Return 'exit rule
oName = "!!Leave The Rule!!12345"
End If
oFound = False
'look for Modelstate and set active if found
For Each oModelState In oDoc.ComponentDefinition.ModelStates
If oModelState.Name = oName Then
oDoc.ComponentDefinition.ModelStates.Item(oName).Activate()
oFound = True
End If
Next
'create ModelState in the top level if it wasn't found
If oFound = False And oName <> "!!Leave The Rule!!12345" Then
oModelState = oDoc.ComponentDefinition.ModelStates.Add(oName)
End If
Return oName
End Function
'This sub Traverses the assembly & applies the model states to any assembly that can have one
Sub TraverseAssemblyMS(oName As String)
Dim oDoc As AssemblyDocument
oDoc = ThisApplication.ActiveDocument
Dim oOCD As ComponentDefinition
oOCD = oDoc.ComponentDefinition
Dim oOcc As ComponentOccurrence
' Get all occurrences from component definition for Assembly document
For Each oOcc In oOCD.Occurrences
Dim bWasSuppressed As Boolean = False
If oOcc.Suppressed Then
bWasSuppressed = True
oOcc.Unsuppress
End If
Dim docFNmae As String
Dim oOccDef As ComponentDefinition
oOccDef = oOcc.Definition
docFName = oOccDef.Document.FullFileName
oOccObjectType = oOccDef.Type
' 'check for content center at the top level.
If oOcc.SubOccurrences.Count <> 0 And Not UCase(docFName).Contains("REELEX\CONTENT CENTER FILES") And Not UCase(docFName).Contains("REELEX\DESIGNS\PARTS") And Not UCase(docFName).Contains("\FRAME\") And Not oOcc.IsiAssemblyMember Then
CreateModelState(oOcc, oName)
processAllSubOccMS(oOcc, oName)
Else If oOcc.IsiAssemblyMember
End If
InventorVb.DocumentUpdate()
Next
End Sub
' This function is called for processing sub assembly. It is called recursively
' to iterate through the entire assembly tree.
Private Sub processAllSubOccMS (ByVal oOcc As ComponentOccurrence, oName As String)
Dim oSubCompOcc As ComponentOccurrence
For Each oSubCompOcc In oOcc.SubOccurrences
Dim bWasSuppressed As Boolean = False
'This means that this ModelState already existed. So gotta open the parent file, then unsuppress.
If oSubCompOcc.Suppressed Then
bWasSuppressed = True
UnsuppressInParent(oSubCompOcc, oName)
InventorVb.DocumentUpdate()
End If
Dim docFNmae As String
Dim oOccDef As ComponentDefinition
oOccDef = oSubCompOcc.Definition
docFName = oOccDef.Document.FullFileName
'If the occurence is located in content center
If oSubCompOcc.SubOccurrences.Count <> 0 And Not UCase(docFName).Contains("REELEX\CONTENT CENTER FILES") And Not UCase(docFName).Contains("REELEX\DESIGNS\PARTS") And Not UCase(docFName).Contains("\FRAME\") And Not oSubCompOcc.IsiAssemblyMember Then
'If it's got subOccurences and its not Content Center, not a part, and not a frame, there might be CC lower, so keep going
'Recursively call this Sub
Call processAllSubOccMS(oSubCompOcc, oName)
'Create the model state in a subassembly
CreateModelStateinSub(oSubCompOcc, oName)
Else If oSubCompOcc.IsiAssemblyMember Then
End If
Next
End Sub
Sub CreateModelState(oOcc As ComponentOccurrence, oName As String)
'It's safe to define oOcd as an Assembly Component Definition because that's a condition for calling this Sub
Dim oOcd As AssemblyComponentDefinition
oOcd = oOcc.Definition
Dim oOcdModelStates As ModelStates
oOcdModelStates = oOcd.ModelStates
'Create a list & add all model states to the list.
Dim oList As New ArrayList
For Each oModelState In oOcdModelStates
oList.Add(oModelState.Name)
Next
'If the list does not contain the new Model States, then add it. If it does, then activate the selected model states
If Not oList.Contains(oName) Then
oOcdModelStates.Add(oName)
oOcc.ActiveModelState = oName
Else
oOcc.ActiveModelState = oName
End If
End Sub
Sub CreateModelStateinSub(oOcc As ComponentOccurrence, oName As String)
oParent = oOcc.ParentOccurrence.Definition.Document.fullfilename
oDoc = ThisApplication.Documents.Open(oOcc.Definition.Document.FullFileName, False)
' 'It's safe to define oOcd as an Assembly Component Definition because that's a condition for calling this Sub
Dim oOcd As AssemblyComponentDefinition
oOcd = oDoc.ComponentDefinition
'oOcd = oOcc.Definition
' Dim oModelState As ModelState
Dim oOcdModelStates As ModelStates
oOcdModelStates = oOcd.ModelStates
' 'Create a list & add all model states to the list.
Dim oList As New ArrayList
For Each oModelState In oOcdModelStates
oList.Add(oModelState.Name)
Next
'If the list does not contain the new Model States, then add it. If it does, then activate the selected model states
If Not oList.Contains(oName) Then
oOcdModelStates.Add(oName)
End If
'Now the Model State should be added. Now the PARENT must be opened, correct model state activated in Parent, then activate the correct model state in the occurence within the parent
oPDoc = ThisApplication.Documents.Open(oParent, False)
oPDoc.ComponentDefinition.ModelStates.Item(oName).Activate()
For Each iOcc In oPDoc.ComponentDefinition.Occurrences
If iOcc.Definition.Document Is oOcc.Definition.Document Then
iOcc.ActiveModelState = oName
End If
Next
End Sub
Sub TraverseAssemblySuppress(oName As String)
Dim oDoc As AssemblyDocument
oDoc = ThisApplication.ActiveDocument
Dim oOCD As ComponentDefinition
oOCD = oDoc.ComponentDefinition
Dim oOcc As ComponentOccurrence
' Get all occurrences from component definition for Assembly document
For Each oOcc In oOCD.Occurrences
Dim docFNmae As String
Dim oOccDef As ComponentDefinition
oOccDef = oOcc.Definition
docFName = oOccDef.Document.FullFileName
' 'check for content center at the top level.
If UCase(docFName).Contains("REELEX\CONTENT CENTER FILES") Then
'Suppress the occurence. This works on top level only
oOcc.Suppress
'Otherwise, check to see that it is an assembly that is not a part or frame.
Else If oOcc.SubOccurrences.Count <> 0 And Not UCase(docFName).Contains("REELEX\DESIGNS\PARTS") And Not UCase(docFName).Contains("\FRAME\") Then
'We want to keep traversing to either leaf nodes or CC
ProcessAllSubOccSuppress(oOcc, oName)
End If
Next
End Sub
Private Sub ProcessAllSubOccSuppress(ByVal oOcc As ComponentOccurrence, oName As String)
Dim oSubCompOcc As ComponentOccurrence
'MessageBox.Show("The program got here 0 " & oOcc.Name)
'if the subassembly is an iAssembly
If oOcc.IsiAssemblyMember Then
'MessageBox.Show("The program got here 1")
Dim oPFactory As String
oPFactory = oOcc.Definition.iAssemblyMember.ParentFactory.Parent.Document.FullFileName
'MessageBox.Show("The program got here 2" & oPFactory)
'Open the Factory Document
oPDoc = ThisApplication.Documents.Open(oPFactory, True)
'MessageBox.Show("The program got here 3")
MessageBox.Show("The code has encountered an iAssembly. It will now open the iAssembly Factory and exclude all Content Center. Please take note of the following: " & vbCr & vbCr & "- You will need to manually ""dirty"" the iassembly. You can do this by toggling exclusion on any component in the iassembly. " & vbCr & vbCr & " - Any component that is ""included"" in the table will still apear in the upper level browser & will need to be manually unchecked when running ETM. " & vbCr & vbCr & "- All content Center that is excluded by the code will need to be manually un-excluded. ", oOcc.Name)
'Iterate through the iassembly
For Each oSubCompOcc In oOcc.SubOccurrences
Dim oOccDef As ComponentDefinition
Dim docFNmae As String
oOccDef = oSubCompOcc.Definition
docFName = oOccDef.Document.FullFileName
'If the occurence is located in content center
If UCase(docFName).Contains("REELEX\CONTENT CENTER FILES") Then
oOcc.Definition.Document.Dirty = True
For Each iOcc In oPDoc.ComponentDefinition.Occurrences
If iOcc.Name = oSubCompOcc.Name Then
iOcc.Excluded = True
End If
Next
' Else if it's an assembly that's not a frame or a Part
Else If oSubCompOcc.SubOccurrences.Count <> 0 And Not UCase(docFName).Contains("REELEX\DESIGNS\PARTS") And Not UCase(docFName).Contains("\FRAME\") Then
ProcessAllSubOccSuppress(oSubCompOcc, oName)
End If
Next
Else
'MessageBox.Show("The program got here 5 " & oOcc.Name)
'Open the parent document
'Set the model state in the parent
Dim oParent As String
oParent = oOcc.Definition.Document.fullFileName
'MessageBox.Show("The program got here 6 " & oParent)
oPDoc = ThisApplication.Documents.Open(oParent, False)
oPDoc.ComponentDefinition.ModelStates.Item(oName).Activate()
For Each oSubCompOcc In oOcc.SubOccurrences
If oSubCompOcc.Suppressed Then
oSubCompOcc.Unsuppress
End If
Dim oOccDef As ComponentDefinition
Dim docFNmae As String
oOccDef = oSubCompOcc.Definition
docFName = oOccDef.Document.FullFileName
'If the occurence is located in content center
If UCase(docFName).Contains("REELEX\CONTENT CENTER FILES") Then
For Each iOcc In oPDoc.ComponentDefinition.Occurrences
If iOcc.Name = oSubCompOcc.Name Then
iOcc.Suppress
End If
Next
' Else if it's an assembly that's not a frame or a Part
Else If oSubCompOcc.SubOccurrences.Count <> 0 And Not UCase(docFName).Contains("REELEX\DESIGNS\PARTS") And Not UCase(docFName).Contains("\FRAME\") Then
ProcessAllSubOccSuppress(oSubCompOcc, oName)
End If
Next
End If
InventorVb.DocumentUpdate()
End Sub
Private Sub UnsuppressInParent(oOcc As ComponentOccurrence, oName As String)
'Open the parent Document
oParent = oOcc.ParentOccurrence.Definition.Document.fullfilename
oPDoc = ThisApplication.Documents.Open(oParent, False)
'Set the ModelState Active
oPDoc.ComponentDefinition.ModelStates.Item(oName).Activate()
'find the occurence in question and unsuppress it
For Each iOcc In oPDoc.ComponentDefinition.Occurrences
If iOcc.name = oOcc.Name
iOcc.unSuppress
End If
Next
End Sub