001/* DragSourceContext.java --
002   Copyright (C) 2002 Free Software Foundation
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038
039package java.awt.dnd;
040
041import java.awt.Component;
042import java.awt.Cursor;
043import java.awt.Image;
044import java.awt.Point;
045import java.awt.datatransfer.Transferable;
046import java.awt.dnd.peer.DragSourceContextPeer;
047import java.io.Serializable;
048import java.util.TooManyListenersException;
049
050/**
051 * @since 1.2
052 */
053public class DragSourceContext
054  implements DragSourceListener, DragSourceMotionListener, Serializable
055{
056  /**
057   * Compatible with JDK 1.2+
058   */
059  static final long serialVersionUID = -115407898692194719L;
060
061  protected static final int DEFAULT = 0;
062  protected static final int ENTER = 1;
063  protected static final int OVER = 2;
064  protected static final int CHANGED = 3;
065
066  private DragSourceContextPeer peer;
067  private Cursor cursor;
068  private Transferable transferable;
069  private DragGestureEvent trigger;
070  private DragSourceListener dragSourceListener;
071  private boolean useCustomCursor;
072  private int sourceActions;
073  private Image image;
074  private Point offset;
075  
076  /**
077   * Initializes a drag source context.
078   *
079   * @exception IllegalArgumentException If Component or DragSource of trigger
080   * are null, the drag action for the trigger event is DnDConstants.ACTION_NONE
081   * or if the source actions for the DragGestureRecognizer associated with the
082   * trigger event are equal to DnDConstants.ACTION_NONE.
083   * @exception NullPointerException If peer, trans or trigger is null or if the
084   * image is not null but the offset is. 
085   */
086  public DragSourceContext (DragSourceContextPeer peer,
087                            DragGestureEvent trigger, Cursor cursor,
088                            Image image, Point offset, Transferable trans,
089                            DragSourceListener dsl)
090  {    
091    if (peer == null
092        || trigger == null || trans == null
093        || (image != null && offset == null))
094      throw new NullPointerException ();
095
096    if (trigger.getComponent () == null
097        || trigger.getDragSource () == null
098        || trigger.getDragAction () == DnDConstants.ACTION_NONE
099        || trigger.getSourceAsDragGestureRecognizer ()
100              .getSourceActions () == DnDConstants.ACTION_NONE)
101      throw new IllegalArgumentException ();
102
103    this.peer = peer;
104    this.trigger = trigger;
105    this.cursor = cursor;
106    this.image = image;
107    this.offset = offset;
108    this.transferable = trans;
109    this.dragSourceListener = dsl;
110    this.sourceActions = trigger.getSourceAsDragGestureRecognizer().getSourceActions();
111    
112    setCursor(cursor);
113    updateCurrentCursor(trigger.getDragAction(), sourceActions, DEFAULT);
114  }
115
116  /**
117   * Returns the DragSource object associated with the
118   * DragGestureEvent.
119   * 
120   * @return the DragSource associated with the trigger.
121   */
122  public DragSource getDragSource()
123  {
124    return trigger.getDragSource ();
125  }
126
127  /**
128   * Returns the component associated with this.
129   * 
130   * @return the component associated with the trigger.
131   */
132  public Component getComponent()
133  {
134    return trigger.getComponent ();
135  }
136
137  /**
138   * Gets the trigger associated with this.
139   * 
140   * @return the trigger.
141   */
142  public DragGestureEvent getTrigger()
143  {
144    return trigger;
145  }
146
147  /**
148   * Returns the source actions for the DragGestureRecognizer.
149   * 
150   * @return the source actions for DragGestureRecognizer.
151   */
152  public int getSourceActions()
153  {
154    if (sourceActions == 0)
155      sourceActions = trigger.getSourceAsDragGestureRecognizer().getSourceActions();
156    return sourceActions;
157  }
158
159  /**
160   * Sets the cursor for this drag operation to the specified cursor.
161   * 
162   * @param cursor c - the Cursor to use, or null to use the default drag
163   *          cursor.
164   */
165  public void setCursor(Cursor cursor)
166  {
167    if (cursor == null)
168      useCustomCursor = false;
169    else
170      useCustomCursor = true;
171    this.cursor = cursor;
172    peer.setCursor(cursor);
173  }
174
175  /**
176   * Returns the current cursor or null if the default
177   * drag cursor is used.
178   * 
179   * @return the current cursor or null.
180   */
181  public Cursor getCursor()
182  {
183    return cursor;
184  }
185
186  /**
187   * Adds a <code>DragSourceListener</code>.
188   *
189   * @exception TooManyListenersException If a <code>DragSourceListener</code>
190   * has already been added.
191   */
192  public void addDragSourceListener (DragSourceListener dsl)
193    throws TooManyListenersException
194  {
195    if (dragSourceListener != null)
196      throw new TooManyListenersException ();
197
198    dragSourceListener = dsl;
199  }
200
201  public void removeDragSourceListener (DragSourceListener dsl)
202  {
203    if (dragSourceListener == dsl)
204      dragSourceListener = null;
205  }
206
207  /**
208   * This function tells the peer that the DataFlavors have been modified.
209   */
210  public void transferablesFlavorsChanged()
211  {
212    peer.transferablesFlavorsChanged();
213  }
214
215  /**
216   * Calls dragEnter on the listeners registered with this
217   * and with the DragSource.
218   * 
219   * @param e - the DragSourceDragEvent
220   */
221  public void dragEnter(DragSourceDragEvent e)
222  {
223    if (dragSourceListener != null)
224      dragSourceListener.dragEnter(e);
225    
226    DragSource ds = getDragSource();
227    DragSourceListener[] dsl = ds.getDragSourceListeners();
228    for (int i = 0; i < dsl.length; i++)
229      dsl[i].dragEnter(e);
230    
231    updateCurrentCursor(e.getDropAction(), e.getTargetActions(), ENTER);
232  }
233
234  /**
235   * Calls dragOver on the listeners registered with this
236   * and with the DragSource.
237   * 
238   * @param e - the DragSourceDragEvent
239   */
240  public void dragOver(DragSourceDragEvent e)
241  {
242    if (dragSourceListener != null)
243      dragSourceListener.dragOver(e);
244    
245    DragSource ds = getDragSource();
246    DragSourceListener[] dsl = ds.getDragSourceListeners();
247    for (int i = 0; i < dsl.length; i++)
248      dsl[i].dragOver(e);
249    
250    updateCurrentCursor(e.getDropAction(), e.getTargetActions(), OVER);
251  }
252  
253  /**
254   * Calls dragExit on the listeners registered with this
255   * and with the DragSource.
256   * 
257   * @param e - the DragSourceEvent
258   */
259  public void dragExit(DragSourceEvent e)
260  {
261    if (dragSourceListener != null)
262      dragSourceListener.dragExit(e);
263    
264    DragSource ds = getDragSource();
265    DragSourceListener[] dsl = ds.getDragSourceListeners();
266    for (int i = 0; i < dsl.length; i++)
267      dsl[i].dragExit(e);
268    
269    updateCurrentCursor(DnDConstants.ACTION_NONE, DnDConstants.ACTION_NONE,
270                        DEFAULT);
271  }
272
273  /**
274   * Calls dropActionChanged on the listeners registered with this
275   * and with the DragSource.
276   * 
277   * @param e - the DragSourceDragEvent
278   */
279  public void dropActionChanged(DragSourceDragEvent e)
280  {
281    if (dragSourceListener != null)
282      dragSourceListener.dropActionChanged(e);
283    
284    DragSource ds = getDragSource();
285    DragSourceListener[] dsl = ds.getDragSourceListeners();
286    for (int i = 0; i < dsl.length; i++)
287      dsl[i].dropActionChanged(e);
288    
289    updateCurrentCursor(e.getDropAction(), e.getTargetActions(), CHANGED);
290  }
291
292  /**
293   * Calls dragDropEnd on the listeners registered with this
294   * and with the DragSource.
295   * 
296   * @param e - the DragSourceDropEvent
297   */
298  public void dragDropEnd(DragSourceDropEvent e)
299  {
300    if (dragSourceListener != null)
301      dragSourceListener.dragDropEnd(e);
302    
303    DragSource ds = getDragSource();
304    DragSourceListener[] dsl = ds.getDragSourceListeners();
305    for (int i = 0; i < dsl.length; i++)
306      dsl[i].dragDropEnd(e);
307  }
308
309  /**
310   * Calls dragMouseMoved on the listeners registered with the DragSource.
311   * 
312   * @param e - the DragSourceDragEvent
313   */
314  public void dragMouseMoved(DragSourceDragEvent e)
315  {
316    DragSource ds = getDragSource();
317    DragSourceMotionListener[] dsml = ds.getDragSourceMotionListeners();
318    for (int i = 0; i < dsml.length; i++)
319      dsml[i].dragMouseMoved(e);
320  }
321
322  /**
323   * Returns the Transferable set with this object.
324   * 
325   * @return the transferable.
326   */
327  public Transferable getTransferable()
328  {
329    return transferable;
330  }
331
332  /**
333   * This function sets the drag cursor for the specified operation, actions and
334   * status if the default drag cursor is active. Otherwise, the cursor is not
335   * updated in any way.
336   * 
337   * @param dropOp - the current operation.
338   * @param targetAct - the supported actions.
339   * @param status - the status of the cursor (constant).
340   */
341  protected void updateCurrentCursor(int dropOp, int targetAct, int status)
342  {
343    if (! useCustomCursor)
344      {
345        Cursor newCursor = null;
346        switch (status)
347          {
348          default:
349            targetAct = DnDConstants.ACTION_NONE;
350          case ENTER:
351          case CHANGED:
352          case OVER:
353            int action = dropOp & targetAct;
354            if (action == DnDConstants.ACTION_NONE)
355              {
356                if ((dropOp & DnDConstants.ACTION_LINK) != 0)
357                  newCursor = DragSource.DefaultLinkNoDrop;
358                else if ((dropOp & DnDConstants.ACTION_MOVE) != 0)
359                  newCursor = DragSource.DefaultMoveNoDrop;
360                else
361                  newCursor = DragSource.DefaultCopyNoDrop;
362              }
363            else
364              {
365                if ((dropOp & DnDConstants.ACTION_LINK) != 0)
366                  newCursor = DragSource.DefaultLinkDrop;
367                else if ((dropOp & DnDConstants.ACTION_MOVE) != 0)
368                  newCursor = DragSource.DefaultMoveDrop;
369                else
370                  newCursor = DragSource.DefaultCopyDrop;
371              }
372          }
373        
374        if (cursor == null || ! cursor.equals(newCursor))
375          {
376            cursor = newCursor;
377            DragSourceContextPeer p = peer;
378            if (p != null)
379              p.setCursor(cursor);
380          }
381      }
382  }
383} // class DragSourceContext