InstallatioNode Write to DataModel before OpenView

Hi

For the URCap I’m creating, I read settings from a file which is performed in the initialization of the contribution node.
Once these settings are readed out, they are stored in the DataModel. This works well because I have a second method executed after the first one where I read the settings back from the DataModel, and these are correct. But at the moment I open the installation node (and thus the method OpenView executes), the values stored in the DataModel are not obtained but the default values are.
Anybody an idea why this is?
Thanks in advance.

Hi @d.verhofstadt,

The DataModel is a part of the current installation file. Maybe your first write/read is before Polyscope have loaded the installation file.

Hi @Ebbe

I thought so too, but normally the contribution and view are initialized again each time a new Installation is loaded. This would mean that the desired Installation is already loaded and initialized before the OpenView method is executed (by going to the installation node).
But perhaps changes made to the DataModel during Initialization of the node have to be saved?
Is there a way to program the URCap such that these changes are saved in the installation file? I see that the Dashboard server doesn’t provide a means for this.

If not, I will see if I can find another way to temporarily store the values and write them later on to the DataModel.

Hi @d.verhofstadt,

I tried to reproduce by writing into the DataModel in the constructor of the installation node contribution. But that worked fine for me. Can you give some more details about your case?

Hi @Ebbe

What I do is reading out of settings from a file. This is done in a separate method which is called at the end of the initialization of the View class (since then the contribution is also already initialized). This method is defined in the contribution class, and inside this method the values are written to the DataModel. After this is done, there is a 2nd method which is executed immediately after the reading out. Inside this second method, for debugging, I read out the values stored in the DataModel variable. These values are still correct at this point. But when I open the node, and the OpenView is executed, the values returned from the DataModel are not the new values but the ones stored in the installation file before I rebooted Polyscope.

In case you cannot reproduce this behavior, I will see if I can reproduce this problem in another URCap (a smaller one) of which I can send/post the code.

Hi Ebbe

Sorry for the late response. I have reproduced the problem in the following code (zip attached):

Contribution:

package com.DVInc.TestURCap.impl;

import com.ur.urcap.api.contribution.InstallationNodeContribution;
import com.ur.urcap.api.contribution.installation.InstallationAPIProvider;
import com.ur.urcap.api.domain.data.DataModel;
import com.ur.urcap.api.domain.script.ScriptWriter;
import com.ur.urcap.api.domain.userinteraction.keyboard.KeyboardInputCallback;
import com.ur.urcap.api.domain.userinteraction.keyboard.KeyboardInputFactory;
import com.ur.urcap.api.domain.userinteraction.keyboard.KeyboardTextInput;

public class TestURCapInstallationNodeContribution implements InstallationNodeContribution{

private final KeyboardInputFactory keyboardFactory;
private final TestURCapInstallationNodeView view;
private DataModel model;
private static final String KEY_TEXTFIELDINPUT = "TestURCapTextFieldInput";
private static final String DEFAULTVALUE_TEXTFIELDINPUT = "Default";

public TestURCapInstallationNodeContribution(InstallationAPIProvider apiProvider, DataModel model, TestURCapInstallationNodeView view) {
	this.keyboardFactory = apiProvider.getUserInterfaceAPI().getUserInteraction().getKeyboardInputFactory();
	this.view = view;
	this.model = model;
}

@Override
public void openView() {
	String storedValue = model.get(KEY_TEXTFIELDINPUT, DEFAULTVALUE_TEXTFIELDINPUT);
	System.out.println("In Openview(), value stored in DataModel: "+storedValue);
	view.setDataModelContentText(storedValue);
	
}

@Override
public void closeView() {
}

@Override
public void generateScript(ScriptWriter writer) {
}

public void setValueDuringInitializing() {
	String newModelValue = "Set after Initializing";
	System.out.println("In method setValueDuringInitializin(), is key textFieldInput set in model?: "+Boolean.toString(model.isSet(KEY_TEXTFIELDINPUT)));
	System.out.println("In method setValueDuringInitializin(), value stored in dataModel: "+model.get(KEY_TEXTFIELDINPUT, DEFAULTVALUE_TEXTFIELDINPUT));
	System.out.println("In method setValueDuringInitializin(), new value stored in dataModel: "+newModelValue);
	model.set(KEY_TEXTFIELDINPUT, newModelValue);
}


public KeyboardTextInput getKeyboardTextInput() {
	return keyboardFactory.createStringKeyboardInput();
}

public KeyboardInputCallback<String> getKeyboardTextInputCallback() {
	return new KeyboardInputCallback<String>() {
		@Override
		public void onOk(String value) {
			view.setInputFieldText(value);
			model.set(KEY_TEXTFIELDINPUT, value);
		}
		
	};
}

}

View:

package com.DVInc.TestURCap.impl;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;

import com.ur.urcap.api.contribution.installation.swing.SwingInstallationNodeView;
import com.ur.urcap.api.domain.userinteraction.keyboard.KeyboardTextInput;

public class TestURCapInstallationNodeView implements SwingInstallationNodeView<TestURCapInstallationNodeContribution>{
private Style style;

private JTextField	inputText;
private JTextArea	dataModelContentText;

public TestURCapInstallationNodeView(Style style) {
	this.style = style;
}

@Override
public void buildUI(JPanel panel, TestURCapInstallationNodeContribution contribution) {
	panel.setAlignmentX(Component.LEFT_ALIGNMENT);
	panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
	
	panel.add(createInput(contribution));
	panel.add(createVerticalSpacing());
	panel.add(createDataModelCheck());
	
	contribution.setValueDuringInitializing();
}

private JPanel createInput(final TestURCapInstallationNodeContribution contribution) {
	JPanel inputPanel = new JPanel();
	inputPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
	inputPanel.setLayout(new BoxLayout(inputPanel, BoxLayout.Y_AXIS));
	
	JTextArea messageText = new JTextArea();
	messageText.setAlignmentX(Component.LEFT_ALIGNMENT);
	messageText.setBorder(BorderFactory.createEmptyBorder());
	messageText.setBackground(inputPanel.getBackground());
	messageText.setText("Enter something to be stored in dataModel:");
	messageText.setFont(style.getTextFont());
	messageText.setMaximumSize(messageText.getPreferredSize());
	
	inputText = new JTextField();
	inputText.setAlignmentX(Component.LEFT_ALIGNMENT);
	inputText.setPreferredSize(style.getInputFieldSize());
	inputText.setMaximumSize(inputText.getPreferredSize());
	inputText.setText("");
	inputText.addMouseListener(new MouseAdapter() {
		public void mousePressed(MouseEvent e) {
			KeyboardTextInput keyboardInput = contribution.getKeyboardTextInput();
			keyboardInput.show(inputText, contribution.getKeyboardTextInputCallback());
		}
	});
	
	inputPanel.add(messageText);
	inputPanel.add(createVerticalSpacing());
	inputPanel.add(inputText);
	
	return inputPanel;
}

private JPanel createDataModelCheck() {
	JPanel dataModelContentPanel = new JPanel();
	dataModelContentPanel.setAlignmentX(Component.LEFT_ALIGNMENT);
	dataModelContentPanel.setLayout(new BoxLayout(dataModelContentPanel, BoxLayout.Y_AXIS));
	
	JTextArea messageText = new JTextArea();
	messageText.setAlignmentX(Component.LEFT_ALIGNMENT);
	messageText.setBorder(BorderFactory.createEmptyBorder());
	messageText.setBackground(dataModelContentPanel.getBackground());
	messageText.setText("Value of inputTextField stored in DataModel is:");
	messageText.setFont(style.getTextFont());
	messageText.setMaximumSize(messageText.getPreferredSize());
	
	dataModelContentText = new JTextArea();
	dataModelContentText.setAlignmentX(Component.LEFT_ALIGNMENT);
	dataModelContentText.setBorder(BorderFactory.createEmptyBorder());
	dataModelContentText.setBackground(dataModelContentPanel.getBackground());
	dataModelContentText.setText("");
	dataModelContentText.setFont(style.getTextFont());
	
	dataModelContentPanel.add(messageText);
	dataModelContentPanel.add(createVerticalSpacing());
	dataModelContentPanel.add(dataModelContentText);
	
	return dataModelContentPanel;
}

public void setInputFieldText(String message) {
	inputText.setText(message);
}

public void setDataModelContentText(String message) {
	dataModelContentText.setText(message);
}

private Component createVerticalSpacing() {
	return Box.createRigidArea(new Dimension(0, style.getVerticalSpacing()));
}
}

If you install this on the robot, enter a value in the textField and save the installation. Then reboot and from the “System.out.println()” comments you will see that in the method “setValueDuringInitializing()” the value “Set after Initializing” should be stored in the DataModel. However, once you open the node (and OpenView is executed), the value returned from the model is not this one, but the one stored before the reboot.

Why is this? Why is it not the value written in the method “setValueDuringInitializing()”?
Is also tried to see if calling this method at the end of the contribution constructor or at the end of the View constructor would make a difference, but it didn’t.

Hopefully this makes the problem clear and hopefully there is a solution to this problem.
Furthermore, it could also be informative to know that I created the URCap (the one I developed and also this TestURCap) with API 1.5.0 such that it would already work for SW 3.8.0 and SW 5.2.0.

com.DVInc.TestURCap.zip (59.2 KB)

Hi @Ebbe

The debugging in the method “setValueDuringInitializing()” is not so convincing, so I changed it to:

public void setValueDuringInitializing() {
	String newModelValue = "Set after Initializing";
	System.out.println("In method setValueDuringInitializin(), is key textFieldInput set in model?: "+Boolean.toString(model.isSet(KEY_TEXTFIELDINPUT)));
	System.out.println("In method setValueDuringInitializin(), value stored in dataModel: "+model.get(KEY_TEXTFIELDINPUT, DEFAULTVALUE_TEXTFIELDINPUT));
	model.set(KEY_TEXTFIELDINPUT, newModelValue);
	System.out.println("In method setValueDuringInitializin(), new value stored in dataModel: "+model.get(KEY_TEXTFIELDINPUT, DEFAULTVALUE_TEXTFIELDINPUT));
} 

Now it is clear that the value “Set after initializing” is stored in the DataModel. But when OpenView is executed, it will not be this value that is returned, but the one stored in the installation file.

Updated version of the entire URCap:
com.DVInc.TestURCap.zip (59.1 KB)

Hi @d.verhofstadt,

I see the issue. It seems like Polyscope is reading the data stored in the installation two times. I created a thread and delayed the initializing write into the DataModel 100ms as a workaround.

Hi @Ebbe

Oke, thanks for the support. I had hoped that this is normal such that perhaps in a way it could be circumvented/avoided or even used to my benefit.

But at least the idea of the delay works as a workaround.
This 100ms delay, is it reliable to work in all cases? For instance, in same cases the booting of PolyScope takes longer than initially. Would in such a case the 100 ms be enough?

I will first consider if it is enough by working with variables for this application. So, writing the value to a variable in the initialization, and store them in the DataModel only the first time the OpenView is executed. This does sound the same as reading the settings only the first time when the OpenView is executed, but the difference is that the settings that have been read out in the initialization are already used before the OpenView is executed.

If this should not be sufficient, the workaround of the Delay will be used, for which my thanks.

Just found this again when searching for something in the urcap_tutorial_swing.pdf. This explains why the changes made to the DataModel are ignored.

Hi @d.verhofstadt,

It is great with an explanation. Since the workaround with 100ms seems to work, I would assume you could find an appropriate dealy that will suit your needs.

Hi @Ebbe

Yes, thanks again