alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (CDragSourceContextPeer.java)

This example Java source code file (CDragSourceContextPeer.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

accessibletext, awt, cdragsourcecontextpeer, component, cursor, datatransfer, dnd, drag, draggestureevent, drop, image, inputevent, invaliddndoperationexception, jcomponent, mouseevent, override, point, rectangle, swing, thread

The CDragSourceContextPeer.java Java example source code

/*
 * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code 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
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */


package sun.lwawt.macosx;

import java.awt.*;
import java.awt.datatransfer.*;
import java.awt.dnd.*;
import java.awt.event.*;
import java.awt.image.*;
import java.awt.peer.*;

import javax.swing.*;
import javax.swing.text.*;
import javax.accessibility.*;

import java.util.Map;
import java.util.concurrent.Callable;

import sun.awt.dnd.*;
import sun.lwawt.LWComponentPeer;
import sun.lwawt.LWWindowPeer;
import sun.lwawt.PlatformWindow;


public final class CDragSourceContextPeer extends SunDragSourceContextPeer {

    private static final CDragSourceContextPeer fInstance = new CDragSourceContextPeer(null);

    private Image  fDragImage;
    private CImage fDragCImage;
    private Point  fDragImageOffset;

    private static Component hoveringComponent = null;

    private static double fMaxImageSize = 128.0;

    static {
        String propValue = java.security.AccessController.doPrivileged(new sun.security.action.GetPropertyAction("apple.awt.dnd.defaultDragImageSize"));
        if (propValue != null) {
            try {
                double value = Double.parseDouble(propValue);
                if (value > 0) {
                    fMaxImageSize = value;
                }
            } catch(NumberFormatException e) {}
        }
    }

    private CDragSourceContextPeer(DragGestureEvent dge) {
        super(dge);
    }

    public static CDragSourceContextPeer createDragSourceContextPeer(DragGestureEvent dge) throws InvalidDnDOperationException {
        fInstance.setTrigger(dge);

        return fInstance;
    }

    // We have to overload this method just to be able to grab the drag image and its offset as shared code doesn't store it:
    public void startDrag(DragSourceContext dsc, Cursor cursor, Image dragImage, Point dragImageOffset) throws InvalidDnDOperationException {
        fDragImage = dragImage;
        fDragImageOffset = dragImageOffset;

        super.startDrag(dsc, cursor, dragImage, dragImageOffset);
    }

    protected void startDrag(Transferable transferable, long[] formats, Map formatMap) {
        DragGestureEvent trigger = getTrigger();
        InputEvent         triggerEvent = trigger.getTriggerEvent();

        Point dragOrigin = new Point(trigger.getDragOrigin());
        int extModifiers = (triggerEvent.getModifiers() | triggerEvent.getModifiersEx());
        long timestamp   = triggerEvent.getWhen();
        int clickCount   = ((triggerEvent instanceof MouseEvent) ? (((MouseEvent) triggerEvent).getClickCount()) : 1);

        Component component = trigger.getComponent();
        // For a lightweight component traverse up the hierarchy to the root
        Point loc = component.getLocation();
        Component rootComponent = component;
        while (!(rootComponent instanceof Window)) {
            dragOrigin.translate(loc.x, loc.y);
            rootComponent = rootComponent.getParent();
            loc = rootComponent.getLocation();
        }

        // If there isn't any drag image make one of default appearance:
        if (fDragImage == null)
            this.setDefaultDragImage(component);

        // Get drag image (if any) as BufferedImage and convert that to CImage:
        Point dragImageOffset;

        if (fDragImage != null) {
            try {
                fDragCImage = CImage.getCreator().createFromImageImmediately(fDragImage);
            } catch(Exception e) {
                // image creation may fail for any reason
                throw new InvalidDnDOperationException("Drag image can not be created.");
            }
            if (fDragCImage == null) {
                throw new InvalidDnDOperationException("Drag image is not ready.");
            }

            dragImageOffset = fDragImageOffset;
        } else {

            fDragCImage = null;
            dragImageOffset = new Point(0, 0);
        }

        try {
            //It sure will be LWComponentPeer instance as rootComponent is a Window
            PlatformWindow platformWindow = ((LWComponentPeer)rootComponent.getPeer()).getPlatformWindow();
            long nativeViewPtr = CPlatformWindow.getNativeViewPtr(platformWindow);
            if (nativeViewPtr == 0L) throw new InvalidDnDOperationException("Unsupported platform window implementation");

            // Create native dragging source:
            final long nativeDragSource = createNativeDragSource(component, nativeViewPtr, transferable, triggerEvent,
                (int) (dragOrigin.getX()), (int) (dragOrigin.getY()), extModifiers,
                clickCount, timestamp, fDragCImage, dragImageOffset.x, dragImageOffset.y,
                getDragSourceContext().getSourceActions(), formats, formatMap);

            if (nativeDragSource == 0)
                throw new InvalidDnDOperationException("");

            setNativeContext(nativeDragSource);
        }

        catch (Exception e) {
            throw new InvalidDnDOperationException("failed to create native peer: " + e);
        }

        SunDropTargetContextPeer.setCurrentJVMLocalSourceTransferable(transferable);

        CCursorManager.getInstance().setCursor(getCursor());

        // Create a new thread to run the dragging operation since it's synchronous, only coming back
        // after dragging is finished. This leaves the AWT event thread free to handle AWT events which
        // are posted during dragging by native event handlers.

        try {
            Thread dragThread = new Thread() {
                public void run() {
                    final long nativeDragSource = getNativeContext();
                    try {
                        doDragging(nativeDragSource);
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        releaseNativeDragSource(nativeDragSource);
                        fDragImage = null;
                        if (fDragCImage != null) {
                            fDragCImage.dispose();
                            fDragCImage = null;
                        }
                    }
                }
            };

            dragThread.start();
        }

        catch (Exception e) {
            final long nativeDragSource = getNativeContext();
            setNativeContext(0);
            releaseNativeDragSource(nativeDragSource);
            SunDropTargetContextPeer.setCurrentJVMLocalSourceTransferable(null);
            throw new InvalidDnDOperationException("failed to start dragging thread: " + e);
        }
    }

    private void setDefaultDragImage(Component component) {
        boolean handled = false;

        // Special-case default drag image, depending on the drag source type:
        if (component.isLightweight()) {
            if (component instanceof JTextComponent) {
                this.setDefaultDragImage((JTextComponent) component);
                handled = true;
            } else if (component instanceof JTree) {
                            this.setDefaultDragImage((JTree) component);
                            handled = true;
                        } else if (component instanceof JTable) {
                            this.setDefaultDragImage((JTable) component);
                            handled = true;
                        } else if (component instanceof JList) {
                            this.setDefaultDragImage((JList) component);
                            handled = true;
                        }
        }

        if (handled == false)
            this.setDefaultDragImage();
    }

    private void setDefaultDragImage(JTextComponent component) {
        DragGestureEvent trigger = getTrigger();
        int selectionStart = component.getSelectionStart();
        int selectionEnd = component.getSelectionEnd();
        boolean handled = false;

        // Make sure we're dragging current selection:
        int index = component.viewToModel(trigger.getDragOrigin());
        if ((selectionStart < selectionEnd) && (index >= selectionStart) && (index <= selectionEnd)) {
            try {
                Rectangle selectionStartBounds = component.modelToView(selectionStart);
                Rectangle selectionEndBounds = component.modelToView(selectionEnd);

                Rectangle selectionBounds = null;

                // Single-line selection:
                if (selectionStartBounds.y == selectionEndBounds.y) {
                    selectionBounds = new Rectangle(selectionStartBounds.x, selectionStartBounds.y,
                        selectionEndBounds.x - selectionStartBounds.x + selectionEndBounds.width,
                        selectionEndBounds.y - selectionStartBounds.y + selectionEndBounds.height);
                }

                // Multi-line selection:
                else {
                    AccessibleContext ctx = component.getAccessibleContext();
                    AccessibleText at = (AccessibleText) ctx;

                    selectionBounds = component.modelToView(selectionStart);
                    for (int i = selectionStart + 1; i <= selectionEnd; i++) {
                                            Rectangle charBounds = at.getCharacterBounds(i);
                                            // Invalid index returns null Rectangle
                                            // Note that this goes against jdk doc - should be empty, but is null instead
                                            if (charBounds != null) {
                                                selectionBounds.add(charBounds);
                                            }
                    }
                }

                this.setOutlineDragImage(selectionBounds);
                handled = true;
            }

            catch (BadLocationException exc) {
                // Default the drag image to component bounds.
            }
        }

        if (handled == false)
            this.setDefaultDragImage();
    }


    private void setDefaultDragImage(JTree component) {
        Rectangle selectedOutline = null;

        int[] selectedRows = component.getSelectionRows();
        for (int i=0; i<selectedRows.length; i++) {
            Rectangle r = component.getRowBounds(selectedRows[i]);
            if (selectedOutline == null)
                selectedOutline = r;
            else
                selectedOutline.add(r);
        }

        if (selectedOutline != null) {
            this.setOutlineDragImage(selectedOutline);
        } else {
            this.setDefaultDragImage();
        }
    }

    private void setDefaultDragImage(JTable component) {
        Rectangle selectedOutline = null;

        // This code will likely break once multiple selections works (3645873)
        int[] selectedRows = component.getSelectedRows();
        int[] selectedColumns = component.getSelectedColumns();
        for (int row=0; row<selectedRows.length; row++) {
            for (int col=0; col<selectedColumns.length; col++) {
                Rectangle r = component.getCellRect(selectedRows[row], selectedColumns[col], true);
                if (selectedOutline == null)
                    selectedOutline = r;
                else
                    selectedOutline.add(r);
            }
        }

        if (selectedOutline != null) {
            this.setOutlineDragImage(selectedOutline);
        } else {
            this.setDefaultDragImage();
        }
    }

    private void setDefaultDragImage(JList component) {
        Rectangle selectedOutline = null;

        // This code actually works, even under the (non-existant) multiple-selections, because we only draw a union outline
        int[] selectedIndices = component.getSelectedIndices();
        if (selectedIndices.length > 0)
            selectedOutline = component.getCellBounds(selectedIndices[0], selectedIndices[selectedIndices.length-1]);

        if (selectedOutline != null) {
            this.setOutlineDragImage(selectedOutline);
        } else {
            this.setDefaultDragImage();
        }
    }


    private void setDefaultDragImage() {
        DragGestureEvent trigger = this.getTrigger();
        Component comp = trigger.getComponent();

        setOutlineDragImage(new Rectangle(0, 0, comp.getWidth(), comp.getHeight()), true);
    }

    private void setOutlineDragImage(Rectangle outline) {
        setOutlineDragImage(outline, false);
    }

    private void setOutlineDragImage(Rectangle outline, Boolean shouldScale) {
        int width = (int)outline.getWidth();
        int height = (int)outline.getHeight();

        double scale = 1.0;
        if (shouldScale) {
            final int area = width * height;
            final int maxArea = (int)(fMaxImageSize * fMaxImageSize);

            if (area > maxArea) {
                scale = (double)area / (double)maxArea;
                width /= scale;
                height /= scale;
            }
        }

        if (width <=0) width = 1;
        if (height <=0) height = 1;

        DragGestureEvent trigger = this.getTrigger();
        Component comp = trigger.getComponent();
        Point compOffset = comp.getLocation();

        // For lightweight components add some special treatment:
        if (comp instanceof JComponent) {
            // Intersect requested bounds with visible bounds:
            Rectangle visibleBounds = ((JComponent) comp).getVisibleRect();
            Rectangle clipedOutline = outline.intersection(visibleBounds);
            if (clipedOutline.isEmpty() == false)
                outline = clipedOutline;

            // Compensate for the component offset (e.g. when contained in a JScrollPane):
            outline.translate(compOffset.x, compOffset.y);
        }

        GraphicsConfiguration config = comp.getGraphicsConfiguration();
        BufferedImage dragImage = config.createCompatibleImage(width, height, Transparency.TRANSLUCENT);

        Color paint = Color.gray;
        BasicStroke stroke = new BasicStroke(2.0f);
        int halfLineWidth = (int) (stroke.getLineWidth() + 1) / 2; // Rounded up.

        Graphics2D g2 = (Graphics2D) dragImage.getGraphics();
        g2.setPaint(paint);
        g2.setStroke(stroke);
        g2.drawRect(halfLineWidth, halfLineWidth, width - 2 * halfLineWidth - 1, height - 2 * halfLineWidth - 1);
        g2.dispose();

        fDragImage = dragImage;


        Point dragOrigin = trigger.getDragOrigin();
        Point dragImageOffset = new Point(outline.x - dragOrigin.x, outline.y - dragOrigin.y);
        if (comp instanceof JComponent) {
            dragImageOffset.translate(-compOffset.x, -compOffset.y);
        }

        if (shouldScale) {
            dragImageOffset.x /= scale;
            dragImageOffset.y /= scale;
        }

        fDragImageOffset = dragImageOffset;
    }

    /**
     * upcall from native code
     */
    private void dragMouseMoved(final int targetActions,
                                final int modifiers,
                                final int x, final int y) {

        try {
            Component componentAt = LWCToolkit.invokeAndWait(
                    new Callable<Component>() {
                        @Override
                        public Component call() {
                            LWWindowPeer mouseEventComponent = LWWindowPeer.getWindowUnderCursor();
                            if (mouseEventComponent == null) {
                                return null;
                            }
                            Component root = SwingUtilities.getRoot(mouseEventComponent.getTarget());
                            if (root == null) {
                                return null;
                            }
                            Point rootLocation = root.getLocationOnScreen();
                            return getDropTargetAt(root, x - rootLocation.x, y - rootLocation.y);
                        }
                    }, getComponent());

            if(componentAt != hoveringComponent) {
                if(hoveringComponent != null) {
                    dragExit(x, y);
                }
                if(componentAt != null) {
                    dragEnter(targetActions, modifiers, x, y);
                }
                hoveringComponent = componentAt;
            }

            postDragSourceDragEvent(targetActions, modifiers, x, y,
                    DISPATCH_MOUSE_MOVED);
        } catch (Exception e) {
            throw new InvalidDnDOperationException("Failed to handle DragMouseMoved event");
        }
    }

    //Returns the first lightweight or heavyweight Component which has a dropTarget ready to accept the drag
    //Should be called from the EventDispatchThread
    private static Component getDropTargetAt(Component root, int x, int y) {
        if (!root.contains(x, y) || !root.isEnabled() || !root.isVisible()) {
            return null;
        }

        if (root.getDropTarget() != null && root.getDropTarget().isActive()) {
            return root;
        }

        if (root instanceof Container) {
            for (Component comp : ((Container) root).getComponents()) {
                Point loc = comp.getLocation();
                Component dropTarget = getDropTargetAt(comp, x - loc.x, y - loc.y);
                if (dropTarget != null) {
                    return dropTarget;
                }
            }
        }

        return null;
    }

    /**
     * upcall from native code - reset hovering component
     */
    private void resetHovering() {
        hoveringComponent = null;
    }

    @Override
    protected void setNativeCursor(long nativeCtxt, Cursor c, int cType) {
        CCursorManager.getInstance().setCursor(c);
    }

    // Native support:
    private native long createNativeDragSource(Component component, long nativePeer, Transferable transferable,
        InputEvent triggerEvent, int dragPosX, int dragPosY, int extModifiers, int clickCount, long timestamp,
        CImage nsDragImage, int dragImageOffsetX, int dragImageOffsetY,
        int sourceActions, long[] formats, Map formatMap);

    private native void doDragging(long nativeDragSource);

    private native void releaseNativeDragSource(long nativeDragSource);
}

Other Java examples (source code examples)

Here is a short list of links related to this Java CDragSourceContextPeer.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.