
org.bidib.wizard.mvc.stepcontrol.view.StepControlPanel Maven / Gradle / Ivy
package org.bidib.wizard.mvc.stepcontrol.view;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.net.URL;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Collections;
import java.util.Comparator;
import java.util.EventObject;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ListModel;
import javax.swing.RowSorter;
import javax.swing.SortOrder;
import javax.swing.SwingUtilities;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableModel;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.bidib.jbidibc.core.AccessoryState;
import org.bidib.jbidibc.core.node.ConfigurationVariable;
import org.bidib.jbidibc.core.utils.AccessoryStateUtils.ErrorAccessoryState.AccessoryExecutionState;
import org.bidib.jbidibc.core.utils.ByteUtils;
import org.bidib.jbidibc.core.utils.ProductUtils;
import org.bidib.wizard.comm.FeedbackPortStatus;
import org.bidib.wizard.locale.Resources;
import org.bidib.wizard.main.DefaultApplicationContext;
import org.bidib.wizard.mvc.common.view.converter.StringToUnsignedLongConverter;
import org.bidib.wizard.mvc.common.view.converter.TurnTableTypeConverter;
import org.bidib.wizard.mvc.common.view.cvdefinition.CvDefinitionTreeTableModel;
import org.bidib.wizard.mvc.common.view.cvdefinition.CvDefintionPanelProvider;
import org.bidib.wizard.mvc.common.view.cvdefinition.CvValueUtils;
import org.bidib.wizard.mvc.common.view.table.ButtonColumn;
import org.bidib.wizard.mvc.common.view.table.CustomBooleanCellEditor;
import org.bidib.wizard.mvc.common.view.table.CustomBooleanCellRenderer;
import org.bidib.wizard.mvc.common.view.table.LineNumberTableRowHeader;
import org.bidib.wizard.mvc.main.model.MainModel;
import org.bidib.wizard.mvc.main.model.Node;
import org.bidib.wizard.mvc.main.model.Port;
import org.bidib.wizard.mvc.main.model.listener.CvDefinitionRequestListener;
import org.bidib.wizard.mvc.main.model.listener.DefaultFeedbackPortListener;
import org.bidib.wizard.mvc.main.view.component.DefaultTabSelectionPanel;
import org.bidib.wizard.mvc.main.view.cvdef.CvNode;
import org.bidib.wizard.mvc.main.view.cvdef.LongCvNode;
import org.bidib.wizard.mvc.main.view.menu.BasicPopupMenu;
import org.bidib.wizard.mvc.main.view.panel.listener.TabSelectionListener;
import org.bidib.wizard.mvc.main.view.panel.listener.TabStatusListener;
import org.bidib.wizard.mvc.main.view.statusbar.StatusBar;
import org.bidib.wizard.mvc.main.view.table.PortHighlighter;
import org.bidib.wizard.mvc.stepcontrol.model.StepControlAspect;
import org.bidib.wizard.mvc.stepcontrol.model.StepControlAspect.Polarity;
import org.bidib.wizard.mvc.stepcontrol.model.StepControlModel;
import org.bidib.wizard.mvc.stepcontrol.model.StepControlModel.TurnTableType;
import org.bidib.wizard.utils.ImageUtils;
import org.bidib.wizard.utils.IntegerEditor;
import org.jdesktop.swingx.JXTable;
import org.jdesktop.swingx.decorator.Highlighter;
import org.jdesktop.swingx.decorator.HighlighterFactory;
import org.jdesktop.swingx.sort.TableSortController;
import org.jdesktop.swingx.treetable.TreeTableNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.jgoodies.binding.PresentationModel;
import com.jgoodies.binding.adapter.BasicComponentFactory;
import com.jgoodies.binding.adapter.SingleListSelectionAdapter;
import com.jgoodies.binding.list.SelectionInList;
import com.jgoodies.binding.value.ConverterValueModel;
import com.jgoodies.binding.value.ValueHolder;
import com.jgoodies.binding.value.ValueModel;
import com.jgoodies.forms.builder.ButtonBarBuilder;
import com.jgoodies.forms.builder.DefaultFormBuilder;
import com.jgoodies.forms.factories.Borders;
import com.jgoodies.forms.layout.FormLayout;
import com.vlsolutions.swing.toolbars.ToolBarConstraints;
import com.vlsolutions.swing.toolbars.ToolBarPanel;
import com.vlsolutions.swing.toolbars.VLToolBar;
import eu.hansolo.steelseries.extras.Led;
public class StepControlPanel implements TabSelectionListener, CvDefintionPanelProvider {
private static final Logger LOGGER = LoggerFactory.getLogger(StepControlPanel.class);
private static final String READ = "read";
private static final String WRITE = "write";
private static final String KEYWORD_PATTERN_POLARITY = "target_polarity_%d";
private static final String KEYWORD_PATTERN_POSITION = "target_position_%d";
private static final String KEYWORD_STEP_POSITION = "step_position";
private static final String KEYWORD_CONFIGURED_ASPECTS = "configured_aspects";
private static final String KEYWORD_TABLETYPE = "tabletype";
private static final int EXTRA_VERTICAL_SPACE = 4;
private static final int MAX_CONFIGURED_ASPECTS = 48;
private static final long INACTIVE_POSITION_VALUE = 0xFFFFFFFFL;
private final StepControlModel stepControlModel;
private final TabStatusListener tabStatusListener;
private JXTable table;
private JPanel component;
private Node selectedNode;
private SelectionInList aspectSelection;
private PresentationModel stepControlPresentationModel;
private ImageIcon accessoryErrorIcon;
private ImageIcon accessorySuccessfulIcon;
private ImageIcon accessoryWaitIcon;
private ImageIcon accessoryUnknownIcon;
private JLabel executionStateIconLabel = new JLabel();
private AccessoryExecutionState accessoryExecutionState;
private List cvDefinitionRequestListeners =
new LinkedList();
private Map mapKeywordToNode;
private List requiredConfigVariables = new LinkedList<>();
private final MainModel mainModel;
private boolean initialized;
private StatusBar statusBar;
private List fieldsToUpdate = new LinkedList<>();
private List occupancyLeds = new LinkedList<>();
private JButton readButton;
private JButton writeButton;
private VLToolBar toolbarCvDefinition;
public StepControlPanel(final MainModel mainModel, final TabStatusListener tabStatusListener) {
this.tabStatusListener = tabStatusListener;
this.mainModel = mainModel;
stepControlModel = new StepControlModel();
statusBar = DefaultApplicationContext.getInstance().get("statusBar", StatusBar.class);
}
public void createComponent() {
DefaultTabSelectionPanel container = new DefaultTabSelectionPanel() {
private static final long serialVersionUID = 1L;
@Override
public void tabSelected(boolean selected) {
LOGGER.debug("Select tab, current component: is StepControlPanel.");
StepControlPanel.this.tabSelected(selected);
}
};
DefaultFormBuilder defaultFormBuilder = new DefaultFormBuilder(new FormLayout("p, 3dlu, p:g"), container);
defaultFormBuilder.border(Borders.TABBED_DIALOG);
initializeAccessoryStateIcons();
ImageIcon iconReadAndCreate =
ImageUtils.createImageIcon(StepControlPanel.class, "/icons/stepcontrol/SetCurrentPosition.png");
ImageIcon iconReadPosition =
ImageUtils.createImageIcon(StepControlPanel.class, "/icons/stepcontrol/ReadPosition.png");
aspectSelection =
new SelectionInList<>((ListModel) stepControlModel.getStepControlAspectsListModel());
stepControlPresentationModel = new PresentationModel<>(new ValueHolder(stepControlModel, true));
executionStateIconLabel = new JLabel();
defaultFormBuilder.append("Execution state: ", executionStateIconLabel);
defaultFormBuilder.appendRow("5dlu");
table =
new JXTable(
new AspectTableAdapter(
aspectSelection, new String[] { Resources.getString(StepControlPanel.class, "position"),
Resources.getString(StepControlPanel.class, "polarity"),
Resources.getString(StepControlPanel.class, "action") }) {
private static final long serialVersionUID = 1L;
@Override
public void fireTableDataChanged() {
// preserve selection calling fireTableDataChanged()
int[] sel = null;
int[] index = null;
if (table != null) {
sel = table.getSelectedRows();
index = new int[1];
index[0] = table.getRowSorter().convertRowIndexToModel(sel[0]);
LOGGER.info("tableDataChanged, sel: {}, index: {}", sel, index);
}
super.fireTableDataChanged();
if (index != null) {
setSelectedIndex(index[0]);
}
}
}) {
private static final long serialVersionUID = 1L;
@Override
public boolean editCellAt(final int row, int column, EventObject e) {
boolean isEditing = super.editCellAt(row, column, e);
LOGGER.info("isEditing: {}", isEditing);
// this is necessary for the polarity toggle button to work correct
if (column == AspectTableAdapter.COLUMN_POLARITY) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if (getCellEditor() != null) {
getCellEditor().stopCellEditing();
// keep selection
getSelectionModel().setSelectionInterval(row, row);
}
}
});
}
return isEditing;
}
protected RowSorter extends TableModel> createDefaultRowSorter() {
return new TableSortController(
getModel()) {
@Override
public void toggleSortOrder(int column) {
LOGGER.debug("toggleSortOrder on column: {}", column);
// do nothing to prevent toggle sort order
}
};
}
};
table.setSelectionModel(new SingleListSelectionAdapter(aspectSelection.getSelectionIndexHolder()));
table.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
table.setRowHeight(table.getRowHeight() + EXTRA_VERTICAL_SPACE);
table.getColumn(AspectTableAdapter.COLUMN_POSITION).setPreferredWidth(100);
table.getColumn(AspectTableAdapter.COLUMN_POLARITY).setPreferredWidth(70);
// add highlighter that evaluate if the port is enabled
PortHighlighter portHighlighter = new PortHighlighter();
Highlighter simpleStriping = HighlighterFactory.createSimpleStriping();
table.setHighlighters(simpleStriping, portHighlighter);
JScrollPane scrollPane = new JScrollPane(table);
scrollPane.setPreferredSize(table.getPreferredSize());
LineNumberTableRowHeader tableLineNumber = new LineNumberTableRowHeader(scrollPane, table);
tableLineNumber.setBackground(Color.LIGHT_GRAY);
tableLineNumber.setVerticalOffset(EXTRA_VERTICAL_SPACE);
scrollPane.setRowHeaderView(tableLineNumber);
table.getModel().addTableModelListener(new TableModelListener() {
@Override
public void tableChanged(TableModelEvent e) {
LOGGER.info("The table has changed, e: {}", e);
tabStatusListener.updatePendingChanges(component, true);
}
});
defaultFormBuilder.appendRow("fill:200dlu:g");
defaultFormBuilder.nextLine(2);
defaultFormBuilder.append(scrollPane);
// create the 'detail panel'
DefaultFormBuilder detailFormBuilder = new DefaultFormBuilder(new FormLayout("p, 3dlu, p, 3dlu, p, 3dlu, p:g"));
// use converter for turntable model
final ValueModel turnTableTypeConverterModel =
new ConverterValueModel(
stepControlPresentationModel.getBufferedModel(StepControlModel.PROPERTYNAME_TURNTABLE_TYPE),
new TurnTableTypeConverter());
JTextField turnTableType = BasicComponentFactory.createTextField(turnTableTypeConverterModel);
turnTableType.setEditable(false);
detailFormBuilder.append(Resources.getString(StepControlPanel.class, "turntableType"), turnTableType, 5);
detailFormBuilder.nextLine();
final ValueModel currentPositionConverterModel =
new ConverterValueModel(
stepControlPresentationModel.getBufferedModel(StepControlModel.PROPERTYNAME_CURRENT_POSITION),
new StringToUnsignedLongConverter());
JTextField currentPosition = BasicComponentFactory.createTextField(currentPositionConverterModel);
detailFormBuilder.append(Resources.getString(StepControlPanel.class, "position"), currentPosition, 5);
detailFormBuilder.nextLine();
// add the occupancy leds
Led occupancy1 = new Led();
occupancy1.setPreferredSize(new Dimension(32, 32));
Led occupancy2 = new Led();
occupancy2.setPreferredSize(new Dimension(32, 32));
Led occupancy3 = new Led();
occupancy3.setPreferredSize(new Dimension(32, 32));
Led occupancy4 = new Led();
occupancy4.setPreferredSize(new Dimension(32, 32));
occupancyLeds.add(occupancy1);
occupancyLeds.add(occupancy2);
occupancyLeds.add(occupancy3);
occupancyLeds.add(occupancy4);
detailFormBuilder.append(Resources.getString(StepControlPanel.class, "occupancy"),
buildLeftAlignedButtonBar(occupancy1, occupancy2, occupancy3, occupancy4), 5);
detailFormBuilder.nextLine();
// lower part of the detail form
JButton readCurrentPosAndCreateAspect = new JButton(iconReadAndCreate);
readCurrentPosAndCreateAspect.setMargin(new Insets(0, 0, 0, 0));
readCurrentPosAndCreateAspect.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
LOGGER.info("Create new aspect from data in form.");
fireCreateNewAspect();
}
});
JButton readCurrentPos = new JButton(iconReadPosition);
readCurrentPos.setMargin(new Insets(0, 0, 0, 0));
readCurrentPos.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
LOGGER.info("Read current position.");
fireReadPos();
}
});
detailFormBuilder.append(buildLeftAlignedButtonBar(readCurrentPosAndCreateAspect, readCurrentPos), 7);
defaultFormBuilder.append(detailFormBuilder.build());
component = defaultFormBuilder.build();
// the name is displayed on the tab
component.setName(getName());
final AspectTablePopupMenu menu = new AspectTablePopupMenu();
table.addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
handleMouseEvent(e, menu);
}
public void mouseReleased(MouseEvent e) {
handleMouseEvent(e, menu);
}
});
// do not allow drag columns to other position
table.getTableHeader().setReorderingAllowed(false);
table.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
table.getColumn(AspectTableAdapter.COLUMN_POLARITY).setCellEditor(
new CustomBooleanCellEditor("/icons/stepcontrol/arrow_right.png", "/icons/stepcontrol/arrow_left.png"));
table.getColumn(AspectTableAdapter.COLUMN_POLARITY).setCellRenderer(
new CustomBooleanCellRenderer("/icons/stepcontrol/arrow_right.png", "/icons/stepcontrol/arrow_left.png"));
table.getColumn(AspectTableAdapter.COLUMN_POSITION).setCellRenderer(new LongRenderer());
table.getColumn(AspectTableAdapter.COLUMN_POSITION).setCellEditor(new IntegerEditor(0, Integer.MAX_VALUE));
table.getColumnExt(AspectTableAdapter.COLUMN_POLARITY).setSortable(false);
table.getColumnExt(AspectTableAdapter.COLUMN_PERFORM_ASPECT).setSortable(false);
table.setSortOrder(AspectTableAdapter.COLUMN_POSITION, SortOrder.ASCENDING);
Action performAspect = new AbstractAction() {
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent e) {
int modelRow = Integer.valueOf(e.getActionCommand());
firePerformAspect(modelRow);
}
};
// add the button renderer to the column
new ButtonColumn(table, performAspect, AspectTableAdapter.COLUMN_PERFORM_ASPECT);
// add the pending changes listener to the stepControlModel
stepControlModel.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
LOGGER.info("Property has changed, evt: {}", evt);
tabStatusListener.updatePendingChanges(component, true);
}
});
toolbarCvDefinition = new VLToolBar("stepControlCvDefinition");
addButtons(toolbarCvDefinition);
addToolBar(toolbarCvDefinition, new ToolBarConstraints(0, 2));
// initially invisible
toolbarCvDefinition.setVisible(false);
mainModel.addFeedbackPortListener(new DefaultFeedbackPortListener() {
@Override
public void statusChanged(Port port, FeedbackPortStatus status) {
if (port.getId() < occupancyLeds.size()) {
LOGGER.info("The status of the feedback port has changed: {}, status: {}", port, status);
Led occupancyLed = occupancyLeds.get(port.getId());
if (occupancyLed != null) {
occupancyLed.setLedOn(status == FeedbackPortStatus.OCCUPIED ? true : false);
}
}
else {
LOGGER.debug("Port number of feedback port is out of range: {}", port.getId());
}
}
});
}
/**
* Initialize the accessory state icons
*/
private void initializeAccessoryStateIcons() {
// Set the icon for leaf nodes.
accessoryErrorIcon = ImageUtils.createImageIcon(StepControlPanel.class, "/icons/accessory-error.png");
accessorySuccessfulIcon = ImageUtils.createImageIcon(StepControlPanel.class, "/icons/accessory-successful.png");
accessoryWaitIcon = ImageUtils.createImageIcon(StepControlPanel.class, "/icons/accessory-wait.png");
accessoryUnknownIcon = ImageUtils.createImageIcon(StepControlPanel.class, "/icons/accessory-unknown.png");
}
private void firePerformAspect(int row) {
LOGGER.info("Aspect is performed on row: {}", row);
for (CvDefinitionRequestListener l : cvDefinitionRequestListeners) {
l.activateAspect(row);
}
}
private void readCurrentValuesFromCV(final Node node) {
LOGGER.info("Read the values from CV for node: {}", node);
if (node == null || !ProductUtils.isStepControl(node.getUniqueId())) {
LOGGER.warn("No node available or not a StepControl: {}", node);
// TODO clear model
if (mapKeywordToNode != null) {
mapKeywordToNode.clear();
}
return;
}
LOGGER.info("Get the cvDefinitionTreeTableModel from the node: {}", node);
CvDefinitionTreeTableModel cvDefinitionTreeTableModel = node.getCvDefinitionTreeTableModel();
if (cvDefinitionTreeTableModel != null) {
// search the keywords
mapKeywordToNode = new LinkedHashMap<>();
TreeTableNode rootNode = cvDefinitionTreeTableModel.getRoot();
if (rootNode != null) {
harvestKeywordNodes(rootNode, mapKeywordToNode);
}
LOGGER.info("Found keywords in nodes: {}", mapKeywordToNode.keySet());
}
else {
LOGGER.warn("No cvDefinitionTreeTableModel available for node: {}", node);
}
// TODO make this more clever? only load values that are not loaded already? is this clever? how about changed
// values?
// read the values from the node
if (MapUtils.isNotEmpty(mapKeywordToNode)) {
List configVariables = new LinkedList<>();
for (CvNode cvNode : mapKeywordToNode.values()) {
// LOGGER.info("Process cvNode: {}", cvNode);
prepareConfigVariables(cvNode, configVariables, node.getCvNumberToNodeMap());
}
// keep the list of config variables
this.requiredConfigVariables.clear();
if (CollectionUtils.isNotEmpty(configVariables)) {
this.requiredConfigVariables.addAll(configVariables);
}
fireLoadConfigVariables(configVariables);
}
else {
LOGGER.warn("No values available in mapKeywordToNode!");
}
}
private void prepareConfigVariables(
final CvNode cvNode, final List configVariables,
final Map cvNumberToNodeMap) {
try {
switch (cvNode.getCV().getType()) {
case LONG:
// LONG nodes are processed
LongCvNode masterNode = ((LongCvNode) cvNode).getMasterNode();
configVariables.add(masterNode.getConfigVar());
for (CvNode slaveNode : masterNode.getSlaveNodes()) {
configVariables.add(slaveNode.getConfigVar());
}
break;
case INT:
// INT nodes are processed
configVariables.add(cvNode.getConfigVar());
int highCvNum = Integer.parseInt(cvNode.getCV().getHigh());
if (highCvNum == cvNode.getCV().getNumber()) {
// search the low CV
CvNode lowCvNode = cvNumberToNodeMap.get(cvNode.getCV().getLow());
configVariables.add(lowCvNode.getConfigVar());
}
else {
// search the high CV
CvNode highCvNode = cvNumberToNodeMap.get(cvNode.getCV().getHigh());
configVariables.add(highCvNode.getConfigVar());
}
break;
default:
configVariables.add(cvNode.getConfigVar());
break;
}
}
catch (Exception ex) {
LOGGER.warn("Prepare config variables to read from node failed.", ex);
}
}
private void harvestKeywordNodes(TreeTableNode parentNode, Map mapKeywordToNode) {
if (parentNode != null) {
for (int index = 0; index < parentNode.getChildCount(); index++) {
TreeTableNode childNode = parentNode.getChildAt(index);
if (childNode instanceof CvNode) {
CvNode cvNode = (CvNode) childNode;
if (StringUtils.isNotBlank(cvNode.getCV().getKeyword())) {
LOGGER.info("The current node has a keyword: {}", cvNode.getCV().getKeyword());
mapKeywordToNode.put(cvNode.getCV().getKeyword(), cvNode);
}
}
harvestKeywordNodes(childNode, mapKeywordToNode);
}
}
}
public void addCvDefinitionRequestListener(CvDefinitionRequestListener l) {
cvDefinitionRequestListeners.add(l);
}
private void fireLoadConfigVariables(List configVariables) {
// TODO decouple the AWT-thread from this work?
LOGGER.info("Load the config variables.");
for (CvDefinitionRequestListener l : cvDefinitionRequestListeners) {
l.loadCvValues(configVariables);
}
}
private JComponent buildButtonBar(JButton... button) {
return new ButtonBarBuilder().addGlue().addButton(button).build();
}
private JComponent buildLeftAlignedButtonBar(JComponent... button) {
return new ButtonBarBuilder().addButton(button).addGlue().build();
}
public JPanel getComponent() {
return component;
}
public String getName() {
return Resources.getString(getClass(), "name");
}
@Override
public void tabSelected(boolean selected) {
LOGGER.info("Tab is selected: {}, initialized: {}", selected, initialized);
// show the toolbar
toolbarCvDefinition.setVisible(selected);
if (selected && !initialized) {
statusBar.setStatus(Resources.getString(StepControlPanel.class, "loading_cvvalues"));
// call this method after node was selected
SwingUtilities.invokeLater(new Runnable() {
public void run() {
readCurrentValuesFromCV(selectedNode);
}
});
}
if (!selected && mainModel.getSelectedNode() == null) {
LOGGER.info("The tab is no longer selected and the selected node is null, reset the selected node!");
selectedNode = null;
}
}
private void handleMouseEvent(MouseEvent e, AspectTablePopupMenu aspectTableMenu) {
if (e.isPopupTrigger()) {
int row = table.rowAtPoint(e.getPoint());
int column = table.columnAtPoint(e.getPoint());
showAspectTableMenu(e, aspectTableMenu, row, column);
}
}
private void showAspectTableMenu(MouseEvent e, AspectTablePopupMenu aspectTableMenu, int row, int column) {
Object value = null;
if (row > -1) {
table.setRowSelectionInterval(row, row);
value = table.getValueAt(row, -1);
}
aspectTableMenu.setDeleteEnabled(value instanceof StepControlAspect);
aspectTableMenu.show(e.getComponent(), e.getX(), e.getY());
}
private final class AspectTablePopupMenu extends BasicPopupMenu {
private static final long serialVersionUID = 1L;
private JMenuItem newLabel;
private JMenuItem deleteLabel;
public AspectTablePopupMenu() {
newLabel = new JMenuItem(Resources.getString(StepControlPanel.class, "newAspect") + " ...");
newLabel.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (stepControlModel.getStepControlAspects().size() < MAX_CONFIGURED_ASPECTS) {
int stepNumber = table.getRowCount() + 1;
StepControlAspect aspect = new StepControlAspect(stepNumber, 0, Polarity.normal);
stepControlModel.addStepControlAspect(aspect);
}
else {
LOGGER.warn("Maximum number of aspects reached.");
JOptionPane.showMessageDialog(component,
Resources.getString(StepControlPanel.class, "max_aspect_message"),
Resources.getString(StepControlPanel.class, "max_aspect_title"), JOptionPane.ERROR_MESSAGE);
}
}
});
add(newLabel);
deleteLabel = new JMenuItem(Resources.getString(StepControlPanel.class, "deleteAspect") + " ...");
deleteLabel.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
int selectedRow = table.getSelectedRow();
if (selectedRow > -1) {
Object aspect = table.getValueAt(selectedRow, -1);
if (aspect instanceof StepControlAspect) {
stepControlModel.removeStepControlAspect((StepControlAspect) aspect);
}
}
}
});
add(deleteLabel);
}
public void setDeleteEnabled(boolean enabled) {
deleteLabel.setEnabled(enabled);
}
}
private void fireCreateNewAspect() {
if (stepControlModel.getStepControlAspects().size() < MAX_CONFIGURED_ASPECTS) {
// create new aspect using the 'actual position'
Long position =
(Long) stepControlPresentationModel.getBufferedValue(StepControlModel.PROPERTYNAME_CURRENT_POSITION);
if (position == null) {
position = 0L;
}
StepControlAspect stepControlAspect = new StepControlAspect(null, position, Polarity.normal);
stepControlModel.addStepControlAspect(stepControlAspect);
aspectSelection.setSelection(stepControlAspect);
int index = aspectSelection.getSelectionIndex();
setSelectedIndex(index);
}
else {
LOGGER.warn("Maximum number of aspects reached.");
JOptionPane.showMessageDialog(component, Resources.getString(StepControlPanel.class, "max_aspect_message"),
Resources.getString(StepControlPanel.class, "max_aspect_title"), JOptionPane.ERROR_MESSAGE);
}
}
private void setSelectedIndex(int index) {
index = table.getRowSorter().convertRowIndexToView(index);
table.getSelectionModel().setSelectionInterval(index, index);
if (true) {
Rectangle cellRect = table.getCellRect(index, 0, false);
if (cellRect != null) {
table.scrollRectToVisible(cellRect);
}
}
}
private void fireReadPos() {
LOGGER.info("Read the current position.");
CvNode cvNode = mapKeywordToNode.get(KEYWORD_STEP_POSITION);
if (cvNode != null) {
List configVariables = new LinkedList<>();
prepareConfigVariables(cvNode, configVariables, selectedNode.getCvNumberToNodeMap());
fireLoadConfigVariables(configVariables);
}
else {
LOGGER.warn("The step_position CV is not available.");
}
}
/**
* The CV definition of the node has changed.
*/
public void cvDefinitionChanged() {
LOGGER.info("The cv definition has changed, selected node: {}", selectedNode);
if (selectedNode != null && selectedNode.equals(mainModel.getSelectedNode())) {
LOGGER.info("The node in the model has not changed.");
return;
}
if (readButton != null) {
readButton.setEnabled(false);
}
if (writeButton != null) {
writeButton.setEnabled(false);
}
selectedNode = mainModel.getSelectedNode();
// clear the aspects
stepControlModel.clearModel();
requiredConfigVariables.clear();
if (mapKeywordToNode != null) {
LOGGER.info("Clear the mapKeywordToNode.");
mapKeywordToNode.clear();
}
// force reload of CV values
initialized = false;
if (selectedNode != null) {
if (readButton != null) {
// enable the read button to get the values of the configuration variables for this node on
// request
readButton.setEnabled(CollectionUtils.isNotEmpty(selectedNode.getConfigVariables()));
}
if (writeButton != null) {
// enable the write button to write the values of the configuration variables for this node on
// request
writeButton.setEnabled(CollectionUtils.isNotEmpty(selectedNode.getConfigVariables()));
}
}
// load the aspects initially
if (selectedNode != null && ProductUtils.isStepControl(selectedNode.getUniqueId())) {
LOGGER.info("The currently selected node is a StepControl.");
fieldsToUpdate.add(KEYWORD_CONFIGURED_ASPECTS);
}
}
/**
* The values of the current CV definition have changed.
*/
public void cvDefinitionValuesChanged() {
LOGGER.info("The cv defintion values have changed.");
if (selectedNode == null || !ProductUtils.isStepControl(selectedNode.getUniqueId())) {
LOGGER.info("The currently selected node is not a StepControl.");
return;
}
if (MapUtils.isEmpty(mapKeywordToNode)) {
LOGGER.info("No mapKeywordToNode value available.");
return;
}
try {
Integer value = getConfigVarIntValue(KEYWORD_TABLETYPE);
TurnTableType turnTableType = TurnTableType.fromValue(ByteUtils.getLowByte(value));
stepControlModel.setTurnTableType(turnTableType);
}
catch (Exception ex) {
LOGGER.warn("Set the turnTableType failed.", ex);
}
try {
Long stepPosition1 = getConfigVarLongValue(KEYWORD_STEP_POSITION);
stepControlModel.setCurrentPosition(stepPosition1);
}
catch (Exception ex) {
LOGGER.warn("Set the current position failed.", ex);
}
if (fieldsToUpdate.contains(KEYWORD_CONFIGURED_ASPECTS)) {
LOGGER.info("Prepare the configured aspects.");
// create the list of aspects with the values from the config variables
List configuredAspects = new LinkedList<>();
for (int index = 0; index < MAX_CONFIGURED_ASPECTS; index++) {
try {
Integer targetPolarity = getConfigVarIntValue(String.format(KEYWORD_PATTERN_POLARITY, index));
Long targetPosition = getConfigVarLongValue(String.format(KEYWORD_PATTERN_POSITION, index));
if (targetPosition < INACTIVE_POSITION_VALUE) {
StepControlAspect stepControlAspect =
new StepControlAspect(null, targetPosition.longValue(), Polarity.valueOf(targetPolarity
.intValue()));
LOGGER.info("Adding new stepControlAspect: {}", stepControlAspect);
configuredAspects.add(stepControlAspect);
}
else {
LOGGER.info("No active position at index {}, skip further creation of aspects, position: {}",
index, targetPosition);
break;
}
}
catch (IllegalArgumentException ex) {
LOGGER.warn("Prepare configured step control aspect failed: {}", ex.getMessage());
}
catch (Exception ex) {
LOGGER.warn("Prepare configured step control aspect failed.", ex);
}
}
stepControlModel.setStepControlAspects(configuredAspects);
fieldsToUpdate.remove(KEYWORD_CONFIGURED_ASPECTS);
}
if (!initialized) {
initialized = true;
LOGGER.info("Reset the pending changes flag on the tab.");
tabStatusListener.updatePendingChanges(component, false);
}
}
private CvNode getNode(String keyword) {
CvNode cvNode = mapKeywordToNode.get(keyword);
return cvNode;
}
private Integer getConfigVarIntValue(String keyword) {
CvNode cvNode = getNode(keyword);
Integer value = null;
if (cvNode != null) {
switch (cvNode.getCV().getType()) {
case INT:
// process integer values
value = Integer.parseInt(cvNode.getConfigVar().getValue());
int highCvNum = Integer.parseInt(cvNode.getCV().getHigh());
if (highCvNum == cvNode.getCV().getNumber()) {
// search the low CV
CvNode lowCvNode = selectedNode.getCvNumberToNodeMap().get(cvNode.getCV().getLow());
value = (value << 8) | Integer.parseInt(lowCvNode.getConfigVar().getValue());
}
else {
// search the high CV
CvNode highCvNode = selectedNode.getCvNumberToNodeMap().get(cvNode.getCV().getHigh());
value = (value << 8) | Integer.parseInt(highCvNode.getConfigVar().getValue());
}
break;
default:
value = Integer.parseInt(cvNode.getConfigVar().getValue());
break;
}
}
return value;
}
private Long getConfigVarLongValue(String keyword) {
CvNode cvNode = getNode(keyword);
Long value = null;
if (cvNode != null) {
switch (cvNode.getCV().getType()) {
case LONG:
// process long values
LongCvNode masterNode = ((LongCvNode) cvNode).getMasterNode();
long longValue = 0;
CvNode[] slaveNodes = masterNode.getSlaveNodes().toArray(new CvNode[0]);
for (int index = 2; index > -1; index--) {
CvNode slaveNode = slaveNodes[index];
longValue = (longValue << 8) | Integer.parseInt(slaveNode.getConfigVar().getValue());
}
longValue = (longValue << 8) | Integer.parseInt(masterNode.getConfigVar().getValue());
value = ((long) longValue) & 0xffffffffL;
break;
default:
break;
}
}
return value;
}
public void executionStateChanged(
AccessoryExecutionState executionState, int accessoryId, int aspect, AccessoryState accessoryState) {
LOGGER.debug("The execution state has changed: {}, accessoryId: {}, aspect: {}", executionState, accessoryId,
aspect);
if (aspect == -1 || executionState == null) {
executionState = AccessoryExecutionState.IDLE;
}
executionStateIconLabel.setToolTipText(null);
switch (executionState) {
case ERROR:
executionStateIconLabel.setIcon(accessoryErrorIcon);
if (accessoryState != null) {
executionStateIconLabel.setToolTipText(accessoryState.getErrorInformation());
}
break;
case RUNNING:
executionStateIconLabel.setIcon(accessoryWaitIcon);
break;
case SUCCESSFUL:
executionStateIconLabel.setIcon(accessorySuccessfulIcon);
break;
case UNKNOWN:
executionStateIconLabel.setIcon(accessoryUnknownIcon);
break;
default:
executionStateIconLabel.setIcon(null);
break;
}
}
static class LongRenderer extends DefaultTableCellRenderer.UIResource {
private static final long serialVersionUID = 1L;
private NumberFormat formatter;
public LongRenderer() {
super();
setHorizontalAlignment(JLabel.RIGHT);
}
public void setValue(Object value) {
if (formatter == null) {
formatter = new DecimalFormat("#");
}
if (value instanceof Number) {
long sourceValue = ((Number) value).longValue();
long lValue = ((long) sourceValue) & 0xffffffffL;
setText(formatter.format(lValue));
}
else {
setText(null);
}
}
}
private void addButtons(VLToolBar toolBar) {
// read button
readButton =
makeNavigationButton("load-from-node", "/32x32", READ,
Resources.getString(getClass(), "toolbar.readallcv"),
Resources.getString(getClass(), "toolbar.readallcv.alttext"));
readButton.setEnabled(false);
toolBar.add(readButton);
readButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
readCurrentValuesFromCV(selectedNode);
}
});
// write button
writeButton =
makeNavigationButton("save-to-node", "/32x32", WRITE,
Resources.getString(getClass(), "toolbar.writeallcv"),
Resources.getString(getClass(), "toolbar.writeallcv.alttext"));
toolBar.add(writeButton);
writeButton.setEnabled(false);
writeButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
LOGGER.info("Write the CV values.");
// prepare the cv list to write
final List cvList = new LinkedList<>();
// collect the new values
int aspectIndex = 0;
List aspects = new LinkedList<>();
// get the aspects from the model
aspects.addAll(stepControlModel.getStepControlAspects());
Collections.sort(aspects, new Comparator() {
@Override
public int compare(StepControlAspect o1, StepControlAspect o2) {
return Long.compare(o1.getPosition(), o2.getPosition());
}
});
// check the aspects
for (StepControlAspect currentAspect : aspects) {
LOGGER.info("Prepare aspect to save: {}", currentAspect);
prepareCvValues(aspectIndex, currentAspect, cvList);
aspectIndex++;
}
// add the terminating aspects by setting 0xFFFF as position
if (aspectIndex < MAX_CONFIGURED_ASPECTS) {
StepControlAspect currentAspect =
new StepControlAspect(null, INACTIVE_POSITION_VALUE, Polarity.normal);
prepareCvValues(aspectIndex, currentAspect, cvList);
aspectIndex++;
}
// check the turntable type
CvNode tableTypeNode = getNode(KEYWORD_TABLETYPE);
TurnTableType turnTableType = stepControlModel.getTurnTableType();
CvValueUtils.compareAndAddNewValue(tableTypeNode, Integer.toString(turnTableType.getCvValue()), cvList);
// write the values on the node
CvValueUtils.writeCvValues(cvList, selectedNode.getCvNumberToNodeMap(), StepControlPanel.this);
}
});
}
private void prepareCvValues(
int aspectIndex, StepControlAspect currentAspect, final List cvList) {
// prepare the keyword to search
String keywordPolarity = String.format(KEYWORD_PATTERN_POLARITY, aspectIndex);
CvNode polarityNode = getNode(keywordPolarity);
Polarity polarity = currentAspect.getPolarity();
CvValueUtils.compareAndAddNewValue(polarityNode, Integer.toString(polarity.getCvValue()), cvList);
// the target position is a long type
String keywordPosition = String.format(KEYWORD_PATTERN_POSITION, aspectIndex);
// get the master
LongCvNode positionNode = (LongCvNode) getNode(keywordPosition);
int position = (int) currentAspect.getPosition();
// prepare the master value
LOGGER.info("The new position is: {}", position);
byte[] bytes = new byte[4];
bytes[0] = ByteUtils.getLowByte(position);
bytes[1] = ByteUtils.getHighByte(position);
bytes[2] = ByteUtils.getHighWordLowByte(position);
bytes[3] = ByteUtils.getHighWordHighByte(position);
LOGGER.debug("Current slave CV#: {}, value: {}", positionNode.getCV().getNumber(), ByteUtils.getInt(bytes[0]));
CvValueUtils.compareAndAddNewValue(positionNode, Integer.toString(ByteUtils.getInt(bytes[0])), cvList);
// add the slaves
int idx = 1;
for (CvNode slaveNode : positionNode.getSlaveNodes()) {
LOGGER.debug("Current slave CV#: {}, value: {}", slaveNode.getCV().getNumber(),
ByteUtils.getInt(bytes[idx]));
CvValueUtils.compareAndAddNewValue(slaveNode, Integer.toString(ByteUtils.getInt(bytes[idx])), cvList);
idx++;
}
}
private JButton makeNavigationButton(
String imageName, String pathExt, String actionCommand, String toolTipText, String altText) {
// Look for the image.
String imgLocation = "/icons/" + imageName + ".png";
if (pathExt != null) {
imgLocation = "/icons" + pathExt + "/" + imageName + ".png";
}
URL imageURL = StepControlPanel.class.getResource(imgLocation);
// Create and initialize the button.
JButton button = new JButton();
button.setActionCommand(actionCommand);
button.setToolTipText(toolTipText);
if (imageURL != null) { // image found
button.setIcon(new ImageIcon(imageURL, altText));
}
else { // no image found
button.setText(altText);
LOGGER.warn("Resource not found: {}", imgLocation);
}
return button;
}
private void addToolBar(final VLToolBar toolBar, ToolBarConstraints constraints) {
ToolBarPanel topToolBarPanel = (ToolBarPanel) DefaultApplicationContext.getInstance().get("topToolBarPanel");
topToolBarPanel.add(toolBar, constraints);
}
private void removeToolBar(final VLToolBar toolBar) {
ToolBarPanel topToolBarPanel = (ToolBarPanel) DefaultApplicationContext.getInstance().get("topToolBarPanel");
topToolBarPanel.remove(toolBar);
}
@Override
public void checkPendingChanges() {
boolean hasPendingChanges = hasPendingChanges();
if (!hasPendingChanges) {
tabStatusListener.updatePendingChanges(component, false);
}
}
private boolean hasPendingChanges() {
// TODO implement hasPendingChanges()
return false;
}
@Override
public void writeConfigVariables(List cvList) {
fireWriteConfigVariables(cvList);
}
private void fireWriteConfigVariables(List cvList) {
// TODO decouple the AWT-thread from this work?
for (CvDefinitionRequestListener l : cvDefinitionRequestListeners) {
l.writeCvValues(cvList);
}
}
@Override
public void refreshDisplayedValues() {
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy