/******************************************************************************* * Mission Control Technologies, Copyright (c) 2009-2012, United States Government * as represented by the Administrator of the National Aeronautics and Space * Administration. All rights reserved. * * The MCT platform is licensed under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0. * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. * * MCT includes source code licensed under additional open source licenses. See * the MCT Open Source Licenses file included with this distribution or the About * MCT Licenses dialog available at runtime from the MCT Help menu for additional * information. *******************************************************************************/ package org.acme.example.view; import gov.nasa.arc.mct.components.AbstractComponent; import gov.nasa.arc.mct.components.FeedProvider; import gov.nasa.arc.mct.gui.FeedView; import gov.nasa.arc.mct.roles.events.AddChildEvent; import gov.nasa.arc.mct.roles.events.ReloadEvent; import gov.nasa.arc.mct.roles.events.RemoveChildEvent; import gov.nasa.arc.mct.services.component.ViewInfo; import java.awt.BorderLayout; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.JTextField; import javax.swing.table.AbstractTableModel; /** * This view displays the children of a component in a table format. It makes * use of the view properties to keep track of the number of children that will * be displayed for a particular component. When the number of children property * is changed, it is persisted to the database. * */ public class ShowChildrenInTableView extends FeedView { private static final long serialVersionUID = 5541863528199833270L; private static final String MAX_TABLE_ROW = "MAX_TABLE_ROW"; private ExampleTableModel tableModel; private ControlPanel controlPanel; public ShowChildrenInTableView(AbstractComponent ac, ViewInfo vi) { super(ac,vi); setLayout(new BorderLayout()); // Get the number of rows to be displayed from the view properties. String maxTableRowStr = getViewProperties().getProperty(MAX_TABLE_ROW, String.class); int maxTableRow = 3; if (maxTableRowStr != null) { maxTableRow = Integer.parseInt(maxTableRowStr); } tableModel = new ExampleTableModel(maxTableRow); JTable table = new JTable(tableModel); controlPanel = new ControlPanel(tableModel, maxTableRow); add(controlPanel, BorderLayout.NORTH); JScrollPane pane = new JScrollPane(table); add(pane, BorderLayout.CENTER); } @Override public Collection<FeedProvider> getVisibleFeedProviders() { // this implementation could have been optimized to build the initial // list of // components in the constructor and then use the // updateMonitoredGUI(AddChildEvent) // and updateMonitoredGUI(RemoveChildEvent) to change the list saving // the iterations // during each rendering cycle List<FeedProvider> feeds = new ArrayList<FeedProvider>( getManifestedComponent().getComponents().size()); for (AbstractComponent childComp : getManifestedComponent().getComponents()) { FeedProvider fp = getFeedProvider(childComp); if (fp != null) { feeds.add(fp); } } return feeds; } @Override public void synchronizeTime(Map<String, List<Map<String, String>>> data, long syncTime) { updateFromFeed(data); } // this method is called during the feed rendering cycle to update the table // based on // new feed data. This method will always be called on the AWT thread, while // the request // will be done off the AWT thread so this method is intended to be // efficient @Override public void updateFromFeed(Map<String, List<Map<String, String>>> data) { // show only one data point if (!data.isEmpty()) { tableModel.setFeedData(data); tableModel.refresh(); } } /** * This method will refresh the manifestation when the number of children to * be displayed is changed. */ @Override public void updateMonitoredGUI() { String maxTableRowStr = getViewProperties().getProperty(MAX_TABLE_ROW, String.class); if (maxTableRowStr != null) { controlPanel.update(Integer.parseInt(maxTableRowStr)); } } /** * Refresh the table model in response to the change in children */ @Override public void updateMonitoredGUI(AddChildEvent event) { tableModel.refresh(); } /** * Refresh the table model in response to the change in children */ @Override public void updateMonitoredGUI(RemoveChildEvent event) { tableModel.refresh(); } /** * Refresh the table model in response to the change in children, this could * be caused by a aborted change */ @Override public void updateMonitoredGUI(ReloadEvent event) { tableModel.refresh(); } @Override public void enterLockedState() { controlPanel.enableEdit(); } @Override public void exitLockedState() { controlPanel.disableEdit(); } /** * This inner class provides a panel which allows a user to specify the * number of children to be displayed in the table of a particular * component. * */ private final class ControlPanel extends JPanel { private static final long serialVersionUID = 6117168640139158850L; private JLabel noOfRowsLabel = new JLabel("Num of Rows to display:"); private JLabel displayNoOfRowsLabel; private JTextField editNoOfRowField; private String maxTableRowStr; private ExampleTableModel tableModel; public ControlPanel(final ExampleTableModel tableModel, int maxTableRow) { setLayout(new BorderLayout()); this.tableModel = tableModel; this.maxTableRowStr = String.valueOf(maxTableRow); displayNoOfRowsLabel = new JLabel(maxTableRowStr); editNoOfRowField = new JTextField(maxTableRowStr); editNoOfRowField.addFocusListener(new FocusListener() { @Override public void focusLost(FocusEvent e) { String currentText = editNoOfRowField.getText().trim(); if (maxTableRowStr == null || !maxTableRowStr.equals(currentText)) { maxTableRowStr = currentText; tableModel.setMaxRowAndSave(Integer .parseInt(currentText)); } } @Override public void focusGained(FocusEvent e) { } }); add(noOfRowsLabel, BorderLayout.WEST); add(editNoOfRowField, BorderLayout.CENTER); } public void update(int maxTableRow) { String newMaxTableRowStr = String.valueOf(maxTableRow); if (!this.maxTableRowStr.equals(newMaxTableRowStr)) { displayNoOfRowsLabel.setText(newMaxTableRowStr); editNoOfRowField.setText(newMaxTableRowStr); this.maxTableRowStr = newMaxTableRowStr; tableModel.setMaxRow(maxTableRow); } } public void enableEdit() { remove(displayNoOfRowsLabel); add(editNoOfRowField, BorderLayout.CENTER); } public void disableEdit() { String newMaxTableRowStr = getViewProperties().getProperty( MAX_TABLE_ROW, String.class); if (newMaxTableRowStr != null) { editNoOfRowField.setText(newMaxTableRowStr); displayNoOfRowsLabel.setText(newMaxTableRowStr); } if (!maxTableRowStr.equals(newMaxTableRowStr) && newMaxTableRowStr != null) { this.maxTableRowStr = newMaxTableRowStr; tableModel.setMaxRow(Integer.parseInt(maxTableRowStr)); } remove(editNoOfRowField); add(displayNoOfRowsLabel, BorderLayout.CENTER); } } /** * A simple table model for the table. * */ private class ExampleTableModel extends AbstractTableModel { private static final long serialVersionUID = 866084276868380575L; private String[] columnNames = { "Component id", "Display Name", "Component Type", "Feed Data"}; private Object[][] data; private int maxRow; private Map<String, List<Map<String, String>>> feedData = Collections .<String, List<Map<String, String>>> emptyMap(); public ExampleTableModel(int maxRow) { this.maxRow = maxRow; populateData(); } private void populateData() { AbstractComponent parentComp = getManifestedComponent(); int numOfChildren = 0; boolean hasChildren = !parentComp.getComponents().isEmpty(); if (hasChildren) { numOfChildren = maxRow < parentComp.getComponents().size() ? maxRow : parentComp.getComponents().size(); } data = new Object[numOfChildren][columnNames.length]; if (numOfChildren > 0) { Iterator<AbstractComponent> children = parentComp.getComponents().iterator(); for (int i = 0; i < numOfChildren; i++) { AbstractComponent childComp = children.next(); data[i][0] = childComp.getId(); data[i][1] = childComp.getDisplayName(); data[i][2] = childComp.getClass().getName(); FeedProvider fp = childComp.getCapability(FeedProvider.class); List<Map<String, String>> feedVal = fp == null ? null : feedData.get(fp.getSubscriptionId()); if (feedVal != null && !feedVal.isEmpty()) { Map<String, String> valMap = feedVal.get(0); String feedData = valMap.get(FeedProvider.NORMALIZED_VALUE_KEY); data[i][3] = feedData == null ? "" : feedData; } else { data[i][3] = ""; } } } } @Override public int getColumnCount() { return columnNames.length; } @Override public int getRowCount() { return data.length; } @Override public Object getValueAt(int rowIndex, int columnIndex) { return data[rowIndex][columnIndex]; } @Override public Class<?> getColumnClass(int columnIndex) { return String.class; } @Override public String getColumnName(int column) { return columnNames[column]; } public void setFeedData(Map<String, List<Map<String, String>>> feedData) { this.feedData = feedData; } public void refresh() { populateData(); fireTableStructureChanged(); } public void setMaxRow(int maxRow) { if (this.maxRow != maxRow) { this.maxRow = maxRow; refresh(); } } /** * Set the maximum number of rows to be displayed and persist the * MAX_TABLE_ROW view property to the database. * * @param maxRow * The maximum number of rows to be displayed */ public void setMaxRowAndSave(int maxRow) { if (this.maxRow != maxRow) { setMaxRow(maxRow); getViewProperties().setProperty(MAX_TABLE_ROW, String.valueOf(maxRow)); getManifestedComponent().save(); } } } }