Solibri API - Code Example
UI Component Example
This example shows how to define a custom rule parameters UI for a rule. You can download the examples project from here.
Defining a parameters UI using the API components
The UI components included in the Solibri API are used for defining the layout of the UI components. In order to create a custom UI, the getParametersUIDefinition method declared in Rule needs to be overriden.
The example UI consists of three panels. The panels are handled using the container classes that can contain other UI components. Container can also be placed within other containers to create more complicated layouts. This is done in the middle panel of the example UI.
UIComponentExample.java
package com.solibri.smc.api.examples.beginner;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.io.Serial;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JTextPane;
import com.solibri.smc.api.checking.BooleanParameter;
import com.solibri.smc.api.checking.DoubleParameter;
import com.solibri.smc.api.checking.EnumerationParameter;
import com.solibri.smc.api.checking.FilterParameter;
import com.solibri.smc.api.checking.OneByOneRule;
import com.solibri.smc.api.checking.PropertyReferenceParameter;
import com.solibri.smc.api.checking.Result;
import com.solibri.smc.api.checking.ResultFactory;
import com.solibri.smc.api.checking.RuleParameters;
import com.solibri.smc.api.checking.RuleResources;
import com.solibri.smc.api.checking.StringParameter;
import com.solibri.smc.api.checking.TableParameter;
import com.solibri.smc.api.model.Component;
import com.solibri.smc.api.model.PropertyReference;
import com.solibri.smc.api.model.PropertyType;
import com.solibri.smc.api.ui.BorderType;
import com.solibri.smc.api.ui.RuleParameterCustomUi;
import com.solibri.smc.api.ui.UIComponent;
import com.solibri.smc.api.ui.UIContainer;
import com.solibri.smc.api.ui.UIContainerHorizontal;
import com.solibri.smc.api.ui.UIContainerVertical;
import com.solibri.smc.api.ui.UIImage;
import com.solibri.smc.api.ui.UILabel;
import com.solibri.smc.api.ui.UIRadioButtonPanel;
import com.solibri.smc.api.ui.UIRadioButtonPanelHorizontal;
import com.solibri.smc.api.ui.UIRuleParameter;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
/**
* This example shows how to define a custom layout for the rule parameters UI
* of your own rules.
*/
public final class UIComponentExample extends OneByOneRule {
/*
* Retrieve the parameters creator.
*/
private final RuleParameters params = RuleParameters.of(this);
/*
* Get a reference to the default filter by using getDefaultFilter. This is the filter that is used for
* selecting which components are checked by the rule.
*/
private final FilterParameter componentFilterParameter = this.getDefaultFilterParameter();
/*
* Create a parameter for handling double values.
*/
private final DoubleParameter doubleParameter = params.createDouble("rpDoubleParameter", PropertyType.LENGTH);
/*
* Create a parameter for handling boolean values.
*/
private final BooleanParameter booleanParameter = params.createBoolean("rpBooleanParameter");
/*
* Create a parameter for handling property references. Property references can be used for retrieving the
* value of a property from a component's property sets.
*/
private final PropertyReferenceParameter propertyReferenceParameter = params.createPropertyReference("rpPropertyReferenceParameter");
private final EnumerationParameter enumerationParameterForRadioButtons = params.createEnumeration("rpEnumerationParameterForRadioButtons",
Arrays.asList("rpEnumerationParameterForRadioButtons.OPTION1", "rpEnumerationParameterForRadioButtons.OPTION2",
"rpEnumerationParameterForRadioButtons.OPTION3"));
private final EnumerationParameter enumerationParameterForComboBox = params.createEnumeration("rpEnumerationParameterForComboBox",
Arrays.asList("rpEnumerationParameterForComboBox.OPTION1", "rpEnumerationParameterForComboBox.OPTION2",
"rpEnumerationParameterForComboBox.OPTION3"));
private final TableParameter tableParameter = params.createTable("rpTableParameter",
Arrays.asList("rpTableParameter.LENGTH", "rpTableParameter.HEIGHT"), Arrays.asList(PropertyType.LENGTH, PropertyType.LENGTH));
/**
* A string parameter, whose value will be edited by a custom editor.
*/
private final StringParameter customStringParameter = params.createString("rpCustomStringParameter");
/*
* Retrieve a reference to the resources of this rule. The resources of a rule can contain
* resources such as strings and images.
*/
private final RuleResources resources = RuleResources.of(this);
@Override
public Collection<Result> check(Component component, ResultFactory resultFactory) {
/*
* The values of the parameters can be accessed using the getValue
* method.
*/
Double doubleParameterValue = doubleParameter.getValue();
System.out.println("The value of the double parameter is " + doubleParameterValue);
Boolean booleanParameterValue = booleanParameter.getValue();
System.out.println("The value of the boolean parameter is " + booleanParameterValue);
PropertyReference propertyReference = propertyReferenceParameter.getValue();
if (propertyReference == null) {
System.out.println("The referred property is not set");
} else {
System.out.println("The name of the referred property is " + propertyReference.getPropertyName());
}
/*
* Get the value of the referenced property from the component and print it if the value is present.
* If the component does not have the property specified by the reference, then the property value will
* be empty.
*/
Optional<?> propertyValue = component.getPropertyValue(propertyReference);
if (propertyValue.isPresent()) {
System.out.println("The value of the referred property is " + propertyValue.get());
}
/*
* The value of an enumeration parameter is the string key of the
* selected option.
*/
String enumerationParameterValue = enumerationParameterForRadioButtons.getValue();
System.out.println("The value of the enumeration parameter is " + enumerationParameterValue);
/*
* The values from the table parameter are printed.
*/
int rows = tableParameter.getValue().getRowCount();
int columns = tableParameter.getValue().getColumnCount();
System.out.println("The table has " + rows + " rows and " + columns + " columns.");
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
String value = tableParameter.getValue().getValueAt(i, j);
System.out.println("The value at position row: " + i + ", column: " + j + " is " + value);
}
}
/*
* This rule does not produce results.
*/
return Collections.emptySet();
}
/**
* In order to create a custom parameters UI for your rule, the method
* {@link com.solibri.smc.api.checking.Rule#getParametersUIDefinition()} needs to be overridden.
*/
@Override
public UIContainer getParametersUIDefinition() {
/*
* Create the main container for the UI definition. The container has a
* title and a line border. The getString method is used to get the
* string value from the properties file of the rule.
*/
UIContainer mainContainer = UIContainerVertical.create(resources.getString("uiMainContainer.TITLE"), BorderType.LINE);
/*
* Add a new container to the main container. Containers can be placed
* within other containers to create different layouts. mainContainer is
* a vertical container, so each new component is added below the
* previously added one.
*/
mainContainer.addComponent(createFilterContainer());
/*
* Create and add a container with parameters and an image.
*/
mainContainer.addComponent(createContainerWithParametersAndImage());
/*
* Create and add a container with a label and a radio button panel with images.
*/
mainContainer.addComponent(createContainerWithLabelAndRadioButtonWithImages());
mainContainer.addComponent(createCustomStringParameterComponent());
/*
* Return the container that contains all of the UI components for the parameters panel.
*/
return mainContainer;
}
/**
* A custom UI for a string parameter that presents a text panel and a button.
* Modifications to the text panel are committed when the button is pressed.
*/
private final class CustomStringParameterComponent implements RuleParameterCustomUi {
private final StringParameter customStringParameter;
private final JTextPane textPane = new JTextPane();
private final CommitAction commitAction = new CommitAction();
@SuppressFBWarnings(value = "SE_BAD_FIELD", justification = "This class is not serialized")
private class CommitAction extends AbstractAction {
@Serial private static final long serialVersionUID = -1;
CommitAction() {
putValue(Action.NAME, resources.getString("CommitButton.NAME"));
}
@Override
public void actionPerformed(ActionEvent e) {
final String text = textPane.getText();
customStringParameter.setValue(text);
}
}
private CustomStringParameterComponent(StringParameter customStringParameter) {
this.customStringParameter = customStringParameter;
}
@Override
public void setEnabler(UIComponent enabler) {
}
@Override
public Optional<UIComponent> getEnabler() {
return Optional.empty();
}
@Override
public java.awt.Component getComponent() {
JButton commitButton = new JButton(commitAction);
final int gap = 5;
JPanel panel = new JPanel(new BorderLayout(gap, gap));
textPane.setText(customStringParameter.getValue());
panel.add(commitButton, BorderLayout.WEST);
panel.add(textPane, BorderLayout.CENTER);
return panel;
}
@Override
public void setEditable(boolean editable) {
commitAction.setEnabled(editable);
textPane.setEditable(editable);
}
}
private UIComponent createCustomStringParameterComponent() {
UIContainer container = UIContainerVertical.create(resources.getString("customStringContainer.TITLE"),
BorderType.LINE);
container.addComponent(new CustomStringParameterComponent(customStringParameter));
return container;
}
/**
* This method creates the top panel of the parameters UI.
*/
private UIContainer createFilterContainer() {
/*
* Add a container that contains just a FilterParameter.
*/
UIContainer filterContainer = UIContainerVertical.create(resources.getString("uiFilterContainer.TITLE"), BorderType.LINE);
/*
* Rule parameters are added to the user interface by using
* UIRuleParameter objects.
*/
filterContainer.addComponent(UIRuleParameter.create(componentFilterParameter));
return filterContainer;
}
/**
* This method creates the middle panel of the parameters UI.
*/
private UIContainer createContainerWithParametersAndImage() {
/*
* This container uses horizontal layout to place a column of parameters
* next to an image.
*/
UIContainer horizontalContainer = UIContainerHorizontal.create(resources.getString("uiParameterContainer.TITLE"), BorderType.LINE);
/*
* Create a vertical container without title of border.
*/
UIContainer parameterContainer = UIContainerVertical.create();
/*
* Add different types of parameters into the parameter container.
* In a vertical container the UI component that is is added first will
* be placed topmost.
*/
parameterContainer.addComponent(UIRuleParameter.create(doubleParameter));
parameterContainer.addComponent(UIRuleParameter.create(booleanParameter));
parameterContainer.addComponent(UIRuleParameter.create(propertyReferenceParameter));
parameterContainer.addComponent(UIRuleParameter.create(enumerationParameterForComboBox));
/*
* Add the parameter container to the horizontal container. As the
* parameter container is added first, it will be at the leftmost side
* of the container in the UI.
*/
horizontalContainer.addComponent(parameterContainer);
/*
* Create an image from the image URL and add it to the container. The
* image will appear on the right side of the parameters.
*/
UIImage image = UIImage.create(resources.getImageUrl(resources.getString("uiParameterContainerImage")));
horizontalContainer.addComponent(image);
return horizontalContainer;
}
/**
* This method creates the bottom panel of the parameters UI.
*/
private UIContainer createContainerWithLabelAndRadioButtonWithImages() {
UIContainer radioButtonContainer = UIContainerVertical.create(resources.getString("uiRadioButtonContainer.TITLE"), BorderType.LINE);
/*
* Create a simple text label and add it at the top of the container.
*/
UILabel textLabel = UILabel.create(resources.getString("uiRadioButtonContainer.LABEL"));
radioButtonContainer.addComponent(textLabel);
/*
* Enumeration parameters can be represented in the UI using radio
* buttons. Radio buttons can be placed horizontally or vertically and
* can contain images alongside the options. This example shows a radio
* button panel with three options in a horizontal layout and images.
*/
UIRadioButtonPanel radioButtonPanel = UIRadioButtonPanelHorizontal.create(enumerationParameterForRadioButtons);
/*
* The enumeration parameter has three possible options for values, so
* three images are needed. The first image is the one that is attached
* to the first option, the second image is attached to the third option
* and so on.
*/
List<UIImage> radioButtonImages = new ArrayList<>();
radioButtonImages.add(UIImage.create(resources.getImageUrl(resources.getString("rpEnumerationParameterForRadioButtons.IMAGE1"))));
radioButtonImages.add(UIImage.create(resources.getImageUrl(resources.getString("rpEnumerationParameterForRadioButtons.IMAGE2"))));
radioButtonImages.add(UIImage.create(resources.getImageUrl(resources.getString("rpEnumerationParameterForRadioButtons.IMAGE3"))));
/*
* Add the images to the radio button panel.
*/
radioButtonPanel.addOptionImages(radioButtonImages);
radioButtonContainer.addComponent(radioButtonPanel);
return radioButtonContainer;
}
}
UIComponentExample.properties
The properties that are used in the UI are defined in the properties file.
DEFAULT_NAME=UI Component Example
DEFAULT_DESCRIPTION=This rule displays different types of parameter UI components
AUTHOR=Solibri, Inc.
AUTHOR_TAG=SOL
UID=EX5
VERSION=1.1
DATE=2023-01-12
uiMainContainer.TITLE = Main Container
uiFilterContainer.TITLE = Filter Container
rpComponentFilter.NAME = Components to Check
rpComponentFilter.DESCRIPTION = This filter specifies the set of components to check.
uiParameterContainer.TITLE = Parameter Container
rpDoubleParameter.NAME = Double parameter
rpDoubleParameter.DESCRIPTION = Double parameter tooltip
rpDoubleParameter.DEFAULT_VALUE = 0
rpBooleanParameter.NAME = Boolean parameter
rpBooleanParameter.DESCRIPTION = Boolean parameter tooltip
rpBooleanParameter.DEFAULT_VALUE = false
rpPropertyReferenceParameter.NAME = Property reference parameter
rpPropertyReferenceParameter.DESCRIPTION = Property reference parameter tooltip
uiParameterContainerImage = images/image.png
uiRadioButtonContainer.TITLE = Radio Button Container
uiRadioButtonContainer.LABEL = This is a text label
rpEnumerationParameterForRadioButtons.NAME = Radio button
rpEnumerationParameterForRadioButtons.DESCRIPTION = Radio button tooltip
rpEnumerationParameterForRadioButtons.DEFAULT_VALUE = 2
rpEnumerationParameterForRadioButtons.OPTION1 = Option 1
rpEnumerationParameterForRadioButtons.OPTION2 = Option 2
rpEnumerationParameterForRadioButtons.OPTION3 = Option 3
rpEnumerationParameterForComboBox.NAME = Combo box parameter
rpEnumerationParameterForComboBox.DESCRIPTION = Combo box parameter tooltip
rpEnumerationParameterForComboBox.DEFAULT_VALUE = 2
rpEnumerationParameterForComboBox.OPTION1 = Option 1
rpEnumerationParameterForComboBox.OPTION2 = Option 2
rpEnumerationParameterForComboBox.OPTION3 = Option 3
rpEnumerationParameterForRadioButtons.IMAGE1 = images/radio_button_1.png
rpEnumerationParameterForRadioButtons.IMAGE2 = images/radio_button_2.png
rpEnumerationParameterForRadioButtons.IMAGE3 = images/radio_button_3.png
# We can define multiple default values for the table parameter.
# rpTableParameter.DEFAULT_VALUE first lists all the properties that define the rows
# and then the row parameters define the values in them.
rpTableParameter.DEFAULT_VALUE = rpTableParameter.DEFAULT_VALUE_ROW1,rpTableParameter.DEFAULT_VALUE_ROW2
rpTableParameter.DEFAULT_VALUE_ROW1 = 1,2
rpTableParameter.DEFAULT_VALUE_ROW2 = 300,400
CommitButton.NAME = Commit Changes
customStringContainer.TITLE = Custom Parameter UI