| /* |
| * Copyright (c) 2009, Tony Kohar. All Rights Reserved. |
| * |
| * 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.zest.envisage.graph; |
| |
| import java.awt.Dimension; |
| import java.awt.FontMetrics; |
| import java.awt.geom.Area; |
| import java.awt.geom.Rectangle2D; |
| import prefuse.Display; |
| import prefuse.action.layout.graph.TreeLayout; |
| import prefuse.render.Renderer; |
| import prefuse.visual.NodeItem; |
| |
| /* package */ final class StackedLayout |
| extends TreeLayout |
| { |
| /* package */ static int INSET = 10; |
| |
| private int zoom = 2; |
| |
| /* package */ StackedLayout( String group ) |
| { |
| super( group ); |
| } |
| |
| @Override |
| public void run( double frac ) |
| { |
| // setup |
| NodeItem root = getLayoutRoot(); |
| layout( root, 0, 0 ); |
| |
| Rectangle2D bounds = root.getBounds(); |
| Display display = this.getVisualization().getDisplay( 0 ); |
| Dimension size = new Dimension( (int) bounds.getWidth(), (int) bounds.getHeight() ); |
| display.setSize( size ); |
| |
| if( !display.isValid() ) |
| { |
| display.validate(); |
| } |
| } |
| |
| /* package */ void zoomOut() |
| { |
| zoom--; |
| if( zoom < 1 ) |
| { |
| zoom = 1; |
| } |
| } |
| |
| /* package */ void zoomIn() |
| { |
| zoom++; |
| if( zoom > 4 ) |
| { |
| zoom = 4; |
| } |
| } |
| |
| /* package */ void zoom( int zoom ) |
| { |
| this.zoom = zoom; |
| } |
| |
| /* package */ int getZoom() |
| { |
| return zoom; |
| } |
| |
| private Dimension getItemMinSize( NodeItem node, Dimension minSize ) |
| { |
| if( minSize == null ) |
| { |
| minSize = new Dimension( 0, 0 ); |
| } |
| |
| String label = node.getString( "name" ); |
| FontMetrics fm = Renderer.DEFAULT_GRAPHICS.getFontMetrics( StackedGraphDisplay.FONT ); |
| int width = fm.stringWidth( label ); |
| int height = fm.getHeight(); |
| minSize.setSize( width + INSET + INSET, height + INSET + INSET ); |
| |
| return minSize; |
| } |
| |
| private void layout( NodeItem node, double x, double y ) |
| { |
| Dimension minSize = getItemMinSize( node, null ); |
| node.setBounds( x, y, minSize.width, minSize.height ); |
| |
| int depth = node.getDepth(); |
| |
| if( depth > zoom ) |
| { |
| node.setBounds( x, y, 0, 0 ); |
| node.setVisible( false ); |
| } |
| else |
| { |
| node.setVisible( true ); |
| } |
| |
| double cx = x + INSET; |
| double cy = y + minSize.height; |
| |
| Area area = new Area( node.getBounds() ); |
| |
| boolean hasChild = false; |
| for( int i = 0; i < node.getChildCount(); i++ ) |
| { |
| hasChild = true; |
| NodeItem child = (NodeItem) node.getChild( i ); |
| |
| layout( child, cx, cy ); |
| area.add( new Area( child.getBounds() ) ); |
| |
| // shifting location calculation |
| Rectangle2D nodeRect = child.getBounds(); |
| if( depth == 0 ) |
| { |
| // layer |
| cy = cy + ( INSET * 2 ) + nodeRect.getHeight(); |
| } |
| if( depth == 1 ) |
| { |
| // module |
| cx = cx + INSET + nodeRect.getWidth(); |
| } |
| else if( depth == 2 ) |
| { |
| // type container |
| cx = cx + INSET + nodeRect.getWidth(); |
| } |
| else if( depth == 3 ) |
| { |
| // type |
| cy = cy + INSET + nodeRect.getHeight(); |
| } |
| } |
| |
| Rectangle2D bounds = area.getBounds2D(); |
| if( hasChild && depth <= zoom ) |
| { |
| bounds.setRect( x, y, bounds.getWidth() + INSET, bounds.getHeight() + INSET ); |
| } |
| |
| node.setBounds( x, y, bounds.getWidth(), bounds.getHeight() ); |
| |
| // relayout the child so it have consistent width or height |
| //int depth = parent.getDepth(); |
| if( depth == 0 ) |
| { |
| arrangeChildVertically( node ); |
| } |
| else if( depth == 1 ) |
| { |
| arrangeChildHorizontally( node ); |
| } |
| else if( depth == 2 ) |
| { |
| arrangeChildHorizontally( node ); |
| } |
| else if( depth == 3 ) |
| { |
| arrangeChildVertically( node ); |
| } |
| } |
| |
| private void arrangeChildVertically( NodeItem parent ) |
| { |
| double maxW = 0; |
| for( int i = 0; i < parent.getChildCount(); i++ ) |
| { |
| NodeItem node = (NodeItem) parent.getChild( i ); |
| Rectangle2D bounds = node.getBounds(); |
| maxW = Math.max( maxW, bounds.getWidth() ); |
| } |
| |
| for( int i = 0; i < parent.getChildCount(); i++ ) |
| { |
| NodeItem node = (NodeItem) parent.getChild( i ); |
| Rectangle2D bounds = node.getBounds(); |
| node.setBounds( bounds.getX(), bounds.getY(), maxW, bounds.getHeight() ); |
| } |
| } |
| |
| private void arrangeChildHorizontally( NodeItem parent ) |
| { |
| double maxH = 0; |
| for( int i = 0; i < parent.getChildCount(); i++ ) |
| { |
| NodeItem node = (NodeItem) parent.getChild( i ); |
| Rectangle2D bounds = node.getBounds(); |
| maxH = Math.max( maxH, bounds.getHeight() ); |
| } |
| |
| for( int i = 0; i < parent.getChildCount(); i++ ) |
| { |
| NodeItem node = (NodeItem) parent.getChild( i ); |
| Rectangle2D bounds = node.getBounds(); |
| node.setBounds( bounds.getX(), bounds.getY(), bounds.getWidth(), maxH ); |
| } |
| } |
| } |