The Connectivity API
also provides easy methods for creating and deleting connections, but
we are simply interested in traversing connections in order to check or
export the process steps to another application.
Here is the top part of my Write Chapter Sub-process page which demonstrates some of the key features of the Connectivity API. They are done in the following sequence:
1. The flow shapes are connected together creating a logical sequence of steps.
2. Some steps have an associated callout with extra Notes.
3. Some steps are within a Container shape to define the Phase.
Now we will traverse the
diagram in code, and list out the steps in their phases with any
associated notes, but first we need to understand a few of the new
methods in the Connectivity API.
The Shape.ConnectedShapes method
The Shape.ConnectedShapes method returns an array of identifiers (IDs) of shapes that are one degree of separation away from the given shape (that is, separated by a 1-D connector).
The method has two arguments, Flags and CategoryFilter.
Flags: This filters the list of returned shape IDs by the directionality of the connectors, using the VisConnectedShapesFlags enum for All, Incoming, or Outgoing nodes.
CategoryFilter: This filters the list of
returned shape IDs by limiting it to IDs of shapes that match the
specified category. A shape's categories can be found in the User.msvShapeCategories cell of its ShapeSheet.
So, we can use the new ConnectedShapes method to list all of the significant connections in my Write Chapter Sub-process page. I have used the existence of the Prop.Cost cell as a test for shape significance.
Public Sub ListNextConnections()
Dim shp As Visio.Shape
Dim connectorShape As Visio.Shape
Dim sourceShape As Visio.Shape
Dim targetShape As Visio.Shape
Dim aryTargetIDs() As Long
Dim arySourceIDs() As Long
Dim targetID As Long
Dim sourceID As Long
Dim i As Integer
Const CheckProp As String = "Prop.Cost"
For Each shp In Visio.ActivePage.Shapes
If Not shp.OneD Then
If shp.CellExists(CheckProp, Visio.visExistsAnywhere) Then
Debug.Print "Shape", shp.Name, shp.Text
arySourceIDs = shp.ConnectedShapes(visConnectedShapesOutgoingNodes, "")
For i = 0 To UBound(arySourceIDs)
Set sourceShape = Visio.ActivePage.Shapes.ItemFromID(arySourceIDs(i))
If sourceShape.CellExists(CheckProp, Visio.visExistsAnywhere) Then
Debug.Print , "<", sourceShape.Name, sourceShape.Text
End If
Next
aryTargetIDs = shp.ConnectedShapes(visConnectedShapesIncomingNodes, "")
For i = 0 To UBound(aryTargetIDs)
Set targetShape = Visio.ActivePage.Shapes.ItemFromID(aryTargetIDs(i))
If targetShape.CellExists(CheckProp,
Visio.visExistsAnywhere) Then
Debug.Print , ">", targetShape.Name, targetShape.Text
End If
Next
End If
End If
Next
End Sub
The top of the output from this function will appear as follows:
|
Shape
|
Start/End
|
Editorial Process
| |
| |
<
|
Document
|
Author Submits 1st Draft
|
|
Shape
|
Document
|
Author Submits 1st Draft
| |
| |
<
|
Decision
|
Editorial Review
|
| |
>
|
Start/End
|
Editorial Process
|
| |
>
|
Decision
|
Editorial Review
|
|
Shape
|
Decision
|
Editorial Review
| |
| |
<
|
Document
|
Author Submits 1st Draft
|
| |
<
|
Process
|
1st Draft Peer Reviewed
|
| |
>
|
Document
|
Author Submits 1st Draft
|
The Shape.GluedShapes method
The Shape.GluedShapes
method returns an array of identifiers for the shapes that are glued to a
shape. For instance, if the given shape is a 2-D shape that has
multiple connectors attached to it, this method would return the IDs of
those connectors. If the given shape is a connector, this method would
return the IDs of the shapes to which its ends are glued.
The method has three arguments, Flags, CategoryFilter, and OtherConnectedShape:
Flags: This filters the list of returned shape IDs by the directionality of the connectors, using the VisGluedShapesFlags enum for All1D All2D, Incoming1D, Incoming2D, Outgoing1D, or Outgoing2D nodes.
CategoryFilter: This filters the list of
returned shape IDs by limiting it to IDs of shapes that match the
specified category. A shape's categories can be found in the User.msvShapeCategories cell of its ShapeSheet.
OtherConnectedShape: Optional additional shape to which returned shapes must also be glued.
The method is used as follows :
arIDs = Shape.GluedShapes(Flags, CategoryFilter, pOtherConnectedShape)
The Shape.MemberOfContainers property
We can return an array of IDs of the Containers that a shape is within.
You can use the ID to return the Container shape, get its ContainerProperties object, and, in this case, return the text from the shape.
Here is a private function that I will use in the main function in the following code:
Private Function getContainerText(ByVal shp As Visio.Shape) As String
'Return text of any containers,
'or an empty string if there are none
Dim aryTargetIDs() As Long
Dim targetShape As Visio.Shape
Dim returnText As String
Dim i As Integer
returnText = ""
aryTargetIDs = shp.MemberOfContainers
On Error GoTo exitHere
For i = 0 To UBound(aryTargetIDs)
Set targetShape = shp.ContainingPage.Shapes.ItemFromID(aryTargetIDs(i))
If Len(returnText) = 0 Then
returnText = targetShape.ContainerProperties.Shape.Text
Else
returnText = returnText & vbCrLf & targetShape.ContainerProperties.Shape.Text
End If
Next
exitHere:
getContainerText = returnText
End Function
The Shape.CalloutsAssociated property
This property will return an array of shape IDs of any associated callouts.
You can use the ID to return the callout shape, and, in this case, return the text from within that shape.
Here is a private function that I will use in the main function:
Private Function getCalloutText(ByVal shp As Visio.Shape) As String
'Return text of any connected callouts,
'or an empty string if there are none
Dim aryTargetIDs() As Long
Dim targetShape As Visio.Shape
Dim returnText As String
Dim i As Integer
returnText = ""
aryTargetIDs = shp.CalloutsAssociated
On Error GoTo exitHere
For i = 0 To UBound(aryTargetIDs)
Set targetShape = shp.ContainingPage.Shapes.ItemFromID(aryTargetIDs(i))
If Len(returnText) = 0 Then
returnText = targetShape.Characters.Text
Else
returnText = returnText & vbCrLf & targetShape.Characters.Text
End If
Next
exitHere:
getCalloutText = returnText
End Function
Listing the steps in a process flow
In order to create a sequential
listing of the steps in the page, we need to create a function that will
call itself to iterate through the connections out from the source
shape.
Private Function getNextConnected(ByVal shp As Visio.Shape, ByVal dicFlowShapes As Dictionary, ByVal colSteps As Collection) As Collection
'Return a collection of the next connected steps
Dim aryTargetIDs() As Long
Dim targetShape As Visio.Shape
Dim returnCollection As Collection
Dim i As Integer
dicFlowShapes.Add shp.NameID, shp
aryTargetIDs = shp.ConnectedShapes(visConnectedShapesOutgoingNodes, "")
For i = 0 To UBound(aryTargetIDs)
Set targetShape = Visio.ActivePage.Shapes.ItemFromID(aryTargetIDs(i))
If Not targetShape.Master Is Nothing And dicFlowShapes.Exists(targetShape.NameID) = False Then
colSteps.Add targetShape
getNextConnected targetShape, dicFlowShapes, colSteps
End If
Next
Set getNextConnected = colSteps
End Function
Finally, we can create the
public function that will list the steps. For simplicity, I'm only
following the direct route and not displaying the text on the connector
lines.
I have introduced the Visio.Selection object because it contains a collection of shapes returned by the Page.CreateSelection() method, which is extremely useful for getting a filtered collection of shapes by Layer, Master, Type, and so on.
I am also using the Dictionary object in the following code, so you will need to ensure that the Microsoft Scripting Runtime library (C:\Windows\system32\scrun.dll) is ticked in the References dialog opened from the Tools menu in the Visual Basic user interface.
Public Sub ListProcessSteps()
Dim sel As Visio.Selection
Dim pag As Visio.Page
Dim shp As Visio.Shape
Dim shpStart As Visio.Shape
Dim shpEnd As Visio.Shape
Dim iStep As Integer
Dim dicFlowShapes As Dictionary
Set dicFlowShapes = New Dictionary
Set pag = Visio.ActivePage
'Find the Start and End shapes on the Page
'Assume that they are the instances of the Master "Start/End"
'Assume that the Start has no incoming connections
'and the End shape has no outgoing connections
Set sel = pag.CreateSelection(visSelTypeByMaster, 0, pag.Document.Masters("Start/End"))
If Not sel.Count = 2 Then
MsgBox "There must be one Start shape and one End shape only", vbExclamation, "ListProcessSteps"
Exit Sub
End If
For Each shp In sel
If shpStart Is Nothing Then
Set shpStart = shp
Set shpEnd = shp
Else
If UBound(shp.ConnectedShapes( visConnectedShapesOutgoingNodes, "")) > -1 _
And UBound(shp.ConnectedShapes( visConnectedShapesIncomingNodes, "")) = -1 Then
Set shpStart = shp
ElseIf UBound(shp.ConnectedShapes( visConnectedShapesIncomingNodes, "")) > -1 _
And UBound(shp.ConnectedShapes( visConnectedShapesOutgoingNodes, "")) = -1 Then
Set shpEnd = shp
Connectivity APIprocess flow steps, listingEnd If
Next
iStep = 1
Dim nextSteps As Collection
Dim nextShp As Visio.Shape
Dim iNext As Integer
Set nextSteps = New Collection
Set nextSteps = getNextConnected(shpStart, dicFlowShapes, nextSteps)
Debug.Print "Step", "Master.Name", "Phase", "Text", "Notes"
Debug.Print iStep, shpStart.Master.Name, getContainerText(shpStart), shpStart.Text, getCalloutText(shpStart)
For iNext = 1 To nextSteps.Count
iStep = iNext + 1
Set nextShp = nextSteps.Item(iNext)
Debug.Print iStep, nextShp.Master.Name, getContainerText(nextShp), nextShp.Characters.Text, getCalloutText(nextShp)
Next
If Not nextShp Is shpEnd Then
MsgBox "Theprocess did not finish on the End shape", vbExclamation, "ListProcessSteps"
End If
End Sub
With a fanfare of trumpets, we get a simple listing of each step in order:
|
Step
|
Master.Name
|
Phase
|
Text
|
Notes
|
|
1
|
Start/End
|
Editorial Process
| | |
|
2
|
Document
|
Drafting
|
Author Submits 1st Draft
|
This includes suitably formatted text, images, code and any other material
|
|
3
|
Decision
|
Drafting
|
Editorial Review
|
Commissioning Editor establishes that Chapter meets the requirements of the spec, text is suitably formatted, etc
|
|
4
|
Process
|
Drafting
|
1st Draft Peer Reviewed
|
Technical quality of the material is checked is it accurate, informative, and appropriate to the level of the audience?
|
|
5
|
Process
|
Editing
|
Editorial Acceptance Verdict
|
Commissioning Editor evaluates reviewer comments to verify that the Chapter meets the "Editorial Acceptance" standard
|
|
6
|
Process
|
Editing
|
Author Rewrite
|
Author addresses comments, adds any extra material requested
|
|
7
|
Process
|
Editing
|
Final Edit
| |
|
8
|
Decision
|
Editing
|
Pass?
|
Finer iterations of chapter required?
|
|
9
|
Process
|
Production
|
Production Phase
|
Indexing, Layout, Proofing
|
|
10
|
Process
|
Production
|
Author Review of "PreFinal" PDF
|
Author inspects finished PDF to see if there are any last minute changes required and if they are happy with the chapters
|
|
11
|
Start/End
|
Publication
| |