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