Sort Modelstates with api?

Sort Modelstates with api?

dg2405
Advocate Advocate
631 Views
11 Replies
Message 1 of 12

Sort Modelstates with api?

dg2405
Advocate
Advocate

Is there a way to sort modelstates with api?

0 Likes
Accepted solutions (1)
632 Views
11 Replies
Replies (11)
Message 2 of 12

WCrihfield
Mentor
Mentor

Hi @dg2405.  Can you please be more specific about what you are trying to do?  If you just mean get the names of the ModelStates into a list, then sort the list, that is fairly simple using something like the following code:

Dim oPDoc As PartDocument = ThisDoc.FactoryDocument
Dim oMSs As ModelStates = oPDoc.ComponentDefinition.ModelStates
Dim oMSNames As New List(Of String)
For Each oMS As ModelState In oMSs : oMSNames.Add(oMS.Name) : Next
oMSNames.Sort
a = InputListBox("", oMSNames, "", "ModelState Names Sorted")

...but somehow I suspect that is not what you meant.  Do you mean that you want to rearrange the order that the ModelStates appear within the Model States folder in your model browser tree?  If so, that may be possible, to a certain degree.  But the 'Master/Primary' ModelState will always remain at the top of that list, because it can not be moved.  I do know that the others can be moved manually, so I would assume we could move them by code too, if that is what you are wanting here.  Please elaborate on your request a bit more, so we fully understand what you want to achieve.

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 3 of 12

dg2405
Advocate
Advocate

I want to sort the modelstates alphabetically ascending, but found nothing in the API...

0 Likes
Message 4 of 12

WCrihfield
Mentor
Mentor

I created something that I thought would work for that scenario, but it keeps throwing an 'unspecified error' every time, and I am not sure why.  I am currently using 2022.4 version of Inventor, so the original ModelState is still named "Master", instead of "Primary", just so you know.  If you are using 2023 version, you may have to change some things within the code.

 

I am using a SortedDictionary type variable to hold a list of pairs, with each pair consisting of the ModelState.Name (as the 'Key' of the pair) and the ModelState object itself, as the 'Value' of the pair.  Due to the type of dictionary, the pairs will already be sorted by their 'Keys' (the Name) as they are entered into the dictionary.  Then get the 'Model' browser pane object to a variable.  Then I create BrowserNode type variables for the 'ModelStates' folder, the 'Master' ModelState, and one to hold the previous node, for use within the loop later.  Then I loop through each pair within the dictionary (again, already in alphabetical order now), and attempt to use the Reorder method of the BrowserPane to position the current BrowserNode (from the dictionary) just below the 'previous' BrowserNode.  For the first run of the loop, the previous node is the node for the Master/Primary ModelState.  Then I set that current node as the previous node at the end of the loop, so the next loop will know which node to place the next one after.

Dim oPDoc As PartDocument = ThisDoc.FactoryDocument
Dim oMSs As ModelStates = oPDoc.ComponentDefinition.ModelStates
Dim oMSDict As New SortedDictionary(Of String, Inventor.ModelState)
For Each oMS As ModelState In oMSs
	If oMS.ModelStateType = ModelStateTypeEnum.kMasterModelStateType Then Continue For
	oMSDict.Add(oMS.Name, oMS)
Next
Dim oBPane As BrowserPane = oPDoc.BrowserPanes.Item("Model")
Dim oMSFolder, oMasterMSNode, oPreviousNode As BrowserNode
oMasterMSNode = oBPane.GetBrowserNodeFromObject(oMSs.Item(1))
oMSFolder = oMasterMSNode.Parent
If Not oMSFolder.Expanded Then oMSFolder.Expanded = True
For Each oPair In oMSDict
	Dim oMSNode As BrowserNode = oBPane.GetBrowserNodeFromObject(oPair.Value)
	If IsNothing(oPreviousNode) Then oPreviousNode = oMasterMSNode
	oBPane.Reorder(oPreviousNode, False, oMSNode)
	oPreviousNode = oMSNode
Next

This seems like the normal way to do this task, but for whatever reason, it has not been working in my tests so far.  If you are using a newer version of Inventor, maybe it will work better for you.  Or maybe someone else here on the forums will figure out why it is not working, and be able to correct it.

 

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 5 of 12

dg2405
Advocate
Advocate

GetBrowserNodeFromObject always is giving the TopNode, thats the problem...

oBPane.GetBrowserNodeFromObject(oMSs.Item(1))
oBPane.GetBrowserNodeFromObject(oPair.Value)

 

0 Likes
Message 6 of 12

WCrihfield
Mentor
Mentor

I'm using oMSs.Item(1), because the first ModelState in the ModelStates collection is always the Master/Primary one, because it was the first one to exist in the file.  I am getting the BrowserNode for that original ModelState, because I want to be able to avoid trying to move that one, because it will not move.  Within the Reorder method, I try to use that one as a position holder that I want the other (oMSNode) object to be positioned after, but only the first time around.  After the first time, the 'oPreviousNode' variable is then set to 'oMSNode', which is retrieved from the dictionary, and the dictionary should not contain that master/primary ModelState, due to my filter.

I have modified my code below to include several extra checks, similar to what I was working with originally, before simplifying it back down.  A couple of the these checks are comparing the BrowserNode I am getting to the 'TopNode' object, and uses a MsgBox to report either way.  Then I am also including several more Logger lines in there, which report the 'FullPath' of those two BrowserNode objects, to show which one is being worked with.

Dim oPDoc As PartDocument = ThisDoc.FactoryDocument
Dim oMSs As ModelStates = oPDoc.ComponentDefinition.ModelStates
Dim oMSDict As New SortedDictionary(Of String, Inventor.ModelState)
For Each oMS As ModelState In oMSs
	'this next line prevents the 'Master' ModelState from being added to the collection
	If oMS.ModelStateType = ModelStateTypeEnum.kMasterModelStateType Then Continue For
	oMSDict.Add(oMS.Name, oMS)
	Logger.Info("ModelState named:  " & oMS.Name & " added to list.")
Next
Dim oBPane As BrowserPane = oPDoc.BrowserPanes.Item("Model")
If IsNothing(oBPane) Then Logger.Debug("oBPane Is Nothing") : Exit Sub
Dim oTopNode As BrowserNode = oBPane.TopNode
If IsNothing(oTopNode) Then Logger.Debug("oTopNode Is Nothing") : Exit Sub
Dim oMSFolder, oMasterMSNode, oPreviousNode As BrowserNode
oMasterMSNode = oBPane.GetBrowserNodeFromObject(oMSs.Item(1))
Logger.Info("oMasterMSNode.FullPath = " & oMasterMSNode.FullPath)
If oMasterMSNode Is oTopNode Then
	MsgBox("oMasterMSNode Is oTopNode = True", , "")
Else
	MsgBox("oMasterMSNode Is oTopNode = False", , "")
End If
oMSFolder = oMasterMSNode.Parent
Logger.Info("oMSFolder.BrowserNodeDefinition.Label = " & oMSFolder.BrowserNodeDefinition.Label)
If Not oMSFolder.Expanded Then oMSFolder.Expanded = True
For Each oPair In oMSDict
	Dim oMSNode As BrowserNode = oBPane.GetBrowserNodeFromObject(oPair.Value)
	Logger.Info("oMSNode.FullPath = " & oMSNode.FullPath)
	If oMSNode Is oTopNode Then
		MsgBox("oMSNode Is oTopNode = True", , "")
	Else
		MsgBox("oMSNode Is oTopNode = False", , "")
	End If
	'this next line will only work the first time, when it is Nothing, then will not be used anymore
	If IsNothing(oPreviousNode) Then oPreviousNode = oMasterMSNode
	Logger.Info("oPreviousNode.FullPath = " & oPreviousNode.FullPath)
	oBPane.Reorder(oPreviousNode, False, oMSNode)
	oPreviousNode = oMSNode
Next

 

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 7 of 12

dg2405
Advocate
Advocate

When you log:

BrowserNodeDefinition.Label

 then in the Logger the Label is always the same as from the TopNode!

0 Likes
Message 8 of 12

WCrihfield
Mentor
Mentor

Yes, I saw that too.  I do not even need to use the folder where the ModelStates are stored, so I got rid of that part in a new dumbed down version of the code.  In this version, I am getting the ModelStates collection from the 'factory' document, then creating a variable to hold each of the three ModelStates in my test part (master, 1, & 2).  Then get the model browser pane.  Then get the BrowserNode for each of those three ModelStates to their own specific variable.  Then I try several variations of the BrowserPane.Reorder method, as simply as I can make it, with the input BrowserNodes in different order.  Failure every time.

Dim oPDoc As PartDocument = ThisDoc.FactoryDocument
Dim oMSs As ModelStates = oPDoc.ComponentDefinition.ModelStates
Dim oMasterMS As ModelState = oMSs.Item("Master")
Dim oMS1 As ModelState = oMSs.Item("Model State1")
Dim oMS2 As ModelState = oMSs.Item("Model State2")
Dim oBPane As BrowserPane = oPDoc.BrowserPanes.Item("Model")
Logger.Info("oBPane.Name = " & oBPane.Name & vbCrLf & _
"oBPane.InternalName = " & oBPane.InternalName)
Dim oMasterMSNode, oMS1Node, oMS2Node As BrowserNode
oMasterMSNode = oBPane.GetBrowserNodeFromObject(oMasterMS)
Logger.Info("oMasterMSNode.FullPath = " & oMasterMSNode.FullPath & vbCrLf & _
"oMasterMSNode.BrowserNodeDefinition.Label = " & oMasterMSNode.BrowserNodeDefinition.Label)
oMS1Node = oBPane.GetBrowserNodeFromObject(oMS1)
Logger.Info("oMS1Node.FullPath = " & oMS1Node.FullPath & vbCrLf & _
"oMS1Node.BrowserNodeDefinition.Label = " & oMS1Node.BrowserNodeDefinition.Label)
oMS2Node = oBPane.GetBrowserNodeFromObject(oMS2)
Logger.Info("oMS2Node.FullPath = " & oMS2Node.FullPath & vbCrLf & _
"oMS2Node.BrowserNodeDefinition.Label = " & oMS2Node.BrowserNodeDefinition.Label)
'oBPane.Reorder(oMasterMSNode, False, oMS1Node)
'oBPane.Reorder(oMasterMSNode, True, oMS1Node)
'oBPane.Reorder(oMasterMSNode, False, oMS2Node)
'oBPane.Reorder(oMasterMSNode, True, oMS2Node)
'oBPane.Reorder(oMS1Node, False, oMS2Node)
'oBPane.Reorder(oMS2Node, False, oMS1Node)
'oBPane.Reorder(oMS1Node, True, oMS2Node)
oBPane.Reorder(oMS2Node, True, oMS1Node)

 

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 9 of 12

dg2405
Advocate
Advocate

The problem is definitly that "GetBrowserNodeFromObject" with a modelstate gives not the node as you expect. I think we should traverse the modelstates-Folder in the pane, take each name of the modelstates to an array, sort them and reorder the nodes according to the array. Directly with the modelstates we won't have luck.

0 Likes
Message 10 of 12

WCrihfield
Mentor
Mentor
Accepted solution

The information in my Logger seemed to be correct for everything except the "Model States" folder itself, as expected, but if it did not come out correct in your tests, then another approach may be in order.  Finding that folder was a bit odd, because its 'Label' is custom to whichever ModelState is currently active at the time (includes the name of the active ModelState).  So, I used the 'StartsWith("Model States") method to find it.  Even then, it still would not let me use the BrowserPane.Reorder method, if one of the input items was the BrowserNode for the 'first/master' ModelState.  However, when I do not include the first/master ModelState's BrowserNode, it did appear to work in some tests.  Because of this, you would not be able to simply put 'all' the nodes into one ArrayList, sort them, then somehow write them back in alphabetical order, because that ArrayList would include the first/master one, which seems to not be allowed.

Here is the code I have for this process path.

oDoc = ThisDoc.Document
If oDoc.DocumentType = kDrawingDocumentObject Then Return
Dim oModelPane As BrowserPane '= oDoc.BrowserPanes.Item("Model")
For Each oBPane As BrowserPane In oDoc.BrowserPanes
	If oBPane.InternalName = "AmBrowserArrangement" Or _
		oBPane.InternalName = "PmDefault" Then
		oModelPane = oBPane
		Exit For
	End If
Next
Logger.Info("oModelPane.InternalName = " & oModelPane.InternalName)
Dim oNodes As BrowserNodesEnumerator = oModelPane.TopNode.BrowserNodes
Dim oMStatesNode As BrowserNode
For Each oNode As BrowserNode In oNodes
'	Logger.Info(oNode.BrowserNodeDefinition.Label)
	If oNode.BrowserNodeDefinition.Label.StartsWith("Model States") Then oMStatesNode = oNode
Next
If IsNothing(oMStatesNode) Then
	Logger.Debug("Model States BrowserNode not found.")
	Exit Sub
End If
Logger.Info("oMStatesNode.FullPath = " & oMStatesNode.FullPath & vbCrLf & _
"oMStatesNode.BrowserNodeDefinition.Label = " & oMStatesNode.BrowserNodeDefinition.Label)
Dim oMSNodes As BrowserNodesEnumerator = oMStatesNode.BrowserNodes
For Each oMSNode As BrowserNode In oMSNodes
	Logger.Info("oMSNode.FullPath = " & oMSNode.FullPath & vbCrLf & _
	"oMSNode.BrowserNodeDefinition.Label = " & oMSNode.BrowserNodeDefinition.Label)
Next
Try
	oModelPane.Reorder(oMSNodes.Item(3), False, oMSNodes.Item(2))
Catch
	Logger.Error("BrowserPane.Reorder method failed.")
End Try

 

Wesley Crihfield

EESignature

(Not an Autodesk Employee)

0 Likes
Message 11 of 12

dg2405
Advocate
Advocate

I changed your code and that works for me. I think at the moment there is no other better way to do that. Here is the code:

 

Dim oPartDoc As PartDocument = ThisDoc.Document
Dim oModelPane As BrowserPane
For Each oBPane As BrowserPane In oPartDoc.BrowserPanes
	If oBPane.InternalName = "AmBrowserArrangement" Or _
		oBPane.InternalName = "PmDefault" Then
		oModelPane = oBPane
		Exit For
	End If
Next
Dim oMStatesNode As BrowserNode
For Each oNode As BrowserNode In oModelPane.TopNode.BrowserNodes
	If oNode.BrowserNodeDefinition.Label.StartsWith("Modellzustände") Then oMStatesNode = oNode
Next
Dim oMSDict As New SortedDictionary(Of String, BrowserNode)
For i = 2 To oMStatesNode.BrowserNodes.Count
	oMSDict.Add(oMStatesNode.BrowserNodes(i).BrowserNodeDefinition.Label, oMStatesNode.BrowserNodes(i))
Next

For Each oPair In oMSDict
	Dim oMSNode As BrowserNode = oPair.Value
	If IsNothing(oPreviousNode) Then oPreviousNode = oMStatesNode.BrowserNodes(1)
	'Logger.Info("oPreviousNode.FullPath = " & oPreviousNode.FullPath)
	oModelPane.Reorder(oPreviousNode, False, oMSNode)
	oPreviousNode = oMSNode
Next
0 Likes
Message 12 of 12

dg2405
Advocate
Advocate

Maybe there is a better way to get the ModelStates-Folder? But for now i don't find any... 

0 Likes