BasicContainer do not persist the components dropped

Hello,

I have created the simplest component extending BasicContainer and it doesn’t persist the components dropped on it, I noticed they are not serialized in the xml of the container.

Component:

public class TestContainer extends BasicContainer{
}

xml generated

<c-c m="privateAdd" s="1;java.awt.Component">
					<c cls="com.company.dev.common.client.TestContainer">
						<c-comm>
							<p2df>800.0;600.0</p2df>
							<ref>34</ref>
							<str>TestContainer</str>
							<lc>0.0;0.0;16;0;-;-</lc>
						</c-comm>
					</c>
				</c-c>

xml that should be generated:

<c-c m="privateAdd" s="1;java.awt.Component">
					<c cls="com.inductiveautomation.factorypmi.application.components.BasicContainer">
						<c-ctor s="1;str"><str>Container</str></c-ctor>
						<c-c m="putClientProperty" s="2;O;O">
							<ref>0</ref>
							<lc>0.0;0.0;16;0;-;-</lc>
						</c-c>
						<c-c m="setBoundsEx" s="1;java.awt.geom.Rectangle2D"><r2dd id="1">0.0;0.0;403.0;310.0</r2dd></c-c>
						<c-c m="setPreferredBoundsEx" s="1;java.awt.geom.Rectangle2D"><ref>1</ref></c-c>
						<c-c m="privateAdd" s="1;java.awt.Component">
							<c cls="com.inductiveautomation.factorypmi.application.components.PMIButton">
								<c-comm>
									<p2df>71.0;27.0</p2df>
									<r2dd>54.0;122.0;71.0;27.0</r2dd>
									<str>Button</str>
									<lc>54.0;122.0;16;0;-;-</lc>
								</c-comm>
								<c-c m="setButtonBG" s="1;clr"><clr>-328965</clr></c-c>
							</c>
						</c-c>
					</c>
				</c-c>

It seems the method c-c m=“privateAdd” s=“1;java.awt.Component” is not serialized, as well as the constructor c-ctor s=“1;str”>Container</c-ctor

How can we create new components based on BasicContainer? And persist the content properly?

Thank you,

The Vision module has a custom serializer for BasicContainer; you could try registering a custom serializer in your module’s configureSerializer hook in the designer scope. The gist of that serializer is that it goes through a specific list of properties, and then also manually inserts a call to privateAdd for each contained component.

1 Like

You are going to run into a limitation of the BasicContainer that stymied my attempts to create a zoomable, scrollable version: It directly uses Swing’s normal nested component infrastructure to hold the user-supplied components. You cannot use any layered components (scrollpane, etc) between the BasicContainer and the VisionComponents it holds because the designer “knows” that a BasicContainer has all of its VisionComponents in that first sublayer.

IA worked around this for Shapes by implementing an alternate container structure where the Designer looks at a different interface to enumerate contained shapes (getChild() and friends, IIRC). But this alternate (nicer) interface is hard-coded to shapes. It would have been nice to have a uniform enumeration interface for nested VisionComponents that didn’t use Swing’s getComponent() interface. Much improvement to Vision’s UI has been stymied by this. ):

Good luck. You are going to need it.

1 Like

Thank you for your answers, following @PGriffith guidance I have successfully registered a serializer for my containers and it is was quite easy because I reused BasicContainerDelegate , but it was not that easy to figure it out and disassemble the whole vision-module etc… Without your help I don’t think I would ever manage it.

Then I ran into problems during the deserialization, because my components extend PathBasedVisionShape and have their own rotationAnchor… well I solved it too but it was not very intuitive.

@pturmel , it is good that you mentioned zooming and scaling because it is really a big limitation for us, our systems span over several hectares and even the smallest subdivision is still 4x bigger than the screen with 1920x1000 res. It is kind of a problem and it makes everything complicated and the solutions are not very aesthetic nor convenient from UX perspective.

Should I investigate AbstractVisionScrollPane or I can give up right now? Should we think about completely replacing Vision with Perspective for that?

Thank you,

Maybe if we both petition @Carl.Gould for an interface change...

(I wouldn't expect such until 8.2, though. From what I saw enumerating callsites, it's probably a substantial undertaking. And IA isn't terribly enthusiastic about enhancements to Vision.)

And that's what I'm very disappointed in IA...
They put the Vision on the side track, despite that is the very best among all other SCADA systems out there... and I still like it more than Perspective... :sunglasses:

1 Like

What is being asked for here is much deeper and more extensive than “an interface change.” You’re really asking for Vision to be re-designed to support extensible container types and to move away from the Swing component model into a custom component model of our own invention, combining standard components and shapes along the way.

This is no small undertaking, and would amount to a substantial re-write of the system (along with associated stability risks and backwards incompatibilities) in order to cater to a small (but enthusiastic) subset of customers interested in extending the system through custom modules.

I’m sorry, but this just doesn’t pencil out for me.

I absolutely understand that it is extensive, though I would distinguish what I would like to see from the approach @damien.boissat is attempting. (More than a bit insane/misguided, IMNSHO. Automating bindings from within components is just wrong. I've recommended an alternate approach a couple times now, and it isn't getting through. :frowning_face: ) What I want might be more palatable.

Let me elaborate:

I would like support for extensible container types. Or more precisely, I'd like to see changes to BasicContainer to make it extensible. The changes would only impact the designer. No client runtime impact at all.

I do not want to move away from the Swing component model. That's just crazy. In fact, I think such an extensible interface should only accept JComponents that implement VisionComponent.

When I was poking around while attempting to implement a "ScrollingContainer" (a while back), I was stymied by the designer's use of the Swing component enumeration methods for designer tree population, too. In other words, I couldn't distinguish a runtime call to .getComponent(int i) (client or designer rendering) from a design-time call from the designer tree or from the designer's mouse-coordinate to component selection infrastructure.

After some headscratching, I decided to instrument my subclass's .getComponent() method to expose the all design-time callers. I came up with:

  • com.jidesoft.utils.JideFocusTracker
  • com.inductiveautomation.factorypmi.application.components.util.ComponentVisitor
  • com.inductiveautomation.factorypmi.designer.workspace.LayoutManipulator
  • com.inductiveautomation.factorypmi.designer.workspace.WindowWorkspace$Delegate

As a proof of concept, I played with this instrumentation to LIE to selected callers, whereupon I was able to display and manipulate a subtree for my test component's functionality. (But not mouse selection in design mode. Didn't look practical.) It definitely wasn't a production solution, as backtraces are expensive in the rendering path.

After some more headscratching, I noticed that shape groups behaved differently. And have a .getChild() method (IIRC) for the designer to use. (Other methods, too, I think.) Anyways, after a peek at some of the designer tree's bytecode, I realized that it hardcodes calling .getComponent() for anything other than a shape group. :frowning_face:

That's where I threw up my hands and abandoned the effort, as I noted over here:

What I would like is to see BasicContainer grow a set of public methods for designer use, .getChild(..), .addChild(..), .removeChild(..), .getChildren(), .getChildCount(), etc, that just call the existing Swing method. And then have all the hardcoded designer call sites that involve designable components call the new methods. You don't even have to factor it out into a new interface, as it just becomes something subclasses of BasicContainer could override.

Very low risk for existing stuff, since anything using BasicContainer would get the same results whichever method is called. If you miss a designer call site, you only prevent new users from succeeding.

I would argue that it isn't very risky, if approached as above.

1 Like

I just want to add that I am not trying to extend the system, but simply to use it. Of course I would be far happier to build it differently but Ignition has been imposed to me and I have almost a thousand tags and devices to represent, based on Autocad drawing. I will not draw them or bind them manually, and I will not neither encapsulate all the bindings and styles and logic inside the java class. If they are some minor changes to do we will not rebuild a module to change 10 components out of 1000.
So far I have managed what I wanted, it is not insane but simply that desperate platform calls from desperate actions

You don't need to build an SDK module in java to do this stuff. If you are only trying to automate existing component types, one time (or few times), just use jython to call the SDK methods from within the designer.

Unless you want scrollable content. Then you need to learn how to use the template canvas. Or you really do need the add-on component I’d like to build.

You might also consider SVG. In Vision, you probably want my Batik module. In Perspective, it would be native.

I have tried to use the scripting and templates, but without success, and the bindings are made of expressions most of the time, there are also mouse listeners etc… So the sdk was the only option I found to build the system in Ignition. Vision was imposed too, and I am switching to 7.9 because it is also imposed at last minute.

Thanks for the help, I will have a look at your module yes

If you gain enough knowledge to succeed with the SDK, you will have enough knowledge to do this in jython. I recommend you learn the SDK, but implement in jython.

I think I understand, except that I’m not clear on what you’re trying to achieve that this would actually unblock.

The proof of concept that I was playing with presented a container of a given size in a root or other container, with a nested container of a separate, possibly larger size that was scrollable in the available space. (With zoom an intended feature, too.) The inner container was fully designable (drop any VisionComponent on the exposed part) and otherwise behaved like any other BasicContainer. The outer container also offered special containers for header, footer, sidebars, and corners. These border containers, when enabled, were also fully designable, with dimensions specified in the outer container’s properties.

The appearance in the designer tree for this component was multi-level: the component itself within a regular container, under that the border containers and the main scrollable container, and under those, any ordinary components.

The key to the problem is that only the BasicContainer can hold design-time components. But its architecture doesn’t allow sliding a scrollcontainer and viewports into the stack.

Here’s a screenshot of the proof of concept before I stopped playing:

Note the “Canvas Size”, “Column Headers”, and “Row Headers” dimensional properties.

Hi Damien, you mentioned that your components extend PathBasedVisionShape. Do you mind sharing how you do that? Or is there documentation somewhere on how this is done?

I've been building components by extending AbstractVisionComponent and AbstractVisionShape. An example on how to extend PathBasedVisionShape would be great!