Browse Source

Merge branch 'updateInProgress' into XChart-integration

Conflicts:
	src/ui/controller/Control.java
	src/utility/ImageImport.java
TomTroppmann 2 years ago
parent
commit
b9f961cfb7

BIN
res/Images/image_not_found.PNG


+ 9 - 3
src/ui/controller/CategoryController.java

@@ -9,6 +9,7 @@ import classes.HolonObject;
 import classes.HolonSwitch;
 import classes.Pair;
 import ui.model.Model;
+import util.Event;
 
 /**
  * Controller for the Categories.
@@ -18,6 +19,7 @@ import ui.model.Model;
 public class CategoryController {
 	private Model model;
 	private MultiPurposeController mpC;
+	private final Event OnCategoryChanged;
 
 	/**
 	 * Constructor.
@@ -26,10 +28,12 @@ public class CategoryController {
 	 *            the Model
 	 * @param mp
 	 *            the MultiPurposeController
+	 * @param control 
 	 */
-	public CategoryController(Model model, MultiPurposeController mp) {
+	public CategoryController(Model model, MultiPurposeController mp, Control control) {
 		this.model = model;
 		this.mpC = mp;
+		this.OnCategoryChanged = control.OnCategoryChanged;
 		initCategories();
 	}
 
@@ -45,6 +49,7 @@ public class CategoryController {
 				"/Images/power-plant.png");
 		addNewHolonObject(mpC.searchCat("Building"), "House", new ArrayList<HolonElement>(), "/Images/home-2.png");
 		addNewHolonSwitch(mpC.searchCat("Component"), "Switch", "/Images/switch-on.png");
+		OnCategoryChanged.broadcast();
 	}
 
 	/**
@@ -63,6 +68,7 @@ public class CategoryController {
 		}
 		model.getCgIdx().put(category.getName(), model.getCategories().size());
 		model.getCategories().add(category);
+		OnCategoryChanged.broadcast();
 	}
 
 	/**
@@ -72,7 +78,6 @@ public class CategoryController {
 	 *            Bezeichnung der neuen Kategorie
 	 */
 	public void addNewCategory(String name) {
-
 		addCategory(new Category(name));
 	}
 
@@ -86,6 +91,7 @@ public class CategoryController {
 		mpC.decIdx(c.getName(), model.getCgIdx());
 		model.getCgIdx().remove(c.getName());
 		model.getCategories().remove(c);
+		OnCategoryChanged.broadcast();
 
 	}
 	
@@ -191,7 +197,7 @@ public class CategoryController {
 		mpC.decIdx(cps.getObjName(), category.getObjIdx());
 		category.getObjIdx().remove(cps.getObjName());
 		category.getObjects().remove(cps);
-
+		OnCategoryChanged.broadcast();
 	}
 
 	/**

+ 3 - 1
src/ui/controller/Control.java

@@ -57,6 +57,8 @@ public class Control {
     
     public Event OnSelectionUpdate = new Event();
 
+    
+    public Event OnCategoryChanged = new Event();
     /**
      * Constructor.
      *
@@ -66,7 +68,7 @@ public class Control {
         this.model = model;
 
         this.multiPurposeController = new MultiPurposeController(model);
-        this.categoryController = new CategoryController(model, multiPurposeController);
+        this.categoryController = new CategoryController(model, multiPurposeController, this);
         this.objectController = new ObjectController(model, multiPurposeController);
         this.canvasController = new CanvasController(model, multiPurposeController);
         this.globalController = new GlobalController(model);

+ 16 - 8
src/ui/model/VisualRepresentationalState.java

@@ -12,6 +12,7 @@ import classes.Edge;
 import classes.Node;
 import ui.model.ExitCable.ExitCableState;
 import classes.GroupNode;
+import classes.HolonObject;
 
 public class VisualRepresentationalState {
 	private ArrayList<Supplier> supplierList = new ArrayList<Supplier>();
@@ -26,6 +27,8 @@ public class VisualRepresentationalState {
 	//ForFastAccessIndividualGroupNodes:
 	private HashMap<GroupNode, DecoratedGroupNode> createdGroupNodes;
 	
+	public HashMap<HolonObject, DecoratedHolonObject> createdHolonObjects;
+	
 	public VisualRepresentationalState(DecoratedState stateFromThisTimestep, MinimumModel minimumModel) {
 		reassignObjects(stateFromThisTimestep, minimumModel);
 	}
@@ -62,6 +65,7 @@ public class VisualRepresentationalState {
 		HashMap<Edge, ArrayList<GroupNode>> inGroupEdges = minimumModel.getInGroupEdges();
 		
 		createdGroupNodes =  new HashMap<GroupNode, DecoratedGroupNode>();
+		createdHolonObjects = new HashMap<HolonObject, DecoratedHolonObject>();
 		
 		ArrayList<IntermediateCalculationCable> exitCables = new ArrayList<IntermediateCalculationCable>();
 		//createThem
@@ -71,28 +75,32 @@ public class VisualRepresentationalState {
 		//unrolling Networks
 		for(DecoratedNetwork net : stateFromThisTimestep.getNetworkList()) {
 			for(Consumer con : net.getConsumerList()) {
-				DecoratedGroupNode groupNodeFromObject = addObject(inGroupObjects, con.getModel(), consumerList, con, createdGroupNodes);
+				DecoratedGroupNode groupNodeFromObject = addObject(inGroupObjects, con.getModel(), consumerList, con);
 				if(groupNodeFromObject != null) {
 					addToGroupNode(con, groupNodeFromObject.getConsumerList());
 				}
+				this.createdHolonObjects.put(con.getModel(), con);
 			}
 			for(Consumer con : net.getConsumerSelfSuppliedList()) {
-				DecoratedGroupNode groupNodeFromObject = addObject(inGroupObjects, con.getModel(), consumerList, con, createdGroupNodes);
+				DecoratedGroupNode groupNodeFromObject = addObject(inGroupObjects, con.getModel(), consumerList, con);
 				if(groupNodeFromObject != null) {
 					addToGroupNode(con, groupNodeFromObject.getConsumerList());
 				}
+				this.createdHolonObjects.put(con.getModel(), con);
 			}
 			for(Supplier sup : net.getSupplierList()) {
-				DecoratedGroupNode groupNodeFromObject = addObject(inGroupObjects, sup.getModel(), supplierList, sup, createdGroupNodes);
+				DecoratedGroupNode groupNodeFromObject = addObject(inGroupObjects, sup.getModel(), supplierList, sup);
 				if(groupNodeFromObject != null) {
 					addToGroupNode(sup, groupNodeFromObject.getSupplierList());
 				}
+				this.createdHolonObjects.put(sup.getModel(), sup);
 			}
 			for(Passiv pas : net.getPassivNoEnergyList()) {
-				DecoratedGroupNode groupNodeFromObject = addObject(inGroupObjects, pas.getModel(), passivList, pas, createdGroupNodes);
+				DecoratedGroupNode groupNodeFromObject = addObject(inGroupObjects, pas.getModel(), passivList, pas);
 				if(groupNodeFromObject != null) {
 					addToGroupNode(pas, groupNodeFromObject.getPassivList());
 				}
+				this.createdHolonObjects.put(pas.getModel(), pas);
 			}
 			for(DecoratedCable cable : net.getDecoratedCableList()) {
 				addCable(cable, inGroupEdges, inGroupObjects,createdGroupNodes, exitCables);
@@ -102,19 +110,19 @@ public class VisualRepresentationalState {
 			addCable(cable, inGroupEdges, inGroupObjects, createdGroupNodes, exitCables);
 		}
 		for(Node node : minimumModel.getNodeList()) {
-			DecoratedGroupNode groupNodeFromObject = addObject(inGroupObjects, node, nodeList ,node, createdGroupNodes);
+			DecoratedGroupNode groupNodeFromObject = addObject(inGroupObjects, node, nodeList ,node);
 			if(groupNodeFromObject != null) {
 				addToGroupNode(node, groupNodeFromObject.getNodeList());
 			}
 		}
 		for(DecoratedSwitch dSwitch: stateFromThisTimestep.getDecoratedSwitches()) {
-			DecoratedGroupNode groupNodeFromObject = addObject(inGroupObjects, dSwitch.getModel(), switchList, dSwitch, createdGroupNodes);
+			DecoratedGroupNode groupNodeFromObject = addObject(inGroupObjects, dSwitch.getModel(), switchList, dSwitch);
 			if(groupNodeFromObject != null) {
 				addToGroupNode(dSwitch, groupNodeFromObject.getSwitchList());
 			}
 		}
 		for(DecoratedGroupNode dGroupNode: createdGroupNodes.values()) {
-			DecoratedGroupNode groupNodeFromObject = addObject(inGroupObjects, dGroupNode.getModel(), groupNodeList, dGroupNode, createdGroupNodes);
+			DecoratedGroupNode groupNodeFromObject = addObject(inGroupObjects, dGroupNode.getModel(), groupNodeList, dGroupNode);
 			if(groupNodeFromObject != null) {
 				addToGroupNode(dGroupNode, groupNodeFromObject.getGroupNodeList());
 			}
@@ -318,7 +326,7 @@ public class VisualRepresentationalState {
 	
 
 	//Generics
-	private <ModelOfObject, DecoratedObject> DecoratedGroupNode addObject(HashMap<ModelOfObject, GroupNode> inGroupObjects, ModelOfObject modelOfObject, ArrayList<DecoratedObject> listToAdd, DecoratedObject object, HashMap<GroupNode, DecoratedGroupNode> createdGroupNodes) {
+	private <ModelOfObject, DecoratedObject> DecoratedGroupNode addObject(HashMap<ModelOfObject, GroupNode> inGroupObjects, ModelOfObject modelOfObject, ArrayList<DecoratedObject> listToAdd, DecoratedObject object) {
 		if(inGroupObjects.containsKey(modelOfObject)) {
 			return  createdGroupNodes.get(inGroupObjects.get(modelOfObject));
 		}

+ 18 - 17
src/ui/view/GUI.java

@@ -184,7 +184,7 @@ public class GUI{
 	private final JLabel minGraph = new JLabel("0%");
 	private final JLabel elementGraph = new JLabel("None ");
 	private final ArrayList<HolonElement> selectedElements = new ArrayList<>();
-	private final JTree tree = new JTree();
+	private final JTree categoryTree = new JTree();
 	/******************************************
 	 ************* Right Container*************
 	 ******************************************
@@ -316,6 +316,7 @@ public class GUI{
 		initialize();
 		updateCategories(model.getCategories());
 		updCon = new UpdateController(model, controller);
+		control.OnCategoryChanged.addListener(() -> this.updateCategoryUI(model.getCategories()));
 	}
 
 
@@ -706,8 +707,8 @@ public class GUI{
 			} catch (Exception e2) {
 				System.out.println(e2.getMessage());
 			}
-
-			tree.repaint();
+			categoryTree.revalidate();
+			categoryTree.repaint();
 		});
 
 
@@ -1395,7 +1396,7 @@ public class GUI{
 		 ****************/
 
 		// Override Key Actions
-		inputMap = tree.getInputMap();
+		inputMap = categoryTree.getInputMap();
 		inputMap.put(KeyStroke.getKeyStroke("control C"), cntrlCDown);
 		inputMap.put(KeyStroke.getKeyStroke("control V"), cntrlVDown);
 		inputMap.put(KeyStroke.getKeyStroke("control X"), cntrlXDown);
@@ -1440,9 +1441,9 @@ public class GUI{
 			}
 		};
 		
-		tree.setCellRenderer(customRenderer);
+		categoryTree.setCellRenderer(customRenderer);
 
-		tree.addMouseMotionListener(new MouseMotionAdapter() {
+		categoryTree.addMouseMotionListener(new MouseMotionAdapter() {
 
 			public void mouseDragged(MouseEvent e){
 				checkForDragAndDrop(e);
@@ -1517,7 +1518,7 @@ public class GUI{
 			}});
 
 		
-		tree.addMouseListener(new MouseAdapter() {
+		categoryTree.addMouseListener(new MouseAdapter() {
 			
 			public void mouseReleased(MouseEvent e) {
 				try {
@@ -1609,16 +1610,16 @@ public class GUI{
 		editItem.setEnabled(false);
 		editItem.addActionListener(actionEvent -> {
 		});
-		tree.addMouseListener(new MouseAdapter() {
+		categoryTree.addMouseListener(new MouseAdapter() {
 		
 			public void mousePressed(MouseEvent e) {
 				try {
-					actualObjectClicked = tree
+					actualObjectClicked = categoryTree
 							.getPathForLocation(e.getX(), e.getY())
 							.getLastPathComponent().toString();
 					// if an Object was selected, the porperties are shown in
 					// the table
-					DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) tree
+					DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) categoryTree
 							.getPathForLocation(e.getX(), e.getY())
 							.getLastPathComponent();
 					if (selectedNode.getLevel() == 2) {
@@ -1700,7 +1701,7 @@ public class GUI{
 				e.printStackTrace();
 			}
 		});
-		scrollPane1.setViewportView(tree);
+		scrollPane1.setViewportView(categoryTree);
 
 		scrollPane1.setColumnHeaderView(panel);
 		panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
@@ -1850,7 +1851,7 @@ public class GUI{
 
 		// Del Button
 		btnDel.addActionListener(actionEvent -> {
-			Object nodeInfo = tree.getLastSelectedPathComponent();
+			Object nodeInfo = categoryTree.getLastSelectedPathComponent();
 			if (nodeInfo != null) {
 				DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) nodeInfo;
 				String nodeName = selectedNode.getUserObject().toString();
@@ -1884,7 +1885,7 @@ public class GUI{
 				JOptionPane.showMessageDialog(holegJFrame,
 						selectObjBeforeErase);
 			}
-			tree.repaint();
+			categoryTree.repaint();
 		});
 		btnDel.setIcon(new ImageIcon(ImageImport.loadImage("Images/minus.png", 16, 16)));
 		btnDel.setToolTipText("<html><b>Delete</b><br>Removes a Category or a Category Item.</html>");
@@ -1936,7 +1937,7 @@ public class GUI{
 					try {
 						controller.loadFile(file.getAbsolutePath());
 						canvas.repaint();
-						tree.repaint();
+						categoryTree.repaint();
 						controller.calculateStateAndVisualForCurrentTimeStep();
 					} catch (IOException | ArchiveException e) {
 						e.printStackTrace();
@@ -2273,7 +2274,7 @@ public class GUI{
 
 			}
 		});
-		tree.setModel(treemodel);
+		categoryTree.setModel(treemodel);
 	}
 
 	/**
@@ -2282,8 +2283,8 @@ public class GUI{
 	 * @param categories
 	 *            the Categories
 	 */
-	public void onChange(ArrayList<Category> categories) {
-		DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
+	public void updateCategoryUI(ArrayList<Category> categories) {
+		DefaultTreeModel model = (DefaultTreeModel) categoryTree.getModel();
 		updateCategories(categories);
 		model.reload();
 	}

+ 77 - 22
src/ui/view/HolonInformationPanel.java

@@ -12,6 +12,7 @@ import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.List;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
@@ -46,10 +47,14 @@ import preferences.ColorPreference;
 import ui.controller.Control;
 import ui.controller.FlexManager;
 import ui.controller.FlexManager.FlexWrapper;
+import ui.model.Consumer;
 import ui.model.DecoratedGroupNode;
 import ui.model.DecoratedGroupNode.PriorityCounts;
+import ui.model.DecoratedHolonObject;
 import ui.model.DecoratedHolonObject.HolonObjectState;
 import ui.model.Model;
+import ui.model.Passiv;
+import ui.model.Supplier;
 import util.StringFormat;
 
 public class HolonInformationPanel extends JPanel {
@@ -89,18 +94,19 @@ public class HolonInformationPanel extends JPanel {
 	}
 
 	public void updateCharts() {
-		// TODO check for a method without instanceof and cast
-		List<GroupNode> list = control.getModel().getSelectedCpsObjects().stream()
-				.filter(object -> object instanceof GroupNode).map(object -> (GroupNode) object)
-				.collect(Collectors.toList());
-		if (list.size() != 1) {
+		DecoratedGroupNode decoratedGroupNode;
+		switch (control.getModel().getSelectedCpsObjects().size()) {
+		case 0:
 			return;
+		case 1:
+			titleTextField.setText(control.getModel().getSelectedCpsObjects().get(0).getName());
+			decoratedGroupNode = multiSelectionToDecoratedGroupNode();
+			break;
+		default:
+			titleTextField.setText(getMultiSelectionName());
+			decoratedGroupNode = multiSelectionToDecoratedGroupNode();
+			break;
 		}
-		GroupNode groupNode = list.get(0);
-		DecoratedGroupNode decoratedGroupNode = control.getSimManager().getActualVisualRepresentationalState()
-				.getCreatedGroupNodes().get(groupNode);
-		// UPDATE NAME
-		titleTextField.setText(groupNode.getName());
 
 		// UPDATE SUPPLY STATE
 		int producerAmount = decoratedGroupNode.getAmountOfSupplier();
@@ -121,13 +127,14 @@ public class HolonInformationPanel extends JPanel {
 
 		// UPDATE PRIORITYS
 		PriorityCounts priorityCounts = decoratedGroupNode.getPriorityCounts();
-		
+
 		priorityChart.updatePieSeries("Essential", priorityCounts.essential);
 		priorityChart.updatePieSeries("High", priorityCounts.high);
 		priorityChart.updatePieSeries("Medium", priorityCounts.medium);
 		priorityChart.updatePieSeries("Low", priorityCounts.low);
-		boolean hasPriority = priorityCounts.essential + priorityCounts.high + priorityCounts.medium + priorityCounts.low > 0;
-		priorityChart.updatePieSeries("No Data", hasPriority?0:1);
+		boolean hasPriority = priorityCounts.essential + priorityCounts.high + priorityCounts.medium
+				+ priorityCounts.low > 0;
+		priorityChart.updatePieSeries("No Data", hasPriority ? 0 : 1);
 		panelPriority.updateToolTips();
 
 		// UPDATE PRODUCTION
@@ -138,7 +145,7 @@ public class HolonInformationPanel extends JPanel {
 		energyChart.updatePieSeries("Consumption", consumption);
 		differenceEnergyLabelAmount.setText(StringFormat.doubleFixedPlaces(1, difference));
 		panelEnergy.updateToolTips();
-		
+
 		// UPDATE FLEXIBILITIES
 		int inUse = 0;
 		int offered = 0;
@@ -146,10 +153,11 @@ public class HolonInformationPanel extends JPanel {
 		int notOffered = 0;
 		int unavailable = 0;
 		FlexManager manager = control.getSimManager().getActualFlexManager();
-		Stream<FlexWrapper> flexWrapperStream = decoratedGroupNode.getFlexibilitiesStream().map(flex -> manager.getFlexWrapperFromFlexibility(flex));
+		Stream<FlexWrapper> flexWrapperStream = decoratedGroupNode.getFlexibilitiesStream()
+				.map(flex -> manager.getFlexWrapperFromFlexibility(flex));
 		List<FlexWrapper> wrapperList = flexWrapperStream.collect(Collectors.toList());
-		for(FlexWrapper wrapper : wrapperList) {
-			switch(wrapper.getState()) {
+		for (FlexWrapper wrapper : wrapperList) {
+			switch (wrapper.getState()) {
 			case IN_USE:
 				inUse++;
 				break;
@@ -167,7 +175,7 @@ public class HolonInformationPanel extends JPanel {
 				break;
 			default:
 				break;
-			
+
 			}
 		}
 		flexibilityChart.updatePieSeries("Offered", offered);
@@ -176,21 +184,68 @@ public class HolonInformationPanel extends JPanel {
 		flexibilityChart.updatePieSeries("Not offered", notOffered);
 		flexibilityChart.updatePieSeries("Unavailable", unavailable);
 		boolean hasFlex = offered + inUse + onCooldown + notOffered + unavailable > 0;
-		flexibilityChart.updatePieSeries("No Data", hasFlex?0:1);
+		flexibilityChart.updatePieSeries("No Data", hasFlex ? 0 : 1);
 		panelFlexibility.updateToolTips();
-		
-		
+
 		// UPDATE ActiveInActive
 		int activeAmount = decoratedGroupNode.getAmountOfAktiveElemntsFromHolonObjects();
 		int inactiveAmounts = decoratedGroupNode.getAmountOfElemntsFromHolonObjects() - activeAmount;
 		activeChart.updatePieSeries("Active", activeAmount);
 		activeChart.updatePieSeries("Inactive", inactiveAmounts);
 		panelActive.updateToolTips();
-		
+
 		this.revalidate();
 		this.repaint();
 	}
 
+	private String getMultiSelectionName() {
+		String name =  control.getModel().getSelectedCpsObjects().stream().map(AbstractCanvasObject::getName)
+				.collect(Collectors.joining(", "));
+		if(name.length() > 25) {
+			name = name.substring(0, 25);
+			name += "...";
+		}
+		return name;
+	}
+
+
+	private DecoratedGroupNode multiSelectionToDecoratedGroupNode() {
+		// TODO Create DecoratedGroupNode
+		DecoratedGroupNode temp = new DecoratedGroupNode(new GroupNode("Temp"));
+
+		// TODO get consumer, supplier, passiv
+		// GroupNodes
+		HashMap<GroupNode, DecoratedGroupNode> accessMapGroupNode = control.getSimManager()
+				.getActualVisualRepresentationalState().getCreatedGroupNodes();
+		List<DecoratedGroupNode> groupNodeList = control.getModel().getSelectedCpsObjects().stream()
+				.filter(object -> object instanceof GroupNode).map(object -> accessMapGroupNode.get(object))
+				.collect(Collectors.toList());
+
+		temp.getGroupNodeList().addAll(groupNodeList);
+
+		// HolonObjects
+		HashMap<HolonObject, DecoratedHolonObject> accessMapHolonObject = control.getSimManager()
+				.getActualVisualRepresentationalState().createdHolonObjects;
+		List<DecoratedHolonObject> holonObjectList = control.getModel().getSelectedCpsObjects().stream()
+				.filter(object -> object instanceof HolonObject).map(object -> accessMapHolonObject.get(object))
+				.collect(Collectors.toList());
+
+		for (DecoratedHolonObject object : holonObjectList) {
+			switch (object.getState()) {
+			case NO_ENERGY:
+				temp.getPassivList().add((Passiv) object);
+				break;
+			case PRODUCER:
+				temp.getSupplierList().add((Supplier) object);
+				break;
+			default:
+				temp.getConsumerList().add((Consumer) object);
+				break;
+			}
+		}
+		return temp;
+	}
+
 	public HolonInformationPanel(Control control) {
 		control.OnSelectionUpdate.addListener(() -> updateCharts());
 		this.control = control;

+ 127 - 140
src/util/ImageImport.java

@@ -1,141 +1,128 @@
-package util;
-
-import java.awt.Image;
-import java.awt.image.BufferedImage;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.HashMap;
-import javax.imageio.ImageIO;
-
-/**
- * 
- * @author TU-Darmstadt BP Gruppe 7 WS17/18
- *	Centralized resource loading methods
- *	for improved performance and easier troubleshooting.
- */
-public class ImageImport {
-	
-	/**
-	 * 30x30 pixel FileNotFound Icon, which can be shown without using I/O operations
-	 * a red cross.
-	 */
-	static private BufferedImage defaultImage;
-	/*
-	 * Save nothing: Reload every image whenever requested.
-	 * Save external: Only save images that were found as external file.
-	 * Save raw: Save all non-scaled images.
-	 * Save everything: self-explanatory.
-	 */
-	private static HashMap<String, Image> imgStorage;
-	private static ImageImport xmp=new ImageImport();//Used to load resources from the JAR.
-	
-	static{
-		/*
-		 * creates the default Image 
-		 */
-		defaultImage = new BufferedImage(30,30,BufferedImage.TYPE_BYTE_INDEXED);
-		for(int x = 0; x < 30; x++)
-			for(int y = 0; y < 30; y++){
-				if(x == 29 || y == 29)
-					//Border Bottom/Left -> Light Grey
-					(defaultImage).setRGB(x, y, 13158600);
-				else if(x == 0 || y == 0)
-					//Border Top/Right -> Dark Grey
-					(defaultImage).setRGB(x, y, 6316128);
-				else if((x == y || x == 31 - y) && 6 < x && x < 25)
-					//Red Cross in the middle
-					(defaultImage).setRGB(x, y, 13107200);
-				else //all other Pixels are white
-					(defaultImage).setRGB(x, y, 16777215);
-			}
-		imgStorage=new HashMap<String, Image>();
-	}
-	
-	/**
-	 * The rawest function replacing the old method without any default parameters.
-	 * Currently not used in HOLEG at all(aside form calls from the convenience methods).
-	 * @param url Path to the image to be loaded.
-	 * @param w Width the loaded image should be scaled to.
-	 * @param h Height the loaded image should be scaled to.
-	 * @param hints Hints for the scaling algorithm to be used.
-	 * Same as the parameter in the getScaledInstance function of Image.
-	 * @return A loaded and scaled image from the requested path.
-	 */
-	static Image loadImage(String url, int w, int h, int hints){
-		String key = url + "?" + w + "?" + h + "?" + hints;
-		if (imgStorage.containsKey(key))
-			return (imgStorage.get(key));
-		else {
-			Image img = loadImage(url).getScaledInstance(w, h, hints);
-			imgStorage.put(key, img);
-			return img;
-		}
-	}
-	
-	/**
-	 * Loads an image from the given path and scales it using the smooth algorithm.
-	 * @param url Path to the image to be loaded.
-	 * @param w Width the loaded image should be scaled to.
-	 * @param h Height the loaded image should be scaled to.
-	 * @return A loaded and (smoothly) scaled image from the requested path.
-	 */
-	public static Image loadImage(String url, int w, int h){
-		return loadImage(url,w,h, Image.SCALE_SMOOTH);
-	}
-	
-	/**
-	 * Loads an image from the given path and scales it using the smooth algorithm.
-	 * @param url Path to the image to be loaded.
-	 * @param w Width the loaded image should be scaled to.
-	 * @param h Height the loaded image should be scaled to.
-	 * @return An image loaded from the requested path.
-	 */
-	public static Image loadImage(String url){
-		if (imgStorage.containsKey(url))
-			return imgStorage.get(url);
-		else {
-			Image img;
-			try {
-				img = ImageIO.read(loadStream(url));
-			} catch (IOException e) {
-				e.printStackTrace();
-				return defaultImage;
-			}
-			imgStorage.put(url, img);
-			return img;
-		}
-	}
-	
-	/**
-	 * Loads any resource with a given path,
-	 * regardless of whether it is inside the jar or an external resource.
-	 * Every loadImage() function uses this as a basis.
-	 * @param url The path (and file name) of the requested resource.
-	 * @return An InputStream from the requested resource.
-	 */
-	public static InputStream loadStream(String url){
-		InputStream o=xmp.getClass().getResourceAsStream(url);
-		if(o!=null)return o;
-		else{
-			boolean rootSymbol=false;	//Whether url starts with a / or \
-			switch(url.charAt(0)){		//So we can make sure to construct res/path correctly.
-			case '/':case '\\':rootSymbol=true;
-			}
-			try {
-				//Mixed separators might cause problems. Will fix later.
-				File f=new File(url);//Possible bug with duplicate names.
-				if(!f.exists())url="res"+(rootSymbol?"":"/")+url;
-				return new FileInputStream(url);
-			} catch (FileNotFoundException e1) {
-				e1.printStackTrace();
-			}
-			return null;
-		}
-	}
-	
-	//Nobody needs an instance of this. I do, because I use it to load images from inside the JAR.
-	private ImageImport(){}
+package util;
+
+import java.awt.Image;
+import java.awt.image.BufferedImage;
+import java.awt.image.ColorModel;
+import java.awt.image.WritableRaster;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import javax.imageio.ImageIO;
+
+/**
+ * 
+ * @author TU-Darmstadt BP Gruppe 7 WS17/18 Centralized resource loading methods
+ *         for improved performance and easier troubleshooting.
+ */
+public class ImageImport {
+	/*
+	 * Save nothing: Reload every image whenever requested. Save external: Only save
+	 * images that were found as external file. Save raw: Save all non-scaled
+	 * images. Save everything: self-explanatory.
+	 */
+	private static HashMap<String, Image> imgStorage;
+	private static ImageImport xmp = new ImageImport();// Used to load resources from the JAR.
+
+	static {
+		imgStorage = new HashMap<String, Image>();
+	}
+
+	/**
+	 * The rawest function replacing the old method without any default parameters.
+	 * Currently not used in HOLEG at all(aside form calls from the convenience
+	 * methods).
+	 * 
+	 * @param url   Path to the image to be loaded.
+	 * @param w     Width the loaded image should be scaled to.
+	 * @param h     Height the loaded image should be scaled to.
+	 * @param hints Hints for the scaling algorithm to be used. Same as the
+	 *              parameter in the getScaledInstance function of Image.
+	 * @return A loaded and scaled image from the requested path.
+	 */
+	static Image loadImage(String url, int w, int h, int hints) {
+		String key = url + "?" + w + "?" + h + "?" + hints;
+		if (imgStorage.containsKey(key))
+			return (imgStorage.get(key));
+		else {
+			Image img = loadImage(url).getScaledInstance(w, h, hints);
+			imgStorage.put(key, img);
+			return img;
+		}
+	}
+
+	/**
+	 * Loads an image from the given path and scales it using the smooth algorithm.
+	 * 
+	 * @param url Path to the image to be loaded.
+	 * @param w   Width the loaded image should be scaled to.
+	 * @param h   Height the loaded image should be scaled to.
+	 * @return A loaded and (smoothly) scaled image from the requested path.
+	 */
+	public static Image loadImage(String url, int w, int h) {
+		return loadImage(url, w, h, Image.SCALE_SMOOTH);
+	}
+
+	/**
+	 * Loads an image from the given path and scales it using the smooth algorithm.
+	 * 
+	 * @param url Path to the image to be loaded.
+	 * @param w   Width the loaded image should be scaled to.
+	 * @param h   Height the loaded image should be scaled to.
+	 * @return An image loaded from the requested path.
+	 */
+	public static Image loadImage(String url) {
+		if (imgStorage.containsKey(url))
+			return imgStorage.get(url);
+		else {
+			Image img;
+			try {
+				img = ImageIO.read(loadStream(url));
+			} catch (IOException e) {
+				System.err.println(e);
+				return null;
+			}
+			imgStorage.put(url, img);
+			return img;
+		}
+	}
+
+	/**
+	 * Loads any resource with a given path, regardless of whether it is inside the
+	 * jar or an external resource. Every loadImage() function uses this as a basis.
+	 * 
+	 * @param url The path (and file name) of the requested resource.
+	 * @return An InputStream from the requested resource.
+	 * @throws FileNotFoundException
+	 */
+	public static InputStream loadStream(String url) throws FileNotFoundException {
+		InputStream o = xmp.getClass().getResourceAsStream(url);
+		if (o != null)
+			return o;
+		else {
+			boolean rootSymbol = false; // Whether url starts with a / or \
+			switch (url.charAt(0)) { // So we can make sure to construct res/path correctly.
+			case '/':
+			case '\\':
+				rootSymbol = true;
+			}
+			File f = new File(url);
+			if (!f.exists()) {
+				url = "res" + (rootSymbol ? "" : "/") + url;
+			}
+			f = new File(url);// Possible bug with duplicate names.
+			if (!f.exists()) {
+				url = "res/Images/image_not_found.png";
+			}
+			return new FileInputStream(url);
+
+		}
+	}
+
+	// Nobody needs an instance of this. I do, because I use it to load images from
+	// inside the JAR.
+	private ImageImport() {
+	}
 }

+ 2 - 1
tests/tests/PraktikumHolonsTestCanvasController.java

@@ -7,6 +7,7 @@ import classes.HolonSwitch;
 import classes.IdCounter;
 import ui.controller.CanvasController;
 import ui.controller.CategoryController;
+import ui.controller.Control;
 import ui.controller.MultiPurposeController;
 import ui.model.Model;
 
@@ -36,7 +37,7 @@ public class PraktikumHolonsTestCanvasController {
 		adapter = new PraktikumHolonsAdapter();
 		model = new Model();
 		mp = new MultiPurposeController(model);
-		cg = new CategoryController(model, mp);
+		cg = new CategoryController(model, mp, new Control(model));
 		controller = new CanvasController(model, mp);
 		IdCounter.setCounter(1); 
 	}

+ 2 - 1
tests/tests/PraktikumHolonsTestCategoryController.java

@@ -8,6 +8,7 @@ import org.junit.Test;
 
 import classes.HolonObject;
 import ui.controller.CategoryController;
+import ui.controller.Control;
 import ui.controller.MultiPurposeController;
 import ui.model.Model;
 
@@ -31,7 +32,7 @@ public class PraktikumHolonsTestCategoryController {
 		adapter = new PraktikumHolonsAdapter();
 		model = new Model();
 		mp = new MultiPurposeController(model);
-		controller = new CategoryController(model, mp);
+		controller = new CategoryController(model, mp, new Control(model));
 	}
 
 	/**

+ 2 - 1
tests/tests/PraktikumHolonsTestObjectController.java

@@ -9,6 +9,7 @@ import classes.AbstractCanvasObject;
 import classes.HolonObject;
 import ui.controller.CanvasController;
 import ui.controller.CategoryController;
+import ui.controller.Control;
 import ui.controller.MultiPurposeController;
 import ui.controller.ObjectController;
 import ui.model.Model;
@@ -35,7 +36,7 @@ public class PraktikumHolonsTestObjectController {
 		adapter = new PraktikumHolonsAdapter();
 		model = new Model();
 		mp = new MultiPurposeController(model);
-		cg = new CategoryController(model, mp);
+		cg = new CategoryController(model, mp, new Control(model));
 		cvs = new CanvasController(model, mp);
 		controller = new ObjectController(model, mp);
 	}