001/* 002 * $Id$ 003 * 004 * Copyright 2009 Sun Microsystems, Inc., 4150 Network Circle, 005 * Santa Clara, California 95054, U.S.A. All rights reserved. 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this library; if not, write to the Free Software 019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 020 * 021 */ 022package org.jdesktop.swingx.plaf.basic.core; 023 024/* 025 * @(#)DragRecognitionSupport.java 1.2 05/11/17 026 * 027 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 028 * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 029 */ 030 031import java.awt.Toolkit; 032import java.awt.event.*; 033import java.awt.dnd.DragSource; 034import javax.swing.*; 035 036import org.jdesktop.swingx.SwingXUtilities; 037//import sun.awt.dnd.SunDragSourceContextPeer; 038//import sun.awt.AppContext; 039 040/** 041 * Drag gesture recognition support for classes that have a 042 * <code>TransferHandler</code>. The gesture for a drag in this class is a mouse 043 * press followed by movement by <code>DragSource.getDragThreshold()</code> 044 * pixels. An instance of this class is maintained per AppContext, and the 045 * public static methods call into the appropriate instance. <p> 046 * 047 * This is a c&p of core (package private) needed for BasicXListUI. It differs from 048 * core in that references to sun packages have been replaced. 049 * <ul> 050 * <li> a static method of SunDragSourceContextPeer has been copied into SwingXUtilities 051 * and is used here 052 * <li> the shared instance of this class is maintained in the UIManager instead of 053 * per appContext. 054 * </ul> 055 * 056 * @author Shannon Hickey 057 * @version 1.2 11/17/05 058 */ 059public class DragRecognitionSupport { 060 private int motionThreshold; 061 private MouseEvent dndArmedEvent; 062 private JComponent component; 063 064 /** 065 * This interface allows us to pass in a handler to mouseDragged, 066 * so that we can be notified immediately before a drag begins. 067 */ 068 public static interface BeforeDrag { 069 public void dragStarting(MouseEvent me); 070 } 071 072 /** 073 * Returns the DragRecognitionSupport for the caller's AppContext. 074 */ 075 private static DragRecognitionSupport getDragRecognitionSupport() { 076// DragRecognitionSupport support = 077// (DragRecognitionSupport)AppContext.getAppContext(). 078// get(DragRecognitionSupport.class); 079// 080// if (support == null) { 081// support = new DragRecognitionSupport(); 082// AppContext.getAppContext().put(DragRecognitionSupport.class, support); 083// } 084 085 DragRecognitionSupport support = (DragRecognitionSupport) 086 UIManager.get("sharedInstance.dragRecognitionSupport"); 087 if (support == null) { 088 support = new DragRecognitionSupport(); 089 UIManager.put("sharedInstance.dragRecognitionSupport", support); 090 } 091 return support; 092 } 093 094 /** 095 * Returns whether or not the event is potentially part of a drag sequence. 096 */ 097 public static boolean mousePressed(MouseEvent me) { 098 return ((DragRecognitionSupport)getDragRecognitionSupport()). 099 mousePressedImpl(me); 100 } 101 102 /** 103 * If a dnd recognition has been going on, return the MouseEvent 104 * that started the recognition. Otherwise, return null. 105 */ 106 public static MouseEvent mouseReleased(MouseEvent me) { 107 return ((DragRecognitionSupport)getDragRecognitionSupport()). 108 mouseReleasedImpl(me); 109 } 110 111 /** 112 * Returns whether or not a drag gesture recognition is ongoing. 113 */ 114 public static boolean mouseDragged(MouseEvent me, BeforeDrag bd) { 115 return ((DragRecognitionSupport)getDragRecognitionSupport()). 116 mouseDraggedImpl(me, bd); 117 } 118 119 private void clearState() { 120 dndArmedEvent = null; 121 component = null; 122 } 123 124 private int mapDragOperationFromModifiers(MouseEvent me, 125 TransferHandler th) { 126 127 if (th == null || !SwingUtilities.isLeftMouseButton(me)) { 128 return TransferHandler.NONE; 129 } 130 // PENDING JW: c'p from SunDragSourceContextPeer 131 return SwingXUtilities. 132 convertModifiersToDropAction(me.getModifiersEx(), 133 th.getSourceActions(component)); 134 } 135 136 /** 137 * Returns whether or not the event is potentially part of a drag sequence. 138 */ 139 private boolean mousePressedImpl(MouseEvent me) { 140 component = (JComponent)me.getSource(); 141 142 if (mapDragOperationFromModifiers(me, component.getTransferHandler()) 143 != TransferHandler.NONE) { 144 145 motionThreshold = DragSource.getDragThreshold(); 146 dndArmedEvent = me; 147 return true; 148 } 149 150 clearState(); 151 return false; 152 } 153 154 /** 155 * If a dnd recognition has been going on, return the MouseEvent 156 * that started the recognition. Otherwise, return null. 157 */ 158 private MouseEvent mouseReleasedImpl(MouseEvent me) { 159 /* no recognition has been going on */ 160 if (dndArmedEvent == null) { 161 return null; 162 } 163 164 MouseEvent retEvent = null; 165 166 if (me.getSource() == component) { 167 retEvent = dndArmedEvent; 168 } // else component has changed unexpectedly, so return null 169 170 clearState(); 171 return retEvent; 172 } 173 174 /** 175 * Returns whether or not a drag gesture recognition is ongoing. 176 */ 177 private boolean mouseDraggedImpl(MouseEvent me, BeforeDrag bd) { 178 /* no recognition is in progress */ 179 if (dndArmedEvent == null) { 180 return false; 181 } 182 183 /* component has changed unexpectedly, so bail */ 184 if (me.getSource() != component) { 185 clearState(); 186 return false; 187 } 188 189 int dx = Math.abs(me.getX() - dndArmedEvent.getX()); 190 int dy = Math.abs(me.getY() - dndArmedEvent.getY()); 191 if ((dx > motionThreshold) || (dy > motionThreshold)) { 192 TransferHandler th = component.getTransferHandler(); 193 int action = mapDragOperationFromModifiers(me, th); 194 if (action != TransferHandler.NONE) { 195 /* notify the BeforeDrag instance */ 196 if (bd != null) { 197 bd.dragStarting(dndArmedEvent); 198 } 199 th.exportAsDrag(component, dndArmedEvent, action); 200 clearState(); 201 } 202 } 203 204 return true; 205 } 206}