/******************************************************************************* * Copyright (c) 2014 Open Door Logistics (www.opendoorlogistics.com) * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Lesser Public License v3 * which accompanies this distribution, and is available at http://www.gnu.org/licenses/lgpl.txt ******************************************************************************/ package com.opendoorlogistics.studio.panels; import gnu.trove.set.hash.TIntHashSet; import java.awt.BorderLayout; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTree; import javax.swing.event.TreeSelectionListener; import javax.swing.tree.*; import com.opendoorlogistics.api.tables.ODLDatastore; import com.opendoorlogistics.api.tables.ODLTableDefinition; import com.opendoorlogistics.core.tables.utils.ExampleData; import com.opendoorlogistics.core.tables.utils.TableUtils; import com.opendoorlogistics.core.utils.strings.Strings; import com.opendoorlogistics.core.utils.ui.ShowPanel; final public class FieldSelectorPanel extends JPanel { private final JTree tree; private final DefaultMutableTreeNode topNode = new DefaultMutableTreeNode(); public FieldSelectorPanel(ODLDatastore<? extends ODLTableDefinition> ds) { this.tree = new JTree(topNode); tree.setRootVisible(false); tree.setSelectionModel(new MyTreeSelectionModel()); setLayout(new BorderLayout()); add(new JScrollPane(tree), BorderLayout.CENTER); update(ds,null); } public void update(ODLDatastore<? extends ODLTableDefinition> ds, TIntHashSet availableTableIds) { String [] current = getSelected(); boolean hasSelected = current!=null && current.length==2; topNode.removeAllChildren(); DefaultMutableTreeNode selNode=null; for (ODLTableDefinition table : TableUtils.getAlphabeticallySortedTables(ds)) { if(availableTableIds!=null && availableTableIds.contains(table.getImmutableId())==false){ continue; } DefaultMutableTreeNode tableNode = new DefaultMutableTreeNode(table.getName()); topNode.add(tableNode); // is this the previously selected table? boolean selTable = hasSelected && Strings.equalsStd(table.getName(), current[0]); int nc = table.getColumnCount(); for (int i = 0; i < nc; i++) { DefaultMutableTreeNode fieldNode = new DefaultMutableTreeNode(table.getColumnName(i)); if(selTable && Strings.equalsStd(table.getColumnName(i), current[1])){ selNode = fieldNode; } tableNode.add(fieldNode); } } // hack otherwise update doesn't work... DefaultTreeModel model = new DefaultTreeModel(topNode); tree.setModel(model); // ensure path is expanded otherwise child nodes will be invisible if top node is invisible tree.expandPath(new TreePath(topNode.getPath())); // also expand all tables Enumeration<?>e= topNode.children(); while(e.hasMoreElements()){ DefaultMutableTreeNode node = (DefaultMutableTreeNode)e.nextElement(); tree.expandPath(new TreePath(node.getPath())); } // reselect if possible if(selNode!=null){ tree.setSelectionPath(new TreePath(selNode.getPath())); } } public String [] getSelected(){ TreePath path = tree.getSelectionPath(); if(path!=null){ Object [] objs = path.getPath(); return new String[]{objs[1].toString(), objs[2].toString()}; } return null; } public static void main(String[] args) { ShowPanel.showPanel(new FieldSelectorPanel(ExampleData.createExampleDatastore(true))); } /** * See http://stackoverflow.com/questions/12629309/create-non-selectable-defaulttreemodel-node-with-children * */ private class MyTreeSelectionModel implements TreeSelectionModel { TreeSelectionModel selectionModel = new DefaultTreeSelectionModel(); private boolean canPathBeAdded(TreePath treePath) { return treePath.getPathCount() > 2; } private TreePath[] getFilteredPaths(TreePath[] paths) { List<TreePath> returnedPaths = new ArrayList<TreePath>(paths.length); for (TreePath treePath : paths) { if (canPathBeAdded(treePath)) { returnedPaths.add(treePath); } } return returnedPaths.toArray(new TreePath[returnedPaths.size()]); } @Override public void setSelectionMode(int mode) { selectionModel.setSelectionMode(mode); } @Override public int getSelectionMode() { return selectionModel.getSelectionMode(); } @Override public void setSelectionPath(TreePath path) { if (canPathBeAdded(path)) { selectionModel.setSelectionPath(path); } } @Override public void setSelectionPaths(TreePath[] paths) { paths = getFilteredPaths(paths); selectionModel.setSelectionPaths(paths); } @Override public void addSelectionPath(TreePath path) { if (canPathBeAdded(path)) { selectionModel.addSelectionPath(path); } } @Override public void addSelectionPaths(TreePath[] paths) { paths = getFilteredPaths(paths); selectionModel.addSelectionPaths(paths); } @Override public void removeSelectionPath(TreePath path) { selectionModel.removeSelectionPath(path); } @Override public void removeSelectionPaths(TreePath[] paths) { selectionModel.removeSelectionPaths(paths); } @Override public TreePath getSelectionPath() { return selectionModel.getSelectionPath(); } @Override public TreePath[] getSelectionPaths() { return selectionModel.getSelectionPaths(); } @Override public int getSelectionCount() { return selectionModel.getSelectionCount(); } @Override public boolean isPathSelected(TreePath path) { return selectionModel.isPathSelected(path); } @Override public boolean isSelectionEmpty() { return selectionModel.isSelectionEmpty(); } @Override public void clearSelection() { selectionModel.clearSelection(); } @Override public void setRowMapper(RowMapper newMapper) { selectionModel.setRowMapper(newMapper); } @Override public RowMapper getRowMapper() { return selectionModel.getRowMapper(); } @Override public int[] getSelectionRows() { return selectionModel.getSelectionRows(); } @Override public int getMinSelectionRow() { return selectionModel.getMinSelectionRow(); } @Override public int getMaxSelectionRow() { return selectionModel.getMaxSelectionRow(); } @Override public boolean isRowSelected(int row) { return selectionModel.isRowSelected(row); } @Override public void resetRowSelection() { selectionModel.resetRowSelection(); } @Override public int getLeadSelectionRow() { return selectionModel.getLeadSelectionRow(); } @Override public TreePath getLeadSelectionPath() { return selectionModel.getLeadSelectionPath(); } @Override public void addPropertyChangeListener(PropertyChangeListener listener) { selectionModel.addPropertyChangeListener(listener); } @Override public void removePropertyChangeListener(PropertyChangeListener listener) { selectionModel.removePropertyChangeListener(listener); } @Override public void addTreeSelectionListener(TreeSelectionListener x) { selectionModel.addTreeSelectionListener(x); } @Override public void removeTreeSelectionListener(TreeSelectionListener x) { selectionModel.removeTreeSelectionListener(x); } } }