You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@taverna.apache.org by st...@apache.org on 2015/03/06 23:34:37 UTC
[41/50] [abbrv] incubator-taverna-workbench git commit: taverna-*
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/f676ef35/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/LinePainter.java
----------------------------------------------------------------------
diff --git a/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/LinePainter.java b/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/LinePainter.java
new file mode 100644
index 0000000..0fb2926
--- /dev/null
+++ b/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/LinePainter.java
@@ -0,0 +1,163 @@
+package net.sf.taverna.t2.lang.ui;
+
+import java.awt.*;
+import java.awt.event.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import javax.swing.text.*;
+
+/*
+ * Track the movement of the Caret by painting a background line at the
+ * current caret position.
+ *
+ * Copied from http://www.camick.com/java/source/LinePainter.java
+ *
+ * Written by Rob Camick
+ */
+public class LinePainter
+ implements Highlighter.HighlightPainter, CaretListener, MouseListener, MouseMotionListener
+{
+ private JTextComponent component;
+
+ private Color color;
+
+ private Rectangle lastView;
+
+ /*
+ * The line color will be calculated automatically by attempting
+ * to make the current selection lighter by a factor of 1.2.
+ *
+ * @param component text component that requires background line painting
+ */
+ public LinePainter(JTextComponent component)
+ {
+ this(component, null);
+ setLighter(component.getSelectionColor());
+ }
+
+ /*
+ * Manually control the line color
+ *
+ * @param component text component that requires background line painting
+ * @param color the color of the background line
+ */
+ public LinePainter(JTextComponent component, Color color)
+ {
+ this.component = component;
+ setColor( color );
+
+ // Add listeners so we know when to change highlighting
+
+ component.addCaretListener( this );
+ component.addMouseListener( this );
+ component.addMouseMotionListener( this );
+
+ // Turn highlighting on by adding a dummy highlight
+
+ try
+ {
+ component.getHighlighter().addHighlight(0, 0, this);
+ }
+ catch(BadLocationException ble) {}
+ }
+
+ /*
+ * You can reset the line color at any time
+ *
+ * @param color the color of the background line
+ */
+ public void setColor(Color color)
+ {
+ this.color = color;
+ }
+
+ /*
+ * Calculate the line color by making the selection color lighter
+ *
+ * @return the color of the background line
+ */
+ public void setLighter(Color color)
+ {
+ int red = Math.min(255, (int)(color.getRed() * 1.2));
+ int green = Math.min(255, (int)(color.getGreen() * 1.2));
+ int blue = Math.min(255, (int)(color.getBlue() * 1.2));
+ setColor(new Color(red, green, blue));
+ }
+
+ // Paint the background highlight
+
+ public void paint(Graphics g, int p0, int p1, Shape bounds, JTextComponent c)
+ {
+ try
+ {
+ Rectangle r = c.modelToView(c.getCaretPosition());
+ g.setColor( color );
+ g.fillRect(0, r.y, c.getWidth(), r.height);
+
+ if (lastView == null)
+ lastView = r;
+ }
+ catch(BadLocationException ble) {System.out.println(ble);}
+ }
+
+ /*
+ * Caret position has changed, remove the highlight
+ */
+ private void resetHighlight()
+ {
+ // Use invokeLater to make sure updates to the Document are completed,
+ // otherwise Undo processing causes the modelToView method to loop.
+
+ SwingUtilities.invokeLater(new Runnable()
+ {
+ public void run()
+ {
+ try
+ {
+ int offset = component.getCaretPosition();
+ Rectangle currentView = component.modelToView(offset);
+
+ if (lastView == null) {
+ lastView = currentView;
+ } else {
+ // Remove the highlighting from the previously highlighted line
+ if (lastView.y != currentView.y)
+ {
+ component.repaint(0, lastView.y, component.getWidth(), lastView.height);
+ lastView = currentView;
+ }
+ }
+ }
+ catch(BadLocationException ble) {}
+ }
+ });
+ }
+
+ // Implement CaretListener
+
+ public void caretUpdate(CaretEvent e)
+ {
+ resetHighlight();
+ }
+
+ // Implement MouseListener
+
+ public void mousePressed(MouseEvent e)
+ {
+ resetHighlight();
+ }
+
+ public void mouseClicked(MouseEvent e) {}
+ public void mouseEntered(MouseEvent e) {}
+ public void mouseExited(MouseEvent e) {}
+ public void mouseReleased(MouseEvent e) {}
+
+ // Implement MouseMotionListener
+
+ public void mouseDragged(MouseEvent e)
+ {
+ resetHighlight();
+ }
+
+ public void mouseMoved(MouseEvent e) {}
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/f676ef35/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/LineWrappingTextArea.java
----------------------------------------------------------------------
diff --git a/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/LineWrappingTextArea.java b/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/LineWrappingTextArea.java
new file mode 100644
index 0000000..dde1566
--- /dev/null
+++ b/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/LineWrappingTextArea.java
@@ -0,0 +1,217 @@
+/*******************************************************************************
+ * 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.lang.ui;
+
+import java.awt.Component;
+import java.awt.Font;
+import java.awt.FontMetrics;
+import java.text.BreakIterator;
+import java.util.ArrayList;
+
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+
+/**
+ * A JTextArea whose text can be line wrapped either
+ * based on the size of the scroll pane that holds the text area or by a given
+ * line width in characters.
+ *
+ * @author Alex Nenadic
+ *
+ */
+@SuppressWarnings("serial")
+public class LineWrappingTextArea extends JTextArea{
+
+ String originalText;
+ String[] wrappedLines;
+ int lineWidth;
+
+ final FontMetrics fontMetrics;
+
+ public LineWrappingTextArea(String text){
+ super(text);
+ setFont(new Font("Monospaced", Font.PLAIN,12));
+ fontMetrics = this.getFontMetrics(this.getFont());
+ setCaretPosition(0);
+ originalText = text;
+ }
+
+ /**
+ * Based on:
+ * @author Robert Hanson
+ * http://progcookbook.blogspot.com/2006/02/text-wrapping-function-for-java.html
+ *
+ * This function takes a string value and a line length, and returns an array of
+ * lines. Lines are cut on word boundaries, where the word boundary is a space
+ * character. Spaces are included as the last character of a word, so most lines
+ * will actually end with a space. This isn't too problematic, but will cause a
+ * word to wrap if that space pushes it past the max line length.
+ *
+ * This is a modified version - added various word boundaries based on Java's word's
+ * BreakIterator in addition to simply space character as in the original function.
+ *
+ *
+ */
+ private String [] wrapTextIntoLines (String text, int len)
+ {
+ // BreakIterator will take care of word boundary characters for us
+ BreakIterator wordIterator = BreakIterator.getWordInstance();
+ wordIterator.setText(text);
+
+ // return empty array for null text
+ if (text == null)
+ return new String[] {};
+
+ // return text if len is zero or less
+ if (len <= 0)
+ return new String[] { text };
+
+ // return text if less than length
+ if (text.length() <= len)
+ return new String[] { text };
+
+ //char[] chars = text.toCharArray(); // no need to copy the text once again
+ ArrayList<String> lines = new ArrayList<String>();
+ StringBuffer line = new StringBuffer();
+ StringBuffer word = new StringBuffer();
+
+ for (int i = 0; i < text.length(); i++) {
+ //for (int i = 0; i < chars.length; i++) {
+ word.append(text.charAt(i));
+ //word.append(chars[i]);
+
+ if (wordIterator.isBoundary(i)){ // is this character a word boundary?
+ //if (chars[i] == ' ') {
+ if ((line.length() + word.length()) > len) {
+ lines.add(line.toString());
+ line.delete(0, line.length());
+ }
+
+ line.append(word);
+ word.delete(0, word.length());
+ }
+ }
+
+ // handle any extra chars in current word
+ if (word.length() > 0) {
+ if ((line.length() + word.length()) > len) {
+ lines.add(line.toString());
+ line.delete(0, line.length());
+ }
+ line.append(word);
+ }
+
+ // handle extra line
+ if (line.length() > 0) {
+ lines.add(line.toString());
+ }
+
+ String[] ret = new String[lines.size()];
+ int c = 0; // counter
+ for (String line2 : lines) {
+ ret[c++] = line2;
+ }
+
+ return ret;
+ }
+
+ public void wrapText() {
+ // Figure out how many characters to leave in one line
+ // Based on the size of JTextArea on the screen and font
+ // size - modified from
+ // http://www.coderanch.com/t/517006/GUI/java/Visible-column-row-count-JTextArea
+
+ // Get width of any char (font is monospaced)
+ final int charWidth = fontMetrics.charWidth('M');
+ // Get the width of the visible viewport of the scroll pane
+ // that contains the lot - loop until such a scroll pane is found
+ JScrollPane scrollPane = null;
+ Component currentComponent = getParent();
+ while (true) {
+ if (currentComponent == null) {
+ break;
+ }
+ if (currentComponent instanceof JScrollPane) {
+ scrollPane = (JScrollPane) currentComponent;
+ break;
+ } else {
+ currentComponent = currentComponent.getParent();
+ }
+ }
+ int prefWidth;
+ int maxChars;
+ if (scrollPane == null) { // We did not find the parent scroll pane
+ maxChars = 80; // wrap into lines of 80 characters
+ } else {
+ prefWidth = scrollPane.getVisibleRect().width;
+// if (scrollPane.getVerticalScrollBar().isVisible()){
+// prefWidth = prefWidth - scrollPane.getVerticalScrollBar().getWidth();
+// }
+ maxChars = prefWidth / charWidth - 3; // -3 because there is some
+ // space between the text
+ // area and the edge of
+ // scroll pane so just to be sure
+ }
+
+ // If we have not wrapped lines before or the
+ // width of the textarea has changed
+ if (wrappedLines == null || lineWidth != maxChars) {
+ lineWidth = maxChars;
+ wrappedLines = wrapTextIntoLines(getText(), lineWidth);
+ }
+
+ if (wrappedLines.length >= 1) {
+ setText(""); // clear the text area
+ StringBuffer buff = new StringBuffer();
+ for (int i = 0; i < wrappedLines.length; i++) {
+ buff.append(wrappedLines[i] + "\n");
+ }
+ // Remove the last \n
+ setText(buff.substring(0, buff.length()-1));
+ repaint();
+ }
+ }
+
+ public void wrapText(int numCharactersPerLine){
+ // If we have not wrapped lines before or the
+ // number of characters per line has changed since last
+ // we wrapped
+ if (wrappedLines == null || lineWidth != numCharactersPerLine) {
+ lineWidth = numCharactersPerLine;
+ wrappedLines = wrapTextIntoLines(getText(), lineWidth);
+ }
+
+ if (wrappedLines.length >= 1) {
+ setText(""); // clear the text area
+ for (int i = 0; i < wrappedLines.length; i++) {
+ append(wrappedLines[i] + "\n");
+ }
+ repaint();
+ }
+
+ }
+
+ public void unwrapText(){
+ setText(originalText);
+ repaint();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/f676ef35/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/NoWrapEditorKit.java
----------------------------------------------------------------------
diff --git a/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/NoWrapEditorKit.java b/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/NoWrapEditorKit.java
new file mode 100644
index 0000000..f032d67
--- /dev/null
+++ b/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/NoWrapEditorKit.java
@@ -0,0 +1,77 @@
+/**
+ *
+ */
+package net.sf.taverna.t2.lang.ui;
+
+import javax.swing.text.AbstractDocument;
+import javax.swing.text.BoxView;
+import javax.swing.text.ComponentView;
+import javax.swing.text.Element;
+import javax.swing.text.IconView;
+import javax.swing.text.LabelView;
+import javax.swing.text.ParagraphView;
+import javax.swing.text.StyleConstants;
+import javax.swing.text.StyledEditorKit;
+import javax.swing.text.View;
+import javax.swing.text.ViewFactory;
+
+
+/**
+ *
+ * The following class is copied from http://forums.sun.com/thread.jspa?threadID=622683
+ *
+ */
+public class NoWrapEditorKit extends StyledEditorKit
+{
+ public ViewFactory getViewFactory()
+ {
+ return new StyledViewFactory();
+ }
+
+ static class StyledViewFactory implements ViewFactory
+ {
+ public View create(Element elem)
+ {
+ String kind = elem.getName();
+
+ if (kind != null)
+ {
+ if (kind.equals(AbstractDocument.ContentElementName))
+ {
+ return new LabelView(elem);
+ }
+ else if (kind.equals(AbstractDocument.ParagraphElementName))
+ {
+ return new ParagraphView(elem);
+ }
+ else if (kind.equals(AbstractDocument.SectionElementName))
+ {
+ return new NoWrapBoxView(elem, View.Y_AXIS);
+ }
+ else if (kind.equals(StyleConstants.ComponentElementName))
+ {
+ return new ComponentView(elem);
+ }
+ else if (kind.equals(StyleConstants.IconElementName))
+ {
+ return new IconView(elem);
+ }
+ }
+
+ return new LabelView(elem);
+ }
+ }
+
+ static class NoWrapBoxView extends BoxView {
+ public NoWrapBoxView(Element elem, int axis) {
+ super(elem, axis);
+ }
+
+ public void layout(int width, int height) {
+ super.layout(32768, height);
+ }
+ public float getMinimumSpan(int axis) {
+ return super.getPreferredSpan(axis);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/f676ef35/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/ReadOnlyTextArea.java
----------------------------------------------------------------------
diff --git a/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/ReadOnlyTextArea.java b/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/ReadOnlyTextArea.java
new file mode 100644
index 0000000..0759605
--- /dev/null
+++ b/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/ReadOnlyTextArea.java
@@ -0,0 +1,50 @@
+/**
+ *
+ */
+package net.sf.taverna.t2.lang.ui;
+
+import javax.swing.JTextArea;
+import javax.swing.text.Document;
+
+/**
+ * @author alanrw
+ *
+ */
+public class ReadOnlyTextArea extends JTextArea {
+
+ public ReadOnlyTextArea () {
+ super();
+ setFields();
+ }
+
+ public ReadOnlyTextArea(Document doc) {
+ super(doc);
+ setFields();
+ }
+
+ public ReadOnlyTextArea (Document doc, String text, int rows, int columns) {
+ super(doc,text,rows,columns);
+ setFields();
+ }
+
+ public ReadOnlyTextArea(int rows, int columns) {
+ super(rows, columns);
+ setFields();
+ }
+
+ public ReadOnlyTextArea(String text) {
+ super(text);
+ setFields();
+ }
+
+ public ReadOnlyTextArea(String text, int rows, int columns) {
+ super(text, rows, columns);
+ setFields();
+ }
+
+ private void setFields() {
+ super.setEditable(false);
+ super.setLineWrap(true);
+ super.setWrapStyleWord(true);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/f676ef35/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/SanitisingDocumentFilter.java
----------------------------------------------------------------------
diff --git a/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/SanitisingDocumentFilter.java b/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/SanitisingDocumentFilter.java
new file mode 100644
index 0000000..2a91e18
--- /dev/null
+++ b/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/SanitisingDocumentFilter.java
@@ -0,0 +1,60 @@
+/**
+ *
+ */
+package net.sf.taverna.t2.lang.ui;
+
+import java.util.regex.Pattern;
+
+import javax.swing.text.AbstractDocument;
+import javax.swing.text.AttributeSet;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+import javax.swing.text.DocumentFilter;
+import javax.swing.text.JTextComponent;
+
+/**
+ * @author alanrw
+ *
+ */
+public class SanitisingDocumentFilter extends DocumentFilter {
+
+ private static SanitisingDocumentFilter INSTANCE = new SanitisingDocumentFilter();
+
+ private SanitisingDocumentFilter () {
+ super();
+ }
+
+ public static void addFilterToComponent(JTextComponent c) {
+ Document d = c.getDocument();
+ if (d instanceof AbstractDocument) {
+ ((AbstractDocument) d).setDocumentFilter(INSTANCE);
+ }
+ }
+
+ public void insertString(DocumentFilter.FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException {
+
+ fb.insertString(offset, sanitiseString(string), attr);
+ }
+
+ public void replace(DocumentFilter.FilterBypass fb, int offset, int length,
+ String text, javax.swing.text.AttributeSet attr)
+
+ throws BadLocationException {
+ fb.replace(offset, length, sanitiseString(text), attr);
+ }
+
+ private static String sanitiseString(String text) {
+ String result = text;
+ if (Pattern.matches("\\w++", text) == false) {
+ result = "";
+ for (char c : text.toCharArray()) {
+ if (Character.isLetterOrDigit(c) || c == '_') {
+ result += c;
+ } else {
+ result += "_";
+ }
+ }
+ }
+ return result;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/f676ef35/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/ShadedLabel.java
----------------------------------------------------------------------
diff --git a/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/ShadedLabel.java b/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/ShadedLabel.java
new file mode 100644
index 0000000..27ebe33
--- /dev/null
+++ b/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/ShadedLabel.java
@@ -0,0 +1,126 @@
+/*******************************************************************************
+ * 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
+ ******************************************************************************/
+/**
+ * This file is a component of the Taverna project,
+ * and is licensed under the GNU LGPL.
+ * Copyright Tom Oinn, EMBL-EBI
+ */
+package net.sf.taverna.t2.lang.ui;
+
+import java.awt.Color;
+import java.awt.FlowLayout;
+import java.awt.GradientPaint;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Paint;
+
+import javax.swing.Box;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.SwingConstants;
+
+/**
+ * A JLabel like component with a shaded background
+ *
+ * @author Tom Oinn
+ */
+public class ShadedLabel extends JPanel {
+
+ // If you change these, please make sure BLUE is really blue, etc.. :-)
+
+ public static Color ORANGE = new Color(238, 206, 143);
+
+ public static Color BLUE = new Color(213, 229, 246);
+
+ public static Color GREEN = new Color(161, 198, 157);
+
+ final JLabel label;
+
+ Color colour;
+
+ Color toColour = Color.WHITE;
+
+ private String text;
+
+ /**
+ * Create a ShadedLabel blending from the specified colour to white (left to
+ * right) and with the specified text.
+ */
+ public ShadedLabel(String text, Color colour) {
+ this(text, colour, false);
+ }
+
+ /**
+ * Create a ShadedLabel blending from the specified colour to either white
+ * if halfShade is false or to a colour halfway between the specified colour
+ * and white if true and with the specified text
+ */
+ public ShadedLabel(String text, Color colour, boolean halfShade) {
+ super(new FlowLayout(FlowLayout.LEFT, 0, 3));
+
+ if (halfShade) {
+ toColour = halfShade(colour);
+ }
+ label = new JLabel("",
+ SwingConstants.LEFT);
+ setText(text);
+ label.setOpaque(false);
+ add(Box.createHorizontalStrut(5));
+ add(label);
+ add(Box.createHorizontalStrut(5));
+ setOpaque(false);
+ this.colour = colour;
+ }
+
+ public void setText(String text) {
+ this.text = text;
+ label.setText("<html><body><b>" + text + "</b></body></html>");
+ invalidate();
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ @Override
+ protected void paintComponent(Graphics g) {
+ final int width = getWidth();
+ final int height = getHeight();
+ Graphics2D g2d = (Graphics2D) g;
+ Paint oldPaint = g2d.getPaint();
+ g2d.setPaint(new GradientPaint(0, 0, this.colour, width, height,
+ toColour));
+ g2d.fillRect(0, 0, width, height);
+ g2d.setPaint(oldPaint);
+ super.paintComponent(g);
+ }
+
+ public static Color halfShade(Color colour) {
+ return new Color((colour.getRed() + 510) / 3,
+ (colour.getGreen() + 510) / 3, (colour.getBlue() + 510) / 3);
+ }
+
+ @Override
+ public boolean isFocusable() {
+ return false;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/f676ef35/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/TableMap.java
----------------------------------------------------------------------
diff --git a/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/TableMap.java b/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/TableMap.java
new file mode 100644
index 0000000..dbef4c0
--- /dev/null
+++ b/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/TableMap.java
@@ -0,0 +1,69 @@
+/**
+ *
+ */
+package net.sf.taverna.t2.lang.ui;
+
+import javax.swing.table.AbstractTableModel;
+import javax.swing.table.TableModel;
+import javax.swing.event.TableModelListener;
+import javax.swing.event.TableModelEvent;
+
+/**
+ * Copied from code found at http://www.informit.com/guides/content.aspx?g=java&seqNum=57
+ *
+ */
+public class TableMap extends AbstractTableModel implements TableModelListener {
+ protected TableModel model;
+
+ public TableModel getModel() {
+ return model;
+ }
+
+ public void setModel(TableModel model) {
+ this.model = model;
+ model.addTableModelListener(this);
+ }
+
+ // By default, implement TableModel by forwarding all messages
+ // to the model.
+
+ public Object getValueAt(int aRow, int aColumn) {
+ return model.getValueAt(aRow, aColumn);
+ }
+
+ public void setValueAt(Object aValue, int aRow, int aColumn) {
+ model.setValueAt(aValue, aRow, aColumn);
+ }
+
+ public int getRowCount() {
+ return (model == null) ? 0 : model.getRowCount();
+ }
+
+ public int getColumnCount() {
+ return (model == null) ? 0 : model.getColumnCount();
+ }
+
+ public String getColumnName(int aColumn) {
+ return model.getColumnName(aColumn);
+ }
+
+ public Class getColumnClass(int aColumn) {
+ return model.getColumnClass(aColumn);
+ }
+
+ public boolean isCellEditable(int row, int column) {
+ return model.isCellEditable(row, column);
+ }
+
+ public int transposeRow(int row) {
+ return row;
+ }
+
+ //
+ // Implementation of the TableModelListener interface,
+ //
+ // By default forward all events to all the listeners.
+ public void tableChanged(TableModelEvent e) {
+ fireTableChanged(e);
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/f676ef35/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/TableSorter.java
----------------------------------------------------------------------
diff --git a/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/TableSorter.java b/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/TableSorter.java
new file mode 100644
index 0000000..7c7083d
--- /dev/null
+++ b/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/TableSorter.java
@@ -0,0 +1,341 @@
+/**
+ *
+ */
+package net.sf.taverna.t2.lang.ui;
+
+/**
+ * Copied from code found at http://www.informit.com/guides/content.aspx?g=java&seqNum=57
+ */
+
+import java.util.Date;
+import java.util.Vector;
+
+import javax.swing.table.TableModel;
+import javax.swing.event.TableModelEvent;
+
+//Imports for picking up mouse events from the JTable.
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.awt.event.InputEvent;
+import javax.swing.JTable;
+import javax.swing.table.JTableHeader;
+import javax.swing.table.TableColumnModel;
+
+public class TableSorter extends TableMap {
+ int indexes[];
+ Vector sortingColumns = new Vector();
+ boolean ascending = true;
+ int compares;
+
+ public TableSorter() {
+ indexes = new int[0]; // for consistency
+ }
+
+ public TableSorter(TableModel model) {
+ setModel(model);
+ }
+
+ public void setModel(TableModel model) {
+ super.setModel(model);
+ reallocateIndexes();
+ }
+
+ public int compareRowsByColumn(int row1, int row2, int column) {
+ Class type = model.getColumnClass(column);
+ TableModel data = model;
+
+ // Check for nulls.
+
+ Object o1 = data.getValueAt(row1, column);
+ Object o2 = data.getValueAt(row2, column);
+
+ // If both values are null, return 0.
+ if (o1 == null && o2 == null) {
+ return 0;
+ } else if (o1 == null) { // Define null less than everything.
+ return -1;
+ } else if (o2 == null) {
+ return 1;
+ }
+
+ if (o1 instanceof Comparable) {
+ return ((Comparable) o1).compareTo(o2);
+ }
+ /*
+ * We copy all returned values from the getValue call in case an
+ * optimised model is reusing one object to return many values. The
+ * Number subclasses in the JDK are immutable and so will not be used in
+ * this way but other subclasses of Number might want to do this to save
+ * space and avoid unnecessary heap allocation.
+ */
+
+ if (type.getSuperclass() == java.lang.Number.class) {
+ Number n1 = (Number) data.getValueAt(row1, column);
+ double d1 = n1.doubleValue();
+ Number n2 = (Number) data.getValueAt(row2, column);
+ double d2 = n2.doubleValue();
+
+ if (d1 < d2) {
+ return -1;
+ } else if (d1 > d2) {
+ return 1;
+ } else {
+ return 0;
+ }
+ } else if (type == java.util.Date.class) {
+ Date d1 = (Date) data.getValueAt(row1, column);
+ long n1 = d1.getTime();
+ Date d2 = (Date) data.getValueAt(row2, column);
+ long n2 = d2.getTime();
+
+ if (n1 < n2) {
+ return -1;
+ } else if (n1 > n2) {
+ return 1;
+ } else {
+ return 0;
+ }
+ } else if (type == String.class) {
+ String s1 = (String) data.getValueAt(row1, column);
+ String s2 = (String) data.getValueAt(row2, column);
+ int result = s1.compareTo(s2);
+
+ if (result < 0) {
+ return -1;
+ } else if (result > 0) {
+ return 1;
+ } else {
+ return 0;
+ }
+ } else if (type == Boolean.class) {
+ Boolean bool1 = (Boolean) data.getValueAt(row1, column);
+ boolean b1 = bool1.booleanValue();
+ Boolean bool2 = (Boolean) data.getValueAt(row2, column);
+ boolean b2 = bool2.booleanValue();
+
+ if (b1 == b2) {
+ return 0;
+ } else if (b1) { // Define false < true
+ return 1;
+ } else {
+ return -1;
+ }
+ } else {
+ Object v1 = data.getValueAt(row1, column);
+ String s1 = v1.toString();
+ Object v2 = data.getValueAt(row2, column);
+ String s2 = v2.toString();
+ int result = s1.compareTo(s2);
+
+ if (result < 0) {
+ return -1;
+ } else if (result > 0) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ public int compare(int row1, int row2) {
+ compares++;
+ for (int level = 0; level < sortingColumns.size(); level++) {
+ Integer column = (Integer) sortingColumns.elementAt(level);
+ int result = compareRowsByColumn(row1, row2, column.intValue());
+ if (result != 0) {
+ return ascending ? result : -result;
+ }
+ }
+ return 0;
+ }
+
+ public void reallocateIndexes() {
+ int rowCount = model.getRowCount();
+
+ // Set up a new array of indexes with the right number of elements
+ // for the new data model.
+ indexes = new int[rowCount];
+
+ // Initialise with the identity mapping.
+ for (int row = 0; row < rowCount; row++) {
+ indexes[row] = row;
+ }
+ }
+
+ public void tableChanged(TableModelEvent e) {
+ // System.out.println("Sorter: tableChanged");
+ reallocateIndexes();
+
+ super.tableChanged(e);
+ }
+
+ public void checkModel() {
+ if (indexes.length != model.getRowCount()) {
+ System.err.println("Sorter not informed of a change in model.");
+ }
+ }
+
+ public void sort(Object sender) {
+ checkModel();
+
+ compares = 0;
+ // n2sort();
+ // qsort(0, indexes.length-1);
+ shuttlesort((int[]) indexes.clone(), indexes, 0, indexes.length);
+ // System.out.println("Compares: "+compares);
+ }
+
+ public void n2sort() {
+ for (int i = 0; i < getRowCount(); i++) {
+ for (int j = i + 1; j < getRowCount(); j++) {
+ if (compare(indexes[i], indexes[j]) == -1) {
+ swap(i, j);
+ }
+ }
+ }
+ }
+
+ // This is a home-grown implementation which we have not had time
+ // to research - it may perform poorly in some circumstances. It
+ // requires twice the space of an in-place algorithm and makes
+ // NlogN assigments shuttling the values between the two
+ // arrays. The number of compares appears to vary between N-1 and
+ // NlogN depending on the initial order but the main reason for
+ // using it here is that, unlike qsort, it is stable.
+ public void shuttlesort(int from[], int to[], int low, int high) {
+ if (high - low < 2) {
+ return;
+ }
+ int middle = (low + high) / 2;
+ shuttlesort(to, from, low, middle);
+ shuttlesort(to, from, middle, high);
+
+ int p = low;
+ int q = middle;
+
+ /*
+ * This is an optional short-cut; at each recursive call, check to see
+ * if the elements in this subset are already ordered. If so, no further
+ * comparisons are needed; the sub-array can just be copied. The array
+ * must be copied rather than assigned otherwise sister calls in the
+ * recursion might get out of sinc. When the number of elements is three
+ * they are partitioned so that the first set, [low, mid), has one
+ * element and and the second, [mid, high), has two. We skip the
+ * optimisation when the number of elements is three or less as the
+ * first compare in the normal merge will produce the same sequence of
+ * steps. This optimisation seems to be worthwhile for partially ordered
+ * lists but some analysis is needed to find out how the performance
+ * drops to Nlog(N) as the initial order diminishes - it may drop very
+ * quickly.
+ */
+
+ if (high - low >= 4 && compare(from[middle - 1], from[middle]) <= 0) {
+ for (int i = low; i < high; i++) {
+ to[i] = from[i];
+ }
+ return;
+ }
+
+ // A normal merge.
+
+ for (int i = low; i < high; i++) {
+ if (q >= high || (p < middle && compare(from[p], from[q]) <= 0)) {
+ to[i] = from[p++];
+ } else {
+ to[i] = from[q++];
+ }
+ }
+ }
+
+ public void swap(int i, int j) {
+ int tmp = indexes[i];
+ indexes[i] = indexes[j];
+ indexes[j] = tmp;
+ }
+
+ // The mapping only affects the contents of the data rows.
+ // Pass all requests to these rows through the mapping array: "indexes".
+
+ public Object getValueAt(int aRow, int aColumn) {
+ checkModel();
+ return model.getValueAt(indexes[aRow], aColumn);
+ }
+
+ public void setValueAt(Object aValue, int aRow, int aColumn) {
+ checkModel();
+ model.setValueAt(aValue, indexes[aRow], aColumn);
+ }
+
+ public void sortByColumn(int column) {
+ sortByColumn(column, true);
+ }
+
+ public void sortByColumn(int column, boolean ascending) {
+ this.ascending = ascending;
+ sortingColumns.removeAllElements();
+ sortingColumns.addElement(new Integer(column));
+ sort(this);
+ super.tableChanged(new TableModelEvent(this));
+ }
+
+ private int lastSortedColumn = -1;
+ private boolean lastAscending = false;
+
+ public void sortColumn(JTable tableView, int column) {
+ int currentlySelectedRow = tableView.getSelectedRow();
+ int underlyingSelectedRow = -1;
+ if (currentlySelectedRow != -1) {
+ underlyingSelectedRow = transposeRow(currentlySelectedRow);
+ }
+ // System.out.println("Sorting ...");
+ boolean ascendingColumn = true;
+ if (lastSortedColumn == column) {
+ ascendingColumn = !lastAscending;
+ }
+ lastSortedColumn = column;
+ lastAscending = ascendingColumn;
+ this.sortByColumn(column, ascendingColumn);
+ if (underlyingSelectedRow != -1) {
+ for (int row = 0; row < indexes.length; row++) {
+ if (transposeRow(row) == underlyingSelectedRow) {
+ tableView.setRowSelectionInterval(row, row);
+ }
+ }
+ }
+ }
+
+ public void resort(JTable tableView) {
+ if (lastSortedColumn != -1) {
+ lastAscending = !lastAscending;
+ sortColumn(tableView, lastSortedColumn);
+ }
+ }
+
+ // There is no-where else to put this.
+ // Add a mouse listener to the Table to trigger a table sort
+ // when a column heading is clicked in the JTable.
+ public void addMouseListenerToHeaderInTable(JTable table) {
+ final TableSorter sorter = this;
+ final JTable tableView = table;
+ tableView.setColumnSelectionAllowed(false);
+ MouseAdapter listMouseListener = new MouseAdapter() {
+
+ private int lastClickedColumn = -1;
+ private boolean lastAscending = false;
+ public void mouseClicked(MouseEvent e) {
+ TableColumnModel columnModel = tableView.getColumnModel();
+ int viewColumn = columnModel.getColumnIndexAtX(e.getX());
+ int column = tableView.convertColumnIndexToModel(viewColumn);
+ if (e.getClickCount() == 1 && column != -1) {
+ sortColumn(tableView, column);
+ }
+ }
+ };
+ JTableHeader th = tableView.getTableHeader();
+ th.addMouseListener(listMouseListener);
+ }
+
+ public int transposeRow(int row) {
+ return indexes[row];
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/f676ef35/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/ValidatingUserInputDialog.java
----------------------------------------------------------------------
diff --git a/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/ValidatingUserInputDialog.java b/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/ValidatingUserInputDialog.java
new file mode 100644
index 0000000..005b4b4
--- /dev/null
+++ b/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/ValidatingUserInputDialog.java
@@ -0,0 +1,274 @@
+/*******************************************************************************
+ * 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.lang.ui;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Font;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.FocusAdapter;
+import java.awt.event.FocusEvent;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.util.Set;
+
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextArea;
+import javax.swing.border.EmptyBorder;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.text.JTextComponent;
+
+import net.sf.taverna.t2.lang.ui.icons.Icons;
+
+/**
+ * A user input dialog that validates the input as the user is entering the
+ * input and gives feedback on why the input is invalid.
+ *
+ * @author David Withers
+ */
+public class ValidatingUserInputDialog extends JDialog {
+
+ private static final long serialVersionUID = 1L;
+
+ private String inputTitle;
+
+ private JButton okButton;
+
+ private JButton cancelButton;
+
+ private JTextArea inputText;
+
+ private JPanel inputPanel;
+
+ private JLabel iconLabel;
+
+ private boolean valid = true;
+
+ private boolean result = false;
+
+ /**
+ * Constructs a new instance of ValidatingUserInputDialog.
+ *
+ * @param inputTitle
+ * the title for the dialog.
+ * @param inputMessage
+ * the message describing what the user should input.
+ */
+ public ValidatingUserInputDialog(String inputTitle, JPanel inputPanel) {
+ this.inputTitle = inputTitle;
+ this.inputPanel = inputPanel;
+ initialize();
+ }
+
+ /**
+ * Adds a text component and the rules for a valid user entry.
+ *
+ * @param textComponent
+ * the text component to validate
+ * @param invalidInputs
+ * a set of inputs that are not valid. This is typically a set of
+ * already used identifiers to avoid name clashes. Can be an
+ * empty set or null.
+ * @param invalidInputsMessage
+ * the message to display if the user enters a value that is in
+ * invalidInputs.
+ * @param inputRegularExpression
+ * a regular expression that specifies a valid user input. Can be
+ * null.
+ * @param inputRegularExpressionMessage
+ * the message to display if the user enters a value that doesn't
+ * match the inputRegularExpression.
+ */
+ public void addTextComponentValidation(final JTextComponent textComponent,
+ final String inputMessage, final Set<String> invalidInputs,
+ final String invalidInputsMessage,
+ final String inputRegularExpression,
+ final String inputRegularExpressionMessage) {
+ textComponent.getDocument().addDocumentListener(new DocumentListener() {
+ public void changedUpdate(DocumentEvent e) {
+ }
+
+ public void insertUpdate(DocumentEvent e) {
+ verify(textComponent.getText(), inputMessage, invalidInputs,
+ invalidInputsMessage, inputRegularExpression,
+ inputRegularExpressionMessage);
+ }
+
+ public void removeUpdate(DocumentEvent e) {
+ verify(textComponent.getText(), inputMessage, invalidInputs,
+ invalidInputsMessage, inputRegularExpression,
+ inputRegularExpressionMessage);
+ }
+ });
+ textComponent.addKeyListener(new KeyAdapter() {
+ boolean okDown = false;
+
+ public void keyPressed(KeyEvent e) {
+ if (okButton.isEnabled() && e.getKeyCode() == KeyEvent.VK_ENTER) {
+ okDown = true;
+ }
+ }
+ public void keyReleased(KeyEvent e) {
+ if (okDown && okButton.isEnabled() && e.getKeyCode() == KeyEvent.VK_ENTER) {
+ okButton.doClick();
+ }
+ }
+ });
+ textComponent.addFocusListener(new FocusAdapter() {
+ public void focusGained(FocusEvent e) {
+ if (valid) {
+ setMessage(inputMessage);
+ }
+ }
+ });
+ }
+
+ /**
+ * Adds a component and a message to display when the component is in focus.
+ *
+ * @param component
+ * the component to add
+ * @param message
+ * the message to display when the component is in focus
+ */
+ public void addMessageComponent(Component component, final String message) {
+ component.addFocusListener(new FocusAdapter() {
+ public void focusGained(FocusEvent e) {
+ if (valid) {
+ setMessage(message);
+ }
+ }
+ });
+ }
+
+ private void initialize() {
+ setLayout(new BorderLayout());
+
+ JPanel messagePanel = new JPanel(new BorderLayout());
+ messagePanel.setBorder(new EmptyBorder(5, 5, 0, 0));
+ messagePanel.setBackground(Color.WHITE);
+
+ add(messagePanel, BorderLayout.NORTH);
+
+ JLabel inputLabel = new JLabel(inputTitle);
+ inputLabel.setBackground(Color.WHITE);
+ Font baseFont = inputLabel.getFont();
+ inputLabel.setFont(baseFont.deriveFont(Font.BOLD));
+ messagePanel.add(inputLabel, BorderLayout.NORTH);
+
+ inputText = new JTextArea();
+ inputText.setMargin(new Insets(5, 10, 10, 10));
+ inputText.setMinimumSize(new Dimension(0, 30));
+ inputText.setFont(baseFont.deriveFont(11f));
+ inputText.setEditable(false);
+ inputText.setFocusable(false);
+ messagePanel.add(inputText, BorderLayout.CENTER);
+
+ iconLabel = new JLabel();
+ messagePanel.add(iconLabel, BorderLayout.WEST);
+
+ add(inputPanel, BorderLayout.CENTER);
+
+ JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.TRAILING));
+ add(buttonPanel, BorderLayout.SOUTH);
+
+ okButton = new JButton("OK");
+ okButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ result = valid;
+ setVisible(false);
+ }
+ });
+ okButton.setEnabled(false);
+ buttonPanel.add(okButton);
+
+ cancelButton = new JButton("Cancel");
+ cancelButton.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ setVisible(false);
+ }
+ });
+ buttonPanel.add(cancelButton);
+
+ setModal(true);
+ setDefaultCloseOperation(HIDE_ON_CLOSE);
+ }
+
+ public void setMessage(String message) {
+ iconLabel.setIcon(null);
+ inputText.setText(message);
+ }
+
+ public void setWarningMessage(String message) {
+ iconLabel.setIcon(Icons.warningIcon);
+ inputText.setText(message);
+ }
+
+ public void setErrorMessage(String message) {
+ iconLabel.setIcon(Icons.severeIcon);
+ inputText.setText(message);
+ }
+
+ private void verify(String text, String inputMessage,
+ Set<String> invalidInputs, String invalidInputsMessage,
+ String inputRegularExpression, String inputRegularExpressionMessage) {
+ if (invalidInputs != null && invalidInputs.contains(text)) {
+ setErrorMessage(invalidInputsMessage);
+ valid = false;
+ } else if (inputRegularExpression != null
+ && !text.matches(inputRegularExpression)) {
+ setErrorMessage(inputRegularExpressionMessage);
+ valid = false;
+ } else {
+ setMessage(inputMessage);
+ valid = true;
+ }
+ okButton.setEnabled(valid);
+// okButton.setSelected(valid);
+ }
+
+ /**
+ * Show the dialog relative to the component. If the component is null then
+ * the dialog is shown in the centre of the screen.
+ *
+ * Returns true if the user input is valid.
+ *
+ * @param component
+ * the component that the dialog is shown relative to
+ * @return true if the user input is valid
+ */
+ public boolean show(Component component) {
+ setLocationRelativeTo(component);
+ setVisible(true);
+ dispose();
+ return result;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/f676ef35/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/icons/Icons.java
----------------------------------------------------------------------
diff --git a/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/icons/Icons.java b/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/icons/Icons.java
new file mode 100644
index 0000000..398b3f4
--- /dev/null
+++ b/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/icons/Icons.java
@@ -0,0 +1,48 @@
+/*******************************************************************************
+ * 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.lang.ui.icons;
+
+import javax.swing.ImageIcon;
+
+import org.apache.log4j.Logger;
+
+public class Icons {
+
+ private static Logger logger = Logger.getLogger(Icons.class);
+
+
+
+ public static ImageIcon okIcon;
+ public static ImageIcon severeIcon;
+ public static ImageIcon warningIcon;
+
+ static {
+ try {
+ Class c = Icons.class;
+ okIcon = new ImageIcon(c.getResource("ok.png"));
+ severeIcon = new ImageIcon(c.getResource("severe.png"));
+ warningIcon = new ImageIcon(c.getResource("warning.png"));
+
+ } catch (Exception ex) {
+ logger.error("Unable to load standard icons", ex);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/f676ef35/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/tabselector/ScrollController.java
----------------------------------------------------------------------
diff --git a/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/tabselector/ScrollController.java b/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/tabselector/ScrollController.java
new file mode 100644
index 0000000..f7218a6
--- /dev/null
+++ b/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/tabselector/ScrollController.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright (C) 2013 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.ui.tabselector;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JButton;
+import javax.swing.JComponent;
+
+/**
+ * Controls tab scrolling when there is not enough space to show all the tabs.
+ *
+ * @author David Withers
+ */
+public class ScrollController {
+
+ private int position;
+ private final JButton scrollLeft;
+ private final JButton scrollRight;
+
+ public ScrollController(final JComponent component) {
+ scrollLeft = new JButton("<");
+ scrollRight = new JButton(">");
+ scrollLeft.setOpaque(true);
+ scrollRight.setOpaque(true);
+ scrollLeft.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ increment();
+ component.doLayout();
+ }
+ });
+ scrollRight.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ decrement();
+ component.doLayout();
+ }
+ });
+ }
+
+ public JButton getScrollLeft() {
+ return scrollLeft;
+ }
+
+ public JButton getScrollRight() {
+ return scrollRight;
+ }
+
+ public int getPosition() {
+ return position;
+ }
+
+ public void reset() {
+ position = 0;
+ }
+
+ public void increment() {
+ position++;
+ }
+
+ public void decrement() {
+ position--;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/f676ef35/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/tabselector/Tab.java
----------------------------------------------------------------------
diff --git a/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/tabselector/Tab.java b/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/tabselector/Tab.java
new file mode 100644
index 0000000..3c40b42
--- /dev/null
+++ b/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/tabselector/Tab.java
@@ -0,0 +1,200 @@
+/*******************************************************************************
+ * Copyright (C) 2012 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.ui.tabselector;
+
+import java.awt.BasicStroke;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.RenderingHints;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.Icon;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JToggleButton;
+import javax.swing.plaf.basic.BasicButtonUI;
+
+/**
+ * Tab button that includes a label and a close button.
+ *
+ * @author David Withers
+ */
+public abstract class Tab<T> extends JToggleButton {
+
+ private static final long serialVersionUID = 1L;
+
+ public final static Color midGrey = new Color(160,160,160);
+ public final static Color lightGrey = new Color(200,200,200);
+
+ protected final T selection;
+ private String name;
+ private Icon icon;
+ private JLabel label;
+
+ public Tab(String name, T selection) {
+ this(name, null, selection);
+ }
+
+ public Tab(String name, Icon icon, T selection) {
+ this.name = name;
+ this.icon = icon;
+ this.selection = selection;
+ initialise();
+ }
+
+ private void initialise() {
+ setUI(new BasicButtonUI());
+ setLayout(new GridBagLayout());
+ setOpaque(false);
+ setBackground(Color.red);
+ setBorder(null);
+
+ GridBagConstraints c = new GridBagConstraints();
+
+ label = new JLabel(this.name);
+ label.setIcon(icon);
+ c.anchor = GridBagConstraints.WEST;
+ c.fill = GridBagConstraints.BOTH;
+ c.insets = new Insets(0, 5, 0, 5);
+ c.weightx = 1;
+ add(label, c);
+
+ JButton button = new CloseWorkflowButton();
+ c.fill = GridBagConstraints.NONE;
+ c.insets = new Insets(0, 0, 0, 5);
+ c.weightx = 0;
+ add(button, c);
+
+ addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ clickTabAction();
+ }
+ });
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ if (!this.name.equals(name)) {
+ this.name = name;
+ label.setText(name);
+ repaint();
+ }
+ }
+
+ public void setIcon(Icon icon) {
+ label.setIcon(icon);
+ repaint();
+ }
+
+ @Override
+ public void updateUI() {
+ // override to ignore UI update
+ }
+
+ @Override
+ protected void paintComponent(Graphics g) {
+ super.paintComponent(g);
+ Graphics2D g2 = (Graphics2D) g.create();
+ if (getModel().isPressed()) {
+ g2.translate(1, 1);
+ }
+ if (!getModel().isSelected()) {
+ g2.setColor(lightGrey);
+ g2.fillRoundRect(1, 0, getWidth() - 3, getHeight() - 1, 4, 10);
+ }
+ g2.setColor(midGrey);
+ g2.drawRoundRect(1, 0, getWidth() - 3, getHeight(), 4, 10);
+ if (getModel().isSelected()) {
+ g2.setColor(getParent().getBackground());
+ g2.drawLine(1, getHeight() - 1, getWidth() - 2, getHeight() - 1);
+ }
+ g2.dispose();
+ }
+
+ protected abstract void clickTabAction();
+
+ protected abstract void closeTabAction();
+
+ @SuppressWarnings("serial")
+ private class CloseWorkflowButton extends JButton {
+
+ private final int size = 15;
+ private final int border = 4;
+
+ public CloseWorkflowButton() {
+ setUI(new BasicButtonUI());
+ setPreferredSize(new Dimension(size, size));
+ setMinimumSize(new Dimension(size, size));
+ setContentAreaFilled(false);
+ setFocusable(false);
+ setToolTipText("Close workflow");
+
+ setRolloverEnabled(true);
+ addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ closeTabAction();
+ }
+ });
+ }
+
+ @Override
+ public void updateUI() {
+ // override to ignore UI update
+ }
+
+ @Override
+ protected void paintComponent(Graphics g) {
+ super.paintComponent(g);
+ Graphics2D g2 = (Graphics2D) g.create();
+ // animate button press
+ if (getModel().isPressed()) {
+ g2.translate(1, 1);
+ }
+ g2.setColor(midGrey);
+ if (getModel().isRollover()) {
+ // draw armed button
+ g2.fillRoundRect(0, 0, size - 1, size - 1, 4, 4);
+ g2.setColor(Color.GRAY);
+ g2.drawRoundRect(0, 0, size - 1, size - 1, 4, 4);
+ g2.setColor(Color.RED);
+ }
+ // draw 'x'
+ g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
+ g2.setStroke(new BasicStroke(2.5f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL));
+ g2.drawLine(border, border, size - border, size - border);
+ g2.drawLine(border, size - border, size - border, border);
+ g2.dispose();
+ }
+
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/f676ef35/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/tabselector/TabLayout.java
----------------------------------------------------------------------
diff --git a/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/tabselector/TabLayout.java b/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/tabselector/TabLayout.java
new file mode 100644
index 0000000..2a12f0e
--- /dev/null
+++ b/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/tabselector/TabLayout.java
@@ -0,0 +1,135 @@
+/*******************************************************************************
+ * Copyright (C) 2012 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.ui.tabselector;
+
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Insets;
+import java.awt.LayoutManager;
+
+/**
+ * LayoutManager for laying out tabs.
+ * <p>
+ * Tabs are made all the same width and prefer to be maximumTabWidth. If there is more than
+ * preferred width available extra space is left blank. If there is not enough width for tabs to be
+ * maximumTabWidth tab width is reduced until it reaches minimumTabWidth. If there is not enough
+ * width to show tabs at minimumTabWidth scroll buttons are shows and tabs can be scrolled within
+ * the available width.
+ *
+ * @author David Withers
+ */
+public class TabLayout implements LayoutManager {
+
+ public static final int DEFAULT_MINIMUM_TAB_WIDTH = 100;
+ public static final int DEFAULT_MAXIMUM_TAB_WIDTH = 250;
+ public static final int DEFAULT_TAB_HEIGHT = 22;
+ public static final int DEFAULT_SCROLL_BUTTON_WIDTH = 22;
+
+ private final int minimumTabWidth, maximumTabWidth, tabHeight, scrollButtonWidth;
+ private final ScrollController scrollController;
+
+ public TabLayout(ScrollController scrollController) {
+ this(scrollController, DEFAULT_MINIMUM_TAB_WIDTH, DEFAULT_MAXIMUM_TAB_WIDTH,
+ DEFAULT_TAB_HEIGHT, DEFAULT_SCROLL_BUTTON_WIDTH);
+ }
+
+ public TabLayout(ScrollController scrollController, int minimumTabWidth, int maximumTabWidth,
+ int tabHeight, int scrollButtonWidth) {
+ this.scrollController = scrollController;
+ this.minimumTabWidth = minimumTabWidth;
+ this.maximumTabWidth = maximumTabWidth;
+ this.tabHeight = tabHeight;
+ this.scrollButtonWidth = scrollButtonWidth;
+ }
+
+ @Override
+ public void removeLayoutComponent(Component comp) {
+ }
+
+ @Override
+ public void layoutContainer(Container parent) {
+ Component[] components = parent.getComponents();
+ int tabs = components.length - 2;
+ if (tabs > 0) {
+ Insets insets = parent.getInsets();
+ int x = insets.left;
+ int y = insets.top;
+ int availableWidth = parent.getWidth() - insets.left - insets.right;
+ int tabWidth = availableWidth / tabs;
+ boolean showScrollButtons = false;
+ if (tabWidth < minimumTabWidth) {
+ tabWidth = minimumTabWidth;
+ showScrollButtons = true;
+ } else if (tabWidth > maximumTabWidth) {
+ tabWidth = maximumTabWidth;
+ }
+ if (showScrollButtons) {
+ scrollController.getScrollLeft().setLocation(x, y);
+ scrollController.getScrollLeft().setSize(
+ new Dimension(scrollButtonWidth, tabHeight));
+ scrollController.getScrollLeft().setVisible(true);
+ scrollController.getScrollLeft().setEnabled(shouldScrollLeft(tabs, availableWidth));
+ x = x + scrollButtonWidth - (scrollController.getPosition() * minimumTabWidth);
+ scrollController.getScrollRight()
+ .setLocation(availableWidth - scrollButtonWidth, y);
+ scrollController.getScrollRight().setSize(
+ new Dimension(scrollButtonWidth, tabHeight));
+ scrollController.getScrollRight().setVisible(true);
+ scrollController.getScrollRight().setEnabled(scrollController.getPosition() > 0);
+ } else {
+ scrollController.getScrollLeft().setVisible(false);
+ scrollController.getScrollRight().setVisible(false);
+ scrollController.reset();
+ }
+ for (int i = 2; i < components.length; i++) {
+ components[i].setLocation(x, y);
+ components[i].setSize(new Dimension(tabWidth, tabHeight));
+ x = x + tabWidth;
+ }
+ }
+ }
+
+ @Override
+ public void addLayoutComponent(String name, Component comp) {
+ }
+
+ @Override
+ public Dimension minimumLayoutSize(Container parent) {
+ return calculateSize(parent.getInsets(), 2, minimumTabWidth);
+ }
+
+ @Override
+ public Dimension preferredLayoutSize(Container parent) {
+ return calculateSize(parent.getInsets(), parent.getComponents().length, maximumTabWidth);
+ }
+
+ private Dimension calculateSize(Insets insets, int tabs, int tabWidth) {
+ int width = insets.left + insets.right + tabs * tabWidth;
+ int height = insets.top + insets.bottom + tabHeight;
+ return new Dimension(width, height);
+ }
+
+ private boolean shouldScrollLeft(int tabs, int availableWidth) {
+ int tabsToShow = tabs - scrollController.getPosition();
+ return (tabsToShow * minimumTabWidth) > (availableWidth - (scrollButtonWidth * 2));
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/f676ef35/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/tabselector/TabSelectorComponent.java
----------------------------------------------------------------------
diff --git a/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/tabselector/TabSelectorComponent.java b/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/tabselector/TabSelectorComponent.java
new file mode 100644
index 0000000..d09b6ec
--- /dev/null
+++ b/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/tabselector/TabSelectorComponent.java
@@ -0,0 +1,99 @@
+/*******************************************************************************
+ * Copyright (C) 2012 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.ui.tabselector;
+
+import java.awt.BorderLayout;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.swing.ButtonGroup;
+import javax.swing.JPanel;
+
+/**
+ * Component for selecting objects using tabs.
+ *
+ * @author David Withers
+ */
+public abstract class TabSelectorComponent<T> extends JPanel {
+
+ private static final long serialVersionUID = 1L;
+
+ private Map<T, Tab<T>> tabMap;
+ private ButtonGroup tabGroup;
+ private ScrollController scrollController;
+
+ public TabSelectorComponent() {
+ tabMap = new HashMap<T, Tab<T>>();
+ tabGroup = new ButtonGroup();
+ setLayout(new BorderLayout());
+ scrollController = new ScrollController(this);
+ add(scrollController.getScrollLeft());
+ add(scrollController.getScrollRight());
+ setLayout(new TabLayout(scrollController));
+ }
+
+ @Override
+ protected void paintComponent(Graphics g) {
+ super.paintComponent(g);
+ Graphics2D g2 = (Graphics2D) g.create();
+ g2.setColor(Tab.midGrey);
+ g2.drawLine(0, getHeight() - 1, getWidth(), getHeight() - 1);
+ g2.dispose();
+ }
+
+ protected abstract Tab<T> createTab(T object);
+
+ public Tab<T> getTab(T object) {
+ return tabMap.get(object);
+ }
+
+ public void addObject(T object) {
+ Tab<T> button = createTab(object);
+ tabMap.put(object, button);
+ tabGroup.add(button);
+ add(button);
+ revalidate();
+ repaint();
+ button.setSelected(true);
+ }
+
+ public void removeObject(T object) {
+ Tab<T> button = tabMap.remove(object);
+ if (button != null) {
+ tabGroup.remove(button);
+ remove(button);
+ revalidate();
+ repaint();
+ }
+ }
+
+ public void selectObject(T object) {
+ Tab<T> button = tabMap.get(object);
+ if (button != null) {
+ button.setSelected(true);
+ } else {
+ addObject(object);
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/f676ef35/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/treetable/AbstractCellEditor.java
----------------------------------------------------------------------
diff --git a/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/treetable/AbstractCellEditor.java b/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/treetable/AbstractCellEditor.java
new file mode 100644
index 0000000..63827bb
--- /dev/null
+++ b/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/treetable/AbstractCellEditor.java
@@ -0,0 +1,81 @@
+/*******************************************************************************
+ * 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.lang.ui.treetable;
+
+import java.util.EventObject;
+
+import javax.swing.CellEditor;
+import javax.swing.event.CellEditorListener;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.EventListenerList;
+
+public class AbstractCellEditor implements CellEditor {
+
+ protected EventListenerList listenerList = new EventListenerList();
+
+ public Object getCellEditorValue() { return null; }
+ public boolean isCellEditable(EventObject e) { return true; }
+ public boolean shouldSelectCell(EventObject anEvent) { return false; }
+ public boolean stopCellEditing() { return true; }
+ public void cancelCellEditing() {}
+
+ public void addCellEditorListener(CellEditorListener l) {
+ listenerList.add(CellEditorListener.class, l);
+ }
+
+ public void removeCellEditorListener(CellEditorListener l) {
+ listenerList.remove(CellEditorListener.class, l);
+ }
+
+ /*
+ * Notify all listeners that have registered interest for
+ * notification on this event type.
+ * @see EventListenerList
+ */
+ protected void fireEditingStopped() {
+ // Guaranteed to return a non-null array
+ Object[] listeners = listenerList.getListenerList();
+ // Process the listeners last to first, notifying
+ // those that are interested in this event
+ for (int i = listeners.length-2; i>=0; i-=2) {
+ if (listeners[i]==CellEditorListener.class) {
+ ((CellEditorListener)listeners[i+1]).editingStopped(new ChangeEvent(this));
+ }
+ }
+ }
+
+ /*
+ * Notify all listeners that have registered interest for
+ * notification on this event type.
+ * @see EventListenerList
+ */
+ protected void fireEditingCanceled() {
+ // Guaranteed to return a non-null array
+ Object[] listeners = listenerList.getListenerList();
+ // Process the listeners last to first, notifying
+ // those that are interested in this event
+ for (int i = listeners.length-2; i>=0; i-=2) {
+ if (listeners[i]==CellEditorListener.class) {
+ ((CellEditorListener)listeners[i+1]).editingCanceled(new ChangeEvent(this));
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/f676ef35/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/treetable/AbstractTreeTableModel.java
----------------------------------------------------------------------
diff --git a/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/treetable/AbstractTreeTableModel.java b/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/treetable/AbstractTreeTableModel.java
new file mode 100644
index 0000000..afec8f3
--- /dev/null
+++ b/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/treetable/AbstractTreeTableModel.java
@@ -0,0 +1,198 @@
+/*
+ * @(#)AbstractTreeTableModel.java 1.2 98/10/27
+ *
+ * Copyright 1997, 1998 by Sun Microsystems, Inc.,
+ * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
+ * All rights reserved.
+ *
+ * This software is the confidential and proprietary information
+ * of Sun Microsystems, Inc. ("Confidential Information"). You
+ * shall not disclose such Confidential Information and shall use
+ * it only in accordance with the terms of the license agreement
+ * you entered into with Sun.
+ */
+package net.sf.taverna.t2.lang.ui.treetable;
+
+import javax.swing.event.EventListenerList;
+import javax.swing.event.TreeModelEvent;
+import javax.swing.event.TreeModelListener;
+import javax.swing.tree.TreePath;
+
+/**
+ * @version 1.2 10/27/98
+ * An abstract implementation of the TreeTableModel interface, handling the list
+ * of listeners.
+ * @author Philip Milne
+ */
+
+public abstract class AbstractTreeTableModel implements TreeTableModel {
+ protected Object root;
+ protected EventListenerList listenerList = new EventListenerList();
+
+ public AbstractTreeTableModel(Object root) {
+ this.root = root;
+ }
+
+ //
+ // Default implementations for methods in the TreeModel interface.
+ //
+
+ public Object getRoot() {
+ return root;
+ }
+
+ public boolean isLeaf(Object node) {
+ return getChildCount(node) == 0;
+ }
+
+ public void valueForPathChanged(TreePath path, Object newValue) {}
+
+ // This is not called in the JTree's default mode: use a naive implementation.
+ public int getIndexOfChild(Object parent, Object child) {
+ for (int i = 0; i < getChildCount(parent); i++) {
+ if (getChild(parent, i).equals(child)) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ public void addTreeModelListener(TreeModelListener l) {
+ listenerList.add(TreeModelListener.class, l);
+ }
+
+ public void removeTreeModelListener(TreeModelListener l) {
+ listenerList.remove(TreeModelListener.class, l);
+ }
+
+ /*
+ * Notify all listeners that have registered interest for
+ * notification on this event type. The event instance
+ * is lazily created using the parameters passed into
+ * the fire method.
+ * @see EventListenerList
+ */
+ protected void fireTreeNodesChanged(Object source, Object[] path,
+ int[] childIndices,
+ Object[] children) {
+ // Guaranteed to return a non-null array
+ Object[] listeners = listenerList.getListenerList();
+ TreeModelEvent e = null;
+ // Process the listeners last to first, notifying
+ // those that are interested in this event
+ for (int i = listeners.length-2; i>=0; i-=2) {
+ if (listeners[i]==TreeModelListener.class) {
+ // Lazily create the event:
+ if (e == null)
+ e = new TreeModelEvent(source, path,
+ childIndices, children);
+ ((TreeModelListener)listeners[i+1]).treeNodesChanged(e);
+ }
+ }
+ }
+
+ /*
+ * Notify all listeners that have registered interest for
+ * notification on this event type. The event instance
+ * is lazily created using the parameters passed into
+ * the fire method.
+ * @see EventListenerList
+ */
+ protected void fireTreeNodesInserted(Object source, Object[] path,
+ int[] childIndices,
+ Object[] children) {
+ // Guaranteed to return a non-null array
+ Object[] listeners = listenerList.getListenerList();
+ TreeModelEvent e = null;
+ // Process the listeners last to first, notifying
+ // those that are interested in this event
+ for (int i = listeners.length-2; i>=0; i-=2) {
+ if (listeners[i]==TreeModelListener.class) {
+ // Lazily create the event:
+ if (e == null)
+ e = new TreeModelEvent(source, path,
+ childIndices, children);
+ ((TreeModelListener)listeners[i+1]).treeNodesInserted(e);
+ }
+ }
+ }
+
+ /*
+ * Notify all listeners that have registered interest for
+ * notification on this event type. The event instance
+ * is lazily created using the parameters passed into
+ * the fire method.
+ * @see EventListenerList
+ */
+ protected void fireTreeNodesRemoved(Object source, Object[] path,
+ int[] childIndices,
+ Object[] children) {
+ // Guaranteed to return a non-null array
+ Object[] listeners = listenerList.getListenerList();
+ TreeModelEvent e = null;
+ // Process the listeners last to first, notifying
+ // those that are interested in this event
+ for (int i = listeners.length-2; i>=0; i-=2) {
+ if (listeners[i]==TreeModelListener.class) {
+ // Lazily create the event:
+ if (e == null)
+ e = new TreeModelEvent(source, path,
+ childIndices, children);
+ ((TreeModelListener)listeners[i+1]).treeNodesRemoved(e);
+ }
+ }
+ }
+
+ /*
+ * Notify all listeners that have registered interest for
+ * notification on this event type. The event instance
+ * is lazily created using the parameters passed into
+ * the fire method.
+ * @see EventListenerList
+ */
+ protected void fireTreeStructureChanged(Object source, Object[] path,
+ int[] childIndices,
+ Object[] children) {
+ // Guaranteed to return a non-null array
+ Object[] listeners = listenerList.getListenerList();
+ TreeModelEvent e = null;
+ // Process the listeners last to first, notifying
+ // those that are interested in this event
+ for (int i = listeners.length-2; i>=0; i-=2) {
+ if (listeners[i]==TreeModelListener.class) {
+ // Lazily create the event:
+ if (e == null)
+ e = new TreeModelEvent(source, path,
+ childIndices, children);
+ ((TreeModelListener)listeners[i+1]).treeStructureChanged(e);
+ }
+ }
+ }
+
+ //
+ // Default impelmentations for methods in the TreeTableModel interface.
+ //
+
+ public Class getColumnClass(int column) { return Object.class; }
+
+ /** By default, make the column with the Tree in it the only editable one.
+ * Making this column editable causes the JTable to forward mouse
+ * and keyboard events in the Tree column to the underlying JTree.
+ */
+ public boolean isCellEditable(Object node, int column) {
+ return getColumnClass(column) == TreeTableModel.class;
+ }
+
+ public void setValueAt(Object aValue, Object node, int column) {}
+
+
+ // Left to be implemented in the subclass:
+
+ /*
+ * public Object getChild(Object parent, int index)
+ * public int getChildCount(Object parent)
+ * public int getColumnCount()
+ * public String getColumnName(Object node, int column)
+ * public Object getValueAt(Object node, int column)
+ */
+}
http://git-wip-us.apache.org/repos/asf/incubator-taverna-workbench/blob/f676ef35/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/treetable/JTreeTable.LICENSE
----------------------------------------------------------------------
diff --git a/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/treetable/JTreeTable.LICENSE b/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/treetable/JTreeTable.LICENSE
new file mode 100644
index 0000000..7500c7a
--- /dev/null
+++ b/taverna-ui/src/main/java/net/sf/taverna/t2/lang/ui/treetable/JTreeTable.LICENSE
@@ -0,0 +1,59 @@
+The license below applies to the classes contained within the
+package net.sf.taverna.t2.lang.ui.treetable package. These classes have been taken
+from the Sun Developer Network tutorial on using JTree components within JTables. The URLs for the tutorials are as follows :
+
+http://java.sun.com/products/jfc/tsc/articles/treetable1/index.html
+http://java.sun.com/products/jfc/tsc/articles/treetable2/index.html
+http://java.sun.com/products/jfc/tsc/articles/bookmarks/index.html#editableJTreeTable
+
+The original web page form of this license is available at :
+
+http://developers.sun.com/license/berkeley_license.html?uid=6910008
+
+Tom Oinn, tmo@ebi.ac.uk, 23rd Feb 2004
+
+-------------------------------------------------------------------------------------
+
+Code sample
+
+License
+
+ Copyright 1994-2004 Sun Microsystems, Inc. All Rights Reserved.
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+
+ 1 Redistribution of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+
+ 2 Redistribution in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+
+ Neither the name of Sun Microsystems, Inc. or the names of contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+
+ This software is provided "AS IS," without a warranty of any kind. ALL
+ EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
+ ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
+ OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MICROSYSTEMS, INC. ("SUN")
+ AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
+ AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
+ DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
+ REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
+ INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE
+ THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS
+ SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+
+
+ You acknowledge that this software is not designed, licensed or intended
+ for use in the design, construction, operation or maintenance of any
+ nuclear facility.
+
+-------------------------------------------------------------------------------------
\ No newline at end of file