// $Id: MotePanel.java,v 1.4.4.3 2003/08/26 09:08:11 cssharp Exp $ /* tab:2 * * * "Copyright (c) 2000 and The Regents of the University * of California. All rights reserved. * * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose, without fee, and without written * agreement is hereby granted, provided that the above copyright * notice and the following two paragraphs appear in all copies of * this software. * * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL * DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS * DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, * UPDATES, ENHANCEMENTS, OR MODIFICATIONS." * * Authors: Phil Levis * Date: October 11 2002 * Desc: Double buffer area and clicking functionaliy. * */ /** * @author Phil Levis */ package net.tinyos.sim; import net.tinyos.sim.event.*; import net.tinyos.sim.plugins.*; import java.awt.*; import java.awt.event.*; import java.util.*; import javax.swing.*; import java.awt.dnd.*; import java.awt.datatransfer.*; import javax.swing.event.*; import java.io.*; public class MotePanel extends JPanel { private TinyViz tv; private Image doubleBufferImage; private Dimension doubleBufferImageSize; private Graphics doubleBufferGraphic; private MouseHandler mouseHandler; public Graphics graphics; private SimEventBus eventBus; private SimState state; private Insets insets; private int xLines = 7; private int yLines = 7; private int numDashes = 63; // number of dashes in lines private boolean gridOn = false; private CoordinateTransformer cT; private SimObjectPopupMenu popup = null; private MouseEvent mouseEvent = null; public MotePanel(TinyViz tv) { this.tv = tv; this.eventBus = tv.getEventBus(); this.state = tv.getSimState(); this.cT = tv.getCoordTransformer(); mouseHandler = new MouseHandler(this, tv); this.setBackground(Color.white); this.addMouseListener(mouseHandler); this.addMouseMotionListener(mouseHandler); this.setPreferredSize(new Dimension((int)cT.getWindowWidth(), (int)cT.getWindowHeight())); this.dtListener = new DTListener(); // component, ops, listener, accepting this.dropTarget = new DropTarget(this, DnDConstants.ACTION_COPY_OR_MOVE, this.dtListener, true); // XXX RepaintManager.currentManager(this).setDoubleBufferingEnabled(false); } public void toggleGrid() { synchronized (eventBus) { gridOn = !gridOn; refresh(); } } //devjani public void putResponder(ResponderDroppedEvent sim) { System.out.println("inside mote putres"+sim.getx()+"**"+ sim.gety()); Image doubleBufferImage = createImage(sim.getx(), sim.gety()); Graphics doubleBufferGraphic = doubleBufferImage.getGraphics(); doubleBufferGraphic.fillRect(0, 0, sim.getx(), sim.gety()); doubleBufferGraphic.setFont(tv.smallFont); super.paint(doubleBufferGraphic);//first paint the panel normally eventBus.drawPlugins(doubleBufferGraphic); graphics.drawImage(doubleBufferImage,0,0, this); } private void drawDottedLine(Graphics g, int x1, int y1, int x2, int y2) { double xDiff = (double)(x2 - x1); double yDiff = (double)(y2 - y1); double dashes = (double)numDashes; for (int i = 0; i < numDashes; i+=2) { double index = (double)i; int xStart = (int)((index / dashes) * xDiff + (double)x1); int yStart = (int)((index / dashes) * yDiff + (double)y1); int xEnd = (int)(((index + 1.0) / dashes) * xDiff + (double)x1); int yEnd = (int)(((index + 1.0) / dashes) * yDiff + (double)y1); g.drawLine(xStart, yStart, xEnd, yEnd); } } public void paintGrid(Graphics graphics) { graphics.setColor(tv.paleBlue); graphics.setFont(tv.smallFont); //String scaleStr = "Scale: " + cT.getMoteScaleWidth() + "x" + cT.getMoteScaleHeight(); //graphics.drawString(scaleStr, 2, 10); int xTick = (int)(cT.getWindowWidth() / (xLines + 1)); int yTick = (int)(cT.getWindowHeight() / (yLines + 1)); // Draw vertical lines for (int i = 0; i < xLines; i++) { int xCoord = xTick * (i + 1); graphics.drawLine(xCoord, 10, xCoord, (int)cT.getWindowHeight()); //drawDottedLine(graphics, xCoord, 10, xCoord, (int)cT.getWindowHeight()); double index = (cT.getMoteScaleWidth() / (double)(xLines + 1)) * (double)(i + 1); String label = "" + index; if (label.length() > 6) {label = label.substring(0,5);} graphics.drawString(label, xCoord-10, 10); } // Draw horizontal lines for (int i = 0; i < yLines; i++) { int yCoord = yTick * (i + 1); graphics.drawLine(0, yCoord, (int)cT.getWindowWidth(), yCoord); //drawDottedLine(graphics, 0, yCoord, (int)cT.getWindowWidth(), yCoord); double index = (cT.getMoteScaleHeight() / (double)(yLines + 1)) * (double)(i + 1); String label = "" + index; if (label.length() > 6) {label = label.substring(0,5);} graphics.drawString(label, 0, yCoord-2); } // Draw thick vertical line separating grid from rest of gui //graphics.fillRect(xTick * (xLines + 1), 0, 40, (int)cT.getWindowWidth()); } public void paint(Graphics graphics) { this.graphics = graphics; // Don't want any events to be processed while we are painting synchronized (eventBus) { if ((popup != null) && (mouseEvent != null)) { //System.out.println("About to call show on PopupMenu"); popup.show(mouseEvent.getComponent(), mouseEvent.getX(), mouseEvent.getY()); //System.out.println("Done calling show on PopupMenu"); mouseEvent = null; popup = null; } else if ((popup != null) || (mouseEvent != null)) { System.out.println("ERROR WITH POPUP MENUS, synchronization is off!"); System.exit(-1); } //System.out.println("paint in TinyVizDoubleBufferPanel called"); //Dimension size = getSize(); //eventBus.enqueuePaintEvent(this); Dimension size = getSize(); if ((doubleBufferImage == null) || (size.width != doubleBufferImageSize.width) || (size.height != doubleBufferImageSize.height)) { doubleBufferImage = createImage(size.width, size.height); doubleBufferImageSize = size; cT.setWindowWidth(size.width); cT.setWindowHeight(size.height); } if (doubleBufferGraphic != null) { doubleBufferGraphic.dispose(); } doubleBufferGraphic = doubleBufferImage.getGraphics(); //doubleBufferGraphic.setColor(Color.gray); doubleBufferGraphic.fillRect(0, 0, (int)size.getWidth(), (int)size.getHeight()); doubleBufferGraphic.setFont(tv.smallFont); super.paint(doubleBufferGraphic);//first paint the panel normally if (gridOn) paintGrid(doubleBufferGraphic); eventBus.drawPlugins(doubleBufferGraphic); mouseHandler.draw(doubleBufferGraphic); graphics.drawImage(doubleBufferImage,0,0,this); } } Runnable waitRunnable = new Runnable() { public void run() { // Do nothing return; } }; public void refreshAndWait() { repaint(); try { SwingUtilities.invokeAndWait(waitRunnable); } catch (Exception ie) { // Ignore } } public void refresh() { repaint(); } public void refresh(SimObjectPopupMenu popup, MouseEvent e) { synchronized (eventBus) { this.popup = popup; this.mouseEvent = e; repaint(); } } public CoordinateTransformer getCoordinateTransformer() { return cT; } /** * DTListener * a listener that tracks the state of the operation * @see java.awt.dnd.DropTargetListener * @see java.awt.dnd.DropTarget */ class DTListener implements DropTargetListener { /** * Called by isDragOk * Checks to see if the flavor drag flavor is acceptable * @param e the DropTargetDragEvent object * @return whether the flavor is acceptable */ private boolean isDragFlavorSupported(DropTargetDragEvent e) { boolean ok=false; if (e.isDataFlavorSupported(StringTransferable.plainTextFlavor)) { ok=true; } else if (e.isDataFlavorSupported( StringTransferable.localStringFlavor)) { ok=true; } else if (e.isDataFlavorSupported(DataFlavor.stringFlavor)) { ok=true; } else if (e.isDataFlavorSupported(DataFlavor.plainTextFlavor)) { ok=true; } return ok; } /** * Called by drop * Checks the flavors and operations * @param e the DropTargetDropEvent object * @return the chosen DataFlavor or null if none match */ private DataFlavor chooseDropFlavor(DropTargetDropEvent e) { if (e.isLocalTransfer() == true && e.isDataFlavorSupported(StringTransferable.localStringFlavor)) { return StringTransferable.localStringFlavor; } DataFlavor chosen = null; if (e.isDataFlavorSupported(StringTransferable.plainTextFlavor)) { chosen = StringTransferable.plainTextFlavor; } else if (e.isDataFlavorSupported( StringTransferable.localStringFlavor)) { chosen = StringTransferable.localStringFlavor; } else if (e.isDataFlavorSupported(DataFlavor.stringFlavor)) { chosen = DataFlavor.stringFlavor; } else if (e.isDataFlavorSupported(DataFlavor.plainTextFlavor)) { chosen = DataFlavor.plainTextFlavor; } return chosen; } /** * Called by dragEnter and dragOver * Checks the flavors and operations * @param e the event object * @return whether the flavor and operation is ok */ private boolean isDragOk(DropTargetDragEvent e) { if(isDragFlavorSupported(e) == false) { return false; } // the actions specified when the source // created the DragGestureRecognizer // int sa = e.getSourceActions(); // the docs on DropTargetDragEvent rejectDrag says that // the dropAction should be examined int da = e.getDropAction(); //System.out.println(" my acceptable actions " + acceptableActions); // we're saying that these actions are necessary /*if ((da & DropLabel.this.acceptableActions) == 0) return false;*/ return true; } /** * start "drag under" feedback on component * invoke acceptDrag or rejectDrag based on isDragOk */ public void dragEnter(DropTargetDragEvent e) { if(isDragOk(e) == false) { e.rejectDrag(); return; } e.acceptDrag(e.getDropAction()); } /** * continue "drag under" feedback on component * invoke acceptDrag or rejectDrag based on isDragOk */ public void dragOver(DropTargetDragEvent e) { if(isDragOk(e) == false) { e.rejectDrag(); return; } e.acceptDrag(e.getDropAction()); } public void dropActionChanged(DropTargetDragEvent e) { if(isDragOk(e) == false) { e.rejectDrag(); return; } e.acceptDrag(e.getDropAction()); } public void dragExit(DropTargetEvent e) { } /** * perform action from getSourceActions on * the transferrable * invoke acceptDrop or rejectDrop * invoke dropComplete * if its a local (same JVM) transfer, use StringTransferable.localStringFlavor * find a match for the flavor * check the operation * get the transferable according to the chosen flavor * do the transfer */ public void drop(DropTargetDropEvent e) { DataFlavor chosen = chooseDropFlavor(e); if (chosen == null) { System.err.println( "No flavor match found" ); e.rejectDrop(); return; } System.err.println( "Chosen data flavor is " + chosen.getMimeType()); // the actual operation int da = e.getDropAction(); // the actions that the source has specified with DragGestureRecognizer int sa = e.getSourceActions(); Point p = e.getLocation(); int xpos = (new Double(p.getX())).intValue(); int ypos = (new Double(p.getY())).intValue(); //devjani ResponderDroppedEvent event = new ResponderDroppedEvent(); event.setx(xpos); event.sety(ypos); System.out.println("*******inside drop : "+event.getx()+"*******"+event.gety()); synchronized(eventBus) { eventBus.addEvent(event); } /* if ( ( sa & DropLabel.this.acceptableActions ) == 0 ) { System.err.println( "No action match found" ); e.rejectDrop(); return; } */ Object data=null; try { /* * the source listener receives this action in dragDropEnd. * if the action is DnDConstants.ACTION_COPY_OR_MOVE then * the source receives MOVE! */ //e.acceptDrop(DropLabel.this.acceptableActions); // e.acceptDrop(DnDConstants.ACTION_MOVE); //e.acceptDrop(DnDConstants.ACTION_COPY); e.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); data = e.getTransferable().getTransferData(chosen); if (data == null) throw new NullPointerException(); } catch ( Throwable t ) { System.err.println( "Couldn't get transfer data: " + t.getMessage()); t.printStackTrace(); e.dropComplete(false); return; } System.out.println( "Got data: " + data.getClass().getName() ); if (data instanceof String ) { String s = (String) data; //DropLabel.this.setText(s); } else if (data instanceof InputStream) { InputStream input = (InputStream)data; InputStreamReader isr = null; // BufferedReader br = null; try { // br = new BufferedReader(isr=new InputStreamReader(input,"Unicode")); isr=new InputStreamReader(input,"Unicode"); } catch(UnsupportedEncodingException uee) { isr=new InputStreamReader(input); } StringBuffer str = new StringBuffer(); int in=-1; try { while((in = isr.read()) >= 0 ) { //System.out.println("read: " + in); if (in != 0) str.append((char)in); } /* you get garbage chars this way try { String line=null; while( (line = br.readLine()) != null) { str.append(line); str.append('\n'); System.out.println( "read: " + line); System.out.println( "read: " + (int)line.charAt(line.length()-1)); } br.close(); */ //DropLabel.this.setText(str.toString()); } catch(IOException ioe) { /* bug #4094987 sun.io.MalformedInputException: Missing byte-order mark e.g. if dragging from MS Word 97 still a bug in 1.2 final */ System.err.println( "cannot read" + ioe); e.dropComplete(false); String message = "Bad drop\n" + ioe.getMessage(); return; } } else { System.out.println( "drop: rejecting"); e.dropComplete(false); return; } e.dropComplete(true); } } public DropTarget dropTarget; public DropTargetListener dtListener; }