package ui.view;
import classes.*;
import ui.controller.Control;
import ui.controller.UpdateController;
import ui.model.Model;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.TimerTask;
/**
* Collection of methods and values needed in both MyCanvas
and UpperNodeCanvas
*
* Although Java works on references we chose to add explicit return values for clearer code understanding in most cases
*
* @author: I. Dix
*/
public abstract class AbstractCanvas extends JPanel {
final JMenuItem itemDelete = new JMenuItem(Languages.getLanguage()[98]);
final JMenuItem itemCut = new JMenuItem(Languages.getLanguage()[95]);
final JMenuItem itemCopy = new JMenuItem(Languages.getLanguage()[96]);
final JMenuItem itemPaste = new JMenuItem(Languages.getLanguage()[97]);
final JMenuItem itemGroup = new JMenuItem(Languages.getLanguage()[99]);
final JMenuItem itemUngroup = new JMenuItem(Languages.getLanguage()[100]);
final JMenuItem itemTrack = new JMenuItem(Languages.getLanguage()[101]);
final JMenuItem itemUntrack = new JMenuItem(Languages.getLanguage()[102]);
final int ANIMTIME = 500; // animation Time
private final int animFPS = 60;
final int animDelay = 1000 / animFPS; // animation Delay
protected Model model;
protected Control controller;
protected int x = 0;
protected int y = 0;
// Selection
AbstractCpsObject tempCps = null;
UpdateController updCon;
// PopUpMenu
JPopupMenu popmenu = new JPopupMenu();
// Tooltip
boolean toolTip; // Tooltip on or off
Position toolTipPos = new Position(); // Tooltip Position
String toolTipText = "";
ArrayList dataSelected = new ArrayList<>();
ArrayList tempSelected = new ArrayList<>();
boolean[] showedInformation = new boolean[5];
boolean dragging = false; // for dragging
boolean dragged = false; // if an object/objects was/were dragged
boolean drawEdge = false; // for drawing edges
boolean doMark = false; // for double click
CpsEdge edgeHighlight = null;
Point mousePosition = new Point(); // Mouse Position when
ArrayList savePos;
// edge Object Start Point
int cx, cy;
int sx, sy; // Mark Coords
Position unPos;
// Animation
Timer animT; // animation Timer
int animDuration = ANIMTIME; // animation Duration
int animSteps = animDuration / animDelay; // animation Steps;
ArrayList animCps = null;
// Graphics
Image img = null; // Contains the image to draw on the Canvas
Graphics2D g2; // For Painting
float scalediv20;
// Mouse
private boolean click = false;
// ------------------------------------------ METHODS ------------------------------------------
String paintEdge(CpsEdge con, String maxCap) {
if (con.getA().getId() != model.getSelectedObjectID() && con.getB().getId() != model.getSelectedObjectID()
&& con != edgeHighlight) {
if (con.getConnected() == CpsEdge.CON_UPPER_NODE) {
setEdgeState(con);
} else {
g2.setColor(Color.DARK_GRAY);
g2.setStroke(new BasicStroke(2));
}
g2.drawLine(con.getA().getPosition().x, con.getA().getPosition().y, con.getB().getPosition().x,
con.getB().getPosition().y);
maxCap = setCapacityString(con, maxCap);
if (showedInformation[0]) {
if (con.getConnected() == CpsEdge.CON_UPPER_NODE
|| con.getConnected() == CpsEdge.CON_UPPER_NODE_AND_INSIDE) {
g2.drawString(con.getFlow() + "/" + maxCap,
(con.getA().getPosition().x + con.getB().getPosition().x) / 2,
(con.getA().getPosition().y + con.getB().getPosition().y) / 2);
} else {
g2.drawString("not connected", (con.getA().getPosition().x + con.getB().getPosition().x) / 2,
(con.getA().getPosition().y + con.getB().getPosition().y) / 2);
}
}
}
return maxCap;
}
void setEdgeState(CpsEdge con) {
if (con.isWorking()) {
g2.setColor(Color.GREEN);
if (con.getCapacity() != CpsEdge.CAPACITY_INFINITE) {
g2.setStroke(new BasicStroke(Math.min(((con.getFlow() / con.getCapacity() * 3) + 1), 4)));
}
} else {
g2.setColor(Color.RED);
g2.setStroke(new BasicStroke(2));
}
}
String setCapacityString(CpsEdge con, String maxCap) {
if (con.getCapacity() == -1) {
maxCap = Character.toString('\u221e');
} else if (con.getCapacity() == -2) {
maxCap = "???";
} else {
maxCap = String.valueOf(con.getCapacity());
}
return maxCap;
}
String drawEdgeLine(CpsEdge con, String maxCap) {
if (con.getA().getId() == model.getSelectedObjectID()
|| model.getSelectedCpsObjects().contains(con.getA()) || tempSelected.contains(con.getA())
|| con.getB().getId() == model.getSelectedObjectID()
|| model.getSelectedCpsObjects().contains(con.getB())
|| tempSelected.contains(con.getB()) && con != edgeHighlight) {
g2.drawLine(con.getA().getPosition().x, con.getA().getPosition().y, con.getB().getPosition().x,
con.getB().getPosition().y);
maxCap = setCapacityString(con, maxCap);
if (showedInformation[0]) {
if (con.getConnected() == CpsEdge.CON_UPPER_NODE
|| con.getConnected() == CpsEdge.CON_UPPER_NODE_AND_INSIDE) {
g2.drawString(con.getFlow() + "/" + maxCap,
(con.getA().getPosition().x + con.getB().getPosition().x) / 2,
(con.getA().getPosition().y + con.getB().getPosition().y) / 2);
} else {
g2.drawString("not connected",
(con.getA().getPosition().x + con.getB().getPosition().x) / 2,
(con.getA().getPosition().y + con.getB().getPosition().y) / 2);
}
}
}
return maxCap;
}
void setEdgePictureAndHighlighting(AbstractCpsObject cps) {
// node image
if (cps instanceof CpsNode && (cps == tempCps || model.getSelectedCpsObject() == cps
|| model.getSelectedCpsObjects().contains(cps) || tempSelected.contains(cps))) {
img = Util.loadImage(this, "/Images/node_selected.png");
} else {
if (cps instanceof HolonSwitch) {
if (((HolonSwitch) cps).getActiveAt()[model.getCurIteration()]) {
((HolonSwitch) cps).setAutoState(true);
} else {
((HolonSwitch) cps).setAutoState(false);
}
}
// Highlighting
if ((cps == tempCps && model.getSelectedCpsObjects().size() == 0 && tempSelected.size() == 0)
|| model.getSelectedCpsObjects().contains(cps) || tempSelected.contains(cps)) {
g2.setColor(Color.BLUE);
g2.fillRect((int) (cps.getPosition().x - controller.getScaleDiv2() - scalediv20),
(int) (cps.getPosition().y - controller.getScaleDiv2() - scalediv20),
(int) (controller.getScale() + (scalediv20 * 2)),
(int) (controller.getScale() + (scalediv20 * 2)));
if (showedInformation[1] && cps instanceof HolonObject) {
g2.setColor(Color.BLACK);
float totalEnergy = ((HolonObject) cps).getCurrentEnergyAtTimeStep(model.getCurIteration());
g2.drawString(Float.toString(totalEnergy), cps.getPosition().x - controller.getScaleDiv2(),
cps.getPosition().y - controller.getScaleDiv2() - 10);
}
} else if (cps instanceof HolonObject) {
g2.setColor(((HolonObject) cps).getColor());
g2.fillRect((int) (cps.getPosition().x - controller.getScaleDiv2() - scalediv20),
(int) (cps.getPosition().y - controller.getScaleDiv2() - scalediv20),
(int) (controller.getScale() + (scalediv20 * 2)),
(int) (controller.getScale() + (scalediv20 * 2)));
if (showedInformation[1]) {
g2.setColor(Color.BLACK);
float totalEnergy = ((HolonObject) cps).getCurrentEnergyAtTimeStep(model.getCurIteration());
g2.drawString(Float.toString(totalEnergy), cps.getPosition().x - controller.getScaleDiv2(),
cps.getPosition().y - controller.getScaleDiv2() - 10);
}
}
// draw image
File checkPath = new File(cps.getImage());
if (checkPath.exists()) {
img = new ImageIcon(cps.getImage()).getImage();
} else {
img = Util.loadImage(this, cps.getImage());
}
}
}
void drawMarker() {
if (sx > x && sy > y) {
g2.drawRect(x, y, sx - x, sy - y);
} else if (sx < x && sy < y) {
g2.drawRect(sx, sy, x - sx, y - sy);
} else if (sx >= x) {
g2.drawRect(x, sy, sx - x, y - sy);
} else if (sy >= y) {
g2.drawRect(sx, y, x - sx, sy - y);
}
}
void showTooltip(Graphics g) {
if (toolTip) {
g2.setColor(new Color(255, 225, 150));
g2.setStroke(new BasicStroke(1));
int textWidth = g.getFontMetrics().stringWidth(toolTipText) + 2; // Text
// width
// fixed x and y Position to the screen
int fixXPos = toolTipPos.x - (textWidth >> 1) + model.getScaleDiv2();
int fixYPos = toolTipPos.y;
if (fixXPos < 0) {
fixXPos = 0;
} else if (fixXPos + textWidth + 1 > this.getWidth()) {
fixXPos -= (fixXPos + textWidth + 1) - this.getWidth();
}
if (fixYPos + 16 > this.getHeight()) {
fixYPos -= (fixYPos + 16) - this.getHeight();
}
g2.fillRect(fixXPos, fixYPos, textWidth, 15);
g2.setColor(Color.BLACK);
g2.drawRect(fixXPos, fixYPos, textWidth, 15);
g2.drawString(toolTipText, fixXPos + 2, fixYPos + 12);
}
}
void setConsoleTextAfterSelect(AbstractCpsObject cps) {
if (model.getShowConsoleLog()) {
controller.addTextToConsole("Selected: ", Color.BLACK, 12, false, false, false);
controller.addTextToConsole("" + cps.getName(), Color.BLUE, 12, true, false, false);
controller.addTextToConsole(", ID:", Color.BLACK, 12, false, false, false);
controller.addTextToConsole("" + cps.getId(), Color.RED, 12, true, false, true);
}
}
void setRightClickMenu(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON3) {
if (tempCps != null) {
itemDelete.setEnabled(true);
itemCut.setEnabled(true);
itemCopy.setEnabled(true);
if (tempCps != null) {
itemGroup.setEnabled(true);
itemTrack.setEnabled(true);
itemUntrack.setEnabled(true);
}
if (tempCps instanceof CpsUpperNode)
itemUngroup.setEnabled(true);
else
itemUngroup.setEnabled(false);
if (model.getSelectedCpsObjects().size() == 0) {
controller.addSelectedObject(tempCps);
}
} else {
itemCut.setEnabled(false);
itemCopy.setEnabled(false);
itemDelete.setEnabled(false);
itemGroup.setEnabled(false);
itemUngroup.setEnabled(false);
itemTrack.setEnabled(false);
itemUntrack.setEnabled(false);
}
mousePosition = this.getMousePosition();
popmenu.show(e.getComponent(), e.getX(), e.getY());
}
}
void markObjects() {
if (doMark) {
doMark = false;
for (AbstractCpsObject cps : tempSelected) {
if (!model.getSelectedCpsObjects().contains(cps)) {
controller.addSelectedObject(cps);
}
}
controller.getObjectsInDepth();
tempSelected.clear();
}
}
int[] determineMousePositionOnEdge(CpsEdge p) {
int lx, ly, hx, hy;
if (p.getA().getPosition().x > p.getB().getPosition().x) {
hx = p.getA().getPosition().x + model.getScaleDiv2() + 7;
lx = p.getB().getPosition().x + model.getScaleDiv2() - 7;
} else {
lx = p.getA().getPosition().x + model.getScaleDiv2() - 7;
hx = p.getB().getPosition().x + model.getScaleDiv2() + 7;
}
if (p.getA().getPosition().y > p.getB().getPosition().y) {
hy = p.getA().getPosition().y + model.getScaleDiv2() + 7;
ly = p.getB().getPosition().y + model.getScaleDiv2() - 7;
} else {
ly = p.getA().getPosition().y + model.getScaleDiv2() - 7;
hy = p.getB().getPosition().y + model.getScaleDiv2() + 7;
}
return new int[]{lx, ly, hx, hy};
}
/**
* Checks if a double click was made.
*
* @return true if doublecklick, false if not
*/
boolean doubleClick() {
if (click) {
click = false;
return true;
} else {
click = true;
java.util.Timer t = new java.util.Timer("doubleclickTimer", false);
t.schedule(new TimerTask() {
@Override
public void run() {
click = false;
}
}, 500);
}
return false;
}
boolean setToolTipInfoAndPosition(boolean on, AbstractCpsObject cps) {
if (x - controller.getScale() <= cx && y - controller.getScale() <= cy && x >= cx && y >= cy) {
on = true;
toolTipPos.x = cps.getPosition().x - controller.getScaleDiv2();
toolTipPos.y = cps.getPosition().y + controller.getScaleDiv2();
toolTipText = cps.getName() + ", " + cps.getId();
}
return on;
}
abstract void drawDeleteEdge();
void triggerUpdateController() {
updCon.paintProperties(tempCps);
updCon.refreshTableHolonElement(model.getMultiTable(), model.getSingleTable());
updCon.refreshTableProperties(model.getPropertyTable());
}
}