package view; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Component; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import javax.swing.BorderFactory; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.SwingUtilities; import javax.swing.border.Border; import bk.LayoutType; import graph.LayeredGraphNode; /** * A drawable representation of a node. * @author kolja * */ public class NodeView extends JPanel implements AnnimatedView, MouseListener { private static final long serialVersionUID = 1L; private LayeredGraphNode model; private LayoutType layout; private JFrame mainView; private int originalWidth; private int originalHeight; public NodeView( LayeredGraphNode model, LayoutType lt, JFrame mv ) { mainView = mv; this.model = model; layout = lt; addMouseListener( this ); originalWidth = (int)model.getWidth( lt ); originalHeight = (int)model.getHeight( lt ); } private synchronized void update() { SwingUtilities.invokeLater(new Runnable() { public void run() { for( ComponentListener l : mainView.getComponentListeners() ) { l.componentResized( new ComponentEvent(mainView, 0) ); } } }); } public int getScaledX( int x ) { double scale1 = Math.min( (getWidth()) / (double)getWidthOfNeededArea(), (getHeight()) / (double)getHeightOfNeededArea()); double scale = Math.min( (getWidth()-50*scale1) / (double)getWidthOfNeededArea(), (getHeight()-50*scale1) / (double)getHeightOfNeededArea()); x *= scale; return x; } public int getScaledY( int y ) { double scale1 = Math.min( (getWidth()) / (double)getWidthOfNeededArea(), (getHeight()) / (double)getHeightOfNeededArea()); double scale = Math.min( (getWidth()-50*scale1) / (double)getWidthOfNeededArea(), (getHeight()-50*scale1) / (double)getHeightOfNeededArea()); y *= scale; return y; } public void updateTooltipText() { if( layout != LayoutType.COMBINED ) { setToolTipText( "Name: " + model.toString() + "
Root: " + model.getRoot( layout ).toString() + "
Shink: " + model.getSink( layout ).toString() + "
Shift: " + model.getShift( layout ) + "" ); } else { setToolTipText( "Name: " + model.toString() + "
result X: " + model.getX( LayoutType.COMBINED ) + "
other layouts: [" + model.getX( LayoutType.LEFTMOST_UPPER ) + "," + model.getX( LayoutType.RIGHTMOST_UPPER ) + "," + model.getX( LayoutType.LEFTMOST_LOWER ) + "," + model.getX( LayoutType.RIGHTMOST_LOWER ) + "]" ); } for( Component c : getComponents() ) { if( !(c instanceof NodeView) ) continue; ((NodeView)c).updateTooltipText(); } } public int getXOffset() { int x = 0; double scale1 = Math.min( (getWidth()) / (double)getWidthOfNeededArea(), (getHeight()) / (double)getHeightOfNeededArea()); double scale = Math.min( (getWidth()-50*scale1) / (double)getWidthOfNeededArea(), (getHeight()-50*scale1) / (double)getHeightOfNeededArea()); x += (getWidth()-50) / 2 - (getWidthOfNeededArea() * scale ) / 2 + 25; return x; } public int getYOffset() { int y = 0; double scale1 = Math.min( (getWidth()) / (double)getWidthOfNeededArea(), (getHeight()) / (double)getHeightOfNeededArea()); double scale = Math.min( (getWidth()-50*scale1) / (double)getWidthOfNeededArea(), (getHeight()-50*scale1) / (double)getHeightOfNeededArea()); y += (getHeight()-50) / 2 - (getHeightOfNeededArea() * scale ) / 2 + 25; return y; } public int getOriginalWidth() { return originalWidth; } public int getOriginalHeight() { return originalHeight; } private int getWidthOfNeededArea() { int max = 0; double min = Double.POSITIVE_INFINITY; for( Component c : getComponents() ) { if( c instanceof NodeView ) { max = Math.max( max, ((NodeView)c).getVirtualX() + ((NodeView)c).getOriginalWidth() ); min = Math.min( ((AnnimatedView)c).getVirtualX(), min); } } return max - (int)min; } private int getHeightOfNeededArea() { int max = 0; double min = Double.POSITIVE_INFINITY; for( Component c : getComponents() ) { if( c instanceof NodeView ) { max = Math.max( max, ((NodeView)c).getVirtualY() + ((NodeView)c).getOriginalHeight() ); min = Math.min( ((AnnimatedView)c).getVirtualY(), min); } } return max - (int)min; } @Override public void doLayout() { double minX = Double.POSITIVE_INFINITY; for( Component c : getComponents() ) { if( !(c instanceof AnnimatedView) ) continue; minX = Math.min( ((AnnimatedView)c).getVirtualX(), minX); } int x = 0; int y = 0; double scale1 = Math.min( (getWidth()) / (double)getWidthOfNeededArea(), (getHeight()) / (double)getHeightOfNeededArea()); double scale = Math.min( (getWidth()-50*scale1) / (double)getWidthOfNeededArea(), (getHeight()-50*scale1) / (double)getHeightOfNeededArea()); x += (getWidth()) / 2 - (getWidthOfNeededArea() * scale ) / 2; y += (getHeight()) / 2 - (getHeightOfNeededArea() * scale ) / 2; for( Component c : getComponents() ) { if( !(c instanceof AnnimatedView) ) continue; AnnimatedView view = (AnnimatedView)c; c.setLocation( getScaledX( view.getVirtualX() - (int)minX ) + x, getScaledY( view.getVirtualY() ) + y); if( c instanceof NodeView ) c.setSize( getScaledX( ((NodeView)c).getOriginalWidth() ), getScaledY( ((NodeView)c).getOriginalHeight() ) ); else c.setSize( getScaledX( view.getVirtualWidth() ), getScaledY( view.getVirtualHeight() ) ); c.doLayout(); } } @Override public void paint( Graphics g ) { if( layout == LayoutType.COMBINED && model.getColor( null ) == null ) return; updateTooltipText(); paintComponent( g ); double minX = Double.POSITIVE_INFINITY; for( Component c : getComponents() ) { if( !(c instanceof AnnimatedView) ) continue; minX = Math.min( ((AnnimatedView)c).getVirtualX(), minX); } int x = 0; double scale1 = Math.min( (getWidth()) / (double)getWidthOfNeededArea(), (getHeight()) / (double)getHeightOfNeededArea()); double scale = Math.min( (getWidth()-50*scale1) / (double)getWidthOfNeededArea(), (getHeight()-50*scale1) / (double)getHeightOfNeededArea()); x += (getWidth()-50) / 2 - (getWidthOfNeededArea() * scale ) / 2 + 25; for( Component c : getComponents() ) { if( c instanceof NodeView ) { if( layout != LayoutType.COMBINED ) { NodeView v = (NodeView)c; v.renderClass( g.create( getScaledX( v.getPlainVirtualX() - (int)minX - 12 ) + x, c.getY() - getScaledY(12), getScaledX( v.getPlainVirtualWidth() + 22 ), c.getHeight() + getScaledY(22) ) ); } } c.paint( g.create( c.getX(), c.getY(), c.getWidth(), c.getHeight() ) ); } } public void renderClass( Graphics g ) { g.setColor( model.getRoot( layout ).getClassColor( layout ) ); if( model.getContainedNodes().size() == 0 && model.getRoot( layout ).getClassColor( layout ) != Color.LIGHT_GRAY ) { g.setColor( new Color( (g.getColor().getRed() + 500) / 3, (g.getColor().getGreen() + 500) / 3, (g.getColor().getBlue() + 500) / 3 ) ); g.fillRect( 0, 0, g.getClipBounds().width, g.getClipBounds().height ); } } @Override public void paintComponent( Graphics g ) { Graphics2D g2 = (Graphics2D)g; g2.setColor( model.getColor( layout ) ); g2.setStroke(new BasicStroke(5)); if( model.getContainedNodes().size() == 0 ) { if( model.getRoot( layout ) == model ) g2.fillOval( 0, 0, getWidth(), getHeight() ); else g2.fillRect( 0, 0, getWidth(), getHeight() ); } boolean selected = model.isSelected( layout ); if( selected ) { g.setColor( Color.BLACK ); if( model.getContainedNodes().size() > 0 ) g.setColor( Color.GRAY ); g.fillRect( 0, 0, getWidth(), getHeight() ); } Border linebor = BorderFactory.createLineBorder(model.getColor( layout ), 5); if( model.getRoot( layout ) != model || model.getContainedNodes().size() != 0 ) linebor.paintBorder( this, g2, 0, 0, getWidth(), getHeight() ); if( model.isMouseOver() && model.getContainedNodes().size() == 0 ) { g.setColor( Color.WHITE ); g.fillOval( getWidth() / 4, getHeight() / 4, getWidth() / 2, getHeight() / 2 ); } } public int getPlainVirtualX() { return (int)model.getX( layout ); } @Override public int getVirtualX() { if( model.isDummyNode() ) return (int)(model.getX( layout ) + getVirtualWidth() / (3/4.0) ); return (int)model.getX( layout ); } @Override public int getVirtualY() { return (int)model.getY( layout ); } @Override public int getVirtualWidth() { if( model.isDummyNode() ) return (int)(model.getWidth( layout ) / 3); return (int)model.getWidth( layout ); } public int getPlainVirtualWidth() { return (int)model.getWidth( layout ); } @Override public int getVirtualHeight() { return (int)model.getHeight( layout ); } @Override public void mouseClicked(MouseEvent e) {} @Override public void mousePressed(MouseEvent e) {} @Override public void mouseReleased(MouseEvent e) {} @Override public void mouseEntered(MouseEvent e) { model.setMouseOver( true ); update(); } @Override public void mouseExited(MouseEvent e) { model.setMouseOver( false ); update(); } }