http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/f676ef35/partition/src/main/java/net/sf/taverna/t2/partition/RootPartition.java ---------------------------------------------------------------------- diff --git a/partition/src/main/java/net/sf/taverna/t2/partition/RootPartition.java b/partition/src/main/java/net/sf/taverna/t2/partition/RootPartition.java deleted file mode 100644 index 64edfd8..0000000 --- a/partition/src/main/java/net/sf/taverna/t2/partition/RootPartition.java +++ /dev/null @@ -1,394 +0,0 @@ -/******************************************************************************* - * Copyright (C) 2007 The University of Manchester - * - * Modifications to the initial code base are copyright of their - * respective authors, or their employers as appropriate. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - ******************************************************************************/ -package net.sf.taverna.t2.partition; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import javax.swing.SwingUtilities; -import javax.swing.event.TreeModelEvent; -import javax.swing.event.TreeModelListener; -import javax.swing.tree.TreeModel; -import javax.swing.tree.TreePath; - -/** - * Subclass of Partition acting as the public access point for the partition - * structure. Exposes a TreeModel for use with a UI. - * - * @author Tom Oinn - * - * @param <ItemType> - * all items added to this partition must cast to this type - */ -public class RootPartition<ItemType extends Comparable> extends - Partition<ItemType, Object, Object> implements TreeModel { - - // Used to track where we ended up putting items with the addOrUpdateItem - // method, this makes checking for duplicate items, reclassification and - // removal of partitions much faster at the expense of a few bytes of memory - private Map<ItemType, Partition<ItemType, ?, ?>> itemToLeafPartition; - - private PropertyExtractorRegistry propertyExtractorRegistry; - - private final SetModelChangeListener<ItemType> setChangeListener = new SetModelChangeListener<ItemType>() { - - private List<Query<?>> queryList = new ArrayList<Query<?>>(); - - public void itemsWereAdded(Set<ItemType> newItems) { - for (ItemType item : newItems) { - addOrUpdateItem(item); - } - } - - @SuppressWarnings("unchecked") - public void itemsWereRemoved(Set<Object> itemsRemoved) { - for (Object item : itemsRemoved) { - try { - removeItem((ItemType) item); - } catch (ClassCastException cce) { - // Obviously wasn't the right type of item but that means it - // couldn't have been added in the first place so we can - // safely ignore this. - } - } - } - - public void addQuery(Query<?> query) { - queryList.add(query); - } - - public List<Query<?>> getQueries() { - return queryList; - } - - }; - - /** - * Build a new empty root partition with the specified list of partition - * algorithm implementations used to recursively allocate new data items to - * the sub-partitions below this one on addition - * - * @param pa - */ - public RootPartition(List<PartitionAlgorithm<?>> pa, - PropertyExtractorRegistry per) { - super(null, pa, null, null); - this.root = this; - this.propertyExtractorRegistry = per; - this.itemToLeafPartition = new HashMap<ItemType, Partition<ItemType, ?, ?>>(); - } - - /** - * The root partition comes with a convenience implementation of - * SetModelChangeListener which can be used to attach it to a compliant - * instance of SetModel (assuming the item types match). This allows the - * SetModel to act as the backing data store for the partition - as Query - * and the various subset / set union operators also implement this it - * provides a relatively simple mechanism to link multiple sets of data to - * this partition. - */ - public SetModelChangeListener<ItemType> getSetModelChangeListener() { - return this.setChangeListener; - } - - /** - * Alter the list of partition algorithms which drive the construction of - * the partitions. Calling this effectively forces a complete rebuild of the - * tree structure which is an expensive operation so be careful when you use - * it. - * - * @param pa - * a new list of PartitionAlgorithmSPI instances to use as the - * basis for the partition structure. - */ - public synchronized void setPartitionAlgorithmList( - List<PartitionAlgorithm<?>> pa) { - if (pa.equals(this.partitionAlgorithms)) { - // At the least this checks for reference equality, although I'm not - // sure it does much more than that. TODO - replace this with a - // smarter check to see whether the list has really changed, doing a - // full re-build is expensive. - return; - } - // First create a copy of the keyset containing all the items we've - // added to this point. - Set<ItemType> itemsToAdd = new HashSet<ItemType>(itemToLeafPartition - .keySet()); - this.partitionAlgorithms = pa; - this.children.clear(); - this.itemToLeafPartition.clear(); - treeStructureChanged(new TreeModelEvent(this, getTreePath())); - for (ItemType item : itemsToAdd) { - addOrUpdateItem(item); - } - sortChildPartitions(); - } - - /** - * Add a new item to the partition structure. If the item already exists - * this is interpreted as a request to reclassify according to properties - * which may have changed. This is not the same as a reclassification due to - * modification of the partition algorithm list, and just refers to the - * specified item. If the item exists already and its classification is - * changed the model will be notified with a removal event from the previous - * location and the item will be added as usual immediately afterwards. - */ - public synchronized void addOrUpdateItem(ItemType item) { - // First check whether the item is already stored - if (itemToLeafPartition.containsKey(item)) { - // request to reclassify item. - List<Partition<ItemType, ?, ?>> partitions = itemToLeafPartition - .get(item).getPartitionPath(); - // partitions[i].getPartitionValue is the result of running - // getPartitionAlgorithms[i-1] on the item, we run through the array - // until either we hit the end (no reclassification) or the item - // classifies differently in which case we remove and re-add it. - for (int i = 1; i < partitions.size(); i++) { - PartitionAlgorithm<?> pa = getPartitionAlgorithms().get( - i - 1); - Object existingValue = partitions.get(i).getPartitionValue(); - Object reclassifiedValue = pa.allocate(item, - getPropertyExtractorRegistry()); - if (existingValue.equals(reclassifiedValue) == false) { - // Items classify differently, remove it - removeItem(item); - // ...and add it back again, forcing reclassification - super.addItem(item); - return; - } - } - // return as the item wasn't changed. - return; - } else { - // Value wasn't already in the map so we just add it as usual - super.addItem(item); - } - - } - - /** - * Remove an item from the partition structure, if this leaves any - * partitions with zero item count they are removed as well to keep things - * tidy. - * - * @param item - * the item to remove from the partition structure. If this isn't - * present in the structure this method does nothing along the - * lines of the collections API. - */ - public synchronized void removeItem(ItemType item) { - Partition<ItemType, ?, ?> partition = itemToLeafPartition.get(item); - if (partition != null) { - // Remove the item from the leaf partition - int previousIndex = partition.getMembers().indexOf(item); - TreePath pathToPartition = partition.getTreePath(); - //partition.removeMember(item); - for (Partition<ItemType, ?, ?> parentPathElement : partition - .getPartitionPath()) { - // Notify path to root that the number of members - // has changed and it should update the renderers of - // any attached trees - treeNodesChanged(new TreeModelEvent(this, parentPathElement - .getTreePath())); - } - partition.removeMember(item); - treeNodesRemoved(new TreeModelEvent(this, pathToPartition, - new int[] { previousIndex }, new Object[] { item })); - // Traverse up the partition path and decrement the item count. If - // any item count becomes zero we mark this as a partition to - // remove, then at the end we remove the highest level one (so we - // only have to send a single delete event to the tree view) - for (Partition<ItemType, ?, ?> p : partition.getPartitionPath()) { - synchronized (p) { - p.itemCount--; - if (p.getItemCount() == 0 && p != this) { - // Can remove this node, all nodes after this will by - // definition have item count of zero. The exception is - // if this is the root node, in which case we just - // ignore it and move on to the next child. This avoids - // deleting the root, which is generally not a smart - // thing to do to a tree. - Partition<ItemType, ?, ?> parent = p.getParent(); - int indexInParent = getIndexOfChild(parent, p); - parent.children.remove(indexInParent); - treeNodesRemoved(new TreeModelEvent(this, parent - .getTreePath(), new int[] { indexInParent }, - new Object[] { p })); - - break; - } - } - } - itemToLeafPartition.remove(item); - } - treeStructureChanged(new TreeModelEvent(this,getTreePath())); - } - - /** - * Called by a leaf Partition when it has stored an item in its member set, - * used to keep track of where items have been stored to make removal more - * efficient. - */ - void itemStoredAt(ItemType item, Partition<ItemType, ?, ?> partition) { - itemToLeafPartition.put(item, partition); - } - - // ---------------------// - // TreeModel interfaces // - // ---------------------// - private List<TreeModelListener> treeListeners = new ArrayList<TreeModelListener>(); - - @SuppressWarnings("unchecked") - public synchronized Object getChild(Object parent, int index) { - if (parent instanceof Partition) { - Partition<ItemType, ?, ?> p = (Partition<ItemType, ?, ?>) parent; - if (p.getMembers().isEmpty() == false) { - if (index < 0 || index >= p.getMembers().size()) { - return null; - } else { - return p.getMembers().get(index); - } - } else { - if (index < 0 || index >= p.getChildren().size()) { - return null; - } else { - return p.getChildren().get(index); - } - } - } - return null; - } - - @SuppressWarnings("unchecked") - public synchronized int getChildCount(Object parent) { - if (parent instanceof Partition) { - Partition<ItemType, ?, ?> p = (Partition<ItemType, ?, ?>) parent; - if (p.getMembers().isEmpty() == false) { - return p.getMembers().size(); - } - return p.getChildren().size(); - } - return 0; - } - - @SuppressWarnings("unchecked") - public synchronized int getIndexOfChild(Object parent, Object child) { - if (parent != null && child != null && parent instanceof Partition - && child instanceof Partition) { - Partition<ItemType, ?, ?> p = (Partition<ItemType, ?, ?>) parent; - Partition<ItemType, ?, ?> c = (Partition<ItemType, ?, ?>) child; - if (p.root == c.root && p.root == this) { - // Parent and child must both be members of this tree structure - return p.getChildren().indexOf(child); - } - } else if (parent != null && child != null - && parent instanceof Partition) { - Partition<ItemType, ?, ?> p = (Partition<ItemType, ?, ?>) parent; - return p.getMembers().indexOf(child); - } - return -1; - - } - - public Object getRoot() { - // The root partition is also the root of the tree model - return this; - } - - public boolean isLeaf(Object node) { - // No leaves at the moment as we're only considering partitions which - // are by definition not leaves (the items within the last partition are - // but at the moment we're not including them in the tree model) - return (!(node instanceof Partition)); - } - - public void removeTreeModelListener(TreeModelListener l) { - treeListeners.remove(l); - } - - public void addTreeModelListener(TreeModelListener l) { - if (treeListeners.contains(l) == false) { - treeListeners.add(l); - } - } - - public void valueForPathChanged(TreePath path, Object newValue) { - // Ignore this, the tree values are never changed by the user in this - // implementation so we don't have to do anything - } - - // -------------------------------------------------------// - // Tree event forwarding helper methods used by Partition // - // -------------------------------------------------------// - - void treeNodesChanged(final TreeModelEvent e) { - SwingUtilities.invokeLater(new Runnable() { - public void run() { - for (TreeModelListener listener : new ArrayList<TreeModelListener>( - treeListeners)) { - listener.treeNodesChanged(e); - } - } - }); - } - - void treeNodesInserted(final TreeModelEvent e) { - SwingUtilities.invokeLater(new Runnable() { - public void run() { - for (TreeModelListener listener : new ArrayList<TreeModelListener>( - treeListeners)) { - listener.treeNodesInserted(e); - } - } - }); - } - - void treeNodesRemoved(final TreeModelEvent e) { - SwingUtilities.invokeLater(new Runnable() { - public void run() { - for (TreeModelListener listener : new ArrayList<TreeModelListener>( - treeListeners)) { - listener.treeNodesRemoved(e); - } - } - }); - } - - void treeStructureChanged(final TreeModelEvent e) { - SwingUtilities.invokeLater(new Runnable() { - public void run() { - for (TreeModelListener listener : new ArrayList<TreeModelListener>( - treeListeners)) { - listener.treeStructureChanged(e); - } - } - }); - } - - public PropertyExtractorRegistry getPropertyExtractorRegistry() { - return this.propertyExtractorRegistry; - } - -}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/f676ef35/partition/src/main/java/net/sf/taverna/t2/partition/SetModel.java ---------------------------------------------------------------------- diff --git a/partition/src/main/java/net/sf/taverna/t2/partition/SetModel.java b/partition/src/main/java/net/sf/taverna/t2/partition/SetModel.java deleted file mode 100644 index 393d697..0000000 --- a/partition/src/main/java/net/sf/taverna/t2/partition/SetModel.java +++ /dev/null @@ -1,53 +0,0 @@ -/******************************************************************************* - * Copyright (C) 2007 The University of Manchester - * - * Modifications to the initial code base are copyright of their - * respective authors, or their employers as appropriate. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - ******************************************************************************/ -package net.sf.taverna.t2.partition; - -import java.util.Set; - -/** - * Extension of the java Set interface with the addition of change listener - * support. Intended to be plugged into the RootPartition class so the partition - * is synchronized with the set membership. - * - * @author Tom Oinn - * - * @param <ItemType> - * the parameterised type of the set - */ -public interface SetModel<ItemType> extends Set<ItemType> { - - /** - * Add a listener to be notified of change events on the set's membership - * - * @param listener - */ - public void addSetModelChangeListener( - SetModelChangeListener<ItemType> listener); - - /** - * Remove a previously registered change listener - * - * @param listener - */ - public void removeSetModelChangeListener( - SetModelChangeListener<ItemType> listener); - -} http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/f676ef35/partition/src/main/java/net/sf/taverna/t2/partition/SetModelChangeListener.java ---------------------------------------------------------------------- diff --git a/partition/src/main/java/net/sf/taverna/t2/partition/SetModelChangeListener.java b/partition/src/main/java/net/sf/taverna/t2/partition/SetModelChangeListener.java deleted file mode 100644 index 176eb7c..0000000 --- a/partition/src/main/java/net/sf/taverna/t2/partition/SetModelChangeListener.java +++ /dev/null @@ -1,42 +0,0 @@ -/******************************************************************************* - * Copyright (C) 2007 The University of Manchester - * - * Modifications to the initial code base are copyright of their - * respective authors, or their employers as appropriate. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - ******************************************************************************/ -package net.sf.taverna.t2.partition; - -import java.util.List; -import java.util.Set; - -/** - * Handler for change events on a SetModel instance - * - * @author Tom Oinn - * - */ -public interface SetModelChangeListener<ItemType> { - - public void itemsWereAdded(Set<ItemType> newItems); - - public void itemsWereRemoved(Set<Object> itemsRemoved); - - public List<Query<?>> getQueries(); - - public void addQuery(Query<?> query); - -} http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/f676ef35/partition/src/main/java/net/sf/taverna/t2/partition/algorithms/CustomPartitionAlgorithm.java ---------------------------------------------------------------------- diff --git a/partition/src/main/java/net/sf/taverna/t2/partition/algorithms/CustomPartitionAlgorithm.java b/partition/src/main/java/net/sf/taverna/t2/partition/algorithms/CustomPartitionAlgorithm.java deleted file mode 100644 index b6a3eea..0000000 --- a/partition/src/main/java/net/sf/taverna/t2/partition/algorithms/CustomPartitionAlgorithm.java +++ /dev/null @@ -1,98 +0,0 @@ -/******************************************************************************* - * Copyright (C) 2007 The University of Manchester - * - * Modifications to the initial code base are copyright of their - * respective authors, or their employers as appropriate. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - ******************************************************************************/ -package net.sf.taverna.t2.partition.algorithms; - -import java.util.ArrayList; -import java.util.List; - -import net.sf.taverna.t2.partition.PartitionAlgorithm; -import net.sf.taverna.t2.partition.PropertyExtractorRegistry; - -/** - * Takes a custom search term and checks against the properties eg - * "operation" of each of the available items. Adds the item to the activity - * palette if it matches - * - * @author Ian Dunlop - * - */ -public class CustomPartitionAlgorithm implements PartitionAlgorithm<Object> { - - private String searchValue; - private List<String> properties; - private static String NO_SEARCH = "No match"; - private static String MATCHING_ITEMS = "Activities with a matching property"; - - public String getSearchValue() { - return searchValue; - } - - public void setSearchValue(String searchValue) { - this.searchValue = searchValue; - } - - public CustomPartitionAlgorithm() { - properties = new ArrayList<String>(); - } - - public CustomPartitionAlgorithm(String searchValue) { - super(); - this.searchValue = searchValue; - // this.propertyName = propertyName; - properties = new ArrayList<String>(); - } - - public void addProperty(String propertyValue) { - properties.add(propertyValue); - } - - /** - * Checks against the items property to see if it contains the search term. - * Search each of the properties in {@link #properties} in turn - */ - public Object allocate(Object newItem, PropertyExtractorRegistry reg) { - for (String property : properties) { - Object propertyValue = reg.getAllPropertiesFor(newItem).get( - property); - String itemString = newItem.toString(); - //search all the properties first - if (propertyValue != null) { - if (((String) propertyValue).contains(getSearchValue() - .toLowerCase())) { - return MATCHING_ITEMS; - } - } - //then the name of the item - if (itemString.toLowerCase().contains( - getSearchValue().toLowerCase())) { - return MATCHING_ITEMS; - } - } - return NO_SEARCH; - - } - - @Override - public String toString() { - return "search term=" + this.searchValue; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/f676ef35/partition/src/main/java/net/sf/taverna/t2/partition/algorithms/LiteralValuePartitionAlgorithm.java ---------------------------------------------------------------------- diff --git a/partition/src/main/java/net/sf/taverna/t2/partition/algorithms/LiteralValuePartitionAlgorithm.java b/partition/src/main/java/net/sf/taverna/t2/partition/algorithms/LiteralValuePartitionAlgorithm.java deleted file mode 100644 index b703d40..0000000 --- a/partition/src/main/java/net/sf/taverna/t2/partition/algorithms/LiteralValuePartitionAlgorithm.java +++ /dev/null @@ -1,106 +0,0 @@ -/******************************************************************************* - * Copyright (C) 2007 The University of Manchester - * - * Modifications to the initial code base are copyright of their - * respective authors, or their employers as appropriate. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - ******************************************************************************/ -package net.sf.taverna.t2.partition.algorithms; - -import net.sf.taverna.t2.partition.PartitionAlgorithm; -import net.sf.taverna.t2.partition.PropertyExtractorRegistry; - -/** - * A naive partition algorithm that simply returns the property value it's been - * configured to use from the property getter. - * - * @author Tom - * - */ -public class LiteralValuePartitionAlgorithm implements - PartitionAlgorithm<Object> { - - private String propertyName = null; - - private static String NO_PROPERTY = "No value"; - - /** - * Default constructor. The property name defaults to null, and needs setting using getPropertyName - */ - public LiteralValuePartitionAlgorithm() { - - } - - /** - * Constructor that initialised the LiteralValuePartitionAlgorithm with a property name - * - * @param propertyName - */ - public LiteralValuePartitionAlgorithm(String propertyName) { - super(); - this.propertyName = propertyName; - } - - public Object allocate(Object newItem, PropertyExtractorRegistry reg) { - if (propertyName == null) { - return NO_PROPERTY; - } - else { - Object propertyValue = reg.getAllPropertiesFor(newItem).get(propertyName); - if (propertyValue == null) { - return NO_PROPERTY; - } - else { - return propertyValue; - } - } - } - - public String getPropertyName() { - return propertyName; - } - - public void setPropertyName(String propertyName) { - this.propertyName = propertyName; - } - - - - /** - * @return true if obj is a LiteralValuePartionAlgorithm and the property names match - */ - @Override - public boolean equals(Object obj) { - if (obj instanceof LiteralValuePartitionAlgorithm) { - LiteralValuePartitionAlgorithm alg = (LiteralValuePartitionAlgorithm)obj; - return getPropertyName().equals(alg.getPropertyName()); - } - else { - return false; - } - } - - @Override - public int hashCode() { - return getPropertyName().hashCode(); - } - - @Override - public String toString() { - return this.propertyName; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/f676ef35/partition/src/main/java/net/sf/taverna/t2/partition/ui/PartitionAlgorithmListEditor.java ---------------------------------------------------------------------- diff --git a/partition/src/main/java/net/sf/taverna/t2/partition/ui/PartitionAlgorithmListEditor.java b/partition/src/main/java/net/sf/taverna/t2/partition/ui/PartitionAlgorithmListEditor.java deleted file mode 100644 index 9c05c44..0000000 --- a/partition/src/main/java/net/sf/taverna/t2/partition/ui/PartitionAlgorithmListEditor.java +++ /dev/null @@ -1,224 +0,0 @@ -/******************************************************************************* - * Copyright (C) 2007 The University of Manchester - * - * Modifications to the initial code base are copyright of their - * respective authors, or their employers as appropriate. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - ******************************************************************************/ -package net.sf.taverna.t2.partition.ui; - -import javax.swing.JComponent; -import javax.swing.JLabel; -import javax.swing.JPanel; - -import net.sf.taverna.t2.partition.PartitionAlgorithm; - -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.RenderingHints; -import java.awt.geom.GeneralPath; -import java.util.List; - -public class PartitionAlgorithmListEditor extends JPanel { - - // Serial version ID - private static final long serialVersionUID = 8206805090698009524L; - - // Index of currently selected 'tab' or -1 if none selected - private int selectedIndex = 1; - - // List of partition algorithm instances acting as the model for this - // component - private List<PartitionAlgorithm<?>> paList; - - private int cornerSep = 8; - private int labelHorizontalPad = 10; - private int labelBottomPad = 2; - private int labelTopPad = 4; - private float selectedStrokeWidth = 3f; - - public List<PartitionAlgorithm<?>> getPartitionAlgorithmList() { - return null; - } - - @Override - public Dimension getPreferredSize() { - if (paList.isEmpty()) { - return new Dimension(0, 16 + labelBottomPad + labelTopPad); - } else { - return new Dimension(0, (int) new Tab(getLabelForPA(paList.get(0))) - .getPreferredSize().getHeight()); - } - } - - public PartitionAlgorithmListEditor( - List<PartitionAlgorithm<?>> currentState) { - super(); - this.paList = currentState; - } - - protected JLabel getLabelForPA(PartitionAlgorithm<?> pa) { - return new JLabel("Test..."); - } - - protected Color getBorderColorForPA(PartitionAlgorithm<?> pa) { - return Color.black; - } - - @Override - protected void paintComponent(Graphics g) { - Graphics2D g2d = (Graphics2D) g.create(); - // Enable anti-aliasing for the curved lines - g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, - RenderingHints.VALUE_ANTIALIAS_ON); - - int selectedStartsAt = 0; - int selectedEndsAt = 0; - Color frameColor = null; - int cumulativeTranslation = 0; - - super.paintComponent(g2d); - - for (int i = 0; i < paList.size(); i++) { - - Tab t = new Tab(getLabelForPA(paList.get(i))); - t.setBackground(new Color(150, 150, 255)); - t.setSelected(i == selectedIndex); - int width = (int) (t.getPreferredSize()).getWidth(); - t.setSize(new Dimension(width, getHeight())); - t.paint(g2d); - - if (i < selectedIndex) { - selectedStartsAt += width; - } else if (i == selectedIndex) { - selectedEndsAt = selectedStartsAt + width; - frameColor = t.getBackground(); - } - cumulativeTranslation += width; - g2d.translate(width, 0); - } - - - // Reset the transform - g2d.translate(-cumulativeTranslation, 0); - if (selectedIndex > 0) { - g2d.setStroke(new BasicStroke(selectedStrokeWidth, BasicStroke.CAP_BUTT, - BasicStroke.JOIN_MITER)); - int height = (int)(getHeight() - selectedStrokeWidth/2); - // Render the selected index line... - if (frameColor != null) { - g2d.setPaint(frameColor.darker()); - } - GeneralPath path = new GeneralPath(); - path.moveTo(0, height); - path.lineTo(selectedStartsAt, height); - path.lineTo(selectedStartsAt, cornerSep); - path.curveTo(selectedStartsAt, cornerSep / 2, selectedStartsAt - + cornerSep / 2, 0, selectedStartsAt + cornerSep, 0); - path.lineTo(selectedEndsAt - cornerSep, 0); - path.curveTo(selectedEndsAt - cornerSep / 2, 0, selectedEndsAt, - cornerSep / 2, selectedEndsAt, cornerSep); - path.lineTo(selectedEndsAt, height); - path.lineTo(getWidth(), height); - - g2d.draw(path); - } - g2d.dispose(); - } - - @SuppressWarnings("serial") - // Renderer for a single tab in the partition algorithm list, used as a - // rubber stamp for a single tab in the tab list. - class Tab extends JComponent { - - // Label to use to render tab contents - private JLabel label; - - // If this is selected then we don't draw the stroke as it'll be drawn - // on later. - private boolean selected = false; - - @Override - // Always false as we don't render the corners - public boolean isOpaque() { - return false; - } - - public void setSelected(boolean b) { - this.selected = b; - - } - - @Override - public Dimension getPreferredSize() { - Dimension d = label.getPreferredSize(); - return new Dimension((int) (d.getWidth()) + labelHorizontalPad * 2, - ((int) d.getHeight()) + labelBottomPad + labelTopPad); - } - - protected Tab(JLabel label) { - super(); - this.label = label; - } - - @Override - public void setBackground(Color colour) { - label.setBackground(colour); - } - - @Override - public Color getBackground() { - return label.getBackground(); - } - - @Override - protected void paintComponent(Graphics g) { - Graphics2D g2d = (Graphics2D) g.create(); - - int width = getWidth(); - int height = getHeight(); - - // Create a general path to draw the tab shape - g2d.setPaint(label.getBackground()); - GeneralPath path = new GeneralPath(); - path.moveTo(0, height); - path.lineTo(0, cornerSep); - path.curveTo(0, cornerSep / 2, cornerSep / 2, 0, cornerSep, 0); - path.lineTo(width - cornerSep, 0); - path.curveTo(width - cornerSep / 2, 0, width, cornerSep / 2, width, - cornerSep); - path.lineTo(width, height); - path.closePath(); - g2d.fill(path); - if (!selected) { - g2d.setPaint(label.getBackground().darker()); - g2d.draw(path); - } - - label.setSize(width - labelHorizontalPad * 2, height - - (labelBottomPad + labelTopPad)); - g2d.translate(labelHorizontalPad, labelTopPad); - label.paint(g2d); - g2d.translate(-labelHorizontalPad, -labelTopPad); - - g2d.dispose(); - } - } - -} http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/f676ef35/partition/src/main/java/net/sf/taverna/t2/partition/ui/TableTreeNodeColumn.java ---------------------------------------------------------------------- diff --git a/partition/src/main/java/net/sf/taverna/t2/partition/ui/TableTreeNodeColumn.java b/partition/src/main/java/net/sf/taverna/t2/partition/ui/TableTreeNodeColumn.java deleted file mode 100644 index c6b4b36..0000000 --- a/partition/src/main/java/net/sf/taverna/t2/partition/ui/TableTreeNodeColumn.java +++ /dev/null @@ -1,69 +0,0 @@ -/******************************************************************************* - * Copyright (C) 2007 The University of Manchester - * - * Modifications to the initial code base are copyright of their - * respective authors, or their employers as appropriate. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - ******************************************************************************/ -package net.sf.taverna.t2.partition.ui; - -import java.awt.Color; -import java.awt.Component; - -/** - * A column used in the tree part of the table tree node renderer - * - * @author Tom Oinn - * - */ -public interface TableTreeNodeColumn { - - /** - * Get a string to use as the header text - * - * @return - */ - public String getShortName(); - - /** - * Get a descriptive string for tooltips etc. - * - * @return - */ - public String getDescription(); - - /** - * Given a node value render the appropriate property for this column - * - * @param value - * @return - */ - public Component getCellRenderer(Object value); - - /** - * Return the width in pixels for this column - * - * @return - */ - public int getColumnWidth(); - - /** - * Get a header colour - the actual column colour will be a stripe of the - * result of applying the lighter operator twice and once to this colour. - */ - public Color getColour(); - -} http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/f676ef35/partition/src/main/java/net/sf/taverna/t2/partition/ui/TableTreeNodeRenderer.java ---------------------------------------------------------------------- diff --git a/partition/src/main/java/net/sf/taverna/t2/partition/ui/TableTreeNodeRenderer.java b/partition/src/main/java/net/sf/taverna/t2/partition/ui/TableTreeNodeRenderer.java deleted file mode 100644 index 12fd2a4..0000000 --- a/partition/src/main/java/net/sf/taverna/t2/partition/ui/TableTreeNodeRenderer.java +++ /dev/null @@ -1,554 +0,0 @@ -/******************************************************************************* - * Copyright (C) 2007 The University of Manchester - * - * Modifications to the initial code base are copyright of their - * respective authors, or their employers as appropriate. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - ******************************************************************************/ -package net.sf.taverna.t2.partition.ui; - -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Paint; -import java.awt.Rectangle; -import java.awt.RenderingHints; -import java.awt.Stroke; -import java.awt.geom.AffineTransform; -import java.awt.geom.GeneralPath; - -import javax.swing.JComponent; -import javax.swing.JLabel; -import javax.swing.JTree; -import javax.swing.UIManager; -import javax.swing.plaf.TreeUI; -import javax.swing.tree.TreeCellRenderer; -import javax.swing.tree.TreeModel; -import javax.swing.tree.TreePath; - -public abstract class TableTreeNodeRenderer implements TreeCellRenderer { - - private static final long serialVersionUID = -7291631337751330696L; - - // The difference in indentation between a node and its child nodes, there - // isn't an easy way to get this other than constructing a JTree and - // measuring it - you'd think it would be a property of TreeUI but - // apparently not. - private static int perNodeOffset = -1; - - // Use this to rubber stamp the original node renderer in before rendering - // the table - private TreeCellRenderer nodeRenderer; - - // Determines the space allocated to leaf nodes and their parents when - // applying the stamp defined by the nodeRenderer - private int nodeWidth; - - // Number of pixels of space to leave between the node label and the table - // header or rows - private int labelToTablePad = 3; - - // Number of pixels to leave around the label rendered into the table cells - private int cellPadding = 4; - - // Drawing borders? - private boolean drawingBorders = true; - - // The number of pixels by which the height of the header is reduced - // compared to the row height, this leaves a small border above the header - // and separates it from the last row of the table above, if any. - private int headerTopPad = 4; - - // The proportion of colour : black or colour : white used to create the - // darker or lighter shades is blendFactor : 1 - private int blendFactor = 2; - - // Colour to use to draw the table borders when they're enabled - private Color borderColour = Color.black; - - /** - * Set the colour to be used to draw the borders if they are displayed at - * all. Defaults to black. - */ - public void setBorderColour(Color borderColour) { - this.borderColour = borderColour; - } - - /** - * The blend factor determines how strong the colour component is in the - * shadow and highlight colours used in the bevelled boxes, the ratio of - * black / white to colour is 1 : blendFactor - * - * @param blendFactor - */ - public void setBlendFactor(int blendFactor) { - this.blendFactor = blendFactor; - } - - /** - * Set whether the renderer will draw borders around the table cells - if - * this is false the table still has the bevelled edges of the cell painters - * so will still look semi-bordered. Defaults to true if not otherwise set. - * - * @param drawingBorders - */ - public void setDrawBorders(boolean drawingBorders) { - this.drawingBorders = drawingBorders; - } - - /** - * Override and implement to get the list of columns for a given partition - * node - currently assumes all partitions use the same column structure - * which I need to fix so it doesn't take a partition as argument (yet). - * - * @return an array of column specifications used to drive the renderer - */ - public abstract TableTreeNodeColumn[] getColumns(); - - /** - * Construct a new TableTreeNodeRenderer - * - * @param nodeRenderer - * The inner renderer used to render the node labels - * @param nodeWidth - * Width of the cell space into which the node label is rendered - * in the table header and row nodes - */ - public TableTreeNodeRenderer(TreeCellRenderer nodeRenderer, int nodeWidth) { - super(); - this.nodeRenderer = nodeRenderer; - this.nodeWidth = nodeWidth; - } - - /** - * Do the magic! - */ - public Component getTreeCellRendererComponent(final JTree tree, - final Object value, final boolean selected, final boolean expanded, - final boolean leaf, final int row, final boolean hasFocus) { - final Component nodeLabel = nodeRenderer.getTreeCellRendererComponent( - tree, value, false, expanded, leaf, row, false); - final int nodeLabelHeight = (int) nodeLabel.getPreferredSize() - .getHeight(); - if (leaf) { - // Rendering the leaf nodes, therefore use the table rendering - // strategy - getPerNodeIndentation(tree, row); - return new JComponent() { - private static final long serialVersionUID = 4993815558563895266L; - - @Override - public Dimension getPreferredSize() { - int width = nodeWidth + labelToTablePad; - for (TableTreeNodeColumn column : getColumns()) { - width += column.getColumnWidth(); - } - return new Dimension(width, nodeLabelHeight); - } - - @Override - protected void paintComponent(Graphics g) { - - Graphics2D g2d = (Graphics2D) g.create(); - AffineTransform originalTransform = g2d.getTransform(); - // Enable anti-aliasing for the curved lines - g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, - RenderingHints.VALUE_ANTIALIAS_ON); - - // This method should paint a bevelled container for the - // original label but it doesn't really work terribly well - // as we can't ensure that the original label is actually - // honouring any opaque flags. - if (drawingBorders) { - paintRectangleWithBevel(g2d, nodeWidth - + labelToTablePad, getHeight(), Color.white); - } - - // Paint original node label - nodeLabel.setSize(new Dimension( - nodeWidth - cellPadding * 2, getHeight() - - (drawingBorders ? 2 : 1))); - g2d.translate(cellPadding, 0); - nodeLabel.paint(g2d); - g2d.translate(-cellPadding, 0); - - if (drawingBorders) { - paintRectangleBorder(g2d, nodeWidth + labelToTablePad, - getHeight(), 0, 0, 1, 1, borderColour); - } - - g2d.translate(nodeWidth + labelToTablePad, 0); - boolean first = true; - for (TableTreeNodeColumn column : getColumns()) { - - Color fillColour = column.getColour().brighter(); - Object parentNode = tree.getPathForRow(row) - .getParentPath().getLastPathComponent(); - int indexInParent = tree.getModel().getIndexOfChild( - parentNode, value); - if ((indexInParent & 1) == 1) { - fillColour = new Color( - (fillColour.getRed() + column.getColour() - .getRed()) / 2, (fillColour - .getGreen() + column.getColour() - .getGreen()) / 2, (fillColour - .getBlue() + column.getColour() - .getBlue()) / 2); - } - - // Paint background and bevel - paintRectangleWithBevel(g2d, column.getColumnWidth(), - getHeight(), fillColour); - - // Paint cell component - Component cellComponent = column.getCellRenderer(value); - cellComponent.setSize(new Dimension(column - .getColumnWidth() - - cellPadding * 2, getHeight())); - g2d.translate(cellPadding, 0); - cellComponent.paint(g2d); - g2d.translate(-cellPadding, 0); - - // Draw border - if (drawingBorders) { - paintRectangleBorder(g2d, column.getColumnWidth(), - getHeight(), 0, 1, 1, first ? 1 : 0, - borderColour); - } - first = false; - - g2d.translate(column.getColumnWidth(), 0); - - } - if (selected) { - g2d.setTransform(originalTransform); - g2d.translate(2, 0); - paintRectangleWithHighlightColour(g2d, getWidth() - - (drawingBorders ? 4 : 2), getHeight() - - (drawingBorders ? 2 : 0)); - } - } - }; - } else { - // If there are no child nodes, or there are child nodes but they - // aren't leaves then we render the cell as normal. If there are - // child nodes and the first one is a leaf (we assume this means - // they all are!) then we render the table header after the label. - if (!expanded) { - return getLabelWithHighlight(nodeLabel, selected); - } - // Expanded so do the model check... - TreeModel model = tree.getModel(); - int childCount = model.getChildCount(value); - if (childCount == 0) { - return getLabelWithHighlight(nodeLabel, selected); - } - Object childNode = model.getChild(value, 0); - if (!model.isLeaf(childNode)) { - return getLabelWithHighlight(nodeLabel, selected); - } - getPerNodeIndentation(tree, row); - // Got to here so we need to render a table header. - return new JComponent() { - private static final long serialVersionUID = -4923965850510357216L; - - @Override - public Dimension getPreferredSize() { - int width = nodeWidth + labelToTablePad + perNodeOffset; - for (TableTreeNodeColumn column : getColumns()) { - width += column.getColumnWidth(); - } - return new Dimension(width, nodeLabelHeight); - } - - @Override - protected void paintComponent(Graphics g) { - - Graphics2D g2d = (Graphics2D) g.create(); - AffineTransform originalTransform = g2d.getTransform(); - // Enable anti-aliasing for the curved lines - g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, - RenderingHints.VALUE_ANTIALIAS_ON); - - // Paint original node label - nodeLabel.setSize(new Dimension(nodeWidth + perNodeOffset, - getHeight())); - nodeLabel.paint(g2d); - - // Draw line under label to act as line above table row - // below - if (drawingBorders) { - GeneralPath path = new GeneralPath(); - path.moveTo(perNodeOffset, getHeight() - 1); - path.lineTo( - perNodeOffset + nodeWidth + labelToTablePad, - getHeight() - 1); - g2d.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT, - BasicStroke.JOIN_MITER)); - g2d.setPaint(borderColour); - g2d.draw(path); - } - - // Move painting origin to the start of the header row - g2d.translate(nodeWidth + perNodeOffset + labelToTablePad, - 0); - - // Paint columns - boolean first = true; - for (TableTreeNodeColumn column : getColumns()) { - - // Paint header cell background with bevel - g2d.translate(0, headerTopPad); - paintRectangleWithBevel(g2d, column.getColumnWidth(), - getHeight() - headerTopPad, column.getColour()); - - // Paint header label - JLabel columnLabel = new JLabel(column.getShortName()); - columnLabel.setSize(new Dimension(column - .getColumnWidth() - - cellPadding * 2, getHeight() - headerTopPad)); - g2d.translate(cellPadding, 0); - columnLabel.paint(g2d); - g2d.translate(-cellPadding, 0); - - // Paint header borders - if (drawingBorders) { - paintRectangleBorder(g2d, column.getColumnWidth(), - getHeight() - headerTopPad, 1, 1, 1, - first ? 1 : 0, borderColour); - } - g2d.translate(0, -headerTopPad); - first = false; - g2d.translate(column.getColumnWidth(), 0); - - } - if (selected) { - g2d.setTransform(originalTransform); - g2d.translate(1, headerTopPad); - paintRectangleWithHighlightColour(g2d, perNodeOffset - + nodeWidth + labelToTablePad - - (drawingBorders ? 2 : 0), getHeight() - - (headerTopPad + 2)); - } - } - }; - - } - - } - - private static Component getLabelWithHighlight(final Component c, - boolean selected) { - if (!selected) { - return c; - } else { - return new JComponent() { - private static final long serialVersionUID = -9175635475959046704L; - - @Override - public Dimension getPreferredSize() { - return c.getPreferredSize(); - } - - @Override - protected void paintComponent(Graphics g) { - Graphics2D g2d = (Graphics2D) g.create(); - c.setSize(new Dimension(getWidth(), getHeight())); - c.paint(g2d); - g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, - RenderingHints.VALUE_ANTIALIAS_ON); - g2d.translate(1, 1); - paintRectangleWithHighlightColour(g2d, getWidth() - 2, - getHeight() - 2); - } - }; - } - } - - private static void paintRectangleBorder(Graphics2D g2d, int width, - int height, int north, int east, int south, int west, Color c) { - Paint oldPaint = g2d.getPaint(); - Stroke oldStroke = g2d.getStroke(); - - g2d.setPaint(c); - - GeneralPath path; - - if (north > 0) { - g2d.setStroke(new BasicStroke(north, BasicStroke.CAP_BUTT, - BasicStroke.JOIN_MITER)); - path = new GeneralPath(); - path.moveTo(0, north - 1); - path.lineTo(width - 1, north - 1); - g2d.draw(path); - } - if (east > 0) { - g2d.setStroke(new BasicStroke(east, BasicStroke.CAP_BUTT, - BasicStroke.JOIN_MITER)); - path = new GeneralPath(); - path.moveTo(width - east, 0); - path.lineTo(width - east, height - 1); - g2d.draw(path); - } - if (south > 0) { - g2d.setStroke(new BasicStroke(south, BasicStroke.CAP_BUTT, - BasicStroke.JOIN_MITER)); - path = new GeneralPath(); - path.moveTo(0, height - south); - path.lineTo(width - 1, height - south); - g2d.draw(path); - } - if (west > 0) { - g2d.setStroke(new BasicStroke(west, BasicStroke.CAP_BUTT, - BasicStroke.JOIN_MITER)); - path = new GeneralPath(); - path.moveTo(west - 1, 0); - path.lineTo(west - 1, height - 1); - g2d.draw(path); - } - - g2d.setPaint(oldPaint); - g2d.setStroke(oldStroke); - } - - /** - * Paint a rectangle with the border colour set from the UIManager - * 'textHighlight' property and filled with the same colour at alpha 50/255. - * Paints from 0,0 to width-1,height-1 into the specified Graphics2D, - * preserving the existing paint and stroke properties on exit. - */ - private static void paintRectangleWithHighlightColour(Graphics2D g2d, - int width, int height) { - GeneralPath path = new GeneralPath(); - path.moveTo(0, 0); - path.lineTo(width - 1, 0); - path.lineTo(width - 1, height - 1); - path.lineTo(0, height - 1); - path.closePath(); - - Paint oldPaint = g2d.getPaint(); - Stroke oldStroke = g2d.getStroke(); - - Color c = UIManager.getColor("textHighlight"); - - g2d.setStroke(new BasicStroke(2, BasicStroke.CAP_BUTT, - BasicStroke.JOIN_MITER)); - g2d.setPaint(c); - g2d.draw(path); - - Color alpha = new Color(c.getRed(), c.getGreen(), c.getBlue(), 50); - g2d.setPaint(alpha); - g2d.fill(path); - - g2d.setPaint(oldPaint); - g2d.setStroke(oldStroke); - - } - - /** - * Paint a bevelled rectangle into the specified Graphics2D with shape from - * 0,0 to width-1,height-1 using the specified colour as a base and - * preserving colour and stroke in the Graphics2D - */ - private void paintRectangleWithBevel(Graphics2D g2d, int width, int height, - Color c) { - if (drawingBorders) { - width = width - 1; - height = height - 1; - } - - GeneralPath path = new GeneralPath(); - path.moveTo(0, 0); - path.lineTo(width - 1, 0); - path.lineTo(width - 1, height - 1); - path.lineTo(0, height - 1); - path.closePath(); - - Paint oldPaint = g2d.getPaint(); - Stroke oldStroke = g2d.getStroke(); - - g2d.setPaint(c); - g2d.fill(path); - - g2d.setStroke(new BasicStroke(1, BasicStroke.CAP_BUTT, - BasicStroke.JOIN_MITER)); - - // Draw highlight (Northeast) - path = new GeneralPath(); - path.moveTo(0, 0); - path.lineTo(width - 1, 0); - path.lineTo(width - 1, height - 1); - Color highlightColour = new Color((c.getRed() * blendFactor + 255) - / (blendFactor + 1), (c.getGreen() * blendFactor + 255) - / (blendFactor + 1), (c.getBlue() * blendFactor + 255) - / (blendFactor + 1)); - g2d.setPaint(highlightColour); - g2d.draw(path); - - // Draw shadow (Southwest) - path = new GeneralPath(); - path.moveTo(0, 0); - path.lineTo(0, height - 1); - path.lineTo(width - 1, height - 1); - Color shadowColour = new Color((c.getRed() * blendFactor) - / (blendFactor + 1), (c.getGreen() * blendFactor) - / (blendFactor + 1), (c.getBlue() * blendFactor) - / (blendFactor + 1)); - g2d.setPaint(shadowColour); - g2d.draw(path); - - g2d.setPaint(oldPaint); - g2d.setStroke(oldStroke); - - } - - /** - * The TreeUI which was used to determine the per node indentation in the - * JTree for which this is a renderer. If this hasn't been set yet then this - * is null. - */ - private static TreeUI cachedTreeUI = null; - - /** - * Use the current TreeUI to determine the indentation per-node in the tree, - * this only works when the treeRow passed in is not the root as it has to - * traverse up to the parent to do anything sensible. Cached and associated - * with the TreeUI so in theory if the look and feel changes the UI changes - * and this is re-generated within the renderer code. - * - * @param tree - * @param treeRow - * @return - */ - private static int getPerNodeIndentation(JTree tree, int treeRow) { - if (perNodeOffset > 0 && tree.getUI() == cachedTreeUI) { - return perNodeOffset; - } - TreeUI uiModel = tree.getUI(); - cachedTreeUI = uiModel; - TreePath path = tree.getPathForRow(treeRow); - Rectangle nodeBounds = uiModel.getPathBounds(tree, path); - Rectangle parentNodeBounds = uiModel.getPathBounds(tree, path - .getParentPath()); - perNodeOffset = (int) nodeBounds.getMinX() - - (int) parentNodeBounds.getMinX(); - return perNodeOffset; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/f676ef35/partition/src/main/java/net/sf/taverna/t2/partition/ui/UITest.java ---------------------------------------------------------------------- diff --git a/partition/src/main/java/net/sf/taverna/t2/partition/ui/UITest.java b/partition/src/main/java/net/sf/taverna/t2/partition/ui/UITest.java deleted file mode 100644 index 05a6112..0000000 --- a/partition/src/main/java/net/sf/taverna/t2/partition/ui/UITest.java +++ /dev/null @@ -1,58 +0,0 @@ -/******************************************************************************* - * Copyright (C) 2007 The University of Manchester - * - * Modifications to the initial code base are copyright of their - * respective authors, or their employers as appropriate. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - ******************************************************************************/ -package net.sf.taverna.t2.partition.ui; - -import java.awt.BorderLayout; -import java.util.ArrayList; -import java.util.List; - -import javax.swing.JFrame; -import javax.swing.JLabel; - -import net.sf.taverna.t2.partition.PartitionAlgorithm; -import net.sf.taverna.t2.partition.algorithms.LiteralValuePartitionAlgorithm; - -public class UITest extends JFrame { - - private static final long serialVersionUID = -734851883737477053L; - - public UITest() { - super(); - getContentPane().setLayout(new BorderLayout()); - List<PartitionAlgorithm<?>> paList = new ArrayList<PartitionAlgorithm<?>>(); - paList.add(new LiteralValuePartitionAlgorithm()); - paList.add(new LiteralValuePartitionAlgorithm()); - paList.add(new LiteralValuePartitionAlgorithm()); - PartitionAlgorithmListEditor pale = new PartitionAlgorithmListEditor(paList); - getContentPane().add(pale, BorderLayout.NORTH); - setVisible(true); - - } - - public static void main(String[] args) { - JLabel l = new JLabel("Foo"); - System.out.println(l.getPreferredSize()); - System.out.println(l.getWidth()); - - new UITest(); - } - -} http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/f676ef35/partition/src/test/java/net/sf/taverna/t2/partition/PartitionTestApplication.java ---------------------------------------------------------------------- diff --git a/partition/src/test/java/net/sf/taverna/t2/partition/PartitionTestApplication.java b/partition/src/test/java/net/sf/taverna/t2/partition/PartitionTestApplication.java deleted file mode 100644 index 07364f1..0000000 --- a/partition/src/test/java/net/sf/taverna/t2/partition/PartitionTestApplication.java +++ /dev/null @@ -1,280 +0,0 @@ -/******************************************************************************* - * Copyright (C) 2007 The University of Manchester - * - * Modifications to the initial code base are copyright of their - * respective authors, or their employers as appropriate. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - ******************************************************************************/ -package net.sf.taverna.t2.partition; - -import java.awt.Color; -import java.awt.Component; -import java.awt.FlowLayout; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.swing.BoxLayout; -import javax.swing.JFrame; -import javax.swing.JLabel; -import javax.swing.JScrollPane; -import javax.swing.JTree; -import javax.swing.SwingUtilities; -import javax.swing.UIManager; -import javax.swing.event.TreeModelEvent; -import javax.swing.tree.TreeCellRenderer; -import javax.swing.tree.TreeModel; -import javax.swing.tree.TreePath; - -import net.sf.taverna.t2.partition.algorithms.LiteralValuePartitionAlgorithm; -import net.sf.taverna.t2.partition.ui.TableTreeNodeColumn; -import net.sf.taverna.t2.partition.ui.TableTreeNodeRenderer; - -/** - * Exercise the partition algorithm codes - * - * @author Tom Oinn - * - */ -public class PartitionTestApplication { - - final static PropertyExtractorRegistry reg = new ExampleExtractorRegistry(); - - public static void main(String[] args) throws InterruptedException { - try { - // Set System L&F - UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - } catch (Exception e) { - // - } - - JFrame frame = new JFrame("Partition test"); - frame.addWindowListener(new WindowAdapter() { - @Override - public void windowClosing(WindowEvent e) { - System.exit(0); - } - - }); - - RootPartition<ExampleItem> partition = new RootPartition<ExampleItem>( - getAlgorithms(), reg); - JTree partitionTree = new AlwaysOpenJTree(partition); - partitionTree.setRowHeight(24); - TreeCellRenderer oldRenderer = partitionTree.getCellRenderer(); - TableTreeNodeRenderer ttnr = new TableTreeNodeRenderer(oldRenderer, 50) { - @Override - public TableTreeNodeColumn[] getColumns() { - return new TableTreeNodeColumn[] { - new TableTreeNodeColumnImpl("int", new Color(150, 150, - 210), 60,reg), - new TableTreeNodeColumnImpl("float", new Color(150, - 210, 150), 60,reg), - new TableTreeNodeColumnImpl("name", new Color(210, 150, - 150), 60,reg) , - new TableTreeNodeColumnImpl("Fish", new Color(210, 150, - 150), 60,reg) }; - } - }; - - ttnr.setBorderColour(new Color(150, 150, 150)); - - partitionTree.setCellRenderer(ttnr); - - frame.getContentPane().setLayout(new BoxLayout(frame.getContentPane(),BoxLayout.Y_AXIS)); - frame.getContentPane().add(new JScrollPane(partitionTree)); - frame.getContentPane().add(new JScrollPane(partitionTree)); - frame.setSize(400, 200); - frame.setVisible(true); - boolean showFrames = false; - //while (true) { - ttnr.setDrawBorders(showFrames); - showFrames = !showFrames; - for (ExampleItem item : exampleItems) { - Thread.sleep(200); - partition.addOrUpdateItem(item); - } -// Thread.sleep(1000); -// for (ExampleItem item : exampleItems) { -// Thread.sleep(400); -// partition.removeItem(item); -// } - //} - } - - static ExampleItem[] exampleItems = new ExampleItem[] { - new ExampleItem("foo", 1, 2.0f), new ExampleItem("bar", 1, 2.0f), - new ExampleItem("foo", 4, 3.7f), new ExampleItem("foo", 3, 2.0f), - new ExampleItem("bar", 1, 3.5f), new ExampleItem("bar", 1, 7.5f), - new ExampleItem("foo", 1, 2.1f), new ExampleItem("bar", 1, 2.3f), - new ExampleItem("foo", 4, 3.8f), new ExampleItem("foo", 3, 2.4f) }; - - static class TableTreeNodeColumnImpl implements TableTreeNodeColumn { - - private String propertyName; - private Color colour; - private int columnWidth; - private PropertyExtractorRegistry reg; - - public TableTreeNodeColumnImpl(String propertyName, Color colour, - int width,PropertyExtractorRegistry reg) { - this.propertyName = propertyName; - this.colour = colour; - this.columnWidth = width; - this.reg=reg; - } - - public Component getCellRenderer(Object value) { - Object propertyValue = reg.getAllPropertiesFor(value).get( - propertyName); - if (propertyValue == null) { - propertyValue = "Not defined"; - } - return new JLabel(propertyValue.toString()); - } - - public Color getColour() { - return this.colour; - } - - public int getColumnWidth() { - return columnWidth; - } - - public String getDescription() { - return "A description..."; - } - - public String getShortName() { - return propertyName; - } - - } - - static List<PartitionAlgorithm<?>> getAlgorithms() { - List<PartitionAlgorithm<?>> paList = new ArrayList<PartitionAlgorithm<?>>(); - LiteralValuePartitionAlgorithm lvpa = new LiteralValuePartitionAlgorithm(); - lvpa.setPropertyName("float"); - - LiteralValuePartitionAlgorithm lvpa2 = new LiteralValuePartitionAlgorithm(); - lvpa2.setPropertyName("int"); - LiteralValuePartitionAlgorithm lvpa3 = new LiteralValuePartitionAlgorithm(); - lvpa3.setPropertyName("name"); - - paList.add(lvpa2); - paList.add(lvpa); - paList.add(lvpa3); - - return paList; - } - - static class ExampleItem implements Comparable<Object>{ - private String name; - private int intValue; - private float floatValue; - - public String getName() { - return this.name; - } - - public int getIntValue() { - return this.intValue; - } - - public float getFloatValue() { - return this.floatValue; - } - - public ExampleItem(String name, int intValue, float floatValue) { - this.name = name; - this.intValue = intValue; - this.floatValue = floatValue; - } - - @Override - public String toString() { - return this.name; - } - - public int compareTo(Object o) { - // TODO Auto-generated method stub - return 0; - } - } - - static class ExampleExtractorRegistry implements PropertyExtractorRegistry { - public Map<String, Object> getAllPropertiesFor(Object target) { - Map<String, Object> properties = new HashMap<String, Object>(); - if (target instanceof ExampleItem) { - ExampleItem item = (ExampleItem) target; - properties.put("name", item.getName()); - properties.put("int", item.getIntValue()); - properties.put("float", item.getFloatValue()); - properties.put("Fish", "Soup"); - } - - return properties; - } - } - - static class AlwaysOpenJTree extends JTree { - - private static final long serialVersionUID = -3769998854485605447L; - - public AlwaysOpenJTree(TreeModel newModel) { - super(newModel); - setEditable(false); - setExpandsSelectedPaths(false); - setDragEnabled(false); - setScrollsOnExpand(false); - // setSelectionModel(SingleSelectionModel.sharedInstance()); - } - - @Override - public void setModel(TreeModel model) { - if (treeModel == model) - return; - if (treeModelListener == null) - treeModelListener = new TreeModelHandler() { - @Override - public void treeNodesInserted(final TreeModelEvent ev) { - if (ev.getChildren()[0] instanceof Partition == false) { - SwingUtilities.invokeLater(new Runnable() { - public void run() { - TreePath path = ev.getTreePath(); - setExpandedState(path, true); - fireTreeExpanded(path); - } - }); - } - - } - - }; - if (model != null) { - model.addTreeModelListener(treeModelListener); - } - TreeModel oldValue = treeModel; - treeModel = model; - firePropertyChange(TREE_MODEL_PROPERTY, oldValue, model); - } - - } - -} http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/f676ef35/partition/src/test/java/net/sf/taverna/t2/partition/algorithms/LiteralValuePartitionAlgorithmTest.java ---------------------------------------------------------------------- diff --git a/partition/src/test/java/net/sf/taverna/t2/partition/algorithms/LiteralValuePartitionAlgorithmTest.java b/partition/src/test/java/net/sf/taverna/t2/partition/algorithms/LiteralValuePartitionAlgorithmTest.java deleted file mode 100644 index 4e8f93c..0000000 --- a/partition/src/test/java/net/sf/taverna/t2/partition/algorithms/LiteralValuePartitionAlgorithmTest.java +++ /dev/null @@ -1,68 +0,0 @@ -/******************************************************************************* - * Copyright (C) 2007 The University of Manchester - * - * Modifications to the initial code base are copyright of their - * respective authors, or their employers as appropriate. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 - ******************************************************************************/ -package net.sf.taverna.t2.partition.algorithms; - -import static org.junit.Assert.*; -import net.sf.taverna.t2.partition.algorithms.LiteralValuePartitionAlgorithm; - -import org.junit.Test; - -public class LiteralValuePartitionAlgorithmTest { - - @Test - public void testEquals() { - LiteralValuePartitionAlgorithm a = new LiteralValuePartitionAlgorithm(); - LiteralValuePartitionAlgorithm b = new LiteralValuePartitionAlgorithm(); - LiteralValuePartitionAlgorithm c = new LiteralValuePartitionAlgorithm(); - - a.setPropertyName("cheese"); - b.setPropertyName("cheese"); - c.setPropertyName("butter"); - - assertEquals("They should be equal",a,a); - assertEquals("They should be equal",a,b); - assertFalse("They should not be equal",a.equals(c)); - assertFalse("They should not be equal",a.equals("cheese")); - } - - @Test - public void testHashcode() { - LiteralValuePartitionAlgorithm a = new LiteralValuePartitionAlgorithm(); - LiteralValuePartitionAlgorithm b = new LiteralValuePartitionAlgorithm(); - LiteralValuePartitionAlgorithm c = new LiteralValuePartitionAlgorithm(); - - a.setPropertyName("cheese"); - b.setPropertyName("cheese"); - c.setPropertyName("Z"); - - assertEquals("They should have the same hashcode",a.hashCode(),b.hashCode()); - } - - @Test - public void testConstructor() { - LiteralValuePartitionAlgorithm p = new LiteralValuePartitionAlgorithm(); - assertNull("The property shoudl default to null",p.getPropertyName()); - - p=new LiteralValuePartitionAlgorithm("pea"); - assertEquals("The property name should default to 'pea'","pea",p.getPropertyName()); - } -} - http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/f676ef35/taverna-beaninfo/pom.xml ---------------------------------------------------------------------- diff --git a/taverna-beaninfo/pom.xml b/taverna-beaninfo/pom.xml new file mode 100644 index 0000000..ea51b1a --- /dev/null +++ b/taverna-beaninfo/pom.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>net.sf.taverna.t2</groupId> + <artifactId>lang</artifactId> + <version>2.0.1-SNAPSHOT</version> + </parent> + <groupId>net.sf.taverna.t2.lang</groupId> + <artifactId>beans</artifactId> + <packaging>bundle</packaging> + <name>BeanInfo extensions</name> + <dependencies> + <dependency> + <groupId>org.apache.log4j</groupId> + <artifactId>com.springsource.org.apache.log4j</artifactId> + <version>${log4j.version}</version> + </dependency> + </dependencies> +</project> http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/f676ef35/taverna-beaninfo/src/main/java/net/sf/taverna/t2/lang/beans/PropertyAnnotated.java ---------------------------------------------------------------------- diff --git a/taverna-beaninfo/src/main/java/net/sf/taverna/t2/lang/beans/PropertyAnnotated.java b/taverna-beaninfo/src/main/java/net/sf/taverna/t2/lang/beans/PropertyAnnotated.java new file mode 100644 index 0000000..aa59e68 --- /dev/null +++ b/taverna-beaninfo/src/main/java/net/sf/taverna/t2/lang/beans/PropertyAnnotated.java @@ -0,0 +1,74 @@ +/********************************************************************** + * Copyright (C) 2009 The University of Manchester + * + * Modifications to the initial code base are copyright of their + * respective authors, or their employers as appropriate. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + **********************************************************************/ +package net.sf.taverna.t2.lang.beans; + +import java.beans.BeanInfo; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.beans.SimpleBeanInfo; + +/** + * A {@link BeanInfo} that includes {@link PropertyDescriptor}s from methods + * annotated using {@link PropertyAnnotation}. + * <p> + * The bean info from the PropertyAnnotation will then be available through + * Java's {@link Introspector}, and allows you to specify details such as + * {@link PropertyAnnotation#displayName()} and + * {@link PropertyAnnotation#hidden()} for the properties of a Java Bean. + * <p> + * This class can either be used as a superclass for the classes containing + * property annotated methods, or put in a neighbouring BeanInfo class. + * <p> + * For instance, if your class is called DescribedClass and has methods + * annotated using {@link PropertyAnnotation}, either let DescribedClass + * subclass {@link PropertyAnnotated}, or make a neighbouring {@link BeanInfo} + * class called DescribedClassBeanInfo, which should subclass + * {@link PropertyAnnotated}. + * + * + * @author Stian Soiland-Reyes + * + */ +public class PropertyAnnotated extends SimpleBeanInfo { + + private static PropertyAnnotationExtractor extractor = new PropertyAnnotationExtractor(); + + /** + * {@inheritDoc} + */ + @Override + public PropertyDescriptor[] getPropertyDescriptors() { + return extractor.getPropertyDescriptors(getDescribedClass()); + } + + /** + * The class that is being described. By default this returns + * {@link #getClass()} so that {@link PropertyAnnotated} can be used as a + * superclass, but if instead the DescribedClassBeanInfo pattern is used, + * subclass PropertyAnnotated in each BeanInfo class, and override this + * method to return the described class. (DescribedClass in this example) + * + */ + public Class<?> getDescribedClass() { + return getClass(); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/f676ef35/taverna-beaninfo/src/main/java/net/sf/taverna/t2/lang/beans/PropertyAnnotation.java ---------------------------------------------------------------------- diff --git a/taverna-beaninfo/src/main/java/net/sf/taverna/t2/lang/beans/PropertyAnnotation.java b/taverna-beaninfo/src/main/java/net/sf/taverna/t2/lang/beans/PropertyAnnotation.java new file mode 100644 index 0000000..5923a21 --- /dev/null +++ b/taverna-beaninfo/src/main/java/net/sf/taverna/t2/lang/beans/PropertyAnnotation.java @@ -0,0 +1,109 @@ +/********************************************************************** + * Copyright (C) 2009 The University of Manchester + * + * Modifications to the initial code base are copyright of their + * respective authors, or their employers as appropriate. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + **********************************************************************/ +package net.sf.taverna.t2.lang.beans; + +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * An annotation of a Java bean style property method, ie. a getXX() or setXX() + * method. + * <p> + * The annotations allow the method to better describe properties such as + * {@link #displayName()}, {@link #shortDescription()} and {@link #hidden()}. + * <p> + * The annotations can be retrieved as {@link PropertyDescriptor} using + * {@link PropertyAnnotationExtractor}, or if {@link PropertyAnnotated} has been + * used (recommended), through Java's BeanInfo support, such as using + * {@link Introspector}. + * <p> + * Annotations can be applied to interfaces or classes, abstract and normal + * methods, as long as they confirm with the Java bean conventions. Annotations + * will be inherited, so overriding methods don't need to reapply the annotations, + * although they can if they want to override. + * <p> + * It is recommended that classes using these annotations either subclass + * {@link PropertyAnnotated} or have a neighbouring BeanInfo class that + * subclasses PropertyAnnotated. + * <p> + * Example usage: + * + * <pre> + * public interface MyBean { + * // Annotation for the property called "name". displayName: Title + * // of the property shown in UI instead of "name". + * @PropertyAnnotation(displayName = "Full name") + * public String getName(); + * + * // Second annotation for the write-method of the same property called + * // "name". Both displayName and shortDescription will be set on the + * // property descriptor. + * @PropertyAnnotation(shortDescription = "The name of the person") + * public void setName(String name); + * + * // Boolean read method for the property "married", two annotations. + * // expert: Only shown in UI under "advanced" views. + * @PropertyAnnotation(expert = true, shortDescription = "Marital status") + * public boolean isMarried(); + * + * // Write-method for the "married" property, no new annotations, but will + * // get the ones from {@link #isMarried()}. + * public void setMarried(boolean married); + * + * // Write-only method, hidden (not shown in UIs). + * @PropertyAnnotation(hidden = true) + * public void setID(String id); + * + * // Read-only method, no annotations, defaults will be used. + * public void getTelephoneNumber(String number); + * } + * </pre> + * + * @see PropertyAnnotated + * @author Stian Soiland-Reyes + * + */ +@Retention(RetentionPolicy.RUNTIME) +@Target( { ElementType.METHOD }) +public @interface PropertyAnnotation { + + /** + * A unique string that means the default should be used + */ + public static String DEFAULT = "Default_8930B86A-50C0-4859-9B6F-DD034B3C5C1E"; + + String displayName() default DEFAULT; + + String name() default DEFAULT; + + String shortDescription() default DEFAULT; + + boolean expert() default false; + + boolean hidden() default false; + + boolean preferred() default false; + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/f676ef35/taverna-beaninfo/src/main/java/net/sf/taverna/t2/lang/beans/PropertyAnnotationExtractor.java ---------------------------------------------------------------------- diff --git a/taverna-beaninfo/src/main/java/net/sf/taverna/t2/lang/beans/PropertyAnnotationExtractor.java b/taverna-beaninfo/src/main/java/net/sf/taverna/t2/lang/beans/PropertyAnnotationExtractor.java new file mode 100644 index 0000000..4524822 --- /dev/null +++ b/taverna-beaninfo/src/main/java/net/sf/taverna/t2/lang/beans/PropertyAnnotationExtractor.java @@ -0,0 +1,202 @@ +/********************************************************************** + * Copyright (C) 2009 The University of Manchester + * + * Modifications to the initial code base are copyright of their + * respective authors, or their employers as appropriate. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + **********************************************************************/ +package net.sf.taverna.t2.lang.beans; + +import java.beans.IntrospectionException; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.WeakHashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * A utility class for extracting {@link PropertyDescriptor}s from a class which + * methods have been described using {@link PropertyAnnotation}. + * + * @author Stian Soiland-Reyes + * + */ +public class PropertyAnnotationExtractor { + + protected static Pattern methodPattern = Pattern + .compile("(get|is|set)(.+)"); + + protected WeakHashMap<Class<?>, List<Method>> allMethodsCache = new WeakHashMap<Class<?>, List<Method>>(); + + protected WeakHashMap<Class<?>, PropertyDescriptor[]> propertyDescriptorsCache = new WeakHashMap<Class<?>, PropertyDescriptor[]>(); + + @SuppressWarnings("unchecked") + protected List<Class> ignoreClasses = Arrays.<Class>asList(Class.class, Object.class, PropertyAnnotated.class); + + /** + * Find PropertyDescriptors for the given bean class based on descriptions + * using {@link PropertyAnnotation}s. + * <p> + * Annotations will be inherited from interfaces and superclasses. + * + * @param beanClass + * @return Array of {@link PropertyDescriptor} + */ + public PropertyDescriptor[] getPropertyDescriptors(Class<?> beanClass) { + PropertyDescriptor[] cached = propertyDescriptorsCache.get(beanClass); + if (cached != null) { + return cached; + } + + Map<String, PropertyDescriptor> descriptors = new HashMap<String, PropertyDescriptor>(); + + for (Method method : allMethods(beanClass)) { + PropertyAnnotation annotation = method + .getAnnotation(PropertyAnnotation.class); + Matcher methodMatcher = methodPattern.matcher(method.getName()); + if (!methodMatcher.matches() && annotation == null) { + continue; + } + + String name = PropertyAnnotation.DEFAULT; + if (annotation != null) { + annotation.name(); + } + if (name.equals(PropertyAnnotation.DEFAULT)) { + name = methodMatcher.group(2); + if (name.length() < 1) { + continue; + } + // decapitalize first letter + name = name.substring(0, 1).toLowerCase() + name.substring(1); + } + Method writeMethod = null; + Method readMethod = null; + if (methodMatcher.group(1).equals("set")) { + writeMethod = method; + if (writeMethod.getParameterTypes().length != 1) { + continue; + } + } else { + readMethod = method; + if (readMethod.getParameterTypes().length != 0) { + continue; + } + } + + PropertyDescriptor descriptor = descriptors.get(name); + try { + if (descriptor == null) { + descriptor = new PropertyDescriptor(name, readMethod, + writeMethod); + descriptors.put(name, descriptor); + } + // Set the one we just found + if (readMethod != null) { + descriptor.setReadMethod(readMethod); + } + if (writeMethod != null) { + descriptor.setWriteMethod(writeMethod); + } + } catch (IntrospectionException ex) { + throw new RuntimeException("Can't inspect property " + name + + " using method " + method, ex); + } + if (annotation != null) { + descriptor.setExpert(annotation.expert()); + descriptor.setHidden(annotation.hidden()); + descriptor.setPreferred(annotation.preferred()); + if (!annotation.displayName() + .equals(PropertyAnnotation.DEFAULT)) { + descriptor.setDisplayName(annotation.displayName()); + } + if (!annotation.shortDescription().equals( + PropertyAnnotation.DEFAULT)) { + descriptor.setShortDescription(annotation + .shortDescription()); + } + } + } + cached = descriptors.values().toArray( + new PropertyDescriptor[descriptors.size()]); + propertyDescriptorsCache.put(beanClass, cached); + return cached; + } + + /** + * Find all {@link Method}s defined in the class, all its superclasses and + * interfaces. This might include methods that override each other. + * <p> + * The list contains first the methods from each of the class's interfaces + * (and the methods they inherit from their interfaces), then recurses for + * the subclass of this class (including any additional interfaces used in + * the superclasses), before finally adding methods declared in the given + * class. + * <p> + * This can be useful to find annotations given to methods that have been + * overridden in subclasses. + * + * @param theClass + * @return + */ + @SuppressWarnings("unchecked") + protected List<Method> allMethods(Class<?> theClass) { + List<Method> methods = allMethodsCache.get(theClass); + if (methods == null) { + methods = new ArrayList<Method>(); + allMethods(theClass, new HashSet<Class>(ignoreClasses), methods); + allMethodsCache.put(theClass, methods); + } + return methods; + } + + @SuppressWarnings("unchecked") + protected void allMethods(Class<?> theClass, Set<Class> visitedClasses, + List<Method> foundMethods) { + if (theClass == null || theClass == Object.class + || theClass == Class.class || !visitedClasses.add(theClass)) { + // Top class or already visted + return; + } + // Let's first dig down into our interfaces + for (Class anInterface : theClass.getInterfaces()) { + allMethods(anInterface, visitedClasses, foundMethods); + } + // And our superclasses + allMethods(theClass.getSuperclass(), visitedClasses, foundMethods); + // Before we find any methods only declared in this class + // (parent methods are already earlier in the list - + // note that the new methods might override earlier methods) + for (Method method : theClass.getDeclaredMethods()) { + int methodModifiers = method.getModifiers(); + if (!Modifier.isPublic(methodModifiers) + || Modifier.isStatic(methodModifiers)) { + continue; + } + assert !foundMethods.contains(method) : "Method discovered twice: " + + method; + foundMethods.add(method); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/f676ef35/taverna-io/pom.xml ---------------------------------------------------------------------- diff --git a/taverna-io/pom.xml b/taverna-io/pom.xml new file mode 100644 index 0000000..1512fd7 --- /dev/null +++ b/taverna-io/pom.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>net.sf.taverna.t2</groupId> + <artifactId>lang</artifactId> + <version>2.0.1-SNAPSHOT</version> + </parent> + <groupId>net.sf.taverna.t2.lang</groupId> + <artifactId>io</artifactId> + <packaging>bundle</packaging> + <name>IO utility classes</name> + <dependencies> + <dependency> + <groupId>org.apache.log4j</groupId> + <artifactId>com.springsource.org.apache.log4j</artifactId> + <version>${log4j.version}</version> + </dependency> + </dependencies> +</project>
