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();
}
}