Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.bidib.wizard.nodes.client.view.NodesClientView Maven / Gradle / Ivy
package org.bidib.wizard.nodes.client.view;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableModel;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.bidib.api.json.types.dccmapping.AccessoryAspectMapping;
import org.bidib.api.json.types.dccmapping.BidibAccessoryAspect;
import org.bidib.api.json.types.dccmapping.DccAccessoryAspect;
import org.bidib.api.json.types.dccmapping.DccAccessoryAspectMapping;
import org.bidib.jbidibc.core.node.ConfigurationVariable;
import org.bidib.jbidibc.core.schema.bidibbase.BaseLabel;
import org.bidib.jbidibc.core.schema.bidiblabels.AccessoryLabel;
import org.bidib.jbidibc.core.schema.bidiblabels.NodeLabels;
import org.bidib.jbidibc.messages.DccAccessory;
import org.bidib.jbidibc.messages.DccAspect;
import org.bidib.jbidibc.messages.utils.ByteUtils;
import org.bidib.jbidibc.messages.utils.NodeUtils;
import org.bidib.wizard.api.locale.Resources;
import org.bidib.wizard.api.model.Accessory;
import org.bidib.wizard.api.model.AccessoryAspect;
import org.bidib.wizard.api.model.AccessoryAspectMacro;
import org.bidib.wizard.api.model.Macro;
import org.bidib.wizard.api.model.MacroRef;
import org.bidib.wizard.api.model.NodeInterface;
import org.bidib.wizard.api.model.NodeProvider;
import org.bidib.wizard.client.common.view.ButtonUtils;
import org.bidib.wizard.client.common.view.DockKeys;
import org.bidib.wizard.common.labels.AccessoryLabelUtils;
import org.bidib.wizard.common.labels.WizardLabelFactory;
import org.bidib.wizard.common.labels.WizardLabelWrapper;
import org.bidib.wizard.common.model.settings.MiscSettingsInterface;
import org.bidib.wizard.core.dialog.FileDialog;
import org.bidib.wizard.nodes.client.controller.InvalidMappingException;
import org.bidib.wizard.nodes.client.controller.listener.NodesClientControllerListener;
import org.bidib.wizard.nodes.client.model.AccessoryAspectTreeTableModel;
import org.bidib.wizard.nodes.client.model.AccessoryNode;
import org.bidib.wizard.nodes.client.model.AccessoryRow;
import org.bidib.wizard.nodes.client.model.AccessorySortableTreeTableModel;
import org.bidib.wizard.nodes.client.model.AspectRow;
import org.bidib.wizard.nodes.client.model.MappingAction;
import org.bidib.wizard.nodes.client.model.NodeRow;
import org.bidib.wizard.nodes.client.model.NodesAccessoryAspect;
import org.oxbow.swingbits.dialog.task.TaskDialogs;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.jgoodies.common.collect.ArrayListModel;
import com.jgoodies.forms.builder.FormBuilder;
import com.jgoodies.forms.debug.FormDebugPanel;
import com.jgoodies.forms.factories.Paddings;
import com.jidesoft.converter.ObjectConverterManager;
import com.jidesoft.grid.AutoFilterTableHeader;
import com.jidesoft.grid.CellEditorManager;
import com.jidesoft.grid.CellRendererManager;
import com.jidesoft.grid.CellStyleTableHeader;
import com.jidesoft.grid.DefaultExpandableRow;
import com.jidesoft.grid.FilterableTreeTableModel;
import com.jidesoft.grid.IntegerCellEditor;
import com.jidesoft.grid.RolloverTableUtils;
import com.jidesoft.grid.Row;
import com.jidesoft.grid.SortableTreeTableModel;
import com.jidesoft.grid.TableModelWrapperUtils;
import com.jidesoft.grid.TablePopupMenuInstaller;
import com.jidesoft.swing.DefaultOverlayable;
import com.jidesoft.swing.InfiniteProgressPanel;
import com.jidesoft.swing.JideScrollPane;
import com.jidesoft.swing.JideSwingUtilities;
import com.jidesoft.swing.TableSearchable;
import com.vlsolutions.swing.docking.DockKey;
import com.vlsolutions.swing.docking.Dockable;
import com.vlsolutions.swing.docking.DockableState;
import com.vlsolutions.swing.docking.DockingDesktop;
import com.vlsolutions.swing.docking.event.DockableSelectionListener;
import com.vlsolutions.swing.docking.event.DockableStateChangeEvent;
import com.vlsolutions.swing.docking.event.DockableStateChangeListener;
public class NodesClientView implements Dockable {
private static final Logger LOGGER = LoggerFactory.getLogger(NodesClientView.class);
private static final String ENCODED_DIALOG_COLUMN_SPECS = "pref, 3dlu, pref, 3dlu, fill:pref:grow";
private static final String ENCODED_DIALOG_ROW_SPECS = "pref, 5dlu, fill:50dlu:grow";
private JComponent contentPanel;
private final DockingDesktop desktop;
private InfiniteProgressPanel progressPanel;
private DefaultOverlayable overlayTable;
private final DockableStateChangeListener dockableStateChangeListener;
private final MiscSettingsInterface miscSettings;
private final NodesClientControllerListener controllerListener;
private AccessoryAspectTreeTableModel accessoryAspectTreeTableModel;
private ArrayListModel accessoryListModel;
private AccessorySortableTreeTableModel accessorySortableTreeTableModel;
private AspectMappingTreeTable treeTable;
private static final String LOAD = "loadFromFile";
private static final String SAVE = "saveToFile";
private static final String CLEAR_ALL = "clearAll";
private JButton loadFromFileButton;
private JButton saveToFileButton;
private JButton loadFromNodeButton;
private JButton saveToNodeButton;
private JButton clearAllOnNodeButton;
private DockableSelectionListener dockableSelectionListener;
private final WizardLabelWrapper wizardLabelWrapper;
public NodesClientView(final DockingDesktop desktop, final NodesClientControllerListener controllerListener,
final MiscSettingsInterface miscSettings, final WizardLabelWrapper wizardLabelWrapper) {
this.desktop = desktop;
this.controllerListener = controllerListener;
this.miscSettings = miscSettings;
this.wizardLabelWrapper = wizardLabelWrapper;
DockKeys.DOCKKEY_NODES_CLIENT_VIEW.setName(Resources.getString(getClass(), "title"));
DockKeys.DOCKKEY_NODES_CLIENT_VIEW.setFloatEnabled(true);
DockKeys.DOCKKEY_NODES_CLIENT_VIEW.setAutoHideEnabled(false);
dockableStateChangeListener = new DockableStateChangeListener() {
@Override
public void dockableStateChanged(DockableStateChangeEvent event) {
LOGGER
.info("The state has changed, newState: {}, prevState: {}", event.getNewState(),
event.getPreviousState());
DockableState newState = event.getNewState();
if (newState.getDockable().equals(NodesClientView.this) && newState.isClosed()) {
LOGGER.info("The NodesClientView is closed.");
// we are closed
desktop.removeDockableStateChangeListener(dockableStateChangeListener);
if (NodesClientView.this.dockableSelectionListener != null) {
desktop.removeDockableSelectionListener(NodesClientView.this.dockableSelectionListener);
NodesClientView.this.dockableSelectionListener = null;
}
// removeToolBar(toolbarNodesClient);
if (controllerListener != null) {
LOGGER.info("Close the view.");
controllerListener.viewClosed();
}
}
}
};
desktop.addDockableStateChangeListener(dockableStateChangeListener);
}
public JComponent initComponents() {
// create form builder
FormBuilder dialogBuilder = null;
boolean debugDialog = false;
if (debugDialog) {
JPanel panel = new FormDebugPanel();
dialogBuilder =
FormBuilder.create().columns(ENCODED_DIALOG_COLUMN_SPECS).rows(ENCODED_DIALOG_ROW_SPECS).panel(panel);
}
else {
JPanel panel = new JPanel(new BorderLayout());
dialogBuilder =
FormBuilder.create().columns(ENCODED_DIALOG_COLUMN_SPECS).rows(ENCODED_DIALOG_ROW_SPECS).panel(panel);
}
dialogBuilder.border(Paddings.DIALOG);
createToolbarButtons();
// prepare the button bar
final FormBuilder buttonBarBuilder =
FormBuilder.create().columns("pref, 3dlu, pref, 3dlu, pref, 3dlu, pref, 3dlu, pref").rows("pref");
buttonBarBuilder.add(loadFromFileButton).xy(1, 1);
buttonBarBuilder.add(saveToFileButton).xy(3, 1);
buttonBarBuilder.add(loadFromNodeButton).xy(5, 1);
buttonBarBuilder.add(saveToNodeButton).xy(7, 1);
buttonBarBuilder.add(clearAllOnNodeButton).xy(9, 1);
JPanel buttons = buttonBarBuilder.build();
dialogBuilder.add(buttons).xyw(1, 1, 5);
// add content
this.accessoryListModel = new ArrayListModel<>();
this.accessoryAspectTreeTableModel = new AccessoryAspectTreeTableModel<>(accessoryListModel);
this.accessorySortableTreeTableModel = new AccessorySortableTreeTableModel(this.accessoryAspectTreeTableModel);
final BiConsumer writeConsumer = (aspectRow, action) -> {
LOGGER.info("Write current aspectRow: {}, action: {}", aspectRow, action);
final List configVariables = new LinkedList<>();
prepareCv(configVariables, aspectRow, action);
if (CollectionUtils.isNotEmpty(configVariables)) {
if (MappingAction.read == action) {
final AccessoryAspectMapping accessoryAspectMapping =
controllerListener.readAccessoryMapping(configVariables);
applyDccAccessoryAspectMapping(accessoryAspectMapping);
}
else {
final AccessoryAspectMapping accessoryAspectMapping =
controllerListener.writeAccessoryMapping(configVariables);
applyDccAccessoryAspectMapping(accessoryAspectMapping);
}
}
else {
LOGGER.warn("No configuration variables to write available.");
throw new InvalidMappingException("Action failed.");
}
};
this.treeTable = new AspectMappingTreeTable(accessorySortableTreeTableModel, writeConsumer);
this.treeTable.setSortable(true);
// JTableHeader header = this.treeTable.getTableHeader();
final AutoFilterTableHeader header = new AutoFilterTableHeader(this.treeTable) {
private static final long serialVersionUID = 1L;
};
header.setAutoFilterEnabled(true);
header.setUseNativeHeaderRenderer(true);
this.treeTable.setTableHeader(header);
this.treeTable.adjustRowHeight();
JideSwingUtilities.insertMouseListener(header, new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
if (e.getSource() instanceof CellStyleTableHeader) {
CellStyleTableHeader _header = (CellStyleTableHeader) e.getSource();
Point p = e.getPoint();
int index = _header.originalColumnAtPoint(p);
if (_header.getTable() != null && index == 0 && p.x < 20) {
LOGGER.info("Collapse/Expand all items.");
boolean isCollapsed = accessorySortableTreeTableModel.isCollapsed();
accessorySortableTreeTableModel.setCollapsed(!isCollapsed);
if (isCollapsed) {
treeTable.expandAll();
}
else {
treeTable.collapseAll();
}
// prevent change sort order
e.consume();
}
}
}
}, 0);
final String[] dccAspectNames =
new String[] { Resources.getString(NodesClientView.class, "aspect-0"),
Resources.getString(NodesClientView.class, "aspect-1") };
ObjectConverterManager
.registerConverter(Integer.class, new DccAspectConverter(dccAspectNames), DccAspectConverter.CONTEXT);
CellEditorManager
.registerEditor(Integer.class, () -> new DccAspectCellEditor(dccAspectNames), DccAspectCellEditor.CONTEXT);
final DefaultTableCellRenderer dccAspectCellRenderer = new DefaultTableCellRenderer() {
private static final long serialVersionUID = 1L;
@Override
protected void setValue(Object value) {
if (value instanceof Integer) {
Integer aspectNumber = (Integer) value;
value = dccAspectNames[aspectNumber];
}
setText((value == null) ? "" : value.toString());
}
};
CellRendererManager.registerRenderer(DccAspect.class, dccAspectCellRenderer, DccAspectCellEditor.CONTEXT);
CellEditorManager.registerEditor(DccAccessory.class, () -> {
IntegerCellEditor editor = new IntegerCellEditor();
editor.setMinInclusive(1);
editor.setMaxInclusive(31);
return editor;
});
final DefaultTableCellRenderer dccAccessoryCellRenderer = new DefaultTableCellRenderer();
dccAccessoryCellRenderer.setHorizontalAlignment(JLabel.TRAILING);
CellRendererManager.registerRenderer(DccAccessory.class, dccAccessoryCellRenderer);
CellRendererManager.registerRenderer(MappingAction.class, new ButtonsCellEditorRenderer());
CellEditorManager.registerEditor(MappingAction.class, () -> new ButtonsCellEditorRenderer());
// popup menu
final AspectMappingTableMenu aspectMappingTableMenu = new AspectMappingTableMenu(this);
final TablePopupMenuInstaller installer = new TablePopupMenuInstaller(this.treeTable) {
@Override
protected JPopupMenu createPopupMenu() {
return aspectMappingTableMenu;
}
@Override
protected void customizeMenuItems(JTable table, JPopupMenu popup, int clickingRow, int clickingColumn) {
LOGGER.info("Customize the popup menu, clickingRow: {}", clickingRow);
super.customizeMenuItems(table, popup, clickingRow, clickingColumn);
popup.removeAll();
if (clickingRow > -1) {
table.setRowSelectionInterval(clickingRow, clickingRow);
SortableTreeTableModel actualFilterableTableModel =
(SortableTreeTableModel) TableModelWrapperUtils
.getActualTableModel(NodesClientView.this.treeTable.getModel(),
SortableTreeTableModel.class);
final Row row = actualFilterableTableModel.getRowAt(clickingRow);
if (row instanceof AspectRow) {
popup.add(aspectMappingTableMenu.getAddMappingItem((AspectRow) row));
popup.add(aspectMappingTableMenu.getDeleteMappingItem((AspectRow) row));
}
}
}
};
final TableColumn column =
this.treeTable.getColumnModel().getColumn(AccessoryAspectTreeTableModel.COLUMN_ACTION);
int columnWidth = 80;
column.setPreferredWidth(columnWidth);
column.setMaxWidth(columnWidth);
column.setMinWidth(columnWidth);
// add searchable feature
final TableSearchable searchable = new TableSearchable(this.treeTable) {
@Override
protected String convertElementToString(Object item) {
if (item instanceof AccessoryRow) {
return ((AccessoryRow) item).getName();
}
return super.convertElementToString(item);
}
};
searchable.setMainIndex(0); // only search for name column
RolloverTableUtils.install(this.treeTable);
JScrollPane scrollTree = new JScrollPane(treeTable);
JideScrollPane scrollPane = new JideScrollPane(scrollTree);
this.overlayTable = new DefaultOverlayable(scrollPane);
this.progressPanel = new InfiniteProgressPanel(3) {
private static final long serialVersionUID = 1L;
@Override
public Dimension getPreferredSize() {
return new Dimension(60, 60);
}
};
overlayTable.addOverlayComponent(progressPanel);
progressPanel.stop();
overlayTable.setOverlayVisible(true);
dialogBuilder.add(overlayTable).xyw(1, 3, 5);
this.contentPanel = dialogBuilder.build();
return this.contentPanel;
}
@Override
public DockKey getDockKey() {
return DockKeys.DOCKKEY_NODES_CLIENT_VIEW;
}
@Override
public Component getComponent() {
return this.contentPanel;
}
private void createToolbarButtons() {
// load button
loadFromFileButton =
ButtonUtils
.makeNavigationButton("loadfromfile.png", "/16x16", LOAD.toLowerCase(),
Resources.getString(getClass(), "button.loadfromfile"),
Resources.getString(getClass(), "button.loadfromfile.alttext"));
loadFromFileButton.setEnabled(true);
loadFromFileButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
loadAccessoryMappingFromFile();
}
});
// save button
saveToFileButton =
ButtonUtils
.makeNavigationButton("savetofile.png", "/16x16", SAVE.toLowerCase(),
Resources.getString(getClass(), "button.savetofile"),
Resources.getString(getClass(), "button.savetofile.alttext"));
saveToFileButton.setEnabled(true);
saveToFileButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
saveAccessoryMapping();
}
});
// load button
loadFromNodeButton =
ButtonUtils
.makeNavigationButton("loadfromnode.png", "/16x16", LOAD.toLowerCase(),
Resources.getString(getClass(), "button.loadfromnode"),
Resources.getString(getClass(), "button.loadfromnode.alttext"));
loadFromNodeButton.setEnabled(false);
loadFromNodeButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
loadAccessoryMappingFromNode();
}
});
// save button
saveToNodeButton =
ButtonUtils
.makeNavigationButton("savetonode.png", "/16x16", SAVE.toLowerCase(),
Resources.getString(getClass(), "button.savetonode"),
Resources.getString(getClass(), "button.savetonode.alttext"));
saveToNodeButton.setEnabled(false);
saveToNodeButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
saveAccessoryMappingToNode();
}
});
// clearAll button
clearAllOnNodeButton =
ButtonUtils
.makeNavigationButton("clearallonnode.png", "/16x16", CLEAR_ALL.toLowerCase(),
Resources.getString(getClass(), "button.clearallonnode"),
Resources.getString(getClass(), "button.clearallonnode.alttext"));
clearAllOnNodeButton.setEnabled(false);
clearAllOnNodeButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
clearAccessoryMappingOnNode();
}
});
}
public void setNodeAccessSupported(boolean nodeAccessSupported) {
if (saveToNodeButton != null) {
saveToNodeButton.setEnabled(nodeAccessSupported);
}
if (loadFromNodeButton != null) {
loadFromNodeButton.setEnabled(nodeAccessSupported);
}
if (clearAllOnNodeButton != null) {
clearAllOnNodeButton.setEnabled(nodeAccessSupported);
}
}
/**
* Prepare the model.
*
* @param nodeProvider
* the node provider
*/
public void prepareModel(final NodeProvider nodeProvider) {
LOGGER.info("Prepare the model, nodeProvider: {}", nodeProvider);
final List accessoryNodes = new LinkedList<>();
if (nodeProvider != null) {
for (NodeInterface node : nodeProvider.getNodes()) {
if (node.hasAccessories()) {
AccessoryNode accessoryNode = createAccessoryNode(node);
accessoryNodes.add(accessoryNode);
}
}
}
// remove all existing items
this.accessoryListModel.clear();
this.accessorySortableTreeTableModel.setCollapsed(true);
for (AccessoryNode accessoryNode : accessoryNodes) {
LOGGER.info("Add accessoryNode: {}", accessoryNode);
// prepare the rows
NodeRow nodeRow = new NodeRow(accessoryNode);
this.accessoryAspectTreeTableModel.addRow(nodeRow);
for (NodesAccessoryAspect accessoryAspect : accessoryNode.getAccessories()) {
AccessoryRow accessoryRow = new AccessoryRow(accessoryAspect);
this.accessoryAspectTreeTableModel.addRow(nodeRow, accessoryRow);
if (CollectionUtils.isEmpty(accessoryAspect.getAspects())) {
LOGGER.warn("No aspects available.");
for (int aspectNumber = 0; aspectNumber < accessoryAspect.getTotalAspects(); aspectNumber++) {
AspectRow aspectRow = new AspectRow(accessoryAspect, aspectNumber, null);
this.accessoryAspectTreeTableModel.addRow(accessoryRow, aspectRow);
}
}
else {
int aspectNumber = 0;
for (AccessoryAspect aspect : accessoryAspect.getAspects()) {
AspectRow aspectRow = new AspectRow(accessoryAspect, aspectNumber, aspect);
this.accessoryAspectTreeTableModel.addRow(accessoryRow, aspectRow);
aspectNumber++;
}
}
}
}
overlayTable.setOverlayVisible(false);
}
private AccessoryNode createAccessoryNode(final NodeInterface node) {
List accessoryAspects = new LinkedList<>();
for (Accessory accessory : node.getAccessories()) {
AccessoryLabel accessoryLabel = getAccessoryAspectsLabels(node, accessory.getId());
final List aspectList = new ArrayList<>();
if (CollectionUtils.isNotEmpty(accessory.getAspects())) {
// prepare the aspects of the selected accessory
// get all macros
List macros = node.getMacros();
MacroRef[] aspects = accessory.getAspects().toArray(new MacroRef[0]);
for (int row = 0; row < aspects.length; row++) {
// get the number of the macro of the selected aspect
MacroRef currentMacro = aspects[row];
if (currentMacro != null && currentMacro.getId() != null) {
final int macroNumber = currentMacro.getId();
LOGGER.info("Adding new aspect, row: {}, macroNumber: {}", row, macroNumber);
if (macroNumber > -1 && macroNumber < macros.size()) {
AccessoryAspectMacro accessoryAspect = new AccessoryAspectMacro(row, currentMacro);
// try to get the user-defined label
accessoryAspect.setLabel(getAccessoryAspectLabel(accessoryLabel, row));
aspectList.add(accessoryAspect);
}
}
}
}
else if (accessory.getTotalAspects() > 0) {
int totalAspects = accessory.getTotalAspects();
if (totalAspects > 0) {
for (int row = 0; row < totalAspects; row++) {
AccessoryAspectMacro accessoryAspect = new AccessoryAspectMacro(row, null);
// try to get the user-defined label
accessoryAspect.setLabel(getAccessoryAspectLabel(accessoryLabel, row));
// prepare AccessoryAspects for non macro mapped nodes
accessoryAspect.setImmutableAccessory(true);
aspectList.add(accessoryAspect);
}
}
}
else {
LOGGER.warn("No aspects available for accessory: {}", accessory);
}
NodesAccessoryAspect accessoryAspect =
new NodesAccessoryAspect(node, accessory, accessory.getTotalAspects(), aspectList);
accessoryAspects.add(accessoryAspect);
}
AccessoryNode accessoryNode = new AccessoryNode(node, accessoryAspects);
return accessoryNode;
}
private NodeLabels getNodeLabels(final NodeInterface node) {
final WizardLabelFactory wizardLabelFactory = wizardLabelWrapper.getWizardLabelFactory();
NodeLabels nodeLabels = wizardLabelFactory.loadLabels(node.getUniqueId());
return nodeLabels;
}
public AccessoryLabel getAccessoryAspectsLabels(final NodeInterface node, int accessoryId) {
NodeLabels nodeLabels = getNodeLabels(node);
if (nodeLabels == null) {
LOGGER.warn("No node labels avaialble.");
return null;
}
return AccessoryLabelUtils.getAccessoryLabel(nodeLabels, accessoryId);
}
private String getAccessoryAspectLabel(AccessoryLabel labels, int aspectIndex) {
if (labels != null) {
BaseLabel baseLabel = AccessoryLabelUtils.getAccessoryAspectLabel(labels, aspectIndex);
if (baseLabel != null) {
String labelString = baseLabel.getLabel();
LOGGER.info("Found the aspect label: {}", labelString);
return labelString;
}
}
return null;
}
private List collectAspectRows(
final AccessoryAspectTreeTableModel treeTableModel) {
List aspectRows = new LinkedList<>();
List rows = treeTableModel.getRows();
for (DefaultExpandableRow row : rows) {
LOGGER.info("Current row: {}", row);
if (row instanceof AspectRow) {
LOGGER.info("Current row is a aspect row: {}", row);
final AspectRow aspectRow = (AspectRow) row;
if (aspectRow.hasValidMapping()) {
aspectRows.add(aspectRow);
}
}
}
return aspectRows;
}
private AccessoryAspectTreeTableModel getTreeTableModel() {
TableModel model = this.treeTable.getModel();
if (model instanceof FilterableTreeTableModel) {
model = ((FilterableTreeTableModel) model).getActualModel();
}
if (model instanceof SortableTreeTableModel) {
model = ((SortableTreeTableModel) model).getActualModel();
}
if (model instanceof AccessoryAspectTreeTableModel) {
AccessoryAspectTreeTableModel treeTableModel =
(AccessoryAspectTreeTableModel) model;
return treeTableModel;
}
throw new IllegalArgumentException("The tableModel is not a AccessoryAspectTreeTableModel.");
}
private void saveAccessoryMapping() {
final List aspectRows = collectAspectRows(getTreeTableModel());
if (!aspectRows.isEmpty()) {
final ObjectMapper objectMapper = new ObjectMapper().registerModule(new JavaTimeModule());
final AccessoryAspectMapping accessoryAspectMapping = new AccessoryAspectMapping();
for (final AspectRow aspectRow : aspectRows) {
// save the mapping
DccAccessoryAspectMapping dccAccessoryAspectMapping = new DccAccessoryAspectMapping();
DccAccessoryAspect dccAccessoryAspect =
new DccAccessoryAspect()
.withDccAccessoryAddress(aspectRow.getDccAccessoryAddress())
.withAspectNumber(aspectRow.getDccAspect());
dccAccessoryAspectMapping.setDccAccessoryAspect(dccAccessoryAspect);
String uniqueId = ByteUtils.formatHexUniqueId(aspectRow.getUniqueId());
BidibAccessoryAspect bidibAccessoryAspect =
new BidibAccessoryAspect()
.withUniqueId(uniqueId).withAccessoryNumber(aspectRow.getAccessoryNumber())
.withAspectNumber(aspectRow.getAspectNumber()).withAccessoryLabel(aspectRow.getAccessoryLabel())
.withAspectLabel(aspectRow.getAspectLabel());
dccAccessoryAspectMapping.setBidibAccessoryAspect(bidibAccessoryAspect);
accessoryAspectMapping.getMappings().add(dccAccessoryAspectMapping);
}
try {
final String mapping =
objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(accessoryAspectMapping);
LOGGER.info("The mapping: {}", mapping);
Frame parentComponent = JideSwingUtilities.getFrame(this.contentPanel);
String storedWorkingDirectory = this.miscSettings.getNodesConfigDir();
FileDialog dialog =
new FileDialog(parentComponent, FileDialog.SAVE, storedWorkingDirectory,
"accessoryNodesMapping" + "." + JSON_EXTENSION, getJsonFileFilter()) {
@Override
public void approve(String fileName) {
LOGGER.info("Save accessory nodes mapping, fileName: {}", fileName);
final File file = new File(fileName);
try (FileOutputStream fos = new FileOutputStream(file)) {
IOUtils.write(mapping, fos, StandardCharsets.UTF_8);
fos.flush();
}
catch (IOException ex) {
LOGGER.warn("Write accessory node mapping to file failed.", ex);
// TODO show dialog
}
}
};
dialog.showDialog();
}
catch (JsonProcessingException ex) {
LOGGER.warn("Convert to JSON failed.", ex);
}
}
}
private void loadAccessoryMappingFromFile() {
Frame parentComponent = JideSwingUtilities.getFrame(this.contentPanel);
String storedWorkingDirectory = this.miscSettings.getNodesConfigDir();
FileDialog dialog =
new FileDialog(parentComponent, FileDialog.OPEN, storedWorkingDirectory,
"accessoryNodesMapping" + "." + JSON_EXTENSION, getJsonFileFilter()) {
@Override
public void approve(String selectedFile) {
File file = new File(selectedFile);
try (FileInputStream fis = new FileInputStream(file)) {
final ObjectMapper objectMapper =
new ObjectMapper().registerModule(new Jdk8Module()).registerModule(new JavaTimeModule());
clearAllDccAccessoryAspectMapping();
final AccessoryAspectMapping accessoryAspectMapping =
objectMapper.readValue(fis, AccessoryAspectMapping.class);
LOGGER.info("Loaded accessoryAspectMapping: {}", accessoryAspectMapping);
NodesClientView.this.miscSettings.setNodesConfigDir(file.getParent());
applyDccAccessoryAspectMapping(accessoryAspectMapping);
}
catch (Exception ex) {
LOGGER.warn("Open file failed.", ex);
}
}
};
dialog.showDialog();
}
private static final String JSON_EXTENSION = "json";
private final String accessoryNodesMappingDescription = "Accessory Nodes Mapping";
private FileFilter getJsonFileFilter() {
FileFilter nodeFilter = new FileNameExtensionFilter(accessoryNodesMappingDescription, JSON_EXTENSION);
return nodeFilter;
}
private void saveAccessoryMappingToNode() {
final List aspectRows = collectAspectRows(getTreeTableModel());
if (!aspectRows.isEmpty()) {
LOGGER.info("Write the aspect mapping to the node.");
final List configVariables = new LinkedList<>();
for (final AspectRow aspectRow : aspectRows) {
prepareCv(configVariables, aspectRow, MappingAction.create);
}
final AccessoryAspectMapping accessoryAspectMapping =
controllerListener.writeAccessoryMapping(configVariables);
applyDccAccessoryAspectMapping(accessoryAspectMapping);
}
}
private void clearAccessoryMappingOnNode() {
LOGGER.info("Delete all aspect mappings on the node.");
final List configVariables = new LinkedList<>();
String aspectMappingWriteCommand = NodesClientControllerListener.MAPPING_AMR_ALL;
String aspectMappingAction = NodesClientControllerListener.MAPPING_DELETE;
final ConfigurationVariable cv = new ConfigurationVariable(aspectMappingWriteCommand, aspectMappingAction);
configVariables.add(cv);
final Consumer resultCallback = successful -> {
// show a dialog
if (successful) {
TaskDialogs
.inform(JOptionPane.getFrameForComponent(desktop),
Resources.getString(NodesClientView.class, "delete-all-mappings-passed.instruction"),
Resources.getString(NodesClientView.class, "delete-all-mappings-passed.text"));
}
else {
TaskDialogs
.error(JOptionPane.getFrameForComponent(desktop),
Resources.getString(NodesClientView.class, "delete-all-mappings-failed.instruction"),
Resources.getString(NodesClientView.class, "delete-all-mappings-failed.text"));
}
};
final AccessoryAspectMapping accessoryAspectMapping = controllerListener.writeAccessoryMapping(configVariables);
evaluateRangeDeleteAll(accessoryAspectMapping, resultCallback);
}
private void prepareCv(
final List configVariables, final AspectRow aspectRow, final MappingAction action) {
long uniqueId = aspectRow.getUniqueId();
Integer accessoryNumber = aspectRow.getAccessoryNumber();
Integer aspectNumber = aspectRow.getAspectNumber();
Integer dccAddress = aspectRow.getDccAccessoryAddress();
Integer dccAspect = aspectRow.getDccAspect();
if (MappingAction.read == action) {
}
else {
if (aspectRow.hasValidMapping()) {
// prepare the aspect mapping write
String aspectMappingValue =
AspectMappingUtils
.prepareAspectMapping(uniqueId, accessoryNumber, aspectNumber, dccAddress, dccAspect);
String aspectMappingWriteCommand =
NodesClientControllerListener.MAPPING_PREFIX_AME + aspectMappingValue;
String aspectMappingAction =
action == MappingAction.delete ? NodesClientControllerListener.MAPPING_DELETE
: NodesClientControllerListener.MAPPING_CREATE;
ConfigurationVariable cv = new ConfigurationVariable(aspectMappingWriteCommand, aspectMappingAction);
configVariables.add(cv);
}
else {
LOGGER.info("The mapping of the aspect row is not valid: {}", aspectRow);
}
}
}
private void loadAccessoryMappingFromNode() {
LOGGER.info("Load the accessory mapping from the node.");
// read the range for all entries from the node
clearAllDccAccessoryAspectMapping();
String aspectMappingReadRangeCommand = NodesClientControllerListener.MAPPING_AMR_ALL;
final List configVariables = new LinkedList<>();
ConfigurationVariable cv = new ConfigurationVariable(aspectMappingReadRangeCommand, null);
configVariables.add(cv);
final AccessoryAspectMapping accessoryAspectMapping = controllerListener.readAccessoryMapping(configVariables);
applyDccAccessoryAspectMapping(accessoryAspectMapping);
}
/**
* Clear all dcc accessory aspect mapping rows.
*/
private void clearAllDccAccessoryAspectMapping() {
for (DefaultExpandableRow row : accessoryListModel) {
if (row instanceof NodeRow) {
final NodeRow nodeRow = (NodeRow) row;
if (nodeRow.hasChildren()) {
List nodeChildren = (List) nodeRow.getChildren();
for (Row nodeRowChild : nodeChildren) {
if (nodeRowChild instanceof AccessoryRow) {
final AccessoryRow accessoryRow = (AccessoryRow) nodeRowChild;
List accessoryChildren = (List) accessoryRow.getChildren();
if (accessoryChildren != null) {
final List saveAccessoryChildren = new ArrayList<>(accessoryChildren);
AspectRow prevAspectRow = null;
for (Row accessoryRowChild : saveAccessoryChildren) {
if (accessoryRowChild instanceof AspectRow) {
final AspectRow aspectRow = (AspectRow) accessoryRowChild;
if (prevAspectRow != null
&& prevAspectRow.getAspectNumber().equals(aspectRow.getAspectNumber())
&& prevAspectRow
.getAccessoryNumber().equals(aspectRow.getAccessoryNumber())) {
// duplicate row found --> remove it
LOGGER.info("Remove duplicate row: {}", aspectRow);
accessoryRow.removeChild(aspectRow);
}
else {
// set the dcc address and dcc aspect to null
aspectRow
.setValueAt(null, AccessoryAspectTreeTableModel.COLUMN_DCC_ADDRESS);
aspectRow.setValueAt(null, AccessoryAspectTreeTableModel.COLUMN_ASPECT);
aspectRow.setDirty(false);
// keep the previous aspect row
prevAspectRow = aspectRow;
}
}
}
}
}
}
}
}
}
}
private void evaluateRangeDeleteAll(
final AccessoryAspectMapping accessoryAspectMapping, final Consumer resultCallback) {
if (accessoryAspectMapping.getMappings().size() == 1) {
final DccAccessoryAspectMapping mapping = accessoryAspectMapping.getMappings().get(0);
if (mapping.getAdditionalProperties().size() == 1) {
for (Entry entry : mapping.getAdditionalProperties().entrySet()) {
if (NodesClientControllerListener.MAPPING_AMR_ALL.equals(entry.getKey())
&& NodesClientControllerListener.MAPPING_DELETE.equals(entry.getValue())) {
LOGGER.info("Range delete all passed.");
resultCallback.accept(Boolean.TRUE);
}
else {
LOGGER.info("Range delete all failed.");
resultCallback.accept(Boolean.FALSE);
}
}
}
else {
LOGGER.warn("Received invalid result for range delete all.");
}
}
else {
LOGGER.warn("Received invalid result for range delete all.");
}
}
private void applyDccAccessoryAspectMapping(final AccessoryAspectMapping accessoryAspectMapping) {
AspectRow firstMappedAspectRow = null;
for (DccAccessoryAspectMapping dccAccessoryAspectMapping : accessoryAspectMapping.getMappings()) {
final BidibAccessoryAspect bidibAccessoryAspect = dccAccessoryAspectMapping.getBidibAccessoryAspect();
final DccAccessoryAspect dccAccessoryAspect = dccAccessoryAspectMapping.getDccAccessoryAspect();
if (bidibAccessoryAspect == null) {
LOGGER.info("Skip current dccAccessoryAspectMapping: {}", dccAccessoryAspectMapping);
continue;
}
// search the node by uniqueId
Long uniqueId = ByteUtils.parseHexUniqueId(bidibAccessoryAspect.getUniqueId());
LOGGER.info("Apply current dccAccessoryAspectMapping: {}", dccAccessoryAspectMapping);
for (DefaultExpandableRow row : accessoryListModel) {
if (row instanceof NodeRow) {
final NodeRow nodeRow = (NodeRow) row;
if (NodeUtils.compareUniqueIdIgnoreClassbits(uniqueId, nodeRow.getUniqueId())) {
if (nodeRow.hasChildren()) {
List nodeChildren = (List) nodeRow.getChildren();
for (Row nodeRowChild : nodeChildren) {
if (nodeRowChild instanceof AccessoryRow) {
final AccessoryRow accessoryRow = (AccessoryRow) nodeRowChild;
if (Objects
.equals(bidibAccessoryAspect.getAccessoryNumber(),
accessoryRow.getAccessoryId())) {
List accessoryChildren = (List) accessoryRow.getChildren();
int aspectIndex = 0;
for (Row accessoryRowChild : accessoryChildren) {
if (accessoryRowChild instanceof AspectRow) {
final AspectRow aspectRow = (AspectRow) accessoryRowChild;
aspectIndex++;
if (Objects
.equals(bidibAccessoryAspect.getAspectNumber(),
aspectRow.getAspectNumber())) {
// found the row to update
LOGGER.info("Found row to update: {}", aspectRow);
Integer dccAccessoryAddress =
dccAccessoryAspect.getDccAccessoryAddress();
Integer dccAspect = dccAccessoryAspect.getAspectNumber();
// check if a mapping is assigned already (dcc address and dcc
// aspect not null)
if (!aspectRow.hasValidMapping() || (aspectRow
.getDccAccessoryAddress().equals(dccAccessoryAddress)
&& aspectRow.getDccAspect().equals(dccAspect))) {
LOGGER
.info("Update existing aspect row: {}, aspectIndex: {}",
aspectRow, aspectIndex);
aspectRow
.setValueAt(dccAccessoryAddress,
AccessoryAspectTreeTableModel.COLUMN_DCC_ADDRESS);
aspectRow
.setValueAt(dccAspect,
AccessoryAspectTreeTableModel.COLUMN_ASPECT);
}
else {
// create a new aspect row
final NodesAccessoryAspect accessoryAspect =
accessoryRow.getAccessoryAspect();
final AccessoryAspect aspect = aspectRow.getAspect();
final AspectRow newAspectRow =
new AspectRow(accessoryAspect, aspectRow.getAspectNumber(),
aspect);
newAspectRow
.setValueAt(dccAccessoryAddress,
AccessoryAspectTreeTableModel.COLUMN_DCC_ADDRESS);
newAspectRow
.setValueAt(dccAspect,
AccessoryAspectTreeTableModel.COLUMN_ASPECT);
LOGGER
.info("Insert new aspect row: {}, aspectIndex: {}",
newAspectRow, aspectIndex);
this.accessoryAspectTreeTableModel
.addRow(accessoryRow, aspectIndex, newAspectRow);
aspectIndex++;
}
aspectRow.setDirty(false);
if (firstMappedAspectRow == null) {
firstMappedAspectRow = aspectRow;
}
break;
}
}
}
}
}
}
}
}
}
}
}
treeTable.expandAll();
if (firstMappedAspectRow != null) {
final AccessoryAspectTreeTableModel treeTableModel = getTreeTableModel();
int rowIndex = treeTableModel.getRowIndex(firstMappedAspectRow);
treeTable.scrollRowToVisible(rowIndex);
}
}
public void addMapping(final AspectRow row) {
LOGGER.info("Add mapping for aspectRow: {}", row);
final AccessoryRow accessoryRow = (AccessoryRow) row.getParent();
int rowNumber = accessoryRow.getChildIndex(row);
rowNumber++;
final NodesAccessoryAspect accessoryAspect = accessoryRow.getAccessoryAspect();
AccessoryAspect aspect = row.getAspect();
final AspectRow aspectRow = new AspectRow(accessoryAspect, row.getAspectNumber(), aspect);
this.accessoryAspectTreeTableModel.addRow(accessoryRow, rowNumber, aspectRow);
}
public void deleteMapping(AspectRow originalAspectRow) {
LOGGER.info("Delete mapping for aspectRow: {}", originalAspectRow);
final AccessoryRow accessoryRow = (AccessoryRow) originalAspectRow.getParent();
// search all items with the same aspectNumber and check if the mapping is different
// if the mapping is different -> delete the row
// if the mapping is not different -> clear the mapping
List accessoryChildren = (List) accessoryRow.getChildren();
if (accessoryChildren != null) {
final List saveAccessoryChildren = new ArrayList<>(accessoryChildren);
final List matchingAspectRows = new ArrayList<>();
for (Row accessoryRowChild : saveAccessoryChildren) {
if (accessoryRowChild instanceof AspectRow) {
final AspectRow aspectRow = (AspectRow) accessoryRowChild;
if (originalAspectRow != null
&& originalAspectRow.getAspectNumber().equals(aspectRow.getAspectNumber())
&& originalAspectRow.getAccessoryNumber().equals(aspectRow.getAccessoryNumber())) {
// duplicate row found --> add it to the list
LOGGER.info("Found duplicate row: {}", aspectRow);
matchingAspectRows.add(aspectRow);
}
}
}
if (matchingAspectRows.size() == 1) {
originalAspectRow.setValueAt(null, AccessoryAspectTreeTableModel.COLUMN_DCC_ADDRESS);
originalAspectRow.setValueAt(null, AccessoryAspectTreeTableModel.COLUMN_ASPECT);
originalAspectRow.setDirty(false);
}
else if (matchingAspectRows.size() > 1) {
accessoryRow.removeChild(originalAspectRow);
}
}
}
}