/* This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2010 Servoy BV This program is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program; if not, see http://www.gnu.org/licenses or write to the Free Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 */ package com.servoy.j2db.util.gui; import java.awt.Component; import java.awt.Container; import java.awt.Rectangle; import java.util.HashSet; import java.util.Set; import javax.swing.JComponent; import javax.swing.RepaintManager; import javax.swing.SwingUtilities; import com.servoy.j2db.util.WeakHashSet; /** * This repaint manager makes sure that overlapping components inside a container are repainted properly.<BR> * * More precisely, it makes sure that, if you have component A on top of component B, and B is repainted then * A will be repainted afterwards in order not to be hidden by B's repaint. * @author acostescu */ public class OverlapRepaintManager extends RepaintManager { private final Set<JComponent> components = new WeakHashSet<JComponent>(); /** * Creates a new OverlapRepaintManager that uses a default RepaintManager instance to handle unaltered operations. */ public OverlapRepaintManager() { super(); } @Override public void addDirtyRegion(final JComponent c, final int x, final int y, final int w, final int h) { synchronized (this) { components.add(c); } super.addDirtyRegion(c, x, y, w, h); // add the dirty region } private void searchOverlappingRegionsInHierarchy(Container parent, JComponent c, Rectangle repaintedArea) { if (parent instanceof JComponent) // this means it is not null also { Rectangle parentRepaintedArea = SwingUtilities.convertRectangle(c, repaintedArea, parent); if (parent.getLayout() instanceof AnchorLayout) // can have overlapped components { Rectangle intersection; Component child[] = parent.getComponents(); for (int i = 0; i < child.length; i++) { if (child[i] == c) break; // only components that have lower index then the repainted component if (!child[i].isVisible()) continue; // and that overlap with this component need to be repainted (as they should be shown on top) intersection = child[i].getBounds().intersection(parentRepaintedArea); if (!intersection.isEmpty()) { super.addDirtyRegion((JComponent)parent, intersection.x, intersection.y, intersection.width, intersection.height); } } } // see if parents overlap on some level searchOverlappingRegionsInHierarchy(parent.getParent(), (JComponent)parent, parentRepaintedArea); } } @Override public void paintDirtyRegions() { Set<JComponent> tmp; synchronized (this) { // swap for thread safety tmp = new HashSet<JComponent>(components); components.clear(); } for (JComponent component : tmp) { Rectangle dirtyRegion = super.getDirtyRegion(component); searchOverlappingRegionsInHierarchy(component.getParent(), component, dirtyRegion); } super.paintDirtyRegions(); } }