/*******************************************************************************
* 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 01.05.2004
*/
package eniac.data;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.util.LinkedList;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
import eniac.Manager;
import eniac.data.control.Controler;
import eniac.data.model.Connector;
import eniac.data.model.EData;
import eniac.data.type.EType;
import eniac.data.view.ConnectorPanel;
import eniac.data.view.EPanel;
import eniac.data.view.parent.ConfigPanel;
import eniac.util.Status;
import eniac.window.EFrame;
import eniac.window.OVWindow;
/**
* @author zoppke
*/
public class CableManager implements Observer, Controler {
// list of cables.
private List<Cable> _cables = new LinkedList<>();
// temporary connectorPanel, when we are dragging on top of it.
private ConnectorPanel _tempCop;
// temporary cable
private Cable _tempCable;
// flag indicating whether we are potentially creating or removing a loadbox
private boolean _loadBox;
// ================================ lifecycle
// ===============================
public CableManager() {
// empty constructor
}
public void init() {
// iterate on all cables and remove the incomplete ones
Cable[] cables = new Cable[_cables.size()];
_cables.toArray(cables);
for (int i = 0; i < cables.length; ++i) {
if (!cables[i].isComplete()) {
removeCable(cables[i]);
}
}
}
// ================================= methods
// ================================
public void paintOnConfigPanel(Graphics g, int lod) {
// get zoom
float zoom = ConfigPanel.heightToPercentage();
// iterate on connectorPanels
for (Cable cable : _cables) {
cable.paintOnConfigPanel(g, zoom, lod);
}
}
public void paintOnBufferedImage(Graphics g, int lod) {
// paint cables
int ovHeight = OVWindow.getInstance().getOVPanel().getHeight();
int configHeight = (int) Status.ZOOMED_HEIGHT.getValue();
float zoom = (float) ovHeight / (float) configHeight;
for (Cable cable : _cables) {
cable.paintOnBufferedImage(g, zoom, lod);
}
}
public void addCop(ConnectorPanel cop) {
// if we already have a cable containing this cop,
// then is nothing to do.
Connector con = (Connector) cop.getData();
Cable cable = findCable(con);
if (cable != null) {
return;
}
// otherwise check cop's partner, if there is any.
int id = con.getPartner();
if (id >= 0) {
IDManager idManager = con.getConfiguration().getIDManager();
Connector partner = (Connector) idManager.get(id);
cable = findCable(partner);
if (cable == null) {
// no cable for the partner. So create new cable.
addCable(new Cable(cop));
}
else {
// we found a cable containing the partner.
// Check, if we are those cable's partner, too.
if (partner.getPartner() == con.getID()) {
cable.addCop(cop);
}
}
}
}
private void addCable(Cable cable) {
_cables.add(cable);
cable.addObserver(this);
}
private void removeCable(Cable cable) {
cable.dispose();
_cables.remove(cable);
update(cable, EData.REPAINT);
}
private Cable findCable(Connector con) {
for (Cable cable : _cables) {
if (cable.containsCon(con)) {
return cable;
}
}
return null;
}
private static Point computeDragPoint(MouseEvent e) {
Point p = ((EPanel) e.getComponent()).getLocationOnConfigPanel();
p.x += e.getX();
p.y += e.getY();
return p;
}
// ============================ Observer methods
// ============================
/**
* @param o
* @param arg
* @see java.util.Observer#update(java.util.Observable, java.lang.Object)
*/
public void update(Observable o, Object arg) {
assert arg != null;
if (arg == EData.REPAINT && Status.LIFECYCLE.getValue() == Manager.LifeCycle.RUNNING) {
// TODO: Find a better way to repaint
EFrame.getInstance().getConfigPanel().repaint();
OVWindow.getInstance().getOVPanel().repaint();
}
}
// =========================== Actionator methods
// ===========================
public void mpressed(MouseEvent e) {
// only track when the left button clicked
if (e.getButton() == MouseEvent.BUTTON1) {
ConnectorPanel cop = (ConnectorPanel) e.getComponent();
Connector con = (Connector) cop.getData();
if (con.isPlugged()) {
// in case of a loadbox just remove loadbox
if (con.getPartner() == con.getID()) {
con.setPlugged(false);
con.setPartnerID(-1);
_loadBox = true;
return;
}
// otherwise find cable and make it dragging.
_tempCable = findCable(con);
_tempCable.removeCop(cop);
_tempCable.setDragPoint(computeDragPoint(e));
_tempCop = cop;
}
else {
_tempCable = new Cable(cop);
_tempCable.setDragPoint(computeDragPoint(e));
addCable(_tempCable);
// if this is an interconnector, set component as tempCop
if (con.getType() == EType.INTER_CONNECTOR) {
_tempCop = cop;
_loadBox = true;
}
}
}
}
public void mreleased(MouseEvent e) {
// only track when the left button clicked
if (e.getButton() == MouseEvent.BUTTON1) {
// determine which component was hit
if (_tempCop == null) {
// we did not hit a connectorPanel
// or the connectorPanel already had a cable.
// Remove cable and forget temporary reference.
if (_tempCable != null) {
removeCable(_tempCable);
_tempCable = null;
}
}
else {
// we hit a connectorPanel. Check, if we should set a loadBox.
Connector con = (Connector) _tempCop.getData();
ConnectorPanel ecop = (ConnectorPanel) e.getSource();
if (_loadBox && ecop == _tempCop) {
// set con as self-partner and remove cable
removeCable(_tempCable);
con.setPartnerID(con.getID());
con.setPlugged(true);
}
else {
// Set cop to cable and keep cable
_tempCable.addCop(_tempCop);
}
// reset temporary references.
_tempCable = null;
_tempCop = null;
}
_loadBox = false;
}
}
public void mdragged(MouseEvent e) {
// if tempcable is null, we are not dragging with left button down.
if (_tempCable == null) {
return;
}
// compute and adjust cables dragpoint
Point dragPoint = computeDragPoint(e);
_tempCable.setDragPoint(dragPoint);
// determine which component we are dragging on
ConfigPanel configPanel = EFrame.getInstance().getConfigPanel();
Component c = configPanel.findComponentAt(dragPoint);
// if component is our temporary cop, then nothing to do
if (_tempCop == c) {
return;
}
// otherwise dispose temporary cop, if any
if (_tempCop != null) {
// if we have a loadbox, we should keep the tempcop plugged.
if (!_loadBox || _tempCop != e.getSource()) {
((Connector) _tempCop.getData()).setPlugged(false);
}
_tempCop = null;
}
// check, if we hit a connectorpanel.
if (c instanceof ConnectorPanel) {
// check if cop is unplugged and a valid partner
ConnectorPanel newCop = (ConnectorPanel) c;
Connector newCon = (Connector) newCop.getData();
ConnectorPanel oldCop = (ConnectorPanel) e.getComponent();
if (!newCon.isPlugged() && Cable.canConnect(newCop, oldCop)) {
// We got possible connection.
_tempCop = newCop;
newCon.setPlugged(true);
}
}
}
}