You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by pp...@apache.org on 2010/10/05 21:22:19 UTC
svn commit: r1004775 [2/3] - in /openjpa/tools/trunk/openjpa-tools/src/main:
java/org/apache/openjpa/swing/ java/org/apache/openjpa/swing/graph/
java/org/apache/openjpa/swing/layout/ java/org/apache/openjpa/swing/print/
java/org/apache/openjpa/tools/ j...
Added: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/EdgeRenderer.java
URL: http://svn.apache.org/viewvc/openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/EdgeRenderer.java?rev=1004775&view=auto
==============================================================================
--- openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/EdgeRenderer.java (added)
+++ openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/EdgeRenderer.java Tue Oct 5 19:22:16 2010
@@ -0,0 +1,61 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+package org.apache.openjpa.swing.graph;
+
+import java.awt.Graphics2D;
+import java.awt.geom.Path2D;
+
+import javax.swing.JLabel;
+
+
+
+
+/**
+ * Renders an edge with decorations such as arrows or line styles.
+ *
+ * @author Pinaki Poddar
+ *
+ */
+public interface EdgeRenderer<V> {
+ /**
+ * Render the given edge as the given path.
+ * Decorate with annotations or arrows, if possible.
+ * @param g the graphics context
+ * @param edgePath the coordinates for the edge.
+ * @param edge that actual edge instance being rendered
+ * @return true if Graphics context has been modified.
+ */
+ public void render(Graphics2D g, Path2D edgePath, Edge<V,V> edge);
+
+ /**
+ * Gets the text for the edge label.
+ *
+ * @param edge
+ * @return null if no label is to be printed. The text string should be returned without any
+ * HTML tags. Because the text is used to determine the bounds and position where the label
+ * can be displayed.
+ */
+ public String getLabelText(Edge<V,V> edge);
+
+ /**
+ * Gets the JLabel for the edge label text.
+ *
+ * @param text The text obtained in a {@link #getLabelText(Edge)} method.
+ * It is done in two steps so that the label can be created with HTML decoration.
+ *
+ * @return a JLabel to be displayed as edge label
+ */
+ public JLabel getLabel(String text);
+
+}
Propchange: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/EdgeRenderer.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/EdgeRenderer.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/EdgeRouter.java
URL: http://svn.apache.org/viewvc/openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/EdgeRouter.java?rev=1004775&view=auto
==============================================================================
--- openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/EdgeRouter.java (added)
+++ openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/EdgeRouter.java Tue Oct 5 19:22:16 2010
@@ -0,0 +1,45 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+package org.apache.openjpa.swing.graph;
+
+import java.awt.geom.Path2D;
+
+
+/**
+ * Computes the path for an edge between two vertices. The
+ * {@linkplain PlacementPlanner} provides the layout information such as the
+ * {@linkplain PlacementPlanner#getBounds(Object) geometric bounds} for the
+ * terminal nodes of a graph or whether a region of the layout is
+ * {@linkplain PlacementPlanner#isReachable(java.awt.geom.Point2D) occupied}.
+ *
+ * @author Pinaki Poddar
+ *
+ * @param <V>
+ * the type of the nodes.
+ */
+public interface EdgeRouter<V> {
+ /**
+ * Compute a path for the given edge in consultation with the placement of
+ * the nodes as provided by the {@linkplain PlacementPlanner planner}.
+ *
+ * @param edge
+ * an edge for which the path is to be computed.
+ * @param source
+ * holds the information about where the nodes are located.
+ * @param target
+ * TODO
+ * @return a path for the edge.
+ */
+ Path2D route(Edge<V, V> edge, Connectable<V> source, Connectable<V> target);
+}
Propchange: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/EdgeRouter.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/EdgeRouter.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/GraphModel.java
URL: http://svn.apache.org/viewvc/openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/GraphModel.java?rev=1004775&view=auto
==============================================================================
--- openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/GraphModel.java (added)
+++ openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/GraphModel.java Tue Oct 5 19:22:16 2010
@@ -0,0 +1,78 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+package org.apache.openjpa.swing.graph;
+
+import java.util.Set;
+
+
+/**
+ * A model for a graph.
+ *
+ * @author Pinaki Poddar
+ *
+ * @param <V> the type of vertex
+ */
+public interface GraphModel<V> {
+ /**
+ * Add a vertex.
+ */
+ void addVertex(V v);
+
+ /**
+ * Gets the vertices.
+ */
+ Iterable<V> getNodes();
+
+ /**
+ * Gets the edges.
+ */
+ Iterable<Edge<V,V>> getEdges();
+
+ /**
+ * Gets the outgoing edges of the given node.
+ */
+ Set<Edge<V,V>> getOutEdges(V v);
+
+ /**
+ * Links two vertices.
+ *
+ * @return an edge created by the current edge factory.
+ */
+ Edge<V,V> link(V v1, V v2);
+
+ /**
+ * Adds an edge.
+ */
+ <V1 extends V,V2 extends V> void link(Edge<V1, V2> edge);
+
+ /**
+ * Affirms if an edge exists between the given vertices.
+ */
+ boolean isLinked(V v1, V v2);
+
+ /**
+ * Gets the edge between the vertices, if any.
+ */
+ Edge<V,V> getEdge(V v1, V v2);
+
+ /**
+ * Sets the factory to create edges.
+ */
+ void setEdgeFactory(EdgeFactory<V,V> factory);
+
+ /**
+ * Sets the factory to create edges.
+ */
+ EdgeFactory<V,V> getEdgeFactory();
+}
Propchange: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/GraphModel.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/GraphModel.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/GraphPanel.java
URL: http://svn.apache.org/viewvc/openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/GraphPanel.java?rev=1004775&view=auto
==============================================================================
--- openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/GraphPanel.java (added)
+++ openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/GraphPanel.java Tue Oct 5 19:22:16 2010
@@ -0,0 +1,515 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+package org.apache.openjpa.swing.graph;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Cursor;
+import java.awt.FontMetrics;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Insets;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.awt.event.MouseMotionListener;
+import java.awt.geom.Path2D;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+
+import javax.swing.BorderFactory;
+import javax.swing.CellRendererPane;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.border.Border;
+
+import org.apache.openjpa.swing.Geometry;
+import org.apache.openjpa.swing.layout.FRLayoutManager;
+
+/**
+ * Swing component for visualization of graph. The graph state is represented via {@linkplain GraphModel}
+ * interface.
+ * <br>
+ * This implementation uses configurable factories to convert the vertices and edges
+ * to visual component and shape respectively. The vertices are converted to Swing components
+ * via {@link NodeViewFactory#getComponent(Object)}. The nodes of different types can be produced by
+ * one or more registered factories. A {@link DefaultNodeFactory default factory} is used by default
+ * to simply a vertex as a JLabel.
+ * <p>
+ * <B>Painting</B>: The Swing components for the vertices are added as children of this container
+ * and hence their painting is controlled by the AWT painting framework itself.
+ * <br>
+ * The shapes are likewise produced by a {@link EdgeViewFactory}. However, unlike vertices, the edge
+ * shapes and annotations are rendered directly by this component via its {@link EdgeRenderer} interface.
+ * <br>
+ * This component lays out, by default, through a {@link FRLayoutManager experimental Layout Manager} that
+ * employs fore-directed spring layout algorithm for absolute positioning of the nodes.
+ *
+ * <p>
+ * <B>Event Management</B>: The vertices can be dragged around with mouse. The edges will be redrawn
+ * when a component is moved.
+ *
+ * <B>Important:</B>Set node/edge factory before setting the graph model.
+ *
+ * @author Pinaki Poddar
+ *
+ * @param <V> the type of graph nodes
+ */
+@SuppressWarnings("serial")
+public class GraphPanel<V> extends JPanel implements MouseListener, MouseMotionListener {
+ // the underlying graph data model
+ private GraphModel<V> model;
+ private Map<V, Connectable<V>> components = new HashMap<V, Connectable<V>>();
+ private Map<Edge<V,V>, Path2D> edgePaths = new HashMap<Edge<V,V>, Path2D>();
+
+ private Map<Class<V>,NodeViewFactory<V>> nodeFactories;
+ protected NodeViewFactory<V> defaultNodeFactory;
+
+ private Map<Class<? extends Edge<?,?>>, EdgeRenderer<V>> edgeRenderers;
+ private Map<Class<? extends Edge<?,?>>, EdgeRouter<V>> edgeRouters;
+ private EdgeRenderer<V> defaultEdgeRenderer;
+ private EdgeRouter<V> defaultEdgeRouter;
+ private List<Mask<V>> nodeMasks;
+ private List<Mask<Edge<V,V>>> edgeMasks;
+ private boolean showEdgeLabels = true;
+ private Rectangle dimension = new Rectangle(0,0,0,0);
+ private Rectangle cdimension = new Rectangle(0,0,0,0);
+ private Insets insets = new Insets(0,0,0,0);
+
+ private static final String USER_OBJECT = "vertex";
+
+ public GraphPanel() {
+ super(true);
+ setLayout(new FRLayoutManager(this));
+ setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
+ setOpaque(true);
+ setBackground(Color.WHITE);
+ defaultNodeFactory = new DefaultNodeFactory<V>();
+ defaultEdgeRenderer = new DefaultEdgeRenderer<V>();
+ defaultEdgeRouter = new RectilinearEdgeRouter<V>();
+ nodeMasks = new ArrayList<Mask<V>>();
+ edgeMasks = new ArrayList<Mask<Edge<V,V>>>();
+ addMouseListener(this);
+ addMouseMotionListener(this);
+ }
+
+ public void setModel(GraphModel<V> graph) {
+ components.clear();
+ edgePaths.clear();
+ this.model = graph;
+ initialize();
+ }
+
+ public GraphModel<V> getModel() {
+ return model;
+ }
+
+
+ /**
+ * Initializes the view.
+ * Creates the visual components for each graph node if they have not been created before.
+ */
+ private void initialize() {
+ if (model == null)
+ return;
+ for (V v : model.getNodes()) {
+ if (!components.containsKey(v)) {
+ if (mask(v)) continue;
+ Connectable<V> c = getNodeFactory(v).createComponent(v,null);
+ c.asComponent().putClientProperty(USER_OBJECT, v);
+ components.put(v,c);
+ }
+ }
+ for (V v : model.getNodes()) {
+ if (mask(v)) continue;
+ Connectable<V> c = components.get(v);
+ Set<Edge<V,V>> edges = model.getOutEdges(v);
+ List<Connectable<V>> links = new ArrayList<Connectable<V>>();
+ for (Edge<V,V> e : edges) {
+ if (mask(e)) continue;
+ links.add(components.get(e.getTarget()));
+ }
+ add(c.asComponent(), links);
+ }
+ }
+
+ /**
+ * Registers a factory to create visual widget for the given type of node.
+ *
+ */
+ public void setNodeFactory(Class<V> type, NodeViewFactory<V> creator) {
+ if (nodeFactories == null) {
+ nodeFactories = new HashMap<Class<V>, NodeViewFactory<V>>();
+ }
+ nodeFactories.put(type, creator);
+ }
+
+ /**
+ * Sets the node factory to be used as default.
+ * @param creator can not be null.
+ */
+ public void setDefaultNodeFactory(NodeViewFactory<V> creator) {
+ if (creator != null) {
+ defaultNodeFactory = creator;
+ } else {
+ throw new IllegalArgumentException("Can not set null factory as default");
+ }
+ }
+
+ /**
+ * Gets the factory that creates widgets for the given node.
+ * If no specific factory has been registered for the type of the given node
+ * returns a default factory.
+ */
+ public NodeViewFactory<V> getNodeFactory(V node) {
+ if (nodeFactories != null && nodeFactories.containsKey(node.getClass()))
+ return nodeFactories.get(node.getClass());
+ return defaultNodeFactory;
+ }
+
+ /**
+ * Gets the renderer that will draw the given edge.
+ */
+ public EdgeRenderer<V> getEdgeRenderer(Edge<V,V> edge) {
+ if (edgeRenderers != null && edgeRenderers.containsKey(edge.getClass()))
+ return edgeRenderers.get(edge.getClass());
+ return defaultEdgeRenderer;
+ }
+
+ public void setEdgeRenderer(Class<? extends Edge<?,?>> edgeType, EdgeRenderer<V> renderer) {
+ if (edgeRenderers == null) {
+ edgeRenderers = new HashMap<Class<? extends Edge<?,?>>, EdgeRenderer<V>>();
+ }
+ edgeRenderers.put(edgeType, renderer);
+ }
+
+ /**
+ * Gets the route that will find route for the given edge.
+ */
+ public EdgeRouter<V> getEdgeRouter(Edge<V,V> edge) {
+ if (edgeRouters != null && edgeRouters.containsKey(edge.getClass()))
+ return edgeRouters.get(edge.getClass());
+ return defaultEdgeRouter;
+ }
+
+ public void setEdgeRouter(Class<Edge<?,?>> edgeType, EdgeRouter<V> router) {
+ if (edgeRouters == null) {
+ edgeRouters = new HashMap<Class<? extends Edge<?,?>>, EdgeRouter<V>>();
+ }
+ edgeRouters.put(edgeType, router);
+ }
+
+ /**
+ * Sets the default renderer to be used for drawing edges.
+ *
+ * @param renderer can not be null.
+ */
+ public void setDefaultEdgeRenderer(EdgeRenderer<V> renderer) {
+ if (renderer != null) {
+ defaultEdgeRenderer = renderer;
+ } else {
+ throw new IllegalArgumentException("Can not set null edge renderer as default");
+ }
+ }
+
+ /**
+ * Gets the component corresponding to the given node.
+ */
+ private Connectable<V> getConnectable(V node) {
+ return components.get(node);
+ }
+
+
+ /**
+ * Overrides painting by drawing the edges directly.
+ */
+ @Override
+ public void paintComponent(Graphics g) {
+ if (model == null)
+ return;
+ super.paintComponent(g); // paints the nodes as child components
+ drawEdges((Graphics2D)g); // edges are drawn directly on the graphics surface
+ }
+
+ private void drawEdges(Graphics2D g2) {
+ if (g2 == null)
+ return;
+ CellRendererPane labelRenderer = new CellRendererPane();
+ EdgeRouter<V> router = null;
+ for (Edge<V,V> edge : model.getEdges()) {
+ if (mask(edge)) continue;
+ router = getEdgeRouter(edge);
+ if (router == null) continue;
+ Path2D path = router.route(edge,
+ getConnectable(edge.getSource()), getConnectable(edge.getTarget()));
+ edgePaths.put(edge, path);
+ EdgeRenderer<V> edgeRenderer = getEdgeRenderer(edge);
+ if (edgeRenderer != null) {
+ Graphics2D gcopy = (Graphics2D)g2.create();
+ edgeRenderer.render(gcopy, path, edge);
+ if (showEdgeLabels) {
+ String text = edgeRenderer.getLabelText(edge);
+ Rectangle position = getTextPositionOnPath(gcopy, path, text);
+ JLabel label = edgeRenderer.getLabel(text);
+ labelRenderer.paintComponent(gcopy, label, this, position);
+ }
+ }
+ }
+ }
+
+ Rectangle getTextPositionOnPath(Graphics g, Path2D path, String text) {
+ List<Point2D> pts = Geometry.getLineSegments(path);
+ Point2D p1 = null;
+ Point2D p2 = null;
+ FontMetrics fm = g.getFontMetrics();
+ Rectangle2D S = fm.getStringBounds(text, g);
+ double sw = S.getWidth()*1.2; // if the text is rendered bold, will take more space
+ double sh = S.getHeight();
+ double dmax = 0;
+ Rectangle2D r = null;
+ for (int i = 0; i < pts.size()-1; i++) {
+ p1 = pts.get(i);
+ p2 = pts.get(i+1);
+ double dx = Math.abs(p1.getX() - p2.getX());
+ double dy = Math.abs(p1.getY() - p2.getY());
+ double d = Math.max(dx, dy);
+ if (d > S.getWidth()) {
+ if (d > dmax) {
+ dmax = d;
+ r = new Rectangle2D.Double((p1.getX()+p2.getX()-sw)/2,
+ (p1.getY()+p2.getY())/2, sw, sh);
+ }
+ }
+ }
+ if (r == null) {
+ r = new Rectangle2D.Double((p1.getX()+p2.getX()-sw)/2, (p1.getY()+p2.getY()-sh)/2, sw, sh);
+ }
+ return new Rectangle((int)r.getX(), (int)r.getY(), (int)r.getWidth(), (int)r.getHeight());
+ }
+
+ /**
+ * Sets if the labels will be shown on the edges.
+ *
+ */
+ public void setShowEdgeLabels(boolean flag) {
+ showEdgeLabels = flag;
+ repaint();
+ }
+
+ /**
+ * Affirms if edge labels will be drawn.
+ *
+ */
+ public boolean showEdgeLabels() {
+ return showEdgeLabels;
+ }
+
+ /** ------------------------------------------------------------------------------------
+ * Event management
+ * ------------------------------------------------------------------------------------
+ */
+ private Component _selected; // the currently selected node
+ private Point _dragStart;
+ private Point _selectedLocation;
+ private Border _preselectionBorder;
+ private Border BORDER_SELECTED = BorderFactory.createLineBorder(Color.RED, 3);
+
+ boolean isSeleceted(Component c) {
+ return c == _selected;
+ }
+
+ @Override
+ public void mouseClicked(MouseEvent evt) {
+ deselect();
+
+ Component c = select(evt.getPoint());
+ if (c != null) {
+ c.dispatchEvent(evt);
+ } else {
+ Edge<V,V> edge = findPathUnderMouse(evt);
+ if (edge != null) {
+ JOptionPane.showMessageDialog(this, "Clicked on " + edge);
+ }
+ }
+
+ }
+
+ @Override
+ public void mouseEntered(MouseEvent e) {
+ }
+
+ @Override
+ public void mouseExited(MouseEvent e) {
+ }
+
+ @Override
+ public void mousePressed(MouseEvent evt) {
+ deselect();
+ Component c = select(evt.getPoint());
+ if (c != null) {
+ _selected = c;
+ _selectedLocation = c.getLocation();
+ _dragStart = evt.getPoint();
+ }
+ }
+
+ @Override
+ public void mouseReleased(MouseEvent evt) {
+ deselect();
+ this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
+ }
+
+ @Override
+ public void mouseDragged(MouseEvent evt) {
+ this.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
+ Point p = evt.getPoint();
+ if (_selected != null) {
+ Graphics g = getGraphics();
+ g.setClip(_dragStart.x, _dragStart.y, _dragStart.x-p.x, _dragStart.y - p.y);
+ p.translate(_selectedLocation.x-_dragStart.x, _selectedLocation.y-_dragStart.y);
+ setLocation(_selected, p.x, p.y);
+ repaint();
+ }
+ }
+
+ @Override
+ public void mouseMoved(MouseEvent evt) {
+ }
+
+ Edge<V, V> findPathUnderMouse(MouseEvent evt) {
+ Point p = evt.getPoint();
+ for (Map.Entry<Edge<V,V>, Path2D> path : edgePaths.entrySet()) {
+ if (path.getValue().contains(p)) {
+ deselect();
+ return path.getKey();
+ }
+ }
+ return null;
+ }
+
+ Component select(Point p) {
+ int n = getComponentCount();
+ for (int i = 0; i < n; i ++) {
+ Component c = getComponent(i);
+ if (c.getBounds().contains(p)) {
+ _selected = c;
+ if (c instanceof JComponent) {
+ _preselectionBorder = ((JComponent)c).getBorder();
+ ((JComponent)c).setBorder(BORDER_SELECTED);
+ }
+ return c;
+ }
+ }
+ return null;
+ }
+
+ void deselect() {
+ if (_selected == null)
+ return;
+ if (_selected instanceof JComponent) {
+ ((JComponent)_selected).setBorder(_preselectionBorder);
+ }
+ _selected = null;
+ }
+
+ void setLocation(Component c, int px, int py) {
+ dimension = getBounds(dimension);
+ insets = getInsets(insets);
+ cdimension = c.getBounds(cdimension);
+ c.setLocation(Math.min(Math.max(px, insets.left), dimension.width - insets.right - cdimension.width),
+ Math.min(Math.max(py, insets.top), dimension.height - insets.bottom - cdimension.height));
+ }
+
+ // Masking
+
+ boolean mask(V v) {
+ for (Mask<V> mask : nodeMasks) {
+ if (mask.apply(v))
+ return true;
+ }
+ return false;
+ }
+
+ boolean mask(Edge<V,V> e) {
+ for (Mask<Edge<V,V>> mask : edgeMasks) {
+ if (mask.apply(e))
+ return true;
+ }
+ return false;
+ }
+
+ public GraphPanel<V> addNodeMask(Mask<V> mask) {
+ nodeMasks.add(mask);
+ repaint();
+ return this;
+ }
+
+ public GraphPanel<V> removeNodeMask(Mask<V> mask) {
+ nodeMasks.add(mask);
+ repaint();
+ return this;
+ }
+
+ public List<Mask<V>> getNodeMasks() {
+ return Collections.unmodifiableList(nodeMasks);
+ }
+ public GraphPanel<V> addEdgeMask(Mask<Edge<V,V>> mask) {
+ edgeMasks.add(mask);
+ repaint();
+ return this;
+ }
+ public GraphPanel<V> removeEdgeMask(Mask<Edge<V,V>> mask) {
+ edgeMasks.add(mask);
+ repaint();
+ return this;
+ }
+
+ public List<Mask<Edge<V,V>>> getEdgeMasks() {
+ return Collections.unmodifiableList(edgeMasks);
+ }
+
+ /**
+ * Create a default model of 24 simple JLabel with random edges
+ * for testing.
+ */
+ public static GraphModel<Object> createDefaultGraphModel() {
+ GraphModel<Object> model = new DefaultGraphModel<Object>();
+ Random random = new Random(System.currentTimeMillis());
+ int N = 24;
+
+ String[] nodes = new String[N];
+ for (int i = 1; i <= N; i++) {
+ nodes[i-1] = "Label-"+i;
+ }
+ model.link(nodes[0], nodes[1]);
+ for (int i = 0; i < N; i++) {
+ for (int j = 0; j < N; j++) {
+ if (i != j && random.nextDouble() < 0.1) {
+ model.link(nodes[i], nodes[j]);
+ }
+ }
+ }
+ return model;
+ }
+}
Propchange: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/GraphPanel.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/GraphPanel.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/Mask.java
URL: http://svn.apache.org/viewvc/openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/Mask.java?rev=1004775&view=auto
==============================================================================
--- openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/Mask.java (added)
+++ openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/Mask.java Tue Oct 5 19:22:16 2010
@@ -0,0 +1,25 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+package org.apache.openjpa.swing.graph;
+
+/**
+ * A predicate that can be applied to nodes/edges of the graph.
+ *
+ * @author Pinaki Poddar
+ *
+ * @param <V>
+ */
+public interface Mask<V> {
+ boolean apply(V v);
+}
Propchange: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/Mask.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/Mask.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/NodeViewFactory.java
URL: http://svn.apache.org/viewvc/openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/NodeViewFactory.java?rev=1004775&view=auto
==============================================================================
--- openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/NodeViewFactory.java (added)
+++ openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/NodeViewFactory.java Tue Oct 5 19:22:16 2010
@@ -0,0 +1,34 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+package org.apache.openjpa.swing.graph;
+
+import java.awt.Graphics;
+
+
+/**
+ * Responsible for creating a Swing component out of a node.
+ *
+ * @author Pinaki Poddar
+ *
+ */
+public interface NodeViewFactory<V> {
+
+ /**
+ * Create a lightweight Swing component as a visual representation of the given node.
+ * @param node
+ * @param g
+ * @return
+ */
+ Connectable<V> createComponent(V node, Graphics g);
+}
Propchange: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/NodeViewFactory.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/NodeViewFactory.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/RectilinearEdgeRouter.java
URL: http://svn.apache.org/viewvc/openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/RectilinearEdgeRouter.java?rev=1004775&view=auto
==============================================================================
--- openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/RectilinearEdgeRouter.java (added)
+++ openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/RectilinearEdgeRouter.java Tue Oct 5 19:22:16 2010
@@ -0,0 +1,70 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+package org.apache.openjpa.swing.graph;
+
+import java.awt.geom.Line2D;
+import java.awt.geom.Path2D;
+import java.awt.geom.Rectangle2D;
+
+import org.apache.openjpa.swing.Geometry;
+
+/**
+ * This implementation computes a rectilinear path between the terminal
+ * nodes.
+ *
+ * @see Geometry#getConnector(Rectangle2D, Rectangle2D)
+ *
+ * @param <V>
+ */
+
+public class RectilinearEdgeRouter<V> implements EdgeRouter<V> {
+
+ public Path2D route(Edge<V, V> edge, Connectable<V> source, Connectable<V> target) {
+ Line2D[] exitPins = null;
+ Line2D[] entryPins = null;
+
+ exitPins = source.getExitPins(edge, target);
+ entryPins = target.getEntryPins(edge, source);
+
+ Line2D[] pair = matchClosestEntryExitPinPair(exitPins, entryPins);
+ return Geometry.getConnector(pair[0], pair[1]);
+ }
+
+ /**
+ * Finds the exit-entry pin pair that are closest to each other.
+ *
+ * @param exitPins
+ * array of exit pins (must contain at least one element)
+ * @param entryPins
+ * array of entry pins (must contain at least one element)
+ * @return 2 line segments, 0-the elements in the exit pin, 1-st element
+ * is the entry pin.
+ */
+ Line2D[] matchClosestEntryExitPinPair(Line2D[] exitPins, Line2D[] entryPins) {
+ double dmin = Double.MAX_VALUE;
+ Line2D[] closest = new Line2D[2];
+ for (Line2D exit : exitPins) {
+ for (Line2D entry : entryPins) {
+ double d = exit.getP2().distance(entry.getP1());
+ if (d < dmin) {
+ closest[0] = exit;
+ closest[1] = entry;
+ dmin = d;
+ }
+ }
+ }
+ return closest;
+ }
+
+}
\ No newline at end of file
Propchange: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/RectilinearEdgeRouter.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/graph/RectilinearEdgeRouter.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/layout/FRLayoutManager.java
URL: http://svn.apache.org/viewvc/openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/layout/FRLayoutManager.java?rev=1004775&view=auto
==============================================================================
--- openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/layout/FRLayoutManager.java (added)
+++ openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/layout/FRLayoutManager.java Tue Oct 5 19:22:16 2010
@@ -0,0 +1,573 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+package org.apache.openjpa.swing.layout;
+
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Insets;
+import java.awt.LayoutManager2;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+
+
+/**
+ * A layout manager to position the components absolutely using
+ * <A HRE="http://www.cs.brown.edu/~rt/gdhandbook/chapters/force-directed.pdf">
+ * Fruchterman-Reingold force-directed algorithm</A>.
+ *
+ * This algorithm determines placement of the components by repulsive and attractive forces.
+ * Repulsive force exists between any two components and is inversely proportional to the
+ * {@link #distance(Rectangle2D, Rectangle2D) distance} between them.
+ * <br>
+ * Attractive force exists between connected components. The connection between the
+ * components can be added by the caller {@linkplain #addNeighbours(Component, Collection) directly}
+ * or {@linkplain #addLayoutComponent(Component, Object) implicitly} while adding the component
+ * to the container.
+ *
+ * @author Pinaki Poddar
+ *
+ */
+@SuppressWarnings("serial")
+public class FRLayoutManager implements LayoutManager2, Serializable {
+ /**
+ * Each component knows which other component it is connected to
+ */
+ private Map<Component, List<Component>> layout;
+
+ /**
+ * Cache of each component's bounds during last layout computation.
+ */
+ private Map<Component, Rectangle2D> bounds;
+
+ private boolean _dirty;
+ private Dimension maxSize;
+ private Dimension minSize;
+ private Dimension preferredSize;
+ private Dimension size;
+ private double aspect = 1.5;
+ private double coefficient;
+ private double relax;
+ private boolean randomInitialization = true;
+
+ private static final double EPSILON = 1.0E-06;
+
+ public FRLayoutManager(Container c) {
+ layout = new HashMap<Component, List<Component>>();
+ bounds = new HashMap<Component, Rectangle2D>();
+ coefficient = 0.75;
+ relax = 1.2;
+ }
+
+ public void addNeighbours(Component comp, Collection<Component> neighbours) {
+ List<Component> list = layout.get(comp);
+ if (list == null) {
+ list = new ArrayList<Component>();
+ layout.put(comp, list);
+ }
+ list.addAll(neighbours);
+ }
+
+ /**
+ * Adds a component to be laid out. The constraints must be in the form of
+ * list of other components in the same container.
+ */
+ @Override
+ public void addLayoutComponent(Component comp, Object constraints) {
+ log("addLayoutComponent: " + comp + " constraints " + constraints);
+ layout.put(comp, (List<Component>)constraints);
+ _dirty = true;
+ }
+
+ @Override
+ public float getLayoutAlignmentX(Container target) {
+ log("getLayoutAlignmentX: " + target);
+ return 0;
+ }
+
+ @Override
+ public float getLayoutAlignmentY(Container target) {
+ log("getLayoutAlignmentY: " + target);
+ return 0;
+ }
+
+ @Override
+ public void invalidateLayout(Container target) {
+ info("FRLayoutManager.invalidateLayout");
+ _dirty = true;
+ }
+
+ @Override
+ public void addLayoutComponent(String name, Component comp) {
+ log("addLayoutComponent: " + comp + " name " + name);
+ _dirty = true;
+ layout.put(comp, null);
+ }
+
+ private Map<Component,Rectangle2D> initializeBoundsRandom(Container parent) {
+ Set<Component> components = layout.keySet();
+ size = parent.getSize();
+ Insets insets = parent.getInsets();
+ info("initializeBoundsRandom: " + toString("Parent Area ", size) + " No of components "
+ + components.size() + " Layout components " + layout.size());
+ Random rng = new Random(System.currentTimeMillis());
+ Map<Component,Rectangle2D> bounds = new HashMap<Component,Rectangle2D>();
+ for (Component c : components) {
+ Point location = c.getLocation();
+ Dimension dc = c.getPreferredSize();
+ if (location.x == 0 && location.y == 0) {
+ double x0 = 0.0;
+ double y0 = 0.0;
+ Rectangle2D b = new Rectangle2D.Double(x0,y0, dc.width, dc.height);
+ int trial = 0;
+ do {
+ x0 = rng.nextDouble()*(size.width-insets.left-insets.right);
+ y0 = rng.nextDouble()*(size.height-insets.top-insets.bottom);
+ b.setRect(x0, y0, dc.width, dc.height);
+ trial++;
+ } while (trial < 10 && !overlaps(b, bounds.values()));
+ bounds.put(c, b);
+ log(toString("Initialize bounds ", b));
+ } else {
+ bounds.put(c, new Rectangle2D.Double(location.x, location.y, dc.width, dc.height));
+ }
+ }
+ return bounds;
+ }
+
+ boolean overlaps(Rectangle2D b, Collection<Rectangle2D> other) {
+ for (Rectangle2D o : other) {
+ if (o.intersects(b)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+
+ private Map<Component,Rectangle2D> initializeBoundsGrid(Container parent) {
+ Set<Component> components = layout.keySet();
+ size = parent.getSize();
+ Insets insets = parent.getInsets();
+ info("initializeBoundsGrid:" + toString("Parent Area ", size));
+ Map<Component,Rectangle2D> bounds = new HashMap<Component,Rectangle2D>();
+
+ int T = components.size();
+ double W = size.width-insets.left-insets.right;
+ double H = size.height-insets.top-insets.bottom;
+ double w = 0.0;
+ double h = 0.0;
+
+ for (Component c : components) {
+ Dimension dc = c.getPreferredSize();
+ w += w + dc.getWidth();
+ h += h + dc.getHeight();
+ }
+ w = w/T;
+ h = h/T;
+
+ double M = W/w;
+ double N = H/h;
+ double f = Math.sqrt(T/(M*N));
+
+ long iM = (long)Math.ceil(M*f);
+ long iN = (long)Math.ceil(N*f);
+
+ double gx = W/iM;
+ double gy = H/iN;
+
+ int i = 0;
+ for (Component c : components) {
+ Dimension dc = c.getPreferredSize();
+ double x0 = gx*(i%iM) + insets.left + (gx-dc.width)/2;
+ double y0 = gy*(i/iN) + insets.top + (gy-dc.height)/2;
+ i++;
+ bounds.put(c, new Rectangle2D.Double(x0, y0, dc.width, dc.height));
+ log(toString("Initialized bounds ",bounds.get(c)));
+ }
+ return bounds;
+ }
+
+ double[] layoutQuality(Map<Component,Rectangle2D> bounds) {
+ double overlap = 0.0;
+ double wirelength = 0.0;
+ int nOverlap = 0;
+ int nEdge = 0;
+ for (Component c1 : bounds.keySet()) {
+ Rectangle2D r1 = bounds.get(c1);
+ for (Component c2 : bounds.keySet()) {
+ if (c1 == c2) continue;
+ Rectangle2D r2 = bounds.get(c2);
+ if (r1.intersects(r2)) {
+ Rectangle2D o = r1.createIntersection(r2);
+ overlap += o.getWidth()*o.getHeight();
+ nOverlap++;
+ }
+
+ }
+ List<Component> neighbours = getNeighbours(c1);
+ if (neighbours == null)
+ continue;
+ for (Component c2 : neighbours) {
+ Rectangle2D r2 = bounds.get(c2);
+ wirelength += new Vector2D(r1.getCenterX()-r2.getCenterX(), r1.getCenterY()-r2.getCenterY()).norm();
+ nEdge++;
+ }
+ }
+ return new double[]{nOverlap, overlap, nEdge, wirelength/Math.max(1, nEdge)};
+ }
+
+
+ private boolean isInitialized() {
+ Set<Component> components = layout.keySet();
+ for (Component c : components) {
+ Point location = c.getLocation();
+ if (location.x != 0 || location.y != 0) {
+ return true;
+ }
+ }
+ info("Initializing layout....");
+ return false;
+ }
+
+ void resize(Dimension newSize, Dimension oldSize, Insets insets) {
+ double scalex = newSize.getWidth()/oldSize.width;
+ double scaley = newSize.getHeight()/oldSize.height;
+ if (Math.abs(scalex-1.0) < 0.01 && Math.abs(scaley - 1) < 0.01)
+ return;
+ AffineTransform transform = new AffineTransform();
+ info("Resizing from " + toString("old size ",oldSize) + " to " + toString(" new size ", newSize));
+ double dx = insets.left*(1-scalex);
+ double dy = insets.top*(1-scaley);
+ transform.scale(scalex, scaley);
+ transform.translate(dx,dy);
+ info("Transform " + transform);
+ Set<Component> components = layout.keySet();
+ for (Component c : components) {
+ Point oldPoint = c.getLocation();
+ Point newPoint = new Point(0,0);
+ transform.transform(oldPoint, newPoint);
+ Dimension oldDim = c.getSize();
+ c.setBounds(newPoint.x, newPoint.y, oldDim.width, oldDim.height);
+ bounds.put(c, new Rectangle2D.Double(newPoint.x, newPoint.y, oldDim.width, oldDim.height));
+ }
+ }
+
+ void find(Container parent) {
+ if (!equals(size, parent.getSize())) {
+// System.err.println("Container size changed " + toString("Container ",parent.getSize()) + toString(" Cached ", size));
+ }
+ for (Component c : layout.keySet()) {
+ Rectangle actual = c.getBounds();
+ Rectangle2D cached = bounds.get(c);
+ if (cached == null) {
+// System.err.println("No cached data");
+ continue;
+ }
+ if (actual.x == 0 && actual.y == 0) {
+// System.err.println("No location assigned : " + c);
+ }
+ if (!equalsLocation(actual, cached)) {
+// System.err.println("Location different : " + toString("Actual ",actual) + toString(" Cached", cached));
+ }
+ if (!equalsSize(actual, cached)) {
+// System.err.println("Dimension different : " + toString("Actual ",actual) + toString(" Cached", cached));
+ }
+ }
+ }
+
+ boolean equals(Dimension a, Dimension b) {
+ if (a == null) {
+ return b == null;
+ } else {
+ if (b == null) {
+ return false;
+ } else {
+ return a.width == b.width && a.height == b.height;
+ }
+ }
+ }
+
+ boolean equalsLocation(Rectangle a, Rectangle2D b) {
+ if (a == null) {
+ return b == null;
+ } else {
+ if (b == null) {
+ return false;
+ } else {
+ return Math.abs(a.x - b.getX()) < 1 && Math.abs(a.y-b.getY()) < 1;
+ }
+ }
+ }
+ boolean equalsSize(Rectangle a, Rectangle2D b) {
+ if (a == null) {
+ return b == null;
+ } else {
+ if (b == null) {
+ return false;
+ } else {
+ return Math.abs(a.width - b.getWidth()) < 1 && Math.abs(a.height-b.getHeight()) < 1;
+ }
+ }
+ }
+
+ /**
+ * Determines the location and dimension of the components in this layout.
+ * First compares the cached data against the parent's components to determine
+ * why the layout operation has been triggered -- for example the parent may have
+ * been resized, or a new component has been added(removed) to(from) the container or
+ * one or more component size has been changed. Once the cause has been determined,
+ * invokes appropriate subroutine to recompute the bounds of the current set of
+ * components.
+ *
+ */
+ @Override
+ public void layoutContainer(Container parent) {
+// find(parent);
+ if (isInitialized()) {
+ resize(parent.getSize(),size, parent.getInsets());
+ size = new Dimension(parent.getSize());
+ _dirty = false;
+ return;
+ }
+
+ bounds = randomInitialization
+ ? initializeBoundsRandom(parent)
+ : initializeBoundsGrid(parent);
+
+ double[] quality = layoutQuality(bounds);
+ info("Initial layout quality " + quality[0] + " Overlap = " + quality[1] +
+ " average edge length " + quality[3] + " of " + quality[2] + " edges");
+ coefficient = Math.sqrt(area(parent.getSize())/layout.size());
+ boolean done = false;
+ double temperature = 100;//area(parent.getSize())/Math.sqrt(components.length);
+ int max = 20;
+ for (int i = 0; !done ; i++) {
+ double displacement = step(parent, bounds, temperature);
+ log("------------------ Step " + i + " Displacement = " + displacement + " --------------------");
+ done = i > max || displacement < 10 || layoutQuality(bounds)[0] <= 1;
+ temperature = Math.max(1.0, temperature*0.99);
+ }
+ Set<Component> components = layout.keySet();
+ for (Component c : components) {
+ Rectangle2D r = bounds.get(c);
+ c.setBounds((int)r.getX(), (int)r.getY(), (int)r.getWidth(), (int)r.getHeight());
+ }
+ quality = layoutQuality(bounds);
+ info("Final layout quality " + quality[0] + " Overlap = " + quality[1] +
+ " average edge length " + quality[3] + " of " + quality[2] + " edges");
+ _dirty = false;
+ }
+
+ /**
+ * Arrange the components by their constraints.
+ * @param parent
+ * @return
+ */
+ private double step(Container parent, Map<Component,Rectangle2D> bounds, double stepSize) {
+ Set<Component> components = layout.keySet();
+ Map<Component, Vector2D> displacements = new HashMap<Component, Vector2D>();
+ for (Component c1 : components) {
+ Vector2D disp = new Vector2D(0,0);
+ displacements.put(c1, disp);
+ Rectangle2D r1 = bounds.get(c1);
+ for (Component c2 : components) {
+ if (c1 == c2) continue;
+ Rectangle2D r2 = bounds.get(c2);
+ Vector2D delta = distance(r1,r2);
+ Vector2D repulsion = delta.copy().times(coefficient*coefficient/Math.max(EPSILON, delta.normSq()));
+ log("Distance " + delta + " Repulsion = " + repulsion);
+ disp.add(repulsion);
+ }
+ }
+
+ for (Component c1 : components) {
+ List<Component> neighbours = getNeighbours(c1);
+ if (neighbours == null || neighbours.isEmpty()) continue;
+ Rectangle2D r1 = bounds.get(c1);
+ for (int j = 0; j < neighbours.size(); j++) {
+ Component c2 = neighbours.get(j);
+ if (c1 == c2) continue;
+ Rectangle2D r2 = bounds.get(c2);
+ Vector2D delta = distance(r1,r2);
+ Vector2D attraction = delta.copy().times(delta.norm()/coefficient);
+ log("Distance " + delta + " Attraction = " + attraction);
+ displacements.get(c1).add(attraction.minus());
+ displacements.get(c1).add(attraction.minus().minus());
+ }
+ }
+ double totalDisplacement = normalize(displacements, stepSize);
+ Rectangle R = parent.getBounds();
+ Insets insets = parent.getInsets();
+ for (Component c : components) {
+ Rectangle2D r = bounds.get(c);
+ Vector2D disp = displacements.get(c);
+ Vector2D newPosition = new Vector2D(r.getX() + disp.x, r.getY() + disp.y);
+ Dimension dc = c.getPreferredSize();
+ newPosition.x = bound(newPosition.x, insets.left, R.width - insets.right - dc.width);
+ newPosition.y = bound(newPosition.y, insets.top, R.height - insets.bottom - dc.height);
+ bounds.put(c, new Rectangle2D.Double(newPosition.x, newPosition.y, r.getWidth(), r.getHeight()));
+ log("Component Displacement " + disp + "Position new : " + newPosition + " Old " + r.getX() + "," + r.getY());
+ }
+ return totalDisplacement;
+ }
+
+ double normalize(Map<Component, Vector2D> displacements, double limit) {
+ double sumx = 0.0;
+ double sumy = 0.0;
+ int N = displacements.size();
+
+ for (Map.Entry<Component, Vector2D> e : displacements.entrySet()) {
+ Vector2D d = e.getValue();
+ sumx += Math.abs(d.x);
+ sumy += Math.abs(d.y);
+ }
+ double total = 0.0;
+ log("Total displacement X= " + sumx + " Y=" + sumy + " Limit " + limit*N);
+ boolean normalize = (sumx > limit*N || sumy > limit*N);
+ double factor = normalize ? limit*N/Math.max(sumx, sumy) : 1.0;
+ for (Map.Entry<Component, Vector2D> e : displacements.entrySet()) {
+ Vector2D d = e.getValue();
+ if (normalize)
+ d.times(factor);
+ total += d.norm();
+ }
+ return total;
+ }
+
+ List<Component> getNeighbours(Component c) {
+ return layout.get(c);
+ }
+
+ @Override
+ public Dimension maximumLayoutSize(Container target) {
+ double area = 0.0;
+ if (_dirty || maxSize == null) {
+ info("Computing maximumLayoutSize: current value " + maxSize);
+ for (Component c : layout.keySet()) {
+ area += area(c.getMaximumSize());
+ }
+ maxSize = calculateDimension(area);
+ }
+ info("maximumLayoutSize: " + maxSize);
+ return maxSize;
+ }
+
+ @Override
+ public Dimension minimumLayoutSize(Container parent) {
+ double area = 0.0;
+ if (_dirty || minSize == null) {
+ info("Computing minimumLayoutSize: current value " + minSize);
+ for (Component c : layout.keySet()) {
+ area += area(c.getMinimumSize());
+ }
+ minSize = calculateDimension(area);
+ }
+ info("minimumLayoutSize: " + minSize);
+ return minSize;
+ }
+
+ @Override
+ public Dimension preferredLayoutSize(Container parent) {
+ double area = 0.0;
+ if (_dirty || preferredSize == null) {
+ info("Computing preferredLayoutSize: " + toString("current value ", preferredSize));
+ for (Component c : layout.keySet()) {
+ area += area(c.getPreferredSize());
+ }
+ preferredSize = calculateDimension(area);
+ }
+ log(toString("preferredLayoutSize: ", preferredSize));
+ return preferredSize;
+ }
+
+ @Override
+ public void removeLayoutComponent(Component comp) {
+ log("removeLayoutComponent: " + comp);
+ _dirty = true;
+ layout.remove(comp);
+ }
+
+ private double area(Dimension d) {
+ return d.width * d.height;
+ }
+
+ private Vector2D distance(Rectangle2D r1, Rectangle2D r2) {
+ double dx = r1.getCenterX() - r2.getCenterX();
+ double dy = r1.getCenterY() - r2.getCenterY();
+ r1.intersects(r2);
+ double fx = 1.0;
+ double fy = 1.0;
+ if (r1.intersects(r2)) {
+ Rectangle2D ir = r1.createIntersection(r2);
+ fx *= ir.getWidth();
+ fy *= ir.getHeight();
+ }
+ return new Vector2D(dx/fx,dy/fy).nudge(EPSILON);
+ }
+
+ Dimension calculateDimension(double area) {
+ double w = Math.sqrt(area*aspect)*relax;
+ double h = Math.sqrt(area/aspect)*relax;
+ return new Dimension((int)w,(int)h);
+ }
+ double attraction(double x) {
+ return x*x/coefficient;
+ }
+
+ double repulsion(double x) {
+ return coefficient*coefficient/x;
+ }
+
+ double bound(double a, double min, double max) {
+ if (min > max) {
+// throw new IllegalArgumentException("Min = " + min + " Max = " + max);
+ return a;
+ }
+ if (a < min) a = min;
+ if (a > max) a = max;
+ return a;
+ }
+
+ private void log(String s) {
+// System.err.println(s);
+ }
+ private void info(String s) {
+// System.err.println(s);
+ }
+ private String toString(String s, Dimension d) {
+ if (d == null) return s + ":" + d;
+ return s + "[" + d.width + "X" + d.height + "]";
+ }
+ private String toString(String s, Rectangle d) {
+ if (d == null) return s + ":" + d;
+ return s + "[" + d.x + "," + d.y + ":" + d.width + "X" + d.height + "]";
+ }
+ private String toString(String s, Rectangle2D d) {
+ if (d == null) return s + ":" + d;
+ return s + "[" + d.getX() + "," + d.getY() + ":" + d.getWidth() + "X" + d.getHeight() + "]";
+ }
+
+
+}
Propchange: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/layout/FRLayoutManager.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/layout/FRLayoutManager.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/layout/Vector2D.java
URL: http://svn.apache.org/viewvc/openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/layout/Vector2D.java?rev=1004775&view=auto
==============================================================================
--- openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/layout/Vector2D.java (added)
+++ openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/layout/Vector2D.java Tue Oct 5 19:22:16 2010
@@ -0,0 +1,143 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+package org.apache.openjpa.swing.layout;
+
+import java.text.DecimalFormat;
+
+/**
+ * A utility for two-dimensional vector operations.
+ * @author Pinaki Poddar
+ *
+ */
+public class Vector2D {
+ DecimalFormat fmt = new DecimalFormat("####.#");
+ double x;
+ double y;
+
+ /**
+ * Construct vector of zero length.
+ */
+ public Vector2D() {
+ this(0,0);
+ }
+
+ /**
+ * Construct a vector of given dimensions.
+ */
+ public Vector2D(double x, double y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ public Vector2D nudge(double epsilon) {
+ if (x == 0) x = epsilon;
+ if (y == 0) y = epsilon;
+ return this;
+ }
+
+ /**
+ * Create a new unit vector for this vector.
+ *
+ * @return a new vector of unit magnitude
+ */
+ public Vector2D unit() {
+ double norm = this.norm();
+
+ return copy().times(1.0/norm);
+ }
+
+ /**
+ * Translate this vector by the given displacement.
+ *
+ * @return this vector
+ */
+ public Vector2D add(double dx, double dy) {
+ x += dx;
+ y += dy;
+ return this;
+ }
+
+ /**
+ * Add the given vector to this vector.
+ *
+ * @return this vector
+ */
+ public Vector2D add(Vector2D other) {
+ return add(other.x, other.y);
+ }
+
+ /**
+ * Turn this vector around.
+ *
+ * @return this vector
+ */
+ public Vector2D minus() {
+ return times(-1);
+ }
+
+ /**
+ * Copy to a new vector.
+ * @return
+ */
+ public Vector2D copy() {
+ return new Vector2D(x,y);
+ }
+
+ public Vector2D times(double c) {
+ x *= c;
+ y *= c;
+ return this;
+ }
+
+ /**
+ * Limit both dimension of this vector within (-box, +box)
+ * @param box must be positive.
+ * @return this vector.
+ */
+ public Vector2D limit(double box) {
+ return limit(-box, box);
+ }
+
+ /**
+ * Limit both dimension of this vector within (min, max)
+ * @param box
+ * @return
+ */
+ public Vector2D limit(double min, double max) {
+ x = bound(x, min, max);
+ y = bound(y, min, max);
+ return this;
+ }
+
+ double bound(double a, double min, double max) {
+ if (min > max)
+ throw new IllegalArgumentException("Minimum bound " + min + " is not less that maximum " + max);
+ if (a < min) a = min;
+ if (a > max) a = max;
+ return a;
+ }
+
+ /**
+ * Gets the L2-norm of this vector.
+ */
+ public double norm() {
+ return Math.sqrt(x*x + y*y);
+ }
+ public double normSq() {
+ return x*x + y*y;
+ }
+ public String toString() {
+ return "(" + fmt.format(x) + "," + fmt.format(y) + ")";
+ }
+}
\ No newline at end of file
Propchange: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/layout/Vector2D.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/layout/Vector2D.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/layout/VerticalLayout.java
URL: http://svn.apache.org/viewvc/openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/layout/VerticalLayout.java?rev=1004775&view=auto
==============================================================================
--- openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/layout/VerticalLayout.java (added)
+++ openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/layout/VerticalLayout.java Tue Oct 5 19:22:16 2010
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.openjpa.swing.layout;
+
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.Insets;
+import java.awt.LayoutManager2;
+
+/**
+ * Lays out componets vertically. Differs from BoxLayout because invisible components
+ * are left out from size computation.
+ *
+ * @author Pinaki Poddar
+ *
+ */
+public class VerticalLayout implements LayoutManager2 {
+ private Container _target;
+ private double _width, _height;
+ private double _minWidth, _minHeight;
+ private double _maxWidth, _maxHeight;
+
+ public VerticalLayout(Container target) {
+ _target = target;
+ }
+
+ public void addLayoutComponent(Component comp, Object constraints) {
+ invalidateLayout(_target);
+ }
+
+ public Dimension maximumLayoutSize(Container target) {
+ int n = _target.getComponentCount();
+ _maxHeight = 0;
+ for (int i = 0; i < n; i++) {
+ Component c = _target.getComponent(i);
+ if (!c.isVisible()) continue;
+ Dimension size = c.getMaximumSize();
+ _maxWidth = Math.max(_maxWidth, size.getWidth());
+ _maxHeight += size.getHeight();
+ }
+ Insets inset = _target.getInsets();
+ Dimension d = new Dimension((int)(_maxWidth + inset.left + inset.right),
+ (int)(_maxHeight + inset.top + inset.bottom));
+// System.err.println("Maximum Layout " + (int)d.getWidth() + "x" + (int)d.getHeight());
+ return d;
+ }
+
+ public Dimension preferredLayoutSize(Container parent) {
+ int n = _target.getComponentCount();
+ _width = _minWidth;
+ _height = 0;
+ for (int i = 0; i < n; i++) {
+ Component c = _target.getComponent(i);
+ Dimension size = c.getPreferredSize();
+ _width = Math.max(_width, size.getWidth());
+ if (!c.isVisible()) continue;
+ _height += size.getHeight();
+ }
+ Insets inset = _target.getInsets();
+ Dimension d = new Dimension((int)(_width + inset.left + inset.right),
+ (int)(_height + inset.top + inset.bottom));
+// System.err.println("Preferred Layout " + (int)d.getWidth() + "x" + (int)d.getHeight());
+ return d;
+ }
+
+ public Dimension minimumLayoutSize(Container parent) {
+ int n = _target.getComponentCount();
+ for (int i = 0; i < n; i++) {
+ Component c = _target.getComponent(i);
+ if (!c.isVisible()) continue;
+ Dimension size = c.getMinimumSize();
+ _minWidth = Math.max(_minWidth, size.getWidth());
+ _minHeight += size.getHeight();
+ }
+ Insets inset = _target.getInsets();
+ Dimension d = new Dimension((int)(_minWidth + inset.left + inset.right),
+ (int)(_minHeight + inset.top + inset.bottom));
+// System.err.println("Minimum Layout " + (int)d.getWidth() + "x" + (int)d.getHeight());
+ return d;
+ }
+
+ public float getLayoutAlignmentX(Container target) {
+ return Component.LEFT_ALIGNMENT;
+ }
+
+ public float getLayoutAlignmentY(Container target) {
+ return Component.TOP_ALIGNMENT;
+ }
+
+ public void invalidateLayout(Container target) {
+ }
+
+ public void addLayoutComponent(String name, Component comp) {
+ invalidateLayout(_target);
+ }
+
+ public void removeLayoutComponent(Component comp) {
+ invalidateLayout(_target);
+ }
+
+ public void layoutContainer(Container parent) {
+ int n = parent.getComponentCount();
+ Insets inset = parent.getInsets();
+ int w = inset.left;
+ int h = inset.top;
+ for (int i = 0; i < n; i++) {
+ Component c = _target.getComponent(i);
+ if (!c.isVisible()) continue;
+ Dimension size = c.getPreferredSize();
+ c.setBounds(w,h, (int)size.getWidth(), (int)size.getHeight());
+ h += size.getHeight();
+ }
+ }
+}
Propchange: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/layout/VerticalLayout.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/layout/VerticalLayout.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/package.html
URL: http://svn.apache.org/viewvc/openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/package.html?rev=1004775&view=auto
==============================================================================
--- openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/package.html (added)
+++ openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/package.html Tue Oct 5 19:22:16 2010
@@ -0,0 +1,23 @@
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+<html>
+<body>
+Few extended Swing widgets and utilities.
+</body>
+</html>
Propchange: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/package.html
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/package.html
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/print/PrintableDelegateComponent.java
URL: http://svn.apache.org/viewvc/openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/print/PrintableDelegateComponent.java?rev=1004775&view=auto
==============================================================================
--- openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/print/PrintableDelegateComponent.java (added)
+++ openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/print/PrintableDelegateComponent.java Tue Oct 5 19:22:16 2010
@@ -0,0 +1,63 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+package org.apache.openjpa.swing.print;
+
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.awt.print.PageFormat;
+import java.awt.print.Printable;
+import java.awt.print.PrinterException;
+
+import javax.swing.JComponent;
+
+
+public class PrintableDelegateComponent extends Vista implements Printable {
+ private final JComponent _del;
+ private double scale = 1.0;
+
+ public PrintableDelegateComponent(JComponent del, PageFormat format) {
+ super();
+ this.format = format;
+ this.printable = this;
+ setPageSize(del.getWidth(), del.getHeight());
+ _del = del;
+ Rectangle componentBounds = _del.getBounds(null);
+ setPageSize(componentBounds.width, componentBounds.height);
+ setScale(1);
+ }
+
+ public PrintableDelegateComponent setScale(double s) {
+ scale = s;
+ setPageSize(s*_del.getWidth(), s*_del.getHeight());
+ return this;
+ }
+
+ @Override
+ public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
+ if (pageIndex >= getNumberOfPages())
+ return NO_SUCH_PAGE;
+ System.err.println(this.getClass().getSimpleName()+".print Page " + pageIndex);
+ Graphics2D g2 = (Graphics2D) graphics;
+
+ g2.translate(pageFormat.getImageableX(), pageFormat.getImageableY());
+ Rectangle componentBounds = _del.getBounds(null);
+ g2.translate(-componentBounds.x, -componentBounds.y);
+ g2.scale(scale, scale);
+ boolean wasBuffered = _del.isDoubleBuffered();
+ _del.paint(g2);
+ _del.setDoubleBuffered(wasBuffered);
+ return PAGE_EXISTS; }
+
+}
Propchange: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/print/PrintableDelegateComponent.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/print/PrintableDelegateComponent.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/print/Vista.java
URL: http://svn.apache.org/viewvc/openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/print/Vista.java?rev=1004775&view=auto
==============================================================================
--- openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/print/Vista.java (added)
+++ openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/print/Vista.java Tue Oct 5 19:22:16 2010
@@ -0,0 +1,82 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+package org.apache.openjpa.swing.print;
+
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.geom.Point2D;
+import java.awt.print.PageFormat;
+import java.awt.print.Pageable;
+import java.awt.print.Printable;
+import java.awt.print.PrinterException;
+
+public abstract class Vista implements Pageable {
+ protected PageFormat format;
+ protected Printable printable;
+ private int totalPages = -1;
+ private int xPages = -1;
+ private int yPages = -1;
+
+ protected Vista() {
+
+ }
+
+ @Override
+ public int getNumberOfPages() {
+ return totalPages;
+ }
+
+ @Override
+ public PageFormat getPageFormat(int pageIndex) throws IndexOutOfBoundsException {
+ if (pageIndex > totalPages) {
+ throw new IndexOutOfBoundsException();
+ }
+ return format;
+ }
+
+ @Override
+ public Printable getPrintable(int pageIndex) throws IndexOutOfBoundsException {
+ if (pageIndex > totalPages) {
+ throw new IndexOutOfBoundsException();
+ }
+ double x0 = (pageIndex % xPages) * format.getImageableWidth();
+ double y0 = (pageIndex / xPages) * format.getImageableHeight();
+ Point2D.Double origin = new Point2D.Double(x0, y0);
+ return new PrintableSinglePage(printable, origin);
+
+ }
+
+ protected void setPageSize(double width, double height) {
+ xPages = (int) ((width + format.getImageableWidth() - 1) / format.getImageableWidth());
+ yPages = (int) ((height + format.getImageableHeight() - 1) / format.getImageableHeight());
+ totalPages = xPages * yPages;
+ }
+
+ private class PrintableSinglePage implements Printable {
+ private final Point2D origin;
+ private final Printable singlePage;
+ public PrintableSinglePage(Printable page, Point2D origin) {
+ super();
+ this.singlePage = page;
+ this.origin = origin;
+ }
+
+ public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
+ Graphics2D g2 = (Graphics2D) graphics;
+ g2.translate(-origin.getX(), -origin.getY());
+ singlePage.print(g2, pageFormat, 1);
+ return PAGE_EXISTS;
+ }
+ }
+}
Propchange: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/print/Vista.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/swing/print/Vista.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/tools/MigrationTool.java
URL: http://svn.apache.org/viewvc/openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/tools/MigrationTool.java?rev=1004775&r1=1004774&r2=1004775&view=diff
==============================================================================
--- openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/tools/MigrationTool.java (original)
+++ openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/tools/MigrationTool.java Tue Oct 5 19:22:16 2010
@@ -20,12 +20,10 @@ package org.apache.openjpa.tools;
import java.io.File;
import java.io.FileInputStream;
-import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
Added: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/tools/metamodel/AttributeLegendView.java
URL: http://svn.apache.org/viewvc/openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/tools/metamodel/AttributeLegendView.java?rev=1004775&view=auto
==============================================================================
--- openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/tools/metamodel/AttributeLegendView.java (added)
+++ openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/tools/metamodel/AttributeLegendView.java Tue Oct 5 19:22:16 2010
@@ -0,0 +1,60 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+package org.apache.openjpa.tools.metamodel;
+
+import java.awt.Color;
+import java.awt.GridLayout;
+import java.awt.image.BufferedImage;
+
+import javax.persistence.metamodel.Attribute;
+import javax.swing.BorderFactory;
+import javax.swing.ImageIcon;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+
+
+/**
+ * Displays color codes of each attribute type.
+ *
+ * @author Pinaki Poddar
+ *
+ */
+@SuppressWarnings("serial")
+public class AttributeLegendView extends JPanel {
+
+ public AttributeLegendView() {
+ super(true);
+ setBorder(BorderFactory.createTitledBorder("Attribute Legends"));
+ setLayout(new GridLayout(0,3));
+ add(createColoredLabel("IDENTITY", MetamodelUIManager.getColor(MetamodelUIManager.COLOR_ATTR_ID)));
+ add(createColoredLabel("VERSION", MetamodelUIManager.getColor(MetamodelUIManager.COLOR_ATTR_VERSION)));
+ for (Attribute.PersistentAttributeType type : Attribute.PersistentAttributeType.values()) {
+ add(createColoredLabel(type.toString().replace('_', ' '), MetamodelUIManager.getColor(type)));
+ }
+ }
+
+ JComponent createColoredLabel(String text, Color c) {
+ int width = 40;
+ int height = 20;
+ BufferedImage bimage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+ for (int i = 0; i < width; i++)
+ for (int j = 0; j < height; j++)
+ bimage.setRGB(i, j, c.getRGB());
+ JLabel label = new JLabel(text, new ImageIcon(bimage), JLabel.LEADING);
+ return label;
+ }
+
+}
Propchange: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/tools/metamodel/AttributeLegendView.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: openjpa/tools/trunk/openjpa-tools/src/main/java/org/apache/openjpa/tools/metamodel/AttributeLegendView.java
------------------------------------------------------------------------------
svn:mime-type = text/plain