/** * <p>A convenience method for specifying the filters to use based on * BufferedImageOps. These will each be individually wrapped by an ImageFilter * and then setFilters(Effect... filters) will be called with the resulting * array</p> * * * @param effects the BufferedImageOps to wrap as filters */ public void setFilters(BufferedImageOp ... effects) { if (effects == null) effects = new BufferedImageOp[0]; BufferedImageOp[] old = getFilters(); this.filters = new BufferedImageOp[effects.length]; System.arraycopy(effects, 0, this.filters, 0, this.filters.length); setDirty(true); firePropertyChange("filters", old, getFilters()); }
/** * Creates a new instance of AbstractPainter. * @param cacheable indicates if this painter should be cacheable */ public AbstractPainter(boolean cacheable) { setCacheable(cacheable); }
/** * Sets the dirty bit. If true, then the painter is considered dirty, and the cache * will be cleared. This property is bound. * * @param d whether this <code>Painter</code> is dirty. */ protected void setDirty(boolean d) { boolean old = isDirty(); this.dirty = d; firePropertyChange("dirty", old, isDirty()); if (isDirty()) { clearCache(); } }
/** * Sets the antialiasing setting. This is a bound property. * @param value the new antialiasing setting */ public void setAntialiasing(boolean value) { boolean old = isAntialiasing(); antialiasing = value; if (old != value) setDirty(true); firePropertyChange("antialiasing", old, isAntialiasing()); }
/** * Sets a new value for the interpolation setting. This setting determines if interpolation * should be used when drawing scaled images. @see java.awt.RenderingHints.KEY_INTERPOLATION. * @param value the new interpolation setting */ public void setInterpolation(Interpolation value) { Object old = getInterpolation(); this.interpolation = value == null ? Interpolation.NearestNeighbor : value; if (old != value) setDirty(true); firePropertyChange("interpolation", old, getInterpolation()); }
if(!isVisible() || width < 1 || height < 1) { return; configureGraphics(g); if (shouldUseCache() || filters.length > 0) { validate(obj); BufferedImage cache = cachedImage == null ? null : cachedImage.get(); boolean invalidCache = null == cache || if (cacheCleared || invalidCache || isDirty()) { configureGraphics(gfx); doPaint(gfx, obj, width, height); } finally { gfx.dispose(); if (!isInPaintContext()) { for (BufferedImageOp f : getFilters()) { cache = f.filter(cache, null); if (shouldUseCache()) { cachedImage = new SoftReference<BufferedImage>(cache); cacheCleared = false; doPaint(g, obj, width, height); setDirty(false);
@Test public void testDefaults() { assertThat(p.getFilters().length, is(0)); assertThat(p.getInterpolation(), is(AbstractPainter.Interpolation.NearestNeighbor)); assertThat(p.isAntialiasing(), is(true)); assertThat(p.isCacheable(), is(false)); assertThat(p.isCacheCleared(), is(true)); assertThat(p.isDirty(), is(false)); assertThat(p.isInPaintContext(), is(false)); assertThat(p.isVisible(), is(true)); assertThat(p.shouldUseCache(), is(p.isCacheable())); }
/** * Issue #??-swingx: clearCache has no detectable effect. Test was poorly designed. It has had * an effect for a long time, but the member is not bound, so the test was failing erroneously. */ @Test public void testClearCacheDetectable() { p.setCacheable(true); p.paint(g, null, 10, 10); // sanity //when caching we get a different graphics object verify(p).doPaint(any(Graphics2D.class), isNull(), eq(10), eq(10)); assertThat("clean after paint", false, is(p.isDirty())); assertThat("cacheable is enabled", true, is(p.isCacheable())); assertThat("has a cached image", false, is(p.isCacheCleared())); p.clearCache(); assertThat("has a cached image", true, is(p.isCacheCleared())); }
((AbstractPainter<?>) p).removePropertyChangeListener(handler); ((AbstractPainter<?>) p).addPropertyChangeListener(handler);
/** * Ensure that paint orders calls correctly. */ @Test public void testInOrderPaintCallsWithoutCaching() { when(p.shouldUseCache()).thenReturn(false); InOrder orderedCalls = inOrder(p); p.paint(g, null, 10, 10); orderedCalls.verify(p).configureGraphics(g); orderedCalls.verify(p, times(0)).validate(null); orderedCalls.verify(p).doPaint(g, null, 10, 10); }
/** * <p>This method is called by the <code>paint</code> method prior to * any drawing operations to configure the drawing surface. The default * implementation sets the rendering hints that have been specified for * this <code>AbstractPainter</code>.</p> * * <p>This method can be overridden by subclasses to modify the drawing * surface before any painting happens.</p> * * @param g the graphics surface to configure. This will never be null. * @see #paint(Graphics2D, Object, int, int) */ protected void configureGraphics(Graphics2D g) { //configure antialiasing if(isAntialiasing()) { g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); } else { g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); } getInterpolation().configureGraphics(g); }
/** * Issue #1218-swingx: must fire property change if contained painter * changed. */ public void testDirtyNotification() { AbstractPainter<Object> child = spy(new DummyPainter()); ((CompoundPainter<?>) p).setPainters(child); assertThat(p.isDirty(), is(true)); verify(child, never()).setDirty(true); p.paint(g, null, 10, 10); assertThat(p.isDirty(), is(false)); PropertyChangeListener pcl = mock(PropertyChangeListener.class); p.addPropertyChangeListener(pcl); child.setDirty(true); assertThat(p.isDirty(), is(true)); ArgumentCaptor<PropertyChangeEvent> captor = ArgumentCaptor.forClass(PropertyChangeEvent.class); verify(pcl).propertyChange(captor.capture()); assertThat(captor.getValue().getSource(), CoreMatchers.<Object>is(sameInstance(p))); assertThat(captor.getValue().getPropertyName(), is("dirty")); assertThat(captor.getAllValues().size(), is(1)); } }
/** * {@link AbstractPainter} will pass any object to * {@link AbstractPainter#doPaint(Graphics2D, Object, int, int) doPaint}. */ @Test public void testPaintWithAnyObject() { p.paint(g, "yo", 10, 10); if (p.isCacheable()) { verify(p).doPaint(any(Graphics2D.class), eq("yo"), eq(10), eq(10)); } else { verify(p).doPaint(g, "yo", 10, 10); } p.clearCache(); p.paint(g, 1f, 10, 10); if (p.isCacheable()) { verify(p).doPaint(any(Graphics2D.class), eq(1f), eq(10), eq(10)); } else { verify(p).doPaint(g, 1f, 10, 10); } }
/** * <p>Sets whether this <code>AbstractPainter</code> can be cached as an image. * If true, this is treated as a hint. That is, a cacheable may or may not be used. * The {@link #shouldUseCache} method actually determines whether the cacheable is used. * However, if false, then this is treated as an absolute value. That is, no * cacheable will be used.</p> * * <p>If set to false, then #clearCache is called to free system resources.</p> * * @param cacheable */ public void setCacheable(boolean cacheable) { boolean old = isCacheable(); this.cacheable = cacheable; firePropertyChange("cacheable", old, isCacheable()); if (!isCacheable()) { clearCache(); } }
/** * {@inheritDoc} */ @Override public void propertyChange(PropertyChangeEvent evt) { CompoundPainter<?> painter = ref.get(); if (painter == null) { AbstractPainter<?> src = (AbstractPainter<?>) evt.getSource(); src.removePropertyChangeListener(this); } else { String property = evt.getPropertyName(); if ("dirty".equals(property) && evt.getNewValue() == Boolean.FALSE) { return; } painter.setDirty(true); } } }
private void paintWithForegroundPainterWithFilters(Graphics g) { BufferedImage im = GraphicsUtilities.createCompatibleTranslucentImage(getWidth(), getHeight()); Graphics2D g2d = im.createGraphics(); try { Graphics gfx = getComponentGraphics(g2d); assert gfx == g2d; paintWithForegroundPainterWithoutFilters(g2d); } finally { g2d.dispose(); } Graphics2D filtered = (Graphics2D) g.create(); try { for (BufferedImageOp filter : ((AbstractPainter<?>) fgPainter).getFilters()) { filtered.setComposite(new FilterComposite(filtered.getComposite(), filter)); } filtered.drawImage(im, 0, 0, this); } finally { filtered.dispose(); } }
/** * Ensures that setting cacheable makes shouldUseCache return true. */ @Test public void testSetCacheableEnablesCache() { p.setCacheable(true); assertThat(p.shouldUseCache(), is(true)); }
/** * Adds a painter to the queue of painters * @param painter the painter that is added */ public void addPainter(Painter<T> painter) { Collection<Painter<T>> old = new ArrayList<Painter<T>>(getPainters()); this.painters.add(painter); if (painter instanceof AbstractPainter) { ((AbstractPainter<?>) painter).addPropertyChangeListener(handler); } setDirty(true); firePropertyChange("painters", old, getPainters()); }
/** * {@link AbstractPainter} will pass {@code null} objects to * {@link AbstractPainter#doPaint(Graphics2D, Object, int, int) doPaint}. */ @Test public void testPaintWithNullObject() { p.paint(g, null, 10, 10); if (p.isCacheable()) { verify(p).doPaint(any(Graphics2D.class), isNull(), eq(10), eq(10)); } else { verify(p).doPaint(g, null, 10, 10); } }
/** * Ensure that shouldUseCache forces the use of the cache. */ @Test public void testShouldUseCacheRepaintsWithCachedCopy() { when(p.shouldUseCache()).thenReturn(true); p.paint(g, null, 10, 10); //when caching we get a different graphics object verify(p, times(1)).doPaint(any(Graphics2D.class), isNull(), eq(10), eq(10)); p.paint(g, null, 10, 10); p.paint(g, null, 10, 10); p.paint(g, null, 10, 10); p.paint(g, null, 10, 10); //we do not invoke doPaint a subsequent calls verify(p, times(1)).doPaint(any(Graphics2D.class), isNull(), eq(10), eq(10)); } }