View Javadoc

1   /*
2    * Copyright (c) 2003-2008 by Cosylab d. d.
3    *
4    * This file is part of CosyBeans-Common.
5    *
6    * CosyBeans-Common is free software: you can redistribute it and/or modify
7    * it under the terms of the GNU General Public License as published by
8    * the Free Software Foundation, either version 3 of the License, or
9    * (at your option) any later version.
10   *
11   * CosyBeans-Common is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU General Public License for more details.
15   *
16   * You should have received a copy of the GNU General Public License
17   * along with CosyBeans-Common.  If not, see <http://www.gnu.org/licenses/>.
18   */
19  
20  package com.cosylab.gui.components.util;
21  
22  import java.awt.datatransfer.DataFlavor;
23  import java.awt.datatransfer.Transferable;
24  import java.awt.datatransfer.UnsupportedFlavorException;
25  import java.awt.event.MouseEvent;
26  import java.awt.event.MouseMotionListener;
27  import java.io.IOException;
28  import java.util.ArrayList;
29  import java.util.HashSet;
30  import java.util.List;
31  import java.util.Set;
32  
33  import javax.swing.JComponent;
34  import javax.swing.TransferHandler;
35  
36  /**
37   * <code>CosyTransferHandler</code> is a common TransferHandler for cosy
38   * displyers.  
39   * 
40   * @author Jaka Bobnar, Cosylab
41   *
42   */
43  public abstract class CosyTransferHandler extends TransferHandler implements MouseMotionListener, Transferable {
44  
45  	public static final void registerTransferHandler(JComponent parent, TransferHandler newT, JComponent... comps) {
46  		TransferHandler oldT= parent.getTransferHandler();
47      	if (oldT instanceof CosyTransferHandler) {
48      		((CosyTransferHandler)oldT).unhookTransferHandler(parent);
49      	}
50  		for (JComponent comp : comps) {
51  	    	if (oldT instanceof CosyTransferHandler) {
52  	    		((CosyTransferHandler)oldT).unhookTransferHandler(comp);
53  	    	}
54  	    	if (newT instanceof CosyTransferHandler) {
55  	    		((CosyTransferHandler)newT).hookTransferHandler(comp);
56  	    	}
57  		}
58  	}
59  	
60  	/**
61  	 * <code>MouseFilter</code> can notify if certain MouseEvent can trigger the 
62  	 * DnD event.
63  	 * 
64  	 * @author <a href="mailto:jaka.bobnar@cosylab.com">Jaka Bobnar</a>
65  	 * @version $Id: CosyTransferHandler.java,v 1.9 2008-04-22 12:28:40 jbobnar Exp $
66  	 *
67  	 */
68  	public static interface MouseFilter {
69  		/**
70  		 * If the event happened in the area where drag is enabled, this method
71  		 * should return true.
72  		 * 
73  		 * @param e
74  		 * @return true if drag is enabled
75  		 */
76  		public boolean isDragArea(MouseEvent e);
77  	}
78  	
79  	private boolean receiveEnabled=true;
80  	private boolean exportEnabled=true;
81  	protected boolean isDragging = false;
82  	private Set<JComponent> hooked= new HashSet<JComponent>();
83  	private List<MouseFilter> filters= new ArrayList<MouseFilter>();	
84  	
85  	/**
86  	 * Creates new instance of CosyTransferHandler.
87  	 * @param property
88  	 * @param reciveEnabled
89  	 * @param exportEnabled
90  	 */
91  	public CosyTransferHandler(boolean receiveEnabled, boolean exportEnabled) {
92  		this.receiveEnabled = receiveEnabled;
93  		this.exportEnabled = exportEnabled;
94  	}
95  	
96  	/**
97  	 * Hooks transfer handler to the given component, using the exising
98  	 * import/export enables flags.
99  	 * 
100 	 * @param comp
101 	 */
102 	public void hookTransferHandler(JComponent comp) {
103 		hookTransferHandler(comp,receiveEnabled,exportEnabled);
104 	}
105 	
106 	/**
107 	 * Unhook transfer handler from the given component.
108 	 * @param comp
109 	 */
110 	public void unhookTransferHandler(JComponent comp) {
111 		comp.removeMouseMotionListener(this);
112 		hooked.remove(comp);
113 	}
114 
115 	/**
116 	 * Hooks transfer handler to the given component. TransferHandler will
117 	 * handler only the specified action.
118 	 * 
119 	 * @param comp component to hook
120 	 * @param canReceive true if drop should be enabled
121 	 * @param canExport true if drag should be enabled
122 	 */
123 	public void hookTransferHandler(JComponent comp, boolean canReceive, boolean canExport) {
124 		if (hooked.contains(comp)) {
125 			return;
126 		}
127 		if (canExport || canReceive) {
128 			hooked.add(comp);
129 			comp.setTransferHandler(this);
130 		} 
131 		if (canExport) {
132 			comp.addMouseMotionListener(this);
133 		} 		
134 	}
135 	
136 	/**
137 	 * Yop may override this method to implement own transferable or override just methods, which are 
138 	 * perscribed by transferable.
139 	 */
140 	@Override
141 	protected Transferable createTransferable(final JComponent c) {
142 		return this;
143 	}
144 
145 	/*
146 	 * (non-Javadoc)
147 	 * @see java.awt.datatransfer.Transferable#getTransferData(java.awt.datatransfer.DataFlavor)
148 	 */
149 	public abstract Object getTransferData(DataFlavor flavor)
150 					throws UnsupportedFlavorException, IOException;
151 	
152 	/*
153 	 * (non-Javadoc)
154 	 * @see java.awt.datatransfer.Transferable#isDataFlavorSupported(java.awt.datatransfer.DataFlavor)
155 	 */
156 	public boolean isDataFlavorSupported(DataFlavor flavor) {
157 		DataFlavor[] flavors= getTransferDataFlavors();
158 		
159 		for (DataFlavor f : flavors) {
160 			if (f.equals(flavor)) {
161 				return true;
162 			}
163 		}
164 		return false;
165 	}
166 
167 	/*
168 	 * (non-Javadoc)
169 	 * @see java.awt.datatransfer.Transferable#getTransferDataFlavors()
170 	 */
171 	public abstract DataFlavor[] getTransferDataFlavors();
172 
173 	/*
174 	 * (non-Javadoc)
175 	 * @see javax.swing.TransferHandler#canImport(javax.swing.JComponent, java.awt.datatransfer.DataFlavor[])
176 	 */
177 	@Override
178 	public boolean canImport(JComponent comp, DataFlavor[] transferFlavors) {
179 		if (!receiveEnabled) return false;
180 		for (DataFlavor flavor : transferFlavors) {
181 			if (isDataFlavorSupported(flavor)) {
182 				return true;
183 			}
184 		}
185 		return false;
186 	}
187 	
188 	/*
189 	 * (non-Javadoc)
190 	 * @see javax.swing.TransferHandler#getSourceActions(javax.swing.JComponent)
191 	 */
192 	@Override
193 	public int getSourceActions(JComponent c) {
194 		return TransferHandler.COPY;
195 	}
196 	
197 	protected boolean isMouseDragGesture(MouseEvent e) {
198 		return (e.getModifiers()&MouseEvent.BUTTON1)!=MouseEvent.BUTTON1;
199 	}
200 
201 	/*
202 	 * (non-Javadoc)
203 	 * @see java.awt.event.MouseMotionListener#mouseDragged(java.awt.event.MouseEvent)
204 	 */
205 	public void mouseDragged(MouseEvent e) {
206 		if (!exportEnabled || !isMouseDragGesture(e)) {
207 			return;
208 		}
209 		
210 		for (MouseFilter f : filters) {
211 			if (!f.isDragArea(e)) {
212 				return;
213 			}
214 		}
215 		//if another MouseMotionListener already exists on that component we have
216 		//overriden its previous function. restore.
217 		JComponent c = (JComponent)e.getComponent();
218 		if (canDrag(c)) {
219 			exportAsDrag(c,e,TransferHandler.COPY);
220 			isDragging = true;
221 		}
222     }
223 	
224 	/*
225 	 * (non-Javadoc)
226 	 * @see javax.swing.TransferHandler#exportDone(javax.swing.JComponent, java.awt.datatransfer.Transferable, int)
227 	 */
228 	@Override
229 	protected void exportDone(JComponent source, Transferable data, int action) {
230 		super.exportDone(source, data, action);
231 		isDragging = false;
232 	}
233 	
234 	/**
235 	 * Return true if this component can start drag gesture for provided component.
236 	 * Default value is same as dragEnabled;
237 	 * @param comp
238 	 * @return true if this component can start drag gesture
239 	 */
240 	protected boolean canDrag(JComponent comp) {
241 		return exportEnabled;
242 	}
243 	
244 	/*
245 	 * (non-Javadoc)
246 	 * @see java.awt.event.MouseMotionListener#mouseMoved(java.awt.event.MouseEvent)
247 	 */
248 	public void mouseMoved(MouseEvent e) {
249 	    //
250     }
251 
252 	
253 	/**
254 	 * Returns true if drag is enabled.
255 	 * 
256 	 * @return the exportEnabled.
257 	 */
258 	public boolean isExportEnabled() {
259 		return exportEnabled;
260 	}
261 
262 	
263 	/**
264 	 * Returns true if drop is enabled.
265 	 * 
266 	 * @return the reciveEnabled.
267 	 */
268 	public boolean isReceiveEnabled() {
269 		return receiveEnabled;
270 	}
271 	
272 	
273 	/**
274 	 * Enables/disables the drag.
275 	 * 
276 	 * @param exportEnabled true if drag is enabled
277 	 * @param comp component on which the drag should be enabled/disabled
278 	 */
279 	public void setExportEnabled(boolean exportEnabled, JComponent comp) {
280 		if (this.exportEnabled != exportEnabled) {
281 			this.exportEnabled = exportEnabled;
282 			unhookTransferHandler(comp);
283 			hookTransferHandler(comp);
284 		}
285 	}
286 
287 	
288 	/**
289 	 * Enables/disables the drop on the given component
290 	 * 
291 	 * @param reciveEnabled true if drop should be enabled
292 	 * @param comp component on which the drop should be enabled/disabled
293 	 */
294 	public void setReceiveEnabled(boolean receiveEnabled, JComponent comp) {
295 		if (this.receiveEnabled != receiveEnabled) {
296 			this.receiveEnabled = receiveEnabled;
297 			unhookTransferHandler(comp);
298 			hookTransferHandler(comp);
299 		}
300 	}
301 	
302 	/**
303 	 * Adds a mouse filter to this handler.
304 	 * 
305 	 * @param f
306 	 */
307 	public void addMouseFilter(MouseFilter f) {
308 		filters.add(f);
309 	}
310 	
311 	/**
312 	 * Removes a mouse filter from this handler.
313 	 * 
314 	 * @param f
315 	 */
316 	public void removeMouseFilter(MouseFilter f) {
317 		filters.remove(f);
318 	}
319 	
320 	/**
321 	 * Returns all mouse filters assigned to this handler
322 	 * 
323 	 * @return
324 	 */
325 	public MouseFilter[] getMouseFilters() {
326 		return filters.toArray(new MouseFilter[filters.size()]);
327 	}
328 
329 }
330 
331 
332 /* __oOo__ */