/******************************************************************************* * Copyright (c) 2003-2005, 2013 Till Zoppke. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v3.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/gpl.html * * Contributors: * Till Zoppke - initial API and implementation ******************************************************************************/ /* * Created on 16.03.2004 */ package eniac.data; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Point; import java.util.Observable; import java.util.Observer; import eniac.data.model.Connector; import eniac.data.model.EData; import eniac.data.model.parent.Configuration; import eniac.data.type.EType; import eniac.data.view.ConnectorPanel; import eniac.data.view.parent.ConfigPanel; import eniac.simulation.EEvent; import eniac.simulation.EEventListener; import eniac.skin.Descriptor; import eniac.util.Status; import eniac.window.EFrame; import eniac.window.OVWindow; /** * @author zoppke */ public class Cable extends Observable implements Observer, EEventListener { // connectorPanels private ConnectorPanel _cop1; private ConnectorPanel _cop2; private Point _dragPoint = null; private boolean _pulseTransmittion = false; // ============================= lifecycle //=============================== public Cable(ConnectorPanel cop) { _cop1 = cop; _cop1.getData().addObserver(this); ((Connector) _cop1.getData()).setPlugged(true); } // =============================== methods //=============================== public boolean isComplete() { return _cop1 != null && _cop2 != null; } public boolean isDragging() { return _dragPoint != null; } public void setDragPoint(Point p) { // adjust dragpoint _dragPoint = p; // notify observing configPanel setChanged(); notifyObservers(EData.REPAINT); // TODO: find finer way of repainting. // Like this the whole configpanel will be updated. } public void paintOnBufferedImage(Graphics g, float zoom, int lod) { // check, if we can paint this cable if (!isComplete() && !isDragging()) { return; } // get points and paint Point p1 = getBufferedPaintPoint(_cop1); Point p2 = getBufferedPaintPoint(_cop2); paint(g, zoom, lod, p1, p2); } private Point getBufferedPaintPoint(ConnectorPanel cop) { if (cop == null) { Dimension ovSize = OVWindow.getInstance().getOVPanel().getSize(); ConfigPanel cp = EFrame.getInstance().getConfigPanel(); int x = _dragPoint.x * ovSize.width / cp.getWidth(); int y = _dragPoint.y * ovSize.height / cp.getHeight(); return new Point(x, y); } return cop.getBufferedPaintPoint(); } public void paintOnConfigPanel(Graphics g, float zoom, int lod) { // check, if we can paint this cable if (!isComplete() && !isDragging()) { return; } // get points and paint Point p1 = getConfigPaintPoint(_cop1); Point p2 = getConfigPaintPoint(_cop2); paint(g, zoom, lod, p1, p2); } private Point getConfigPaintPoint(ConnectorPanel cop) { if (cop == null) { return _dragPoint; } Point p = cop.getLocationOnConfigPanel(); p.x += cop.getWidth() >> 1; p.y += cop.getHeight() >> 1; return p; } private void paintImmediately() { // paint on configpanel ConfigPanel cp = EFrame.getInstance().getConfigPanel(); float zoom = ConfigPanel.heightToPercentage(); paintOnConfigPanel(cp.getGraphics(), zoom, cp.getLod()); // notify observers to cause a repaint of configpanel and ovPanel. setChanged(); notifyObservers(EData.REPAINT); } private void paint(Graphics g, float zoom, int lod, Point p1, Point p2) { // get descriptor EType type = _cop1.getData().getType(); Descriptor descriptor = type.getDescriptor(lod); // if descriptor is null, then return. if (descriptor == null) { return; } // set color for drawing if (_pulseTransmittion && (Boolean) Status.HIGHLIGHT_PULSE.getValue()) { g.setColor((Color) descriptor.get(Descriptor.Key.CABLE_COLOR_HIGHLIGHT)); } else { g.setColor((Color) descriptor.get(Descriptor.Key.CABLE_COLOR)); } // compute helper variables float pixels = ((Integer) descriptor.get(Descriptor.Key.CABLE_PIXELS)).floatValue() * zoom; int dx = p2.x - p1.x; int dy = p2.y - p1.y; float distance = (float) Math.sqrt(dx * dx + dy * dy); float factor1 = pixels / distance; float factor2 = pixels / distance; int xx1 = (int) (dy * factor1) >> 1; int yy1 = (int) (dx * factor1) >> 1; int xx2 = (int) (dy * factor2) >> 1; int yy2 = (int) (dx * factor2) >> 1; // if polygon is too small, draw a line if (xx1 == 0 && yy1 == 0) { g.drawLine(p1.x, p1.y, p2.x, p2.y); } else { // init polygon points and draw polygon int[] px = new int[4]; int[] py = new int[4]; px[0] = p1.x + xx1; py[0] = p1.y - yy1; px[1] = p1.x - xx2; py[1] = p1.y + yy2; px[2] = p2.x - xx1; py[2] = p2.y + yy1; px[3] = p2.x + xx2; py[3] = p2.y - yy2; g.fillPolygon(px, py, 4); } } public boolean containsCop(ConnectorPanel cop) { return _cop1 == cop || _cop2 == cop; } public boolean containsCon(Connector con) { return (_cop1 != null && _cop1.getData() == con) || (_cop2 != null && _cop2.getData() == con); } public void removeCop(ConnectorPanel cop) { disposeCop(cop); if (_cop1 == cop) { _cop1 = _cop2; _cop2 = null; } else if (_cop2 == cop) { _cop2 = null; } else { return; // TODO: log, that cable doesn't contain cop } if (_cop1 == null) { // maybe dispose cable } else { ((Connector) _cop1.getData()).setPartnerID(-1); } } public void dispose() { if (_cop1 != null) { disposeCop(_cop1); _cop1 = null; } if (_cop2 != null) { disposeCop(_cop2); _cop2 = null; } _dragPoint = null; deleteObservers(); } private void disposeCop(ConnectorPanel cop) { Connector con = (Connector) cop.getData(); con.setPlugged(false); con.setPartnerID(-1); con.deleteObserver(this); } public void addCop(ConnectorPanel cop) { // set cop and add observer if (_cop1 == null) { _cop1 = cop; } else if (_cop2 == null) { _cop2 = cop; } else { // TODO: log that cable already was complete return; } cop.getData().addObserver(this); // if cable is completed just now, make its cops plugged partners if (isComplete()) { Connector con1 = (Connector) _cop1.getData(); Connector con2 = (Connector) _cop2.getData(); con1.setPartnerID(con2.getID()); con2.setPartnerID(con1.getID()); con1.setPlugged(true); con2.setPlugged(true); // set dragpoint to null _dragPoint = null; // notify observers // TODO: call observers from CableManager setChanged(); notifyObservers(EData.REPAINT); } } public static boolean canConnect(ConnectorPanel cop1, ConnectorPanel cop2) { // get data types EType type1 = cop1.getData().getType(); EType type2 = cop2.getData().getType(); // check for program connectors if (type1 == EType.PROGRAM_CONNECTOR && type2 == EType.PROGRAM_CONNECTOR) { return true; } // check for digitConnectors if ((type1 == EType.DIGIT_CONNECTOR || type1 == EType.DIGIT_CONNECTOR_CROSS) && (type2 == EType.DIGIT_CONNECTOR || type2 == EType.DIGIT_CONNECTOR_CROSS)) { return true; } // check for (unit-)interconnectors if (type1 == EType.INTER_CONNECTOR && type2 == EType.INTER_CONNECTOR) { return true; } // otherwise return false. return false; } /** * @param o * @param arg * @see java.util.Observer#update(java.util.Observable, java.lang.Object) */ public void update(Observable o, Object arg) { if (arg == Connector.CABLE_TRANSMITTION) { // set pulse transmittion flag for painting _pulseTransmittion = true; // set alarm clock for downlightning long time = (long) Status.SIMULATION_TIME.getValue(); Configuration config = (Configuration) Status.CONFIGURATION.getValue(); config.getCyclingLights().setAlarmClock(time, this); // if we are highlightning, repaint. if ((boolean) Status.HIGHLIGHT_PULSE.getValue()) { paintImmediately(); } } } /** * @param e * @see eniac.simulation.EEventListener#process(eniac.simulation.EEvent) */ public void process(EEvent e) { // check, if this cable hasn't removed if (!isDragging() && !isComplete()) { return; } // check if this cable is addressed correctly if (e.type == EEvent.ALARM && e.listener == this) { _pulseTransmittion = false; paintImmediately(); } } }