Skip to content

Commit b89dc8a

Browse files
authored
Add files via upload
1 parent 26e8096 commit b89dc8a

File tree

1 file changed

+373
-0
lines changed

1 file changed

+373
-0
lines changed

source/ComponentMover.java

Lines changed: 373 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,373 @@
1+
import java.awt.*;
2+
import java.awt.event.*;
3+
import javax.swing.JComponent;
4+
import javax.swing.SwingUtilities;
5+
6+
/**
7+
* This class allows you to move a Component by using a mouse. The Component
8+
* moved can be a high level Window (ie. Window, Frame, Dialog) in which case
9+
* the Window is moved within the desktop. Or the Component can belong to a
10+
* Container in which case the Component is moved within the Container.
11+
*
12+
* When moving a Window, the listener can be added to a child Component of
13+
* the Window. In this case attempting to move the child will result in the
14+
* Window moving. For example, you might create a custom "Title Bar" for an
15+
* undecorated Window and moving of the Window is accomplished by moving the
16+
* title bar only. Multiple components can be registered as "window movers".
17+
*
18+
* Components can be registered when the class is created. Additional
19+
* components can be added at any time using the registerComponent() method.
20+
*/
21+
public class ComponentMover extends MouseAdapter
22+
{
23+
private Insets dragInsets = new Insets(0, 0, 0, 0);
24+
private Dimension snapSize = new Dimension(1, 1);
25+
private Insets edgeInsets = new Insets(0, 0, 0, 0);
26+
private boolean changeCursor = true;
27+
private boolean autoLayout = false;
28+
29+
private Class destinationClass;
30+
private Component destinationComponent;
31+
private Component destination;
32+
private Component source;
33+
34+
private Point pressed;
35+
private Point location;
36+
37+
private Cursor originalCursor;
38+
private boolean autoscrolls;
39+
private boolean potentialDrag;
40+
41+
42+
/**
43+
* Constructor for moving individual components. The components must be
44+
* regisetered using the registerComponent() method.
45+
*/
46+
public ComponentMover()
47+
{
48+
}
49+
50+
/**
51+
* Constructor to specify a Class of Component that will be moved when
52+
* drag events are generated on a registered child component. The events
53+
* will be passed to the first ancestor of this specified class.
54+
*
55+
* @param destinationClass the Class of the ancestor component
56+
* @param component the Components to be registered for forwarding
57+
* drag events to the ancestor Component.
58+
*/
59+
public ComponentMover(Class destinationClass, Component... components)
60+
{
61+
this.destinationClass = destinationClass;
62+
registerComponent( components );
63+
}
64+
65+
/**
66+
* Constructor to specify a parent component that will be moved when drag
67+
* events are generated on a registered child component.
68+
*
69+
* @param destinationComponent the component drage events should be forwareded to
70+
* @param components the Components to be registered for forwarding drag
71+
* events to the parent component to be moved
72+
*/
73+
public ComponentMover(Component destinationComponent, Component... components)
74+
{
75+
this.destinationComponent = destinationComponent;
76+
registerComponent( components );
77+
}
78+
79+
/**
80+
* Get the auto layout property
81+
*
82+
* @return the auto layout property
83+
*/
84+
public boolean isAutoLayout()
85+
{
86+
return autoLayout;
87+
}
88+
89+
/**
90+
* Set the auto layout property
91+
*
92+
* @param autoLayout when true layout will be invoked on the parent container
93+
*/
94+
public void setAutoLayout(boolean autoLayout)
95+
{
96+
this.autoLayout = autoLayout;
97+
}
98+
99+
/**
100+
* Get the change cursor property
101+
*
102+
* @return the change cursor property
103+
*/
104+
public boolean isChangeCursor()
105+
{
106+
return changeCursor;
107+
}
108+
109+
/**
110+
* Set the change cursor property
111+
*
112+
* @param changeCursor when true the cursor will be changed to the
113+
* Cursor.MOVE_CURSOR while the mouse is pressed
114+
*/
115+
public void setChangeCursor(boolean changeCursor)
116+
{
117+
this.changeCursor = changeCursor;
118+
}
119+
120+
/**
121+
* Get the drag insets
122+
*
123+
* @return the drag insets
124+
*/
125+
public Insets getDragInsets()
126+
{
127+
return dragInsets;
128+
}
129+
130+
/**
131+
* Set the drag insets. The insets specify an area where mouseDragged
132+
* events should be ignored and therefore the component will not be moved.
133+
* This will prevent these events from being confused with a
134+
* MouseMotionListener that supports component resizing.
135+
*
136+
* @param dragInsets
137+
*/
138+
public void setDragInsets(Insets dragInsets)
139+
{
140+
this.dragInsets = dragInsets;
141+
}
142+
143+
/**
144+
* Get the bounds insets
145+
*
146+
* @return the bounds insets
147+
*/
148+
public Insets getEdgeInsets()
149+
{
150+
return edgeInsets;
151+
}
152+
153+
/**
154+
* Set the edge insets. The insets specify how close to each edge of the parent
155+
* component that the child component can be moved. Positive values means the
156+
* component must be contained within the parent. Negative values means the
157+
* component can be moved outside the parent.
158+
*
159+
* @param edgeInsets
160+
*/
161+
public void setEdgeInsets(Insets edgeInsets)
162+
{
163+
this.edgeInsets = edgeInsets;
164+
}
165+
166+
/**
167+
* Remove listeners from the specified component
168+
*
169+
* @param component the component the listeners are removed from
170+
*/
171+
public void deregisterComponent(Component... components)
172+
{
173+
for (Component component : components)
174+
component.removeMouseListener( this );
175+
}
176+
177+
/**
178+
* Add the required listeners to the specified component
179+
*
180+
* @param component the component the listeners are added to
181+
*/
182+
public void registerComponent(Component... components)
183+
{
184+
for (Component component : components)
185+
component.addMouseListener( this );
186+
}
187+
188+
/**
189+
* Get the snap size
190+
*
191+
* @return the snap size
192+
*/
193+
public Dimension getSnapSize()
194+
{
195+
return snapSize;
196+
}
197+
198+
/**
199+
* Set the snap size. Forces the component to be snapped to
200+
* the closest grid position. Snapping will occur when the mouse is
201+
* dragged half way.
202+
*/
203+
public void setSnapSize(Dimension snapSize)
204+
{
205+
if (snapSize.width < 1
206+
|| snapSize.height < 1)
207+
throw new IllegalArgumentException("Snap sizes must be greater than 0");
208+
209+
this.snapSize = snapSize;
210+
}
211+
212+
/**
213+
* Setup the variables used to control the moving of the component:
214+
*
215+
* source - the source component of the mouse event
216+
* destination - the component that will ultimately be moved
217+
* pressed - the Point where the mouse was pressed in the destination
218+
* component coordinates.
219+
*/
220+
@Override
221+
public void mousePressed(MouseEvent e)
222+
{
223+
source = e.getComponent();
224+
int width = source.getSize().width - dragInsets.left - dragInsets.right;
225+
int height = source.getSize().height - dragInsets.top - dragInsets.bottom;
226+
Rectangle r = new Rectangle(dragInsets.left, dragInsets.top, width, height);
227+
228+
if (r.contains(e.getPoint()))
229+
setupForDragging(e);
230+
}
231+
232+
private void setupForDragging(MouseEvent e)
233+
{
234+
source.addMouseMotionListener( this );
235+
potentialDrag = true;
236+
237+
// Determine the component that will ultimately be moved
238+
239+
if (destinationComponent != null)
240+
{
241+
destination = destinationComponent;
242+
}
243+
else if (destinationClass == null)
244+
{
245+
destination = source;
246+
}
247+
else // forward events to destination component
248+
{
249+
destination = SwingUtilities.getAncestorOfClass(destinationClass, source);
250+
}
251+
252+
pressed = e.getLocationOnScreen();
253+
location = destination.getLocation();
254+
255+
if (changeCursor)
256+
{
257+
originalCursor = source.getCursor();
258+
source.setCursor( Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR) );
259+
}
260+
261+
// Making sure autoscrolls is false will allow for smoother dragging of
262+
// individual components
263+
264+
if (destination instanceof JComponent)
265+
{
266+
JComponent jc = (JComponent)destination;
267+
autoscrolls = jc.getAutoscrolls();
268+
jc.setAutoscrolls( false );
269+
}
270+
}
271+
272+
/**
273+
* Move the component to its new location. The dragged Point must be in
274+
* the destination coordinates.
275+
*/
276+
@Override
277+
public void mouseDragged(MouseEvent e)
278+
{
279+
Point dragged = e.getLocationOnScreen();
280+
int dragX = getDragDistance(dragged.x, pressed.x, snapSize.width);
281+
int dragY = getDragDistance(dragged.y, pressed.y, snapSize.height);
282+
283+
int locationX = location.x + dragX;
284+
int locationY = location.y + dragY;
285+
286+
// Mouse dragged events are not generated for every pixel the mouse
287+
// is moved. Adjust the location to make sure we are still on a
288+
// snap value.
289+
290+
while (locationX < edgeInsets.left)
291+
locationX += snapSize.width;
292+
293+
while (locationY < edgeInsets.top)
294+
locationY += snapSize.height;
295+
296+
Dimension d = getBoundingSize( destination );
297+
298+
while (locationX + destination.getSize().width + edgeInsets.right > d.width)
299+
locationX -= snapSize.width;
300+
301+
while (locationY + destination.getSize().height + edgeInsets.bottom > d.height)
302+
locationY -= snapSize.height;
303+
304+
// Adjustments are finished, move the component
305+
306+
destination.setLocation(locationX, locationY);
307+
}
308+
309+
/*
310+
* Determine how far the mouse has moved from where dragging started
311+
* (Assume drag direction is down and right for positive drag distance)
312+
*/
313+
private int getDragDistance(int larger, int smaller, int snapSize)
314+
{
315+
int halfway = snapSize / 2;
316+
int drag = larger - smaller;
317+
drag += (drag < 0) ? -halfway : halfway;
318+
drag = (drag / snapSize) * snapSize;
319+
320+
return drag;
321+
}
322+
323+
/*
324+
* Get the bounds of the parent of the dragged component.
325+
*/
326+
private Dimension getBoundingSize(Component source)
327+
{
328+
if (source instanceof Window)
329+
{
330+
GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
331+
Rectangle bounds = env.getMaximumWindowBounds();
332+
return new Dimension(bounds.width, bounds.height);
333+
}
334+
else
335+
{
336+
return source.getParent().getSize();
337+
}
338+
}
339+
340+
/**
341+
* Restore the original state of the Component
342+
*/
343+
@Override
344+
public void mouseReleased(MouseEvent e)
345+
{
346+
if (!potentialDrag) return;
347+
348+
source.removeMouseMotionListener( this );
349+
potentialDrag = false;
350+
351+
if (changeCursor)
352+
source.setCursor( originalCursor );
353+
354+
if (destination instanceof JComponent)
355+
{
356+
((JComponent)destination).setAutoscrolls( autoscrolls );
357+
}
358+
359+
// Layout the components on the parent container
360+
361+
if (autoLayout)
362+
{
363+
if (destination instanceof JComponent)
364+
{
365+
((JComponent)destination).revalidate();
366+
}
367+
else
368+
{
369+
destination.validate();
370+
}
371+
}
372+
}
373+
}

0 commit comments

Comments
 (0)