Component Inspector on KeyPressed


I’m trying to implement a Component inspector that displays all references tagPaths on the component beneath the current mouseposition. It seems to work for simple bindings. But when I test this on Templates, it doesn’t give me any results. Could somebody point me in the right direction to inspect Template Bindings? Any suggestions are very welcom

Right now I came up with this in a Keypressed (shift - F10) script:

from com.inductiveautomation.factorypmi.application import VisionDesktop
from com.inductiveautomation.factorypmi.application.binding import AbstractPropertyAdapter
from com.inductiveautomation.factorypmi.application.binding import AbstractTagAdapter
from com.inductiveautomation.factorypmi.application.binding import ExtensibleBinding
from com.inductiveautomation.factorypmi.application.binding import SQLPropertyAdapter
from com.inductiveautomation.factorypmi.application.binding import TagHistoryAdapter
from com.inductiveautomation.factorypmi.application.binding import ExpressionPropertyAdapter
from com.inductiveautomation.factorypmi.application.binding import IndirectTagBindingAdapter

window = system.nav.desktop(VisionDesktop.CURRENT_DESKTOP.get()).getCurrentWindow()
oWindow = system.gui.getWindow(window)
point = oWindow.mousePosition	
x = int(point.getX())
y = int(point.getY())

component = oWindow.findComponentAt(x,y)

adapters = oWindow.interactionController.getAllAdaptersForTarget(component)

str_list = []
str_list.append("COMPONENT : " + component.getName())

for a in adapters :
	str_list.append( "---------------------------ADAPTERS-------------------------------------")
	str_list.append( "PROPERTY: " + a.getTargetPropertyName() )
	if (isinstance(a, AbstractPropertyAdapter)) :
		str_list.append( 'TARGET : ' + str(a.getTargetFullPath()))
		str_list.append( 'PROP : ' + str(a.getTargetPropertyName())  )
		str_list.append( 'VALUE : ' + str(a.getQValue().getValue()))
	if (isinstance(a,AbstractTagAdapter)) :
		str_list.append( 'TAG : ' + a.getTagPathString() )
	if (isinstance(a,ExtensibleBinding)) :
		str_list.append( 'ExtensibleBinding : ' + str(a.getParameters()) )
	if (isinstance(a,SQLPropertyAdapter)) :
		str_list.append( 'SQL Datasource : ' + str(a.getDatasource()) )
		pullQuery = a.getPullQuery()
		if pullQuery != None :
			str_list.append( 'SQL PULL Query : ' + str(pullQuery.getQuery()) )
		pushQuery = a.getPushQuery()
		if pushQuery != None :
			str_list.append( 'SQL PUSH Query : ' + str(a.getPushQuery().getQuery()) )
	if (isinstance(a,TagHistoryAdapter)) :
		for historicalPath in a.getPathList():
			str_list.append( 'PathListItem : ' + str(historicalPath.getAlias()) )
	if (isinstance(a,ExpressionPropertyAdapter)) : 
		str_list.append('Expression: ' + str(a.getExpressionSource()))

system.gui.messageBox( "\n".join(str_list))

Thanks !

Any suggestions anybody ?

I don’t have an answer for your question itself, but you might want to investigate what exactly you’re getting from findComponentAt(). The various template holders are layered components and you might not be getting a result from fCA() at the nesting level you think. Consider enumerating and printing the parent chain of the returned component up to the enclosing window. (With a recursion limit – you never know.)

Hi Phil,

Thank you for your answer!

The type of the object I get is for example : com.inductiveautomation.factorypmi.application.components.PMILabel . So I guess I’m getting the AWT / Swing component here. What I can’t figure out is to get from this AWT component to the Template ?

Kind regards,

Let me repeat:

You need to see the hierarchy before you’ll be able to algorithmically identify the desired components.

Two possibilities:

  1. I think getComponentAt() returns the top-level component, while findComponentAt() returns the child. Link If your template is at the top level, perhaps use get instead of find.

  2. If your template is not at the top level, you could use findComponentAt() and recursively search up through the parents. Here’s a script I put on a mouse button’s mouse click event.

def compInfo(window, comp):
	# If this is not the top-level component, try again on the parent
	if comp.getParent() != window.getRootContainer():
		return compInfo(window, comp.getParent())
	#Do all of your stuff to get component adapters here
	adapters = "foo"
	str = comp + " has adapters " + adapters
	return str

oWindow = system.gui.getParentWindow(event)
point = oWindow.mousePosition	
x = int(point.getX())
y = int(point.getY())
component = oWindow.findComponentAt(x,y)

print; print
print compInfo(oWindow, component)

If the component is the top-level component on the screen (direct child of the root container), it will print that component’s adapters. If the component is a child of something else, it will go up through its parents until it gets to whatever is a direct child of the root container.

You’ll probably have to tweak your search through the parents for your particular case, perhaps looking at the type of the parent to see when you reach a template. Things might get tricky if you have templates inside templates, or templates inside groups.

Side note: I haven’t confirmed, but you should be able to do oWindow.findComponentAt(point) without having to separate your point into x and y.

Third idea: Perhaps use oWindow.getComponentAt(point) to get the top-level component. Then recursively look for children using component.getComponentAt(point) method on each child, stopping the first time you find a component that has adapters you’re looking for.

If you go this route, you’ll have to adjust the point at every level. I’d keep using Java’s nicely-optimized findComponent() and then climb the parent tree to find the desired component type.

1 Like

The code for converting the point should be a single line, though I don’t know how efficient it is.

from javax.swing import SwingUtilities

SwingUtilities.convertPoint(parentComponent, point, childComponent)

If @thijs1’s script is doing what I think it does, I believe you’ll ultimately want the highest-level component with adapters. You could use find to get the child, work your way up to build the list of all parents, then go through your list to find the highest-level parent that meets your needs. Or you could start at the top with get, work your way down (converting points as you go), and stop when you reach the first one that meets your needs. I don’t know which method would be better.

I don’t have access to Ignition at the moment to try anything out, but I think this is something I want to use as well. If I make any progress with it, I’ll report back.