/* * JAME 6.2.1 * http://jame.sourceforge.net * * Copyright 2001, 2016 Andrea Medeghini * * This file is part of JAME. * * JAME is an application for creating fractals and other graphics artifacts. * * JAME is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * JAME 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with JAME. If not, see <http://www.gnu.org/licenses/>. * */ package net.sf.jame.twister.swing; import java.awt.AlphaComposite; import java.awt.Canvas; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.UnsupportedFlavorException; import java.awt.dnd.DnDConstants; import java.awt.dnd.DragGestureEvent; import java.awt.dnd.DragGestureListener; import java.awt.dnd.DragSource; import java.awt.dnd.DragSourceDragEvent; import java.awt.dnd.DragSourceDropEvent; import java.awt.dnd.DragSourceEvent; import java.awt.dnd.DragSourceListener; import java.awt.dnd.DropTarget; import java.awt.dnd.DropTargetDragEvent; import java.awt.dnd.DropTargetDropEvent; import java.awt.dnd.DropTargetEvent; import java.awt.dnd.DropTargetListener; import java.awt.dnd.InvalidDnDOperationException; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.HashMap; import java.util.TooManyListenersException; import java.util.concurrent.Semaphore; import net.sf.jame.core.extension.ExtensionException; import net.sf.jame.core.swing.util.GUIUtil; import net.sf.jame.core.tree.NodeAction; import net.sf.jame.core.util.IntegerVector2D; import net.sf.jame.core.util.Rectangle; import net.sf.jame.core.util.RenderContext; import net.sf.jame.core.util.RenderContextListener; import net.sf.jame.core.util.Surface; import net.sf.jame.core.util.Tile; import net.sf.jame.twister.ControllerListener; import net.sf.jame.twister.TwisterClip; import net.sf.jame.twister.TwisterClipController; import net.sf.jame.twister.TwisterConfig; import net.sf.jame.twister.TwisterRuntime; import net.sf.jame.twister.effect.extension.EffectExtensionRuntime; import net.sf.jame.twister.renderer.DefaultTwisterRenderer; import net.sf.jame.twister.renderer.OverlayTwisterRenderer; import net.sf.jame.twister.renderer.TwisterRenderer; import net.sf.jame.twister.renderer.TwisterRenderingHints; /** * @author Andrea Medeghini */ public class TwisterPreviewCanvas extends Canvas implements RenderContext { // private static final Logger logger = Logger.getLogger(PreviewCanvas.class); private static final int MIN_HEIGHT = 20; private static final int MIN_WITH = 20; private static final long serialVersionUID = 1L; private static final long frameRate = 25; private RefreshTask refreshCanvas; private TwisterRenderer renderer; private TwisterRuntime runtime; private OverlayTwisterRenderer overlayRenderer; private TwisterRuntime overlayRuntime; private TwisterConfig config; private TwisterClip clip; private Rectangle area; private IntegerVector2D size; private Surface surface; private RenderListener listener; boolean paintBorder = false; boolean isTarget = true; private BufferedImage bufferedImage; private final DropTarget target; private final DragSource source; private boolean dragEnabled = true; private boolean dropEnabled; private TwisterClipController clipController; private final Semaphore semaphore = new Semaphore(1, true); private volatile Thread resizeThread; /** * */ public TwisterPreviewCanvas() { setIgnoreRepaint(true); setMinimumSize(new Dimension(40, 40)); setMaximumSize(new Dimension(200, 200)); setPreferredSize(new Dimension(120, 120)); source = new DragSource(); target = new DropTarget(); final CanvasListener listener = new CanvasListener(); addComponentListener(listener); addMouseListener(listener); setFocusable(true); setBackground(Color.DARK_GRAY); if (source.createDefaultDragGestureRecognizer(this, DnDConstants.ACTION_MOVE, listener) != null) { setDropTarget(target); } try { target.addDropTargetListener(listener); } catch (final TooManyListenersException e) { e.printStackTrace(); } } /** * @return the listener */ public RenderListener getListener() { return listener; } /** * @param listener the listener to set */ public void setListener(final RenderListener listener) { this.listener = listener; } /** * @return the area */ public Rectangle getArea() { return area; } /** * @param area the area to set */ public void setArea(final Rectangle area) { this.area = area; refresh(); } /** * @see net.sf.jame.core.util.RenderContext#acquire() */ public void acquire() throws InterruptedException { semaphore.acquire(); } /** * @see net.sf.jame.core.util.RenderContext#release() */ public void release() { semaphore.release(); } /** * */ public void refresh() { if (refreshCanvas != null) { refreshCanvas.refresh(); } } /** * @return the dragEnabled */ public boolean isDragEnabled() { return dragEnabled; } /** * @param dragEnabled the dragEnabled to set */ public void setDragEnabled(final boolean dragEnabled) { this.dragEnabled = dragEnabled; } /** * @return the dropEnabled */ public boolean isDropEnabled() { return dropEnabled; } /** * @param dropEnabled the dropEnabled to set */ public void setDropEnabled(final boolean dropEnabled) { this.dropEnabled = dropEnabled; } /** * @see java.awt.Canvas#update(java.awt.Graphics) */ @Override public void update(final Graphics g) { paint(g); } /** * @return */ public boolean isStarted() { return (refreshCanvas != null) && refreshCanvas.isStarted(); } /** * */ public void start(final TwisterClip clip) { clipController = new TwisterClipController(clip); clipController.setRenderContext(TwisterPreviewCanvas.this); clipController.addControllerListener(new ControllerListener() { public void actionRedone(final NodeAction action) { } public void actionUndone(final NodeAction action) { } public void configChanged() { } }); clipController.init(); final TwisterConfig config = clipController.getConfig(); if (clipController.getDuration() > 0) { this.clip = clip; setListener(new RenderListener() { public void frameRendered() { if (clipController != null) { if (!clipController.redoAction(1000 / getFrameRate(), true)) { // clipController.init(); suspend(); } } } }); } else { this.clip = null; clipController = null; setListener(null); } final IntegerVector2D size = new IntegerVector2D(Math.max(getWidth(), MIN_WITH), Math.max(getHeight(), MIN_HEIGHT)); init(config, size); if (refreshCanvas == null) { refreshCanvas = new RefreshTask(); refreshCanvas.start(); } } /** * */ public void start(final TwisterConfig config) { clip = null; clipController = null; setListener(null); final IntegerVector2D size = new IntegerVector2D(Math.max(getWidth(), MIN_WITH), Math.max(getHeight(), MIN_HEIGHT)); init(config, size); if (refreshCanvas == null) { refreshCanvas = new RefreshTask(); refreshCanvas.start(); } } /** * */ public void start() { if (clip != null) { start(clip); } else { if (config != null) { start(config); } } } /** * */ public void stop() { if (refreshCanvas != null) { refreshCanvas.stop(); refreshCanvas = null; } dispose(); // refreshTask = null; clipController = null; setListener(null); } /** * @return */ public boolean isSuspended() { return (clipController != null) && (listener == null); } /** * @throws ExtensionException */ public void resume() { setListener(new RenderListener() { public void frameRendered() { if (clipController != null) { if (!clipController.redoAction(1000 / getFrameRate(), true)) { // clipController.init(); suspend(); } } } }); if (!clipController.redoAction(1000 / getFrameRate(), true)) { clipController.init(); } } /** * */ public void suspend() { setListener(null); } /** * @return */ public IntegerVector2D getImageSize() { return size; } /** * @return */ public long getFrameRate() { return TwisterPreviewCanvas.frameRate; } private void init(final TwisterConfig config, final IntegerVector2D size) { final HashMap<Object, Object> hints = new HashMap<Object, Object>(); hints.put(TwisterRenderingHints.KEY_QUALITY, TwisterRenderingHints.QUALITY_REALTIME); if (Boolean.getBoolean("jame.lowMemory")) { hints.put(TwisterRenderingHints.KEY_MEMORY, TwisterRenderingHints.MEMORY_LOW); } if (runtime != null) { runtime.dispose(); } if (overlayRuntime != null) { overlayRuntime.dispose(); } runtime = new TwisterRuntime(config); renderer = new DefaultTwisterRenderer(runtime); renderer.setRenderingHints(hints); renderer.setTile(new Tile(new IntegerVector2D(size.getX(), size.getY()), new IntegerVector2D(size.getX(), size.getY()), new IntegerVector2D(0, 0), new IntegerVector2D(0, 0))); final HashMap<Object, Object> overlayHints = new HashMap<Object, Object>(); overlayHints.put(TwisterRenderingHints.KEY_QUALITY, TwisterRenderingHints.QUALITY_REALTIME); if (Boolean.getBoolean("jame.lowMemory")) { overlayHints.put(TwisterRenderingHints.KEY_MEMORY, TwisterRenderingHints.MEMORY_LOW); } overlayHints.put(TwisterRenderingHints.KEY_TYPE, TwisterRenderingHints.TYPE_OVERLAY); overlayRuntime = new TwisterRuntime(config); overlayRenderer = new OverlayTwisterRenderer(overlayRuntime); overlayRenderer.setRenderingHints(overlayHints); overlayRenderer.setTile(new Tile(new IntegerVector2D(size.getX(), size.getY()), new IntegerVector2D(size.getX(), size.getY()), new IntegerVector2D(0, 0), new IntegerVector2D(0, 0))); this.config = config; this.size = size; } private void dispose() { if (renderer != null) { renderer.dispose(); } if (overlayRenderer != null) { overlayRenderer.dispose(); } renderer = null; overlayRenderer = null; if (runtime != null) { runtime.dispose(); } if (overlayRuntime != null) { overlayRuntime.dispose(); } runtime = null; overlayRuntime = null; } private void resize(final IntegerVector2D size) throws ExtensionException { try { acquire(); stopRenderers(); if (renderer != null) { renderer.setTile(new Tile(new IntegerVector2D(size.getX(), size.getY()), new IntegerVector2D(size.getX(), size.getY()), new IntegerVector2D(0, 0), new IntegerVector2D(0, 0))); } if (overlayRenderer != null) { overlayRenderer.setTile(new Tile(new IntegerVector2D(size.getX(), size.getY()), new IntegerVector2D(size.getX(), size.getY()), new IntegerVector2D(0, 0), new IntegerVector2D(0, 0))); } startRenderers(); this.size = size; if (surface != null) { surface.dispose(); surface = null; } if (bufferedImage != null) { bufferedImage.flush(); bufferedImage = null; } release(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } /** * @see java.awt.Canvas#paint(java.awt.Graphics) */ @Override public void paint(Graphics g) { if (bufferedImage == null) { bufferedImage = new BufferedImage(getWidth(), getHeight(), BufferedImage.TYPE_INT_ARGB); refresh(); } g.drawImage(bufferedImage, 0, 0, this); } private void draw() { if (bufferedImage != null) { Graphics2D g = bufferedImage.createGraphics(); g.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED); g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); paintImage(g); g.dispose(); } } private void clear() { if (bufferedImage != null) { Graphics2D g = bufferedImage.createGraphics(); g.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED); g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); clearImage(g); g.dispose(); } } private void clearImage(final Graphics g) { g.setColor(getBackground()); ((Graphics2D) g).setComposite(AlphaComposite.SrcOver); g.fillRect(0, 0, getWidth(), getHeight()); } private void paintImage(final Graphics2D g) { g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); if (renderer != null) { renderer.prepareImage(true); } if (overlayRenderer != null) { overlayRenderer.prepareImage(true); } if (renderer != null) { final EffectExtensionRuntime<?> effectRuntime = renderer.getRuntime().getEffectElement().getEffectRuntime(); if ((effectRuntime != null) && renderer.getRuntime().getEffectElement().isEnabled()) { if (surface == null) { surface = new Surface(size.getX(), size.getY()); } if (renderer != null) { renderer.drawImage(surface.getGraphics2D()); } effectRuntime.setSize(size); effectRuntime.prepareEffect(); effectRuntime.renderImage(surface); g.setColor(new Color(config.getBackground().getARGB(), true)); g.setComposite(AlphaComposite.SrcOver); g.fillRect(0, 0, surface.getWidth(), surface.getHeight()); g.drawImage(surface.getImage(), 0, 0, null); } else { if (surface != null) { surface.dispose(); surface = null; } if (renderer != null) { renderer.drawImage(g); } } if (overlayRenderer != null) { overlayRenderer.drawImage(g); } } g.setComposite(AlphaComposite.SrcOver); if (area != null) { final int x = (int) Math.rint(area.getX() * renderer.getTile().getImageSize().getX() / area.getW()); final int y = (int) Math.rint(area.getY() * renderer.getTile().getImageSize().getX() / area.getW()); final int w = renderer.getTile().getImageSize().getX(); final int h = (int) Math.rint(area.getH() * renderer.getTile().getImageSize().getX() / area.getW()); final int d = (renderer.getTile().getImageSize().getY() - h) / 2; g.setColor(Color.YELLOW); g.drawRect(x, y + d, w - 1, h - 1); } if (hasFocus()) { g.setClip(null); g.setColor(Color.BLUE); g.drawRect(0, 0, getWidth() - 1, getHeight() - 1); } if (paintBorder) { g.setColor(Color.DARK_GRAY); g.drawRect(0, 0, getWidth() - 1, getHeight() - 1); } g.setColor(Color.DARK_GRAY); g.drawRect(0, 0, getWidth() - 1, getHeight() - 1); } private class RefreshTask implements Runnable { private final Object lock = new Object(); private Thread refreshThread; private boolean running; private boolean refresh; /** * */ public void refresh() { synchronized (lock) { refresh = true; lock.notify(); } } /** * */ public void start() { if (refreshThread == null) { running = true; refreshThread = new Thread(this); refreshThread.setName("PreviewCanvas RefreshTask"); refreshThread.setPriority(Thread.MAX_PRIORITY); refreshThread.setDaemon(true); refreshThread.start(); } } /** * */ public void stop() { if (refreshThread != null) { running = false; refreshThread.interrupt(); try { refreshThread.join(); } catch (final InterruptedException e) { } refreshThread = null; } } /** * @return */ public boolean isStarted() { return refreshThread != null; } /** * @see java.lang.Runnable#run() */ public void run() { try { long startTime = 0; long totalTime = 0; final long pauseTime = 1000 / TwisterPreviewCanvas.frameRate; long sleepTime = pauseTime; long idleTime = 0; while (running) { startTime = System.currentTimeMillis(); acquire(); draw(); refresh |= needsRefresh(); if (listener != null) { listener.frameRendered(); } release(); repaint(); synchronized (lock) { if (refresh || (clipController != null)) { idleTime = System.currentTimeMillis(); } if (System.currentTimeMillis() - idleTime > 500) { if (!refresh) { lock.wait(); } idleTime = System.currentTimeMillis(); } refresh = false; } totalTime = System.currentTimeMillis() - startTime; sleepTime = pauseTime - totalTime; if (!running) { break; } if (sleepTime > 10) { Thread.sleep(sleepTime); } else { Thread.sleep(10); } } } catch (final InterruptedException e) { Thread.currentThread().interrupt(); } catch (final Exception e) { e.printStackTrace(); } clear(); } private boolean needsRefresh() { boolean needsRefresh = false; if (runtime != null) { needsRefresh |= runtime.isChanged(); } if (overlayRuntime != null) { needsRefresh |= overlayRuntime.isChanged(); } return needsRefresh; } } /** * @see net.sf.jame.core.util.RenderContext#startRenderers() */ public void startRenderers() { if (renderer != null) { renderer.startRenderer(); } if (overlayRenderer != null) { overlayRenderer.startRenderer(); } } /** * @see net.sf.jame.core.util.RenderContext#stopRenderers() */ public void stopRenderers() { if (renderer != null) { renderer.abortRenderer(); } if (overlayRenderer != null) { overlayRenderer.abortRenderer(); } if (renderer != null) { renderer.joinRenderer(); } if (overlayRenderer != null) { overlayRenderer.joinRenderer(); } } /** * @see net.sf.jame.core.util.RenderContext#addRenderContextListener(net.sf.jame.core.util.RenderContextListener) */ public void addRenderContextListener(RenderContextListener listener) { } /** * @see net.sf.jame.core.util.RenderContext#removeRenderContextListener(net.sf.jame.core.util.RenderContextListener) */ public void removeRenderContextListener(RenderContextListener listener) { } private void resize() { try { final IntegerVector2D size = new IntegerVector2D(Math.max(getWidth(), MIN_WITH), Math.max(getHeight(), MIN_HEIGHT)); TwisterPreviewCanvas.this.resize(size); refresh(); } catch (final ExtensionException x) { x.printStackTrace(); } catch (final Exception x) { x.printStackTrace(); } catch (final Error x) { x.printStackTrace(); } } private class CanvasListener implements ComponentListener, MouseListener, FocusListener, DropTargetListener, DragGestureListener, DragSourceListener { /** * @see java.awt.event.ComponentListener#componentHidden(java.awt.event.ComponentEvent) */ public void componentHidden(final ComponentEvent e) { } /** * @see java.awt.event.ComponentListener#componentMoved(java.awt.event.ComponentEvent) */ public void componentMoved(final ComponentEvent e) { } /** * @see java.awt.event.ComponentListener#componentResized(java.awt.event.ComponentEvent) */ public void componentResized(final ComponentEvent e) { if ((e.getComponent().getWidth() > 0) && (e.getComponent().getHeight() > 0)) { if (resizeThread == null) { resizeThread = new Thread(new Runnable() { public void run() { try { Thread.sleep(250); } catch (InterruptedException e) { } GUIUtil.executeTask(new Runnable() { public void run() { resize(); } }, false); resizeThread = null; } }, "Resize Thread"); resizeThread.setDaemon(true); resizeThread.start(); } } } /** * @see java.awt.event.ComponentListener#componentShown(java.awt.event.ComponentEvent) */ public void componentShown(final ComponentEvent e) { } /** * @see java.awt.event.MouseListener#mouseClicked(java.awt.event.MouseEvent) */ public void mouseClicked(final MouseEvent e) { try { acquire(); if (isSuspended()) { resume(); } else { suspend(); } release(); refresh(); } catch (InterruptedException x) { Thread.currentThread().interrupt(); } } /** * @see java.awt.event.MouseListener#mouseEntered(java.awt.event.MouseEvent) */ public void mouseEntered(final MouseEvent e) { } /** * @see java.awt.event.MouseListener#mouseExited(java.awt.event.MouseEvent) */ public void mouseExited(final MouseEvent e) { } /** * @see java.awt.event.MouseListener#mousePressed(java.awt.event.MouseEvent) */ public void mousePressed(final MouseEvent e) { } /** * @see java.awt.event.MouseListener#mouseReleased(java.awt.event.MouseEvent) */ public void mouseReleased(final MouseEvent e) { } /** * @see java.awt.event.FocusListener#focusGained(java.awt.event.FocusEvent) */ public void focusGained(final FocusEvent e) { refresh(); } /** * @see java.awt.event.FocusListener#focusLost(java.awt.event.FocusEvent) */ public void focusLost(final FocusEvent e) { refresh(); } /** * @see java.awt.dnd.DropTargetListener#dragEnter(java.awt.dnd.DropTargetDragEvent) */ public void dragEnter(final DropTargetDragEvent e) { if (!isDropEnabled()) { e.rejectDrag(); } else if (isTarget) { final DataFlavor[] flavors = e.getCurrentDataFlavors(); boolean accept = false; for (final DataFlavor element : flavors) { if (element.equals(TransferableTwisterConfig.TWISTER_CONFIG_FLAVOR)) { accept = true; break; } else if (element.equals(TransferableTwisterClip.TWISTER_CLIP_FLAVOR)) { accept = true; break; } } if (accept) { e.acceptDrag(DnDConstants.ACTION_MOVE); paintBorder = true; refresh(); } else { e.rejectDrag(); } } } /** * @see java.awt.dnd.DropTargetListener#dragOver(java.awt.dnd.DropTargetDragEvent) */ public void dragOver(final DropTargetDragEvent e) { } /** * @see java.awt.dnd.DropTargetListener#dragExit(java.awt.dnd.DropTargetEvent) */ public void dragExit(final DropTargetEvent e) { if (isTarget) { paintBorder = false; refresh(); } } /** * @see java.awt.dnd.DropTargetListener#dropActionChanged(java.awt.dnd.DropTargetDragEvent) */ public void dropActionChanged(final DropTargetDragEvent e) { } /** * @see java.awt.dnd.DropTargetListener#drop(java.awt.dnd.DropTargetDropEvent) */ public void drop(final DropTargetDropEvent e) { if (isTarget) { final DataFlavor[] flavors = e.getCurrentDataFlavors(); boolean accept = false; for (final DataFlavor element : flavors) { if (element.equals(TransferableTwisterConfig.TWISTER_CONFIG_FLAVOR)) { try { e.acceptDrop(DnDConstants.ACTION_COPY); final TwisterConfig config = (TwisterConfig) e.getTransferable().getTransferData(TransferableTwisterConfig.TWISTER_CONFIG_FLAVOR); acquire(); stopRenderers(); stop(); start(config); startRenderers(); release(); } catch (final UnsupportedFlavorException x) { x.printStackTrace(); } catch (final IOException x) { x.printStackTrace(); } catch (InterruptedException x) { Thread.currentThread().interrupt(); } accept = true; break; } else if (element.equals(TransferableTwisterClip.TWISTER_CLIP_FLAVOR)) { try { e.acceptDrop(DnDConstants.ACTION_COPY); final TwisterClip clip = (TwisterClip) e.getTransferable().getTransferData(TransferableTwisterClip.TWISTER_CLIP_FLAVOR); acquire(); stopRenderers(); stop(); start(clip); startRenderers(); release(); } catch (final UnsupportedFlavorException x) { x.printStackTrace(); } catch (final IOException x) { x.printStackTrace(); } catch (InterruptedException x) { Thread.currentThread().interrupt(); } accept = true; break; } } if (accept) { e.dropComplete(true); paintBorder = false; refresh(); } else { e.rejectDrop(); } } } /** * @see java.awt.dnd.DragGestureListener#dragGestureRecognized(java.awt.dnd.DragGestureEvent) */ public void dragGestureRecognized(final DragGestureEvent e) { if (isDragEnabled()) { try { if (clip != null) { source.startDrag(e, DragSource.DefaultCopyDrop, new TransferableTwisterClip(clip), this); } else { source.startDrag(e, DragSource.DefaultCopyDrop, new TransferableTwisterConfig(config), this); } paintBorder = true; isTarget = false; refresh(); } catch (final InvalidDnDOperationException x) { x.printStackTrace(); } } } /** * @see java.awt.dnd.DragSourceListener#dragEnter(java.awt.dnd.DragSourceDragEvent) */ public void dragEnter(final DragSourceDragEvent e) { } /** * @see java.awt.dnd.DragSourceListener#dragOver(java.awt.dnd.DragSourceDragEvent) */ public void dragOver(final DragSourceDragEvent e) { } /** * @see java.awt.dnd.DragSourceListener#dragExit(java.awt.dnd.DragSourceEvent) */ public void dragExit(final DragSourceEvent e) { } /** * @see java.awt.dnd.DragSourceListener#dropActionChanged(java.awt.dnd.DragSourceDragEvent) */ public void dropActionChanged(final DragSourceDragEvent e) { } /** * @see java.awt.dnd.DragSourceListener#dragDropEnd(java.awt.dnd.DragSourceDropEvent) */ public void dragDropEnd(final DragSourceDropEvent e) { paintBorder = false; isTarget = true; refresh(); } } }