package com.baselet.element; import java.util.List; import javax.swing.JComponent; import com.baselet.control.HandlerElementMap; import com.baselet.control.basics.Converter; import com.baselet.control.basics.geom.Point; import com.baselet.diagram.DrawPanel; import com.baselet.element.interfaces.GridElement; import com.baselet.element.relation.Relation; public class ElementUtils { /** * Must be overwritten because Swing uses this method to tell if 2 elements are overlapping * It's also used to determine which element gets selected if there are overlapping elements (the smallest one) * IMPORTANT: on overlapping elements, contains is called for all elements until the first one returns true, then the others contain methods are not called * * In future this logic should be the same as in BaseletGWT.DrawPanel.getGridElementOnPosition() which is much simpler because its externally calculated * (this migration is only possible if there are not GridElement Listeners, but instead only one Diagram Listener which delegates the event to the specific GridElement like in GWT) */ public static boolean checkForOverlap(GridElement gridElement, Point p) { JComponent component = (JComponent) gridElement.getComponent(); java.awt.Rectangle rectangle = component.getVisibleRect(); Point absolute = new Point(gridElement.getRectangle().getX() + p.getX(), gridElement.getRectangle().getY() + p.getY()); if (!rectangle.contains(p.x, p.y)) { return false; } DrawPanel drawPanel = HandlerElementMap.getHandlerForElement(gridElement).getDrawPanel(); List<GridElement> elements = drawPanel.getGridElements(); Selector selector = drawPanel.getSelector(); for (GridElement other : elements) { if (other == gridElement || other.getLayer() < gridElement.getLayer() || !other.isSelectableOn(absolute)) { continue; // ignore this element, elements with a lower layer and elements which are not selectable on the point } // issue #260: if a relation is the only selected element its selection should be retained if (gridElement instanceof Relation && other instanceof Relation) { if (selector.isSelectedOnly(gridElement)) { return true; } if (selector.isSelectedOnly(other)) { return false; } } JComponent otherComponent = (JComponent) other.getComponent(); if (other.getLayer() > gridElement.getLayer()) { // elements with higher layer can "overwrite" contains-value of this // move point to coordinate system of other entity Point other_p = new Point(p.x + gridElement.getRectangle().x - other.getRectangle().x, p.y + gridElement.getRectangle().y - other.getRectangle().y); if (otherComponent.contains(Converter.convert(other_p))) { return false; } } java.awt.Rectangle other_rectangle = otherComponent.getVisibleRect(); // move bounds to coordinate system of this component other_rectangle.x += other.getRectangle().x - gridElement.getRectangle().x; other_rectangle.y += other.getRectangle().y - gridElement.getRectangle().y; // when elements intersect, select the smaller element except if it is an old relation (because they have a larger rectangle than they use). NOTE: Old Relations are not checked because they do not properly implement isSelectableOn if (!(other instanceof com.baselet.element.old.element.Relation) && rectangle.intersects(other_rectangle) && firstSmallerThanSecond(other_rectangle, rectangle)) { return false; } } return true; } private static boolean firstSmallerThanSecond(java.awt.Rectangle first, java.awt.Rectangle second) { int areaFirst = first.getSize().height * first.getSize().width; int areaSecond = second.getSize().height * second.getSize().width; if (areaFirst < areaSecond) { return true; } return false; } }