1
2
3
4
5
6
7
8
9
10
11
12 package com.eviware.soapui.support.dnd;
13
14 import java.awt.AlphaComposite;
15 import java.awt.Color;
16 import java.awt.Component;
17 import java.awt.GradientPaint;
18 import java.awt.Graphics2D;
19 import java.awt.Point;
20 import java.awt.Rectangle;
21 import java.awt.SystemColor;
22 import java.awt.datatransfer.DataFlavor;
23 import java.awt.datatransfer.Transferable;
24 import java.awt.dnd.DnDConstants;
25 import java.awt.dnd.DragGestureEvent;
26 import java.awt.dnd.DragGestureListener;
27 import java.awt.dnd.DragSource;
28 import java.awt.dnd.DragSourceDragEvent;
29 import java.awt.dnd.DragSourceDropEvent;
30 import java.awt.dnd.DragSourceEvent;
31 import java.awt.dnd.DragSourceListener;
32 import java.awt.dnd.DropTarget;
33 import java.awt.dnd.DropTargetDragEvent;
34 import java.awt.dnd.DropTargetDropEvent;
35 import java.awt.dnd.DropTargetEvent;
36 import java.awt.dnd.DropTargetListener;
37 import java.awt.event.ActionEvent;
38 import java.awt.event.ActionListener;
39 import java.awt.event.MouseEvent;
40 import java.awt.geom.AffineTransform;
41 import java.awt.geom.Rectangle2D;
42 import java.awt.image.BufferedImage;
43 import java.util.ArrayList;
44 import java.util.List;
45
46 import javax.swing.Timer;
47 import javax.swing.ToolTipManager;
48
49 import com.eviware.soapui.SoapUI;
50 import com.eviware.soapui.model.ModelItem;
51 import com.eviware.soapui.support.dnd.handlers.InterfaceToProjectDropHandler;
52 import com.eviware.soapui.support.dnd.handlers.MockServiceToProjectDropHandler;
53 import com.eviware.soapui.support.dnd.handlers.OperationToMockServiceDropHandler;
54 import com.eviware.soapui.support.dnd.handlers.RequestToMockOperationDropHandler;
55 import com.eviware.soapui.support.dnd.handlers.RequestToTestCaseDropHandler;
56 import com.eviware.soapui.support.dnd.handlers.RequestToTestStepDropHandler;
57 import com.eviware.soapui.support.dnd.handlers.RequestToTestStepsDropHandler;
58 import com.eviware.soapui.support.dnd.handlers.TestCaseToProjectDropHandler;
59 import com.eviware.soapui.support.dnd.handlers.TestCaseToTestCaseDropHandler;
60 import com.eviware.soapui.support.dnd.handlers.TestCaseToTestSuiteDropHandler;
61 import com.eviware.soapui.support.dnd.handlers.TestStepToTestCaseDropHandler;
62 import com.eviware.soapui.support.dnd.handlers.TestStepToTestStepDropHandler;
63 import com.eviware.soapui.support.dnd.handlers.TestStepToTestStepsDropHandler;
64 import com.eviware.soapui.support.dnd.handlers.TestSuiteToProjectDropHandler;
65
66 public class SoapUIDragAndDropHandler implements DragGestureListener, DragSourceListener
67 {
68 public static final int ON_RANGE = 3;
69 private final SoapUIDragAndDropable<ModelItem> dragAndDropable;
70 private BufferedImage _imgGhost;
71 private Point _ptOffset = new Point();
72 private static List<ModelItemDropHandler<ModelItem>> handlers;
73 private Rectangle2D _raGhost = new Rectangle2D.Float();
74 private final int dropType;
75 private Point _ptLast = new Point();
76
77 static
78 {
79 handlers = new ArrayList<ModelItemDropHandler<ModelItem>>();
80 SoapUIDragAndDropHandler.addDropHandler( new TestStepToTestCaseDropHandler() );
81 SoapUIDragAndDropHandler.addDropHandler( new TestStepToTestStepsDropHandler() );
82 SoapUIDragAndDropHandler.addDropHandler( new TestStepToTestStepDropHandler() );
83 SoapUIDragAndDropHandler.addDropHandler( new TestSuiteToProjectDropHandler() );
84 SoapUIDragAndDropHandler.addDropHandler( new InterfaceToProjectDropHandler() );
85 SoapUIDragAndDropHandler.addDropHandler( new TestCaseToProjectDropHandler() );
86 SoapUIDragAndDropHandler.addDropHandler( new TestCaseToTestSuiteDropHandler() );
87 SoapUIDragAndDropHandler.addDropHandler( new TestCaseToTestCaseDropHandler() );
88 SoapUIDragAndDropHandler.addDropHandler( new RequestToTestCaseDropHandler() );
89 SoapUIDragAndDropHandler.addDropHandler( new RequestToTestStepsDropHandler() );
90 SoapUIDragAndDropHandler.addDropHandler( new RequestToTestStepDropHandler() );
91 SoapUIDragAndDropHandler.addDropHandler( new RequestToMockOperationDropHandler() );
92 SoapUIDragAndDropHandler.addDropHandler( new MockServiceToProjectDropHandler() );
93 SoapUIDragAndDropHandler.addDropHandler( new OperationToMockServiceDropHandler() );
94 }
95
96 @SuppressWarnings("unchecked")
97 public SoapUIDragAndDropHandler( SoapUIDragAndDropable target, int dropType )
98 {
99 this.dragAndDropable = target;
100 this.dropType = dropType;
101
102
103 DropTarget dropTarget = new DropTarget( target.getComponent(), new SoapUIDropTargetListener() );
104 dropTarget.setDefaultActions( DnDConstants.ACTION_COPY_OR_MOVE );
105 }
106
107 @SuppressWarnings("unchecked")
108 public static void addDropHandler( ModelItemDropHandler dropHandler )
109 {
110 handlers.add( dropHandler );
111 }
112
113 public void dragGestureRecognized( DragGestureEvent e )
114 {
115 Point ptDragOrigin = e.getDragOrigin();
116 ModelItem modelItem = dragAndDropable.getModelItemForLocation( ptDragOrigin.x, ptDragOrigin.y );
117 if( modelItem == null )
118 return;
119
120 Rectangle raPath = dragAndDropable.getModelItemBounds( modelItem );
121 if( raPath == null )
122 return;
123
124 _ptOffset = new Point( ptDragOrigin.x - raPath.x, ptDragOrigin.y - raPath.y );
125
126 Component renderer = dragAndDropable.getRenderer( modelItem );
127 if( renderer != null )
128 {
129 renderer.setSize( ( int ) raPath.getWidth(), ( int ) raPath.getHeight() );
130
131
132 _imgGhost = new BufferedImage( ( int ) raPath.getWidth(), ( int ) raPath.getHeight(),
133 BufferedImage.TYPE_INT_ARGB_PRE );
134 Graphics2D g2 = _imgGhost.createGraphics();
135
136
137 g2.setComposite( AlphaComposite.getInstance( AlphaComposite.SRC, 0.5f ) );
138 renderer.paint( g2 );
139
140 g2.setComposite( AlphaComposite.getInstance( AlphaComposite.DST_OVER, 0.5f ) );
141
142 int width = dragAndDropable.getComponent().getWidth();
143 g2.setPaint( new GradientPaint( 0, 0, SystemColor.controlShadow, width, 0, new Color( 255, 255, 255, 0 ) ) );
144 g2.fillRect( 0, 0, width, _imgGhost.getHeight() );
145 g2.dispose();
146 }
147 else
148 {
149 _imgGhost = null;
150 }
151
152 dragAndDropable.selectModelItem( modelItem );
153
154
155 Transferable transferable = new ModelItemTransferable( modelItem );
156
157
158 e.startDrag( null, _imgGhost, new Point( 5, 5 ), transferable, this );
159 }
160
161 public void dragDropEnd( DragSourceDropEvent dsde )
162 {
163 if( _raGhost != null )
164 dragAndDropable.getComponent().repaint( _raGhost.getBounds() );
165
166 _ptOffset = null;
167 SoapUI.getNavigator().getMainTree().setToolTipText( null );
168 }
169
170 public void dragEnter( DragSourceDragEvent dsde )
171 {
172
173 }
174
175 public void dragExit( DragSourceEvent dse )
176 {
177
178 }
179
180 public void dragOver( DragSourceDragEvent dsde )
181 {
182 }
183
184 public void dropActionChanged( DragSourceDragEvent dsde )
185 {
186 }
187
188
189 class SoapUIDropTargetListener implements DropTargetListener
190 {
191
192 private ModelItem _pathLast = null;
193 private Rectangle2D _raCueLine = new Rectangle2D.Float();
194 private Color _colorCueLine;
195 private Timer _timerHover;
196
197 private String dropInfo;
198
199
200 public SoapUIDropTargetListener()
201 {
202 _colorCueLine = new Color( SystemColor.controlShadow.getRed(), SystemColor.controlShadow
203 .getGreen(), SystemColor.controlShadow.getBlue(), 128 );
204
205
206 _timerHover = new Timer( 1000, new ActionListener()
207 {
208 public void actionPerformed( ActionEvent e )
209 {
210 if( _ptOffset != null )
211 dragAndDropable.toggleExpansion( _pathLast );
212 }
213 } );
214 _timerHover.setRepeats( false );
215 }
216
217
218 public void dragEnter( DropTargetDragEvent e )
219 {
220 int dt = getDropTypeAtPoint( e.getLocation() );
221
222 if( dt == DropType.NONE || !isDragAcceptable( e, dt ) )
223 e.rejectDrag();
224 else
225 e.acceptDrag( e.getDropAction() );
226 }
227
228 private int getDropTypeAtPoint( Point pt )
229 {
230 ModelItem modelItem = dragAndDropable.getModelItemForLocation( pt.x, pt.y );
231 if( modelItem == null )
232 return DropType.NONE;
233
234 Rectangle raPath = dragAndDropable.getModelItemBounds( modelItem );
235
236 if( pt.y > (raPath.y + (raPath.getHeight()/2)+ON_RANGE) )
237 {
238 return DropType.AFTER;
239 }
240 else if( pt.y < (raPath.y + (raPath.getHeight()/2)-ON_RANGE) )
241 {
242 return DropType.BEFORE;
243 }
244 else
245 {
246 return DropType.ON;
247 }
248 }
249
250 public void dragExit( DropTargetEvent e )
251 {
252 if( !DragSource.isDragImageSupported() )
253 {
254 dragAndDropable.getComponent().repaint( _raGhost.getBounds() );
255 }
256 }
257
258 /***
259 * This is where the ghost image is drawn
260 */
261 public void dragOver( DropTargetDragEvent e )
262 {
263
264
265 Point pt = e.getLocation();
266 if( pt.equals( _ptLast ) )
267 return;
268
269 _ptLast = pt;
270
271 Graphics2D g2 = ( Graphics2D ) dragAndDropable.getComponent().getGraphics();
272
273
274
275 if( !DragSource.isDragImageSupported() && _imgGhost != null && _ptOffset != null )
276 {
277 dragAndDropable.getComponent().paintImmediately( _raGhost.getBounds() );
278
279
280
281 _raGhost.setRect( pt.x - _ptOffset.x, pt.y - _ptOffset.y, _imgGhost.getWidth(),
282 _imgGhost.getHeight() );
283 g2.drawImage( _imgGhost, AffineTransform.getTranslateInstance( _raGhost.getX(),
284 _raGhost.getY() ), null );
285 }
286 else
287
288 dragAndDropable.getComponent().paintImmediately( _raCueLine.getBounds() );
289
290 ModelItem modelItem = dragAndDropable.getModelItemForLocation( pt.x, pt.y );
291 if( modelItem == null )
292 {
293 e.rejectDrag();
294 return;
295 }
296
297 if( !( modelItem == _pathLast ) )
298 {
299
300 _pathLast = modelItem;
301 _timerHover.restart();
302 }
303
304
305
306 Rectangle raPath = dragAndDropable.getModelItemBounds( modelItem );
307
308 int dt = dropType;
309
310 if( dropType == DropType.AFTER )
311 {
312 _raCueLine.setRect( 0, raPath.y + ( int ) raPath.getHeight()-2, dragAndDropable.getComponent().getWidth(), 2 );
313 }
314 else if( dropType == DropType.BEFORE )
315 {
316 _raCueLine.setRect( 0, raPath.y, dragAndDropable.getComponent().getWidth(), 2 );
317 }
318 else if( dropType == DropType.ON )
319 {
320 _raCueLine.setRect( 0, raPath.y, dragAndDropable.getComponent().getWidth(), raPath.getHeight() );
321 }
322 else
323 {
324 if( pt.y > (raPath.y + (raPath.getHeight()/2)+ON_RANGE) )
325 {
326 _raCueLine.setRect( 0, raPath.y + ( int ) raPath.getHeight() -2, dragAndDropable.getComponent().getWidth(), 2 );
327 dt = DropType.AFTER;
328 }
329 else if( pt.y < (raPath.y + (raPath.getHeight()/2)-ON_RANGE) )
330 {
331 _raCueLine.setRect( 0, raPath.y, dragAndDropable.getComponent().getWidth(), 2 );
332 dt = DropType.BEFORE;
333 }
334 else
335 {
336 _raCueLine.setRect( 0, raPath.y, dragAndDropable.getComponent().getWidth(), raPath.getHeight() );
337 dt = DropType.ON;
338 }
339 }
340
341 boolean dragAcceptable = isDragAcceptable( e, dt );
342 g2.setColor(_colorCueLine );
343 g2.fill( _raCueLine );
344
345 if( dragAcceptable )
346 {
347 dragAndDropable.setDragInfo( dropInfo );
348 }
349 else
350 {
351 dragAndDropable.setDragInfo( "" );
352 }
353
354 ToolTipManager.sharedInstance().mouseMoved(
355 new MouseEvent(dragAndDropable.getComponent(), 0, 0, 0,
356 pt.x, pt.y+10,
357 0, false));
358
359
360 _raGhost = _raGhost.createUnion( _raCueLine );
361
362 if( !dragAcceptable )
363 e.rejectDrag();
364 else
365 e.acceptDrag( e.getDropAction() );
366 }
367
368 public void dropActionChanged( DropTargetDragEvent e )
369 {
370 int dt = getDropTypeAtPoint( e.getLocation() );
371
372 if( dt == DropType.NONE || !isDragAcceptable( e, dt ) )
373 e.rejectDrag();
374 else
375 e.acceptDrag( e.getDropAction() );
376 }
377
378 public void drop( DropTargetDropEvent e )
379 {
380 int dt = getDropTypeAtPoint( e.getLocation() );
381 _timerHover.stop();
382
383 if( dt == DropType.NONE || !isDropAcceptable( e, dt ) )
384 {
385 e.rejectDrop();
386 return;
387 }
388
389 e.acceptDrop( e.getDropAction() );
390
391 Transferable transferable = e.getTransferable();
392
393 DataFlavor[] flavors = transferable.getTransferDataFlavors();
394 for( int i = 0; i < flavors.length; i++ )
395 {
396 DataFlavor flavor = flavors[i];
397 if( flavor.isMimeTypeEqual( DataFlavor.javaJVMLocalObjectMimeType ) )
398 {
399 try
400 {
401 Point pt = e.getLocation();
402 ModelItem pathTarget = dragAndDropable.getModelItemForLocation( pt.x, pt.y );
403 ModelItem pathSource = ( ModelItem ) transferable.getTransferData( flavor );
404
405 for( ModelItemDropHandler<ModelItem> handler : handlers )
406 {
407 if( handler.canDrop( pathSource, pathTarget, e.getDropAction(), dt ) )
408 {
409
410
411
412 handler.drop( pathSource, pathTarget, e.getDropAction(), dt );
413 break;
414 }
415 }
416
417 break;
418 }
419 catch( Exception ioe )
420 {
421 System.out.println( ioe );
422 e.dropComplete( false );
423 return;
424 }
425 }
426 }
427
428 e.dropComplete( true );
429 }
430
431
432 public boolean isDragAcceptable( DropTargetDragEvent e, int dt )
433 {
434
435 if( ( e.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE ) == 0 )
436 {
437 return false;
438 }
439
440
441 if( !e.isDataFlavorSupported( ModelItemTransferable.MODELITEM_DATAFLAVOR ) )
442 {
443 return false;
444 }
445
446 Transferable transferable = e.getTransferable();
447
448 DataFlavor[] flavors = transferable.getTransferDataFlavors();
449 for( int i = 0; i < flavors.length; i++ )
450 {
451 DataFlavor flavor = flavors[i];
452 if( flavor.isMimeTypeEqual( DataFlavor.javaJVMLocalObjectMimeType ) )
453 {
454 try
455 {
456 Point pt = e.getLocation();
457 ModelItem pathTarget = dragAndDropable.getModelItemForLocation( pt.x, pt.y );
458 ModelItem pathSource = ( ModelItem ) transferable.getTransferData( flavor );
459
460 for( ModelItemDropHandler<ModelItem> handler : handlers )
461 {
462 if( handler.canDrop( pathSource, pathTarget, e.getDropAction(), dt ) )
463 {
464 dropInfo = handler.getDropInfo( pathSource, pathTarget, e.getDropAction(), dt );
465
466
467 return true;
468 }
469 }
470
471
472
473 dropInfo = null;
474 }
475 catch( Exception ex )
476 {
477 SoapUI.logError( ex );
478 }
479 }
480 }
481
482 return false;
483 }
484
485 public boolean isDropAcceptable( DropTargetDropEvent e, int dt )
486 {
487
488 if( ( e.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE ) == 0 )
489 return false;
490
491
492 if( !e.isDataFlavorSupported( ModelItemTransferable.MODELITEM_DATAFLAVOR ) )
493 {
494 return false;
495 }
496
497 Transferable transferable = e.getTransferable();
498
499 DataFlavor[] flavors = transferable.getTransferDataFlavors();
500 for( int i = 0; i < flavors.length; i++ )
501 {
502 DataFlavor flavor = flavors[i];
503 if( flavor.isMimeTypeEqual( DataFlavor.javaJVMLocalObjectMimeType ) )
504 {
505 try
506 {
507 Point pt = e.getLocation();
508 ModelItem pathSource = ( ModelItem ) transferable.getTransferData( flavor );
509 ModelItem pathTarget = dragAndDropable.getModelItemForLocation( pt.x, pt.y );
510
511 for( ModelItemDropHandler<ModelItem> handler : handlers )
512 {
513 if( handler.canDrop( pathSource, pathTarget, e.getDropAction(), dt ) )
514 return true;
515 }
516 }
517 catch( Exception ex )
518 {
519 SoapUI.logError( ex );
520 }
521 }
522 }
523
524 return false;
525 }
526 }
527 }