001: /*
002: * @(#)${NAME}.java
003: *
004: * Copyright 2002 - 2005 JIDE Software Inc. All rights reserved.
005: */
006: package com.jidesoft.swing;
007:
008: import com.jidesoft.plaf.UIDefaultsLookup;
009:
010: import javax.swing.*;
011: import javax.swing.event.MouseInputListener;
012: import java.awt.*;
013:
014: /**
015: * Resizable is a class that support resizable feature.
016: * <p/>
017: * To use it and make a component resizable, you just need to
018: * create new Resizable() and pass in that component to the constructor.
019: */
020: public class Resizable {
021:
022: public final static int NONE = 0x0;
023: public final static int UPPER_LEFT = 0x1;
024: public final static int UPPER = 0x2;
025: public final static int UPPER_RIGHT = 0x4;
026: public final static int RIGHT = 0x8;
027: public final static int LOWER_RIGHT = 0x10;
028: public final static int LOWER = 0x20;
029: public final static int LOWER_LEFT = 0x40;
030: public final static int LEFT = 0x80;
031: public final static int ALL = 0xFF;
032:
033: private int _resizableCorners = 0xFF;
034:
035: private int _resizeCornerSize = 16;
036:
037: public static final String PROPERTY_RESIZABLE_CORNERS = "resizableCorner";
038: public static final String PROPERTY_RESIZE_CORNER_SIZE = "resizeCornerSize";
039:
040: protected final JComponent _component;
041: private MouseInputListener _mouseInputAdapter;
042:
043: private boolean _topLevel;
044:
045: /**
046: * Creates a new <code>Resizable</code>. This call will make the component to be resizable.
047: */
048: public Resizable(JComponent component) {
049: _component = component;
050: installListeners();
051: }
052:
053: /**
054: * Gets the resizable corners. The value is a bitwise OR of eight constants defined in {@link Resizable}.
055: *
056: * @return resizable corners.
057: */
058: public int getResizableCorners() {
059: return _resizableCorners;
060: }
061:
062: /**
063: * Sets resizable corners.
064: *
065: * @param resizableCorners new resizable corners. The value is a bitwise OR of eight constants defined in {@link Resizable}.
066: */
067: public void setResizableCorners(int resizableCorners) {
068: if (_resizableCorners != resizableCorners) {
069: int old = _resizableCorners;
070: _resizableCorners = resizableCorners;
071: _component.firePropertyChange(PROPERTY_RESIZABLE_CORNERS,
072: old, _resizableCorners);
073: }
074: }
075:
076: /**
077: * Gets resize corner size. This size is the corner's sensitive area which will trigger the resizing from both sides.
078: *
079: * @return the resize corner size.
080: */
081: public int getResizeCornerSize() {
082: return _resizeCornerSize;
083: }
084:
085: /**
086: * Sets the resize corner size.
087: *
088: * @param resizeCornerSize the resize corner size.
089: */
090: public void setResizeCornerSize(int resizeCornerSize) {
091: if (_resizeCornerSize != resizeCornerSize) {
092: int old = _resizeCornerSize;
093: _resizeCornerSize = resizeCornerSize;
094: _component.firePropertyChange(PROPERTY_RESIZE_CORNER_SIZE,
095: old, _resizeCornerSize);
096: }
097: }
098:
099: /**
100: * Installs the listeners needed to perform resizing operations.
101: * You do not need to call this method directly. Construstor
102: * will call this method automatically.
103: */
104: protected void installListeners() {
105: _mouseInputAdapter = createMouseInputListener();
106: _component.addMouseListener(_mouseInputAdapter);
107: _component.addMouseMotionListener(_mouseInputAdapter);
108: }
109:
110: /**
111: * Uninstalls the listeners that created to perform resizing operations.
112: * After uninstallation, the component will not be resizable anymore.
113: */
114: public void uninstallListeners() {
115: _component.removeMouseListener(_mouseInputAdapter);
116: _component.removeMouseMotionListener(_mouseInputAdapter);
117: _mouseInputAdapter = null;
118: }
119:
120: /**
121: * Creates the MouseInputListener for resizing. Subclass can override
122: * this method to provide its own MouseInputListener to customize exsiting one.
123: *
124: * @return the MouseInputListener for resizing.
125: */
126: protected MouseInputListener createMouseInputListener() {
127: return new ResizableMouseInputAdapter(this );
128: }
129:
130: /**
131: * Gets the mouse adapter for resizing.
132: *
133: * @return the mouse adapter for resizing.
134: */
135: public MouseInputListener getMouseInputAdapter() {
136: return _mouseInputAdapter;
137: }
138:
139: /**
140: * This method is called when resizing opertion started.
141: *
142: * @param resizeCorner the resize corner.
143: */
144: public void beginResizing(int resizeCorner) {
145: }
146:
147: /**
148: * This method is called during the resizing of ResizablePanel. In default implementation, it call
149: * <code><pre>
150: * setPreferredSize(new Dimension(newW, newH));
151: * getParent().doLayout();
152: * </pre></code>
153: * in fact, depending on where you added this ResizablePanel, you may need to override this method
154: * to do something else. For example, {@link ResizableWindow} uses <code>ResizablePanel</code> to
155: * implement resizable feature in JWindow. It overrides this method to call setBounds on JWindow itself.
156: *
157: * @param resizeCorner the resize corner.
158: * @param newX the new x position.
159: * @param newY the new y position.
160: * @param newW the new width.
161: * @param newH the new height.
162: */
163: public void resizing(int resizeCorner, int newX, int newY,
164: int newW, int newH) {
165: Dimension minimumSize = _component.getMinimumSize();
166: Dimension maximumSize = _component.getMaximumSize();
167: if (newW < minimumSize.width) {
168: newW = minimumSize.width;
169: }
170: if (newH < minimumSize.height) {
171: newW = minimumSize.height;
172: }
173: if (newW > maximumSize.width) {
174: newW = maximumSize.width;
175: }
176: if (newH > maximumSize.height) {
177: newH = maximumSize.height;
178: }
179: _component.setPreferredSize(new Dimension(newW, newH));
180: _component.getParent().doLayout();
181: }
182:
183: /**
184: * The method is called when resizing ends.
185: *
186: * @param resizeCorner the resize corner.
187: */
188: public void endResizing(int resizeCorner) {
189: }
190:
191: /**
192: * Checks if the Resizable is added to a top level component.
193: * <p> If it's top level component, it will use screen coordinates
194: * to do all calculations during resizing. If resizing the resizable panel won't affect
195: * any top level container's position, you can return false here.
196: * Otherwise, return true. The default implementation always return false.
197: * Subclasses can override to return different value. In the case of
198: * ResizableWindow or ResizableDialog, this method is overridden and returns true.
199: *
200: * @return false.
201: */
202: public boolean isTopLevel() {
203: return _topLevel;
204: }
205:
206: /**
207: * To indicates this <code>Resizable</code> is installed on a top level component
208: * such as JWindow, JDialog and JFrame v.s. a JPanel which is not a top level component
209: * because a JPanel must be added to another top level component in order to be displayed.
210: *
211: * @param topLevel true or false.
212: */
213: public void setTopLevel(boolean topLevel) {
214: _topLevel = topLevel;
215: }
216:
217: /**
218: * Gets the component which has this Resizable object.
219: *
220: * @return the component which has this Resizable object.
221: */
222: public JComponent getComponent() {
223: return _component;
224: }
225:
226: public static class ResizeCorner extends JComponent {
227: final static int SIZE = 16;
228: private int _corner = LOWER_RIGHT;
229:
230: public ResizeCorner() {
231: }
232:
233: public ResizeCorner(int corner) {
234: _corner = corner;
235: }
236:
237: public int getCorner() {
238: return _corner;
239: }
240:
241: public void setCorner(int corner) {
242: _corner = corner;
243: }
244:
245: @Override
246: public Dimension getPreferredSize() {
247: return new Dimension(SIZE, SIZE);
248: }
249:
250: @Override
251: protected void paintComponent(Graphics g) {
252: super .paintComponent(g);
253: int size = Math.min(getWidth(), getHeight());
254: int count = Math.min(size / 4, 4);
255: Color old = g.getColor();
256: switch (getCorner()) {
257: case LOWER_RIGHT: {
258: g.setColor(UIDefaultsLookup
259: .getColor("controlLtHighlight"));
260: int delta = 0;
261: int x = getWidth() - 1;
262: int y = getHeight() - 1;
263: for (int i = 0; i < count; i++) {
264: delta += 4;
265: g.drawLine(x, y - delta, x - delta, y);
266: }
267: g.setColor(UIDefaultsLookup.getColor("controlShadow"));
268: delta = 0;
269: for (int i = 0; i < count; i++) {
270: delta += 4;
271: g.drawLine(x, y - delta + 1, x - delta + 1, y);
272: g.drawLine(x, y - delta + 2, x - delta + 2, y);
273: }
274: }
275: break;
276: case UPPER_RIGHT: {
277: g.setColor(UIDefaultsLookup
278: .getColor("controlLtHighlight"));
279: int delta = 0;
280: int x = getWidth() - 1;
281: int y = getHeight() - 1;
282: for (int i = 0; i < count; i++) {
283: delta += 4;
284: g.drawLine(x - delta, 0, x, delta);
285: }
286: g.setColor(UIDefaultsLookup.getColor("controlShadow"));
287: delta = 0;
288: for (int i = 0; i < count; i++) {
289: delta += 4;
290: g.drawLine(x - delta + 1, 0, x, delta - 1);
291: g.drawLine(x - delta + 2, 0, x, delta - 2);
292: }
293: }
294: break;
295:
296: }
297: g.setColor(old);
298: }
299: }
300: }
|