/******************************************************************************* * See the NOTICE file distributed with this work for additional information * regarding copyright ownership. * * 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 hr.fer.zemris.vhdllab.applets.schema2.gui.canvas; import hr.fer.zemris.vhdllab.applets.editor.schema2.constants.Constants; import hr.fer.zemris.vhdllab.applets.editor.schema2.enums.ECanvasState; import hr.fer.zemris.vhdllab.applets.editor.schema2.enums.EPropertyChange; import hr.fer.zemris.vhdllab.applets.editor.schema2.exceptions.UnknownComponentPrototypeException; import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.ICommand; import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.ICommandResponse; import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.ILocalGuiController; import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.IQuery; import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.IQueryResult; import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.ISchemaComponent; import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.ISchemaComponentCollection; import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.ISchemaController; import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.ISchemaCore; import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.ISchemaWire; import hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.ISchemaWireCollection; import hr.fer.zemris.vhdllab.applets.editor.schema2.misc.Caseless; import hr.fer.zemris.vhdllab.applets.editor.schema2.misc.DrawingProperties; import hr.fer.zemris.vhdllab.applets.editor.schema2.misc.Rect2d; import hr.fer.zemris.vhdllab.applets.editor.schema2.misc.SMath; import hr.fer.zemris.vhdllab.applets.editor.schema2.misc.SchemaPort; import hr.fer.zemris.vhdllab.applets.editor.schema2.misc.WireSegment; import hr.fer.zemris.vhdllab.applets.editor.schema2.misc.XYLocation; import hr.fer.zemris.vhdllab.applets.editor.schema2.model.SimpleSchemaComponentCollection; import hr.fer.zemris.vhdllab.applets.editor.schema2.model.SimpleSchemaWireCollection; import hr.fer.zemris.vhdllab.applets.editor.schema2.model.commands.DeleteSegmentAndDivideCommand; import hr.fer.zemris.vhdllab.applets.editor.schema2.model.commands.DeleteWireCommand; import hr.fer.zemris.vhdllab.applets.editor.schema2.model.commands.InstantiateComponentCommand; import hr.fer.zemris.vhdllab.applets.editor.schema2.model.commands.MoveComponentCommand; import hr.fer.zemris.vhdllab.applets.editor.schema2.model.queries.FindConnectedPins; import java.awt.Color; import java.awt.Component; import java.awt.Cursor; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Insets; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.image.BufferedImage; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.swing.BorderFactory; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.Timer; public class SchemaCanvas extends JPanel implements PropertyChangeListener, ISchemaCanvas { /** * Generated serial ID */ private static final long serialVersionUID = -179843489371055255L; private static final int MIN_COMPONENT_DISTANCE = 10; /** * Image used to create double-buffer effect. */ protected BufferedImage img = new BufferedImage(1, 1, BufferedImage.TYPE_3BYTE_BGR); /** * Collection containing all components in design. */ protected ISchemaComponentCollection components = new SimpleSchemaComponentCollection(); /** * Collection containing all wires in design. */ protected ISchemaWireCollection wires = new SimpleSchemaWireCollection(); /** * controller na razini schema-editora */ protected ISchemaController controller; /** * controller na razini GUI-a */ protected ILocalGuiController localController; /** * Stanje u kojem se canvas nalazi. */ protected ECanvasState state; /** * komponenta koja se iscrtava kao komponenta za dodati */ protected ISchemaComponent addComponentComponent = null; /** * Lokacija komponente za dodati */ protected int addComponentX = 0, addComponentY = 0; /** * Sadr�ani svi podatci o zici za dodati... */ protected IWirePreLocator preLoc = null; /** * trenutni critical point nad kojim je mis */ private CriticalPoint point = null; /** * akcija za animaciju critical point-a */ private Decrementer decrementer = null; /** * critical point sa kojeg je zica krenula */ protected CriticalPoint wireBeginning = null; /** * critical point gdije je zica zavrsila */ protected CriticalPoint wireEnding = null; private DrawingProperties drawProperties = null; private Timer timer = null; protected Caseless componentToMove = null; private boolean isGridOn =true; //constrictors public SchemaCanvas(ISchemaCore core) { this(); components = core.getSchemaInfo().getComponents(); wires = core.getSchemaInfo().getWires(); repaint(); } /** * Dummy constructor za testiranje panela * */ public SchemaCanvas(ISchemaComponentCollection comp, ISchemaWireCollection wir) { this(); components = comp; wires = wir; repaint(); } public SchemaCanvas() { state = ECanvasState.MOVE_STATE; //init state decrementer = new Decrementer(20, this); timer = new Timer(70,decrementer); drawProperties = new DrawingProperties(); this.addMouseListener(new Mouse1()); this.addMouseMotionListener(new Mose2()); this.setOpaque(true); this.setBorder(BorderFactory.createLineBorder(Color.BLACK, 3)); } //########################## //#########################PROTECTED METHODS################################### /** * Overriden method for painting the canvas. */ @Override protected void paintComponent(Graphics g) { Insets in = this.getInsets(); if(img == null) { img=new BufferedImage(this.getWidth()-in.left-in.right,this.getHeight()-in.top-in.bottom , BufferedImage.TYPE_3BYTE_BGR); drawComponents(); } else { if (img.getHeight()!=this.getHeight()-in.top-in.bottom || img.getWidth()!=this.getWidth()-in.left-in.right){ img=new BufferedImage(this.getWidth()-in.left-in.right,this.getHeight()-in.top-in.bottom , BufferedImage.TYPE_3BYTE_BGR); } drawComponents(); g.drawImage(img, in.left, in.right, img.getWidth(), img.getHeight(), null); } } //##################PRIVATE METHODS############################# /** * Private method responsible for drawing all components and wires contained in components * and wires collections. * */ private void drawComponents() { Graphics2D g = (Graphics2D)img.getGraphics(); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); components = controller.getSchemaInfo().getComponents(); wires = controller.getSchemaInfo().getWires(); g.setColor(CanvasColorProvider.CANVAS_BACKGROUND); g.fillRect(0,0,img.getWidth(),img.getHeight()); int dist = Constants.GRID_SIZE; g.setColor(CanvasColorProvider.GRID_DOT); for(int i = 0; i<=img.getWidth()/dist;i++) for(int j=0;j<=img.getHeight()/dist;j++){ g.fillOval(i*dist, j*dist, 1, 1); } Set<Caseless> names = components.getComponentNames(); int sizeX = 0; int sizeY = 0; Caseless sel = localController.getSelectedComponent(); int type = localController.getSelectedType(); for(Caseless name: names){ ISchemaComponent comp = components.fetchComponent(name); XYLocation componentLocation = components.getComponentLocation(name); Color cl = g.getColor(); g.setColor(type == CanvasToolbarLocalGUIController.TYPE_COMPONENT && name.equals(sel)? CanvasColorProvider.COMPONENT_SELECTED: CanvasColorProvider.COMPONENT); g.translate(componentLocation.x, componentLocation.y); comp.getDrawer().draw(g, drawProperties); g.translate(-componentLocation.x, -componentLocation.y); // String text = name.toString(); Rectangle rect = components.getComponentBounds(name); // FontMetrics fm = g.getFontMetrics(); // int tx=rect.x+rect.width/2-fm.stringWidth(text)/2; // int ty=rect.y; // g.drawString(text,tx,ty); if(rect.x + rect.width + 10 > sizeX)sizeX =rect.x + rect.width + 10; if(rect.y + rect.height + 10 > sizeY)sizeY =rect.y + rect.height + 10; g.setColor(cl); } names=wires.getWireNames(); for(Caseless name: names){ Color cl = g.getColor(); g.setColor(type == CanvasToolbarLocalGUIController.TYPE_WIRE && name.equals(sel)? CanvasColorProvider.SIGNAL_LINE_SELECTED: CanvasColorProvider.SIGNAL_LINE); wires.fetchWire(name).getDrawer().draw(g, drawProperties); Rect2d rect = wires.getBounds(name); if(rect.left + rect.width + 10 > sizeX)sizeX =rect.left + rect.width + 10; if(rect.top + rect.height + 10 > sizeY)sizeY =rect.top + rect.height + 10; g.setColor(cl); } if(addComponentComponent!= null){ Color temp = g.getColor(); g.setColor(CanvasColorProvider.COMPONENT_TO_ADD); g.translate(addComponentX, addComponentY); addComponentComponent.getDrawer().draw(g, drawProperties); g.translate(-addComponentX, -addComponentY); g.setColor(temp); } if(preLoc != null){ Color temp = g.getColor(); g.setColor(preLoc.isWireInstantiable()? CanvasColorProvider.SIGNAL_LINE_TO_ADD: CanvasColorProvider.SIGNAL_LINE_ERROR); preLoc.draw(g); g.setColor(temp); } if(point!=null){ point.draw(g, decrementer.getIznos()); } if(type == CanvasToolbarLocalGUIController.TYPE_WIRE && !Caseless.isNullOrEmpty(sel)){ drawConnectedPins(g,sel); } if(type == CanvasToolbarLocalGUIController.TYPE_COMPONENT && !Caseless.isNullOrEmpty(sel)){ ISchemaComponent comp = components.fetchComponent(sel); if (comp != null && comp.getSchemaPorts() != null) { Color cl = g.getColor(); g.setColor(CanvasColorProvider.SIGNAL_LINE_SELECTED_ONCOMP); for (SchemaPort sp : comp.getSchemaPorts()) { Caseless mappedto = sp.getMapping(); if (Caseless.isNullOrEmpty(mappedto)) continue; if (wires.fetchWire(mappedto) != null) { wires.fetchWire(mappedto).getDrawer().draw(g, drawProperties); drawConnectedPins(g, mappedto); } } g.setColor(cl); } } setCanvasSize(sizeX,sizeY); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); } @SuppressWarnings("unchecked") private void drawConnectedPins(Graphics2D g, Caseless sel) { IQuery q = new FindConnectedPins(sel); IQueryResult r = controller.send(q); List<XYLocation> locList = (List<XYLocation>) r.get(FindConnectedPins.KEY_PIN_LOCATIONS); if (locList != null) { Color cl = g.getColor(); g.setColor(CanvasColorProvider.SIGNAL_LINE_SELECTED_PORT); for(XYLocation xy:locList){ g.fillOval(xy.x-4, xy.y-4, 8, 8); } g.setColor(cl); } } private void setCanvasSize(int sizeX, int sizeY) { Insets in = this.getInsets(); this.setPreferredSize(new Dimension(sizeX+in.left+in.right, sizeY+in.top+in.bottom)); this.revalidate(); } //###########################PUBLIC METHODS########################## /* (non-Javadoc) * @see hr.fer.zemris.vhdllab.applets.schema2.gui.canvas.ISchemaCanvas#setDummyStuff(hr.fer.zemris.vhdllab.applets.schema2.interfaces.ISchemaComponentCollection, hr.fer.zemris.vhdllab.applets.schema2.interfaces.ISchemaWireCollection) */ public void setDummyStuff(ISchemaComponentCollection components, ISchemaWireCollection wires) { this.components = components; this.wires = wires; repaint(); } public void propertyChange(PropertyChangeEvent evt) { // System.out.println("Canvas registered:"+evt.getPropertyName()); if(evt.getPropertyName().equals(EPropertyChange.CANVAS_CHANGE.toString())){ drawComponents(); }else if(evt.getPropertyName().equalsIgnoreCase("GRID")){ isGridOn = localController.isGridON(); }else if(evt.getPropertyName().equalsIgnoreCase(CanvasToolbarLocalGUIController.PROPERTY_CHANGE_SELECTION)){ // System.out.println("Canvas registered: localControler.PROPERTY_CHANGE_SELECTION"); }else if(evt.getPropertyName().equalsIgnoreCase(CanvasToolbarLocalGUIController.PROPERTY_CHANGE_STATE) ||evt.getPropertyName().equalsIgnoreCase(CanvasToolbarLocalGUIController.PROPERTY_CHANGE_COMPONENT_TO_ADD)){ this.setCursor(new Cursor(Cursor.DEFAULT_CURSOR)); modifyTimerStatus(); localController.setSelectedComponent(new Caseless(""), CanvasToolbarLocalGUIController.TYPE_NOTHING_SELECTED); addComponentComponent = null; preLoc = null; point = null; addComponentX = 0; addComponentY = 0; ILocalGuiController tempCont = (CanvasToolbarLocalGUIController) evt.getSource(); state = tempCont.getState(); if(state.equals(ECanvasState.ADD_COMPONENT_STATE)){ this.setCursor(new Cursor(Cursor.HAND_CURSOR)); try { addComponentComponent = controller.getSchemaInfo().getPrototyper().clonePrototype(tempCont.getComponentToAdd(), new HashSet<Caseless>()); } catch (UnknownComponentPrototypeException e) { System.out.println("Canvas Property change | illegal action on component initialization."); e.printStackTrace(); } } // System.out.println("Canvas registered:" + tempCont); } repaint(); } /* (non-Javadoc) * @see hr.fer.zemris.vhdllab.applets.schema2.gui.canvas.ISchemaCanvas#registerSchemaController(hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.ISchemaController) */ public void registerSchemaController(ISchemaController c) { this.controller = c; } /* (non-Javadoc) * @see hr.fer.zemris.vhdllab.applets.schema2.gui.canvas.ISchemaCanvas#registerLocalController(hr.fer.zemris.vhdllab.applets.editor.schema2.interfaces.ILocalGuiController) */ public void registerLocalController(ILocalGuiController cont){ localController = cont; } //#############NESTED CLASSES############## protected class Mouse1 implements MouseListener{ public void mouseClicked(MouseEvent e) { if(e.getButton()==MouseEvent.BUTTON1){ if(state.equals(ECanvasState.ADD_COMPONENT_STATE)){ Caseless comp = localController.getComponentToAdd(); ICommand instantiate = new InstantiateComponentCommand(comp, alignToGrid(addComponentX), alignToGrid(addComponentY)); ICommandResponse response = controller.send(instantiate); System.out.println ("canvas report| component instantiate succesful: "+response.isSuccessful()); } else if(state.equals(ECanvasState.DELETE_STATE)){ ISchemaComponent comp = components.fetchComponent(e.getX(), e.getY(), MIN_COMPONENT_DISTANCE); int distToComp = -1; if(comp != null){ //+5 je zbog crtanja komponenti distToComp = 5 + Math.abs(components.distanceTo(comp.getName(), e.getX(), e.getY())); } ISchemaWire wire = wires.fetchWire(e.getX(), e.getY(), 10); int distToWire = -1; if(wire != null){ distToWire = Math.abs(wires.distanceTo(wire.getName(), e.getX(), e.getY())); } if(distToComp != -1){ if(distToWire != -1){ if(distToComp>=distToWire){ int segNo = SMath.calcClosestSegment(new XYLocation(e.getX(), e.getY()), 10, wire.getSegments()); if (segNo != SMath.ERROR) { WireSegment seg = wire.getSegments().get(segNo); ICommand deleteSegment = new DeleteSegmentAndDivideCommand(wire.getName(),seg); controller.send(deleteSegment); } } } }else{ if(distToWire != -1){ int segNo = SMath.calcClosestSegment(new XYLocation(e.getX(), e.getY()), 10, wire.getSegments()); if (segNo != SMath.ERROR) { WireSegment seg = wire.getSegments().get(segNo); ICommand deleteSegment = new DeleteSegmentAndDivideCommand(wire.getName(),seg); controller.send(deleteSegment); } } } } else if(state.equals(ECanvasState.MOVE_STATE)){ ISchemaComponent comp = components.fetchComponent(e.getX(), e.getY(), MIN_COMPONENT_DISTANCE); int distToComp = -1; if(comp != null){ //+5 je zbog crtanja komponenti... distToComp = 5 + Math.abs(components.distanceTo(comp.getName(), e.getX(), e.getY())); } ISchemaWire wire = wires.fetchWire(e.getX(), e.getY(), 10); int distToWire = -1; if(wire != null){ distToWire = Math.abs(wires.distanceTo(wire.getName(), e.getX(), e.getY())); } if(distToComp != -1){ if(distToWire != -1){ if(distToComp<distToWire){ localController.setSelectedComponent(comp.getName(),CanvasToolbarLocalGUIController.TYPE_COMPONENT); }else{ localController.setSelectedComponent(wire.getName(), CanvasToolbarLocalGUIController.TYPE_WIRE); } }else{ localController.setSelectedComponent(comp.getName(),CanvasToolbarLocalGUIController.TYPE_COMPONENT); } }else{ if(distToWire != -1){ localController.setSelectedComponent(wire.getName(), CanvasToolbarLocalGUIController.TYPE_WIRE); } } } }else if(e.getButton()==MouseEvent.BUTTON3){ if(state.equals(ECanvasState.MOVE_STATE)){ localController.setSelectedComponent(new Caseless(""), CanvasToolbarLocalGUIController.TYPE_NOTHING_SELECTED); }else if(state.equals(ECanvasState.ADD_WIRE_STATE)){ preLoc = null; wireBeginning = null; wireEnding = null; repaint(); }else if(state.equals(ECanvasState.DELETE_STATE)){ ISchemaWire wire = wires.fetchWire(e.getX(), e.getY(), 10); if(wire != null){ if(doDeleteWire(SchemaCanvas.this)){ ICommand delete = new DeleteWireCommand(wire.getName()); ICommandResponse response = controller.send(delete); System.out.println ("canvas report| component delete succesful: "+response.isSuccessful()); } } } } } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) {} public void mousePressed(MouseEvent e) { if(e.getButton() == MouseEvent.BUTTON1){ if(state.equals(ECanvasState.ADD_WIRE_STATE)){ wireBeginning = getCriticalPoint(e.getX(),e.getY()); int x = alignToGrid(e.getX()); int y = alignToGrid(e.getY()); if(wireBeginning!=null){ x=wireBeginning.getX(); y=wireBeginning.getY(); } if(localController.isSmartConectON()){ preLoc = new AdvancedWirePreLocator(new ArrayList<WireSegment>(),controller); preLoc.setX1(x); preLoc.setY1(y); }else{ preLoc = new WirePreLocator(x,y,x,y); } }else if(state.equals(ECanvasState.MOVE_STATE)){ ISchemaComponent comp = components.fetchComponent(e.getX(), e.getY(), MIN_COMPONENT_DISTANCE); if(comp!=null){ componentToMove = comp.getName(); localController.setSelectedComponent(comp.getName(),CanvasToolbarLocalGUIController.TYPE_COMPONENT); } } } } public void mouseReleased(MouseEvent e) { if(e.getButton()==MouseEvent.BUTTON1){ if(state.equals(ECanvasState.ADD_WIRE_STATE)&&preLoc!=null){ wireEnding = getCriticalPoint(e.getX(),e.getY()); int x = alignToGrid(e.getX()); int y = alignToGrid(e.getY()); if(wireEnding!=null){ x=wireEnding.getX(); y=wireEnding.getY(); } preLoc.setX2(x); preLoc.setY2(y); preLoc.revalidateWire(); preLoc.setWireInstantiable(wireBeginning,wireEnding); if(preLoc.isWireInstance()){ preLoc.instantiateWire(controller, wireBeginning, wireEnding); } preLoc = null; wireBeginning = null; wireEnding = null; repaint(); }else if(state.equals(ECanvasState.MOVE_STATE)){ componentToMove = null; } } } } protected class Mose2 implements MouseMotionListener{ public void mouseDragged(MouseEvent e) { if(state.equals(ECanvasState.ADD_WIRE_STATE)&&preLoc!=null){ preLoc.setX2(alignToGrid(e.getX())); preLoc.setY2(alignToGrid(e.getY())); point = getCriticalPoint(e.getX(), e.getY()); preLoc.setWireInstantiable(wireBeginning,point); preLoc.revalidateWire(); modifyTimerStatus(); repaint(); }else if(state.equals(ECanvasState.MOVE_STATE)&&componentToMove!=null){ ISchemaComponent comp = components.fetchComponent(componentToMove); if(comp != null && e.getX()>comp.getWidth()/2&&e.getY()>comp.getHeight()/2){ ICommand move = new MoveComponentCommand( componentToMove,new XYLocation( alignToGrid(e.getX()-comp.getWidth()/2),alignToGrid(e.getY()-comp.getHeight()/2) ) ); controller.send(move); //System.out.println ("canvas report| component delete succesful: "+response.isSuccessful()); } } } public void mouseMoved(MouseEvent e) { if(state.equals(ECanvasState.ADD_COMPONENT_STATE)){ int x = e.getX(); int y = e.getY(); if(x > addComponentComponent.getWidth()/2 && y > addComponentComponent.getHeight()/2 && x < img.getWidth() && y < img.getHeight()) { addComponentX = alignToGrid(x-addComponentComponent.getWidth()/2); addComponentY = alignToGrid(y-addComponentComponent.getHeight()/2); repaint(); } } if(state.equals(ECanvasState.ADD_WIRE_STATE)){ point = getCriticalPoint(e.getX(), e.getY()); modifyTimerStatus(); repaint(); } } } public static boolean doDeleteWire(Component comp) { String[] options={"Yes", "No" }; JLabel name=new JLabel("Delete entire wire?"); JOptionPane optionPane=new JOptionPane(name,JOptionPane.QUESTION_MESSAGE,JOptionPane.OK_CANCEL_OPTION,null,options,options[0]); JDialog dialog=optionPane.createDialog(comp,"VHDLLAB"); dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); dialog.setVisible(true); Object selected=optionPane.getValue(); return selected.equals(options[0]); } public void modifyTimerStatus() { if(point==null)timer.stop(); else{ decrementer.reset(); timer.start(); } } public CriticalPoint getCriticalPoint(int x, int y) { CriticalPoint point = null; ISchemaComponent comp = components.fetchComponent(x,y, MIN_COMPONENT_DISTANCE); if(comp!=null){ Rectangle rect = components.getComponentBounds(comp.getName()); SchemaPort port = comp.getSchemaPort(x-rect.x, y-rect.y, MIN_COMPONENT_DISTANCE); if(port != null){ if(port.getMapping()==null||port.getMapping().equals(new Caseless(""))){ point = new CriticalPoint(port.getOffset().getX()+rect.x,port.getOffset().getY()+rect.y, CriticalPoint.ON_COMPONENT_PLUG,comp.getName(),port.getName()); decrementer.reset(); } } } if(point == null){ ISchemaWire wire = wires.fetchWire(x, y, Constants.GRID_SIZE/2-1); if(wire != null){ point = new CriticalPoint(wire, alignToGrid(x), alignToGrid(y)); } } return point; } protected int alignToGrid(int x){ if(isGridOn) return Math.round((float)x/Constants.GRID_SIZE)*Constants.GRID_SIZE; return x; } }