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