All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jadex.micro.examples.mandelbrot.DisplayPanel Maven / Gradle / Ivy

Go to download

The Jadex micro applications package contains several example applications, benchmarks and testcases using micro agents.

There is a newer version: 4.0.267
Show newest version
package jadex.micro.examples.mandelbrot;

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.geom.Rectangle2D;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.UUID;

import javax.swing.JComponent;
import javax.swing.JProgressBar;
import javax.swing.JViewport;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

import jadex.bridge.IComponentStep;
import jadex.bridge.IExternalAccess;
import jadex.bridge.IInternalAccess;
import jadex.bridge.service.RequiredServiceInfo;
import jadex.bridge.service.component.IRequiredServicesFeature;
import jadex.bridge.service.search.SServiceProvider;
import jadex.bridge.service.types.cms.IComponentManagementService;
import jadex.commons.future.IFuture;
import jadex.commons.future.IIntermediateResultListener;
import jadex.commons.future.IResultListener;
import jadex.commons.future.ISubscriptionIntermediateFuture;
import jadex.commons.gui.future.SwingDefaultResultListener;
import jadex.commons.gui.future.SwingResultListener;

/**
 *  Panel for displaying calculated results.
 */
public class DisplayPanel extends JComponent
{
	//-------- constants --------
	
	/** The help text. */
	public static final String	HELPTEXT	=
		"Use mouse to navigate:\n" +
		"[wheel] zoom in/out\n" +
		"[left button] choose and click into area\n" +
		"[rigth button] drag to move, click for original area.\n";
	
	//-------- attributes --------
	
	/** The service provider. */
	protected IExternalAccess agent;
	
	/** The mandelbrot service. */
	protected IMandelbrotService manservice;
	
	/** The colors for drawing. */
	protected Color[]	colors;
	
	/** The latest area data used for determining original coordinates of painted regions. */
	protected AreaData	data;
	
	/** The current image derived from the results. */
	protected Image	image;
	
	/** The current selection start point (if any). */
	protected Point	point;
	
	/** The current selection range (if any). */
	protected Rectangle	range;
	
	/** Flag indicating that a calculation is in progress. */
	protected boolean	calculating;
	
	/** Progress data objects, available only when calculating (progress data -> percent finished). */
	protected Map	progressdata;
	
	/** Progress update timer. */
	protected Timer	progressupdate;
	
	/** Start point for dragging (if any). */
	protected Point	startdrag;
	
	/** End point for dragging (if any). */
	protected Point	enddrag;
	
	/** The display id. */
	protected String displayid;

	//-------- constructors --------
	
	/**
	 *  Create a new display panel.
	 */
	public DisplayPanel(final IExternalAccess agent, IMandelbrotService manservice)
	{
		this.agent	= agent;
		this.manservice = manservice;
		this.displayid = ""+UUID.randomUUID();
		
		manservice.getDisplayService().addResultListener(new SwingDefaultResultListener()
		{
			public void customResultAvailable(IDisplayService result)
			{
				ISubscriptionIntermediateFuture sub = result.subscribeToDisplayUpdates(displayid);
				sub.addResultListener(new IIntermediateResultListener()
				{
					public void resultAvailable(Collection result)
					{
					}
					
					public void intermediateResultAvailable(Object result)
					{
//						System.out.println("rec: "+result.getClass());
						if(result instanceof AreaData)
						{
							setResults((AreaData)result);
						}
						else if(result instanceof ProgressData)
						{
							addProgress((ProgressData)result);
						}
					}
					
					public void finished()
					{
						// todo: close
					}
					
					public void exceptionOccurred(Exception exception)
					{
						exception.printStackTrace();
					}
				});
				
				setColorScheme(new Color[]{new Color(50, 100, 0), Color.red}, true);
				calcDefaultImage();
				
				// Dragging with right mouse button.
				MouseAdapter draghandler = new MouseAdapter()
				{
					public void mousePressed(MouseEvent e)
					{
						if(!calculating && e.getButton()==MouseEvent.BUTTON3 && e.getClickCount()==1 && image!=null)
						{
							startdrag = new Point(e.getX(), e.getY());
							range	= null;
							point	= null;
						}
						else
						{
							startdrag	= null;
						}
					}
					
					public void mouseDragged(MouseEvent e)
					{
						if(startdrag!=null)
						{
							enddrag = new Point(e.getX(), e.getY());
							repaint();
						}
					}
					
					public void mouseReleased(MouseEvent e)
					{
						if(startdrag!=null && enddrag!=null)
						{
//							System.out.println("dragged: "+startdrag+" "+enddrag);
							dragImage();
						}
					}
				};
				addMouseMotionListener(draghandler);
				addMouseListener(draghandler);
						
				// Zooming with mouse wheel.
				addMouseWheelListener(new MouseAdapter()
				{
					public void mouseWheelMoved(MouseWheelEvent e)
					{
						if(!calculating)
						{
							int sa = e.getScrollAmount();
							double	dir = Math.signum(e.getWheelRotation());
							double	percent	= 10*sa;
							double	factor;
							if(dir>0)
							{
								factor	= (100+percent)/100;
							}
							else
							{
								factor	= 100/(100+percent);
							}
							zoomImage(e.getX(), e.getY(), factor);
						}
					}
				});
				
				// Selecting range and default area.
				addMouseListener(new MouseAdapter()
				{
					public void mouseClicked(MouseEvent e)
					{
						if(SwingUtilities.isRightMouseButton(e))
						{
							calcDefaultImage();
						}
						
						else if(!calculating && range!=null)
						{
							if(e.getX()>=range.x && e.getX()<=range.x+range.width
								&& e.getY()>=range.y && e.getY()<=range.y+range.height)
							{
								zoomIntoRange();
							}
						}
					}
					
					public void mousePressed(MouseEvent e)
					{
						if(!calculating)
						{
							if(SwingUtilities.isRightMouseButton(e))
							{
								DisplayPanel.this.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
							}
							else
							{
								point	= e.getPoint();
								DisplayPanel.this.setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
							}
						}
					}
					
					public void mouseReleased(MouseEvent e)
					{
						if(!calculating)
						{
							DisplayPanel.this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
						}
					}
				});
				addMouseMotionListener(new MouseAdapter()
				{
					public void mouseMoved(MouseEvent e)
					{
						if(!calculating && range!=null)
						{
							if(e.getX()>=range.x && e.getX()<=range.x+range.width
								&& e.getY()>=range.y && e.getY()<=range.y+range.height)
							{
								DisplayPanel.this.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
							}
							else
							{
								DisplayPanel.this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));						
							}
						}
					}
					
					public void mouseDragged(MouseEvent e)
					{
						if(!calculating && point!=null)
						{
							range	= new Rectangle(
								point.x()
								{
									public IFuture execute(IInternalAccess ia)
									{
										// do not depend on hosting component!
//										IFuture	fut	= ia.getServiceContainer().getRequiredService("cmsservice");
										IFuture	fut	= SServiceProvider.getService(ia, IComponentManagementService.class, RequiredServiceInfo.SCOPE_PLATFORM);
										fut.addResultListener(new SwingResultListener(new IResultListener()
										{
											public void resultAvailable(IComponentManagementService cms)
											{
												if(progressdata!=null)
												{
													Object[]	pds	= progressdata.keySet().toArray();
													for(int i=0; i(new IResultListener()
															{
																public void resultAvailable(IExternalAccess	ea)
																{
																	// It is not really possible to define the progress services as required service.
																	// Needs component specific progress service.
																	SServiceProvider.getService(ea, IProgressService.class)
																		.addResultListener(new SwingResultListener(new IResultListener()
																	{
																		public void resultAvailable(IProgressService	ps)
																		{
																			if(ps!=null)
																			{
																				ps.getProgress(progress.getTaskId())
																					.addResultListener(new SwingResultListener(new IResultListener()
																				{
																					public void resultAvailable(Integer current)
																					{
																						if(progressdata!=null && progressdata.containsKey(progress))
																						{
																							Integer	percent	= (Integer)progressdata.get(progress);
																							if(current.intValue()>percent.intValue())
																							{
																								progressdata.put(progress, current);
																								repaint();
																							}
																						}
																					}
					
																					public void exceptionOccurred(Exception exception)
																					{
																						// Component removed.
																						if(progressdata!=null)
																						{
																							progressdata.remove(progress);
																						}
																						else if(progressupdate!=null)
																						{
																							progressupdate.stop();
																							progressupdate	= null;
																						}
																					}
																				}));
																			}
																		}
					
																		public void exceptionOccurred(Exception exception)
																		{
																			// Component removed.
																			if(progressdata!=null)
																			{
																				progressdata.remove(progress);
																			}
																			else if(progressupdate!=null)
																			{
																				progressupdate.stop();
																				progressupdate	= null;
																			}
																		}
																	}));
																}
					
																public void exceptionOccurred(Exception exception)
																{
																	// Component removed.
																	if(progressdata!=null)
																	{
																		progressdata.remove(progress);
																	}
																	else if(progressupdate!=null)
																	{
																		progressupdate.stop();
																		progressupdate	= null;
																	}
																}
															}));
														}
													}
												}
											}
		
											public void exceptionOccurred(Exception exception)
											{
												// ignore
												exception.printStackTrace();
											}
										}));
										return IFuture.DONE;
									}
								});
							}
							else if(progressupdate!=null)
							{
								progressupdate.stop();
								progressupdate	= null;
							}
						}
					});
					progressupdate.start();
				}
			}
		});
	}
	
	//-------- JPanel methods --------
	
	/**
	 *  Paint the results.
	 */
	protected void paintComponent(Graphics g)
	{
		super.paintComponent(g);
		
		// Draw image.
		if(image!=null)
		{
			Rectangle bounds = getInnerBounds(true);
			int	ix	= 0;
			int iy	= 0;
			int	iwidth	= image.getWidth(this);
			int iheight	= image.getHeight(this);
			Rectangle drawarea = scaleToFit(bounds, iwidth, iheight);

			// Zoom into original image while calculating
			if(calculating && range!=null)
			{
				ix	= (range.x-drawarea.x-bounds.x)*iwidth/drawarea.width;
				iy	= (range.y-drawarea.y-bounds.y)*iheight/drawarea.height;
				iwidth	= range.width*iwidth/drawarea.width;
				iheight	= range.height*iheight/drawarea.height;
				
				// Scale again to fit new image size.
				drawarea = scaleToFit(bounds, iwidth, iheight);
				
				g.drawImage(image, bounds.x+drawarea.x, bounds.y+drawarea.y,
					bounds.x+drawarea.x+drawarea.width, bounds.y+drawarea.y+drawarea.height,
					ix, iy, ix+iwidth, iy+iheight, this);
			}
			
			// Offset and clip image and show border while dragging.
			else if(startdrag!=null && enddrag!=null)
			{
				// Draw original image in background
				g.drawImage(image, bounds.x+drawarea.x, bounds.y+drawarea.y,
					bounds.x+drawarea.x+drawarea.width, bounds.y+drawarea.y+drawarea.height,
					ix, iy, ix+iwidth, iy+iheight, this);
				g.setColor(new Color(32,32,32,160));
				g.fillRect(bounds.x+drawarea.x, bounds.y+drawarea.y, drawarea.width, drawarea.height);

				// Draw offsetted image in foreground
				Shape	clip	= g.getClip();
				g.setClip(bounds.x+drawarea.x, bounds.y+drawarea.y, drawarea.width, drawarea.height);
				int	xoff	= enddrag.x-startdrag.x;
				int	yoff	= enddrag.y-startdrag.y;
				g.drawImage(image, bounds.x+drawarea.x+xoff, bounds.y+drawarea.y+yoff,
					bounds.x+drawarea.x+xoff+drawarea.width, bounds.y+drawarea.y+yoff+drawarea.height,
					ix, iy, ix+iwidth, iy+iheight, this);
				g.setClip(clip);
			}
			else
			{
				g.drawImage(image, bounds.x+drawarea.x, bounds.y+drawarea.y,
					bounds.x+drawarea.x+drawarea.width, bounds.y+drawarea.y+drawarea.height,
					ix, iy, ix+iwidth, iy+iheight, this);
			}
			
			// Draw progress boxes.
			if(progressdata!=null)
			{
				JProgressBar	bar	= new JProgressBar(0, 100);
				bar.setStringPainted(true);
				Dimension	barsize	= bar.getPreferredSize();
				for(Iterator it=progressdata.keySet().iterator(); it.hasNext(); )
				{
					ProgressData	progress	= (ProgressData)it.next();
					
					double xf = drawarea.getWidth()/progress.getImageWidth();
					double yf = drawarea.getHeight()/progress.getImageHeight();
					int corx = (int)(progress.getArea().x*xf);
					int cory = (int)(progress.getArea().y*yf);
					int corw = (int)(progress.getArea().width*xf);
					int corh = (int)(progress.getArea().height*yf);
					
					if(!progress.isFinished())
					{
						g.setColor(new Color(32,32,32,160));
						g.fillRect(bounds.x+drawarea.x+corx+1, bounds.y+drawarea.y+cory+1, corw-1, corh-1);							
					}
					g.setColor(Color.white);
					g.drawRect(bounds.x+drawarea.x+corx, bounds.y+drawarea.y+cory, corw, corh);
					
					// Print provider name.
					if(progress.getProviderId()!=null)
					{
						String	name	= progress.getProviderId().toString();
						String	provider	= "";
						int index	=	name.indexOf('@');
						if(index!=-1)
						{
							provider	= name.substring(index+1);
							name	= name.substring(0, index);
						}
//						provider	= progress.getTaskId().toString();
						
						FontMetrics	fm	= g.getFontMetrics();
						Rectangle2D	sb1	= fm.getStringBounds(name, g);
						Rectangle2D	sb2	= fm.getStringBounds(provider, g);
						int width	= (int)Math.max(sb1.getWidth(), sb2.getWidth());
						int	height	= fm.getHeight()*2 + barsize.height + 2;
						if(width8 && corh>8)
						{
							bar.setStringPainted(false);
							int	x	= bounds.x+drawarea.x+corx + 2;
							int	y	= bounds.y+drawarea.y+cory + Math.max((corh-barsize.height)/2, 2);
							bar.setValue(((Number)progressdata.get(progress)).intValue());
							bar.setBounds(0, 0, corw-4, Math.min(barsize.height, corh-4));
							Graphics	g2	= g.create();
							g2.translate(x, y);
							bar.paint(g2);
						}
					}
				}
			}
		}
		
		// Draw range area.
		if(!calculating && range!=null)
		{
			Rectangle bounds = getInnerBounds(false);
			double	rratio	= (double)range.width/range.height;
			double	bratio	= (double)bounds.width/bounds.height;
			
			// Draw left and right boxes to show unused space
			if(rratiobratio)
			{
				int	drawheight	= range.width*bounds.height/bounds.width;
				int offset = (range.height-drawheight)/2;
				g.setColor(new Color(128,128,128,64));
				g.fillRect(range.x, range.y+offset, range.width+1, -offset);
				g.fillRect(range.x, range.y+range.height, range.width+1, -offset);
			}
		
			g.setColor(Color.white);
			g.drawRect(range.x, range.y, range.width, range.height);
		}
	}
	
	/**
	 *  Calculate draw area for image.
	 */
	protected Rectangle scaleToFit(Rectangle bounds, int iwidth, int iheight)
	{
		double	iratio	= (double)iwidth/iheight;
		double	bratio	= (double)bounds.width/bounds.height;
		Rectangle	drawarea	= new Rectangle(0, 0, bounds.width, bounds.height);
		
		// Scale to fit height
		if(iratiobratio)
		{
			 double	wratio	= (double)bounds.width/iwidth;
			 drawarea.height	= (int)(iheight*wratio);
			 drawarea.y	= (bounds.height-drawarea.height)/2;
		}
		return drawarea;
	}

	/**
	 *  Get the bounds with respect to insets (if any).
	 *  @param scrollarea	True when inner bounds of scroll area instead of visible window space should be considered.
	 */
	protected Rectangle getInnerBounds(boolean scrollarea)
	{
		Rectangle	bounds	= getBounds();

		if(!scrollarea && getParent() instanceof JViewport)
		{
			// Get bounds of outer scroll panel
			Rectangle	pbounds	= getParent().getParent().getBounds();
			if(bounds.width>pbounds.width || bounds.height>pbounds.height)
			{
				bounds	= pbounds;
			}
		}
		
		Insets	insets	= getInsets();
		if(insets!=null)
		{
			bounds.x	= insets.left;
			bounds.y	= insets.top;
			bounds.width	-= insets.left + insets.right;
			bounds.height	-= insets.top + insets.bottom;
		}
		else
		{
			bounds.x	= 0;
			bounds.y	= 0;
		}
		return bounds;
	}
	
	/**
	 *  Get the desired size of the panel.
	 */
	public Dimension getMinimumSize()
	{
		Insets	ins	= getInsets();
		Dimension	ret	= new Dimension(ins!=null ? ins.left+ins.right : 0, ins!=null ? ins.top+ins.bottom : 0);
		if(image!=null)
		{
			ret.width	+= image.getWidth(this);
			ret.height	+= image.getHeight(this);
		}
		return ret;
	}
	
	/**
	 *  Get the desired size of the panel.
	 */
	public Dimension getPreferredSize()
	{
		return getMinimumSize();
	}

	/**
	 *  Set the color scheme.
	 */
	public void	setColorScheme(Color[] scheme, boolean cycle)
	{
		if(scheme==null || scheme.length==0)
		{
			colors	= new Color[]{Color.white};
		}
		else if(scheme.length==1)
		{
			colors	= scheme;
		}
		else if(cycle)
		{
			colors	= new Color[scheme.length*16];
			for(int i=0; ibratio)
		{
			int	height	= (int)(bounds.width/rratio);
			bounds.height	= height;
		}
		
		
		// Clear image for painting only background.
		DisplayPanel.this.image	= createImage(bounds.width, bounds.height);
		
		calcArea(settings.getXStart(), settings.getXEnd(), settings.getYStart(), settings.getYEnd(), bounds.width, bounds.height);
	}
	
	/**
	 *  Zoom into the selected range.
	 */
	protected void zoomIntoRange()
	{
		// Calculate bounds relative to original image.
		Rectangle	bounds	= getInnerBounds(true);
		Rectangle	drawarea	= scaleToFit(bounds, image.getWidth(DisplayPanel.this), image.getHeight(DisplayPanel.this));
		final double	x	= (double)(range.x-bounds.x-drawarea.x)/drawarea.width;
		final double	y	= (double)(range.y-bounds.y-drawarea.y)/drawarea.height;
		final double	x2	= x + (double)range.width/drawarea.width;
		final double	y2	= y + (double)range.height/drawarea.height;
		
		// Original bounds
		final double	ox	= data.getXStart();
		final double	oy	= data.getYStart();
		final double	owidth	= data.getXEnd()-data.getXStart();
		final double	oheight	= data.getYEnd()-data.getYStart();
		
		// Calculate pixel width/height of visible area.
		bounds	= getInnerBounds(false);
		double	rratio	= (double)range.width/range.height;
		double	bratio	= (double)bounds.width/bounds.height;
		if(rratiobratio)
		{
			bounds.height	= (int)(bounds.width/rratio);
		}
		final Rectangle	area	= bounds;

		calcArea(ox+owidth*x, ox+owidth*x2, oy+oheight*y, oy+oheight*y2, area.width, area.height);
	}

	/**
	 *  Calculate the given area.
	 */
	protected void calcArea(double x1, double x2, double y1, double y2, int sizex, int sizey)
	{
		AreaData	settings;
		if(data==null)
			settings	= GenerateService.ALGORITHMS[0].getDefaultSettings();
		else
			settings	= data;
		
		final AreaData ad	= new AreaData(x1, x2, y1, y2, sizex, sizey,
			settings.getMax(), settings.getParallel(), settings.getTaskSize(), settings.getAlgorithm(), displayid);
		
		DisplayPanel.this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
		calculating	= true;
		repaint();
		
		if(manservice!=null)
		{
			manservice.getGenerateService()
				.addResultListener(new SwingResultListener(new IResultListener()
			{
				public void resultAvailable(IGenerateService gs)
				{
					gs.generateArea(ad).addResultListener(new SwingDefaultResultListener()
					{
						public void customResultAvailable(AreaData result)
						{
							DisplayPanel.this.setResults(result);
						}
						public void customExceptionOccurred(Exception exception)
						{
							calculating	= false;
							DisplayPanel.this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
							super.customExceptionOccurred(exception);
						}
					});
				}
				
				public void exceptionOccurred(Exception exception)
				{
					// Service not found -> ignore
					calculating	= false;
					DisplayPanel.this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));						
				}
			}));
		}
		else
		{
			agent.scheduleStep(new IComponentStep()
			{
				public IFuture execute(IInternalAccess ia)
				{
					ia.getComponentFeature(IRequiredServicesFeature.class).getRequiredService("generateservice")
						.addResultListener(new SwingResultListener(new IResultListener()
					{
						public void resultAvailable(Object result)
						{
							IGenerateService	gs	= (IGenerateService)result;
							gs.generateArea(ad).addResultListener(new SwingDefaultResultListener()
							{
								public void customResultAvailable(AreaData result)
								{
									DisplayPanel.this.setResults(result);
								}
								public void customExceptionOccurred(Exception exception)
								{
									calculating	= false;
									DisplayPanel.this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
									super.customExceptionOccurred(exception);
								}
							});
						}
						
						public void exceptionOccurred(Exception exception)
						{
							// Service not found -> ignore
							calculating	= false;
							DisplayPanel.this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));						
						}
					}));
					return IFuture.DONE;
				}
			});
		}
	}
	
}