001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.visualweb.designer;
042:
043: import java.awt.Cursor;
044: import java.awt.Graphics;
045: import java.awt.Point;
046: import java.awt.Rectangle;
047: import java.awt.event.MouseEvent;
048:
049: import javax.swing.ImageIcon;
050:
051: import org.netbeans.modules.visualweb.css2.CssBox;
052:
053: /**
054: * Handle drawing (and "undrawing"!) a Marquee - a selection
055: * rectangle (aka "marching ants", aka animated rubber-banding line).
056: *
057: * @todo Provide shift key snap-release here too?
058: *
059: * @author Tor Norbye
060: */
061: public class Marquee extends Interaction {
062: private WebForm webform = null;
063:
064: /* Restore previous cursor after operation. */
065: protected transient Cursor previousCursor = null;
066:
067: /* The rectangle that defines the current marquee selection. */
068: protected Rectangle marqueeBounds; // TODO look up!
069:
070: /* The start start and current point of the marquee session. */
071: protected Point startPoint;
072: protected Point currentPoint;
073: protected Point unsnappedStartPoint;
074: private boolean snap = false;
075: private boolean select = true;
076: private boolean insertCursor = false;
077:
078: /** The box potentially containing the marquee selection. Grid snapping will
079: * be performed with respect to its coordinate system. */
080: private CssBox gridBox;
081:
082: public Marquee(WebForm webform, CssBox gridBox) {
083: this .webform = webform;
084: this .gridBox = gridBox;
085: }
086:
087: /** Cancel operation */
088: public void cancel(DesignerPane pane) {
089: cleanup(pane);
090: marqueeBounds = null;
091: }
092:
093: private void cleanup(DesignerPane pane) {
094: // Restore the cursor to normal
095: pane.setCursor(previousCursor);
096:
097: // Restore status line
098: // StatusDisplayer_RAVE.getRaveDefault().clearPositionLabel();
099:
100: // Clean out the selection rectangle
101: Rectangle dirty = new Rectangle(marqueeBounds);
102: dirty.width++;
103: dirty.height++;
104: pane.repaint(dirty);
105: }
106:
107: /** When the mouse press is released, get rid of the drawn marquee,
108: * and ask the selection manager to select all the components contained
109: * within the marquee bounds.
110: */
111: public void mouseReleased(MouseEvent e) {
112: try {
113: if ((e != null) && !e.isConsumed()
114: && (marqueeBounds != null)) {
115: // XXX shouldn't I get the final coordinates here, rather
116: // than relying on the previous ones from mouseDragged?
117: // TODO Should I pass in the event (e) so that the manager
118: // can say use the control keys and alt keys
119: if (select) {
120: // We should call selectViews even on size (0,0) since we need
121: // to cause an unselection in this case
122: if ((marqueeBounds.width != 0)
123: || (marqueeBounds.height != 0)) {
124: webform.getSelection()
125: .selectComponentRectangle(
126: marqueeBounds, true);
127: } else {
128: webform.getManager().getMouseHandler()
129: .selectAt(e, false);
130: }
131: }
132:
133: //}
134: cleanup(webform.getPane());
135:
136: e.consume();
137: }
138: } finally {
139: currentPoint = null;
140: startPoint = null;
141: marqueeBounds = null;
142: previousCursor = null;
143: }
144: }
145:
146: /**
147: * Resizes the selection rectangle to extend from startpoint to the
148: * new mouse cursor position.
149: */
150: public void mouseDragged(MouseEvent e) {
151: if (!e.isConsumed() && (startPoint != null)) {
152: currentPoint = e.getPoint();
153:
154: DesignerPane pane = webform.getPane();
155: Rectangle old = marqueeBounds;
156:
157: if (snap) {
158: // GridHandler gm = GridHandler.getInstance();
159: // GridHandler gm = webform.getGridHandler();
160: // GridHandler gm = GridHandler.getDefault();
161: // currentPoint.x = gm.snapX(currentPoint.x, gridBox);
162: // currentPoint.y = gm.snapY(currentPoint.y, gridBox);
163: currentPoint.x = webform.snapX(currentPoint.x, gridBox);
164: currentPoint.y = webform.snapY(currentPoint.y, gridBox);
165: }
166:
167: marqueeBounds = new Rectangle(startPoint);
168: marqueeBounds.add(currentPoint);
169:
170: Rectangle dirty;
171:
172: if (old != null) {
173: // compute "union" of the two rectangles so I can erase old "paint"
174: dirty = marqueeBounds.union(old);
175: } else {
176: dirty = new Rectangle(marqueeBounds);
177: }
178:
179: dirty.width++;
180: dirty.height++;
181: pane.repaint(dirty);
182:
183: e.consume();
184:
185: // Show position of component in the status line
186: int x = marqueeBounds.x;
187: int y = marqueeBounds.y;
188:
189: if (x < 0) {
190: x = 0;
191: }
192:
193: if (y < 0) {
194: y = 0;
195: }
196:
197: pane.scrollRectToVisible(new Rectangle(currentPoint));
198:
199: // StatusDisplayer_RAVE.getRaveDefault().setPositionLabelText(x + "," + y);
200: }
201: }
202:
203: public void paint(Graphics g) {
204: // Draw a dashed line instead of a solid line?
205: // float[] dash = {1.0f, 7.0f}; // make a 1-pixel dot every 8th pixel
206: // g.setStroke(new BasicStroke(1.0f, BasicStroke.CAP_SQUARE,
207: // BasicStroke.JOIN_MITER,
208: // 10.0f, dash, 0.0f));
209: if (marqueeBounds != null) {
210: ColorManager colors = webform.getColors();
211: g.setColor(colors.marqueeColor);
212: g.fillRect(marqueeBounds.x + 1, marqueeBounds.y + 1,
213: marqueeBounds.width - 1, marqueeBounds.height - 1);
214: g.setColor(colors.marqueeColorBorder);
215: g.drawRect(marqueeBounds.x, marqueeBounds.y,
216: marqueeBounds.width, marqueeBounds.height);
217: }
218: }
219:
220: /**
221: * Start the marquee at the specified startPoint.
222: */
223: public void mousePressed(MouseEvent e) {
224: if (!e.isConsumed()) {
225: startPoint = e.getPoint();
226:
227: DesignerPane pane = webform.getPane();
228:
229: if (snap) {
230: unsnappedStartPoint = new Point(startPoint.x,
231: startPoint.y);
232:
233: // GridHandler gm = GridHandler.getInstance();
234: // GridHandler gm = webform.getGridHandler();
235: // GridHandler gm = GridHandler.getDefault();
236: // startPoint.x = gm.snapX(startPoint.x, gridBox);
237: // startPoint.y = gm.snapY(startPoint.y, gridBox);
238: startPoint.x = webform.snapX(startPoint.x, gridBox);
239: startPoint.y = webform.snapY(startPoint.y, gridBox);
240: } else {
241: unsnappedStartPoint = startPoint;
242: }
243:
244: marqueeBounds = new Rectangle(startPoint);
245: previousCursor = pane.getCursor();
246:
247: // XXX Why new Cursor? I should use predefined cursor here!!!
248: if (insertCursor) {
249: pane.setCursor(webform.getManager().getInsertCursor());
250: } else {
251: pane.setCursor(Cursor
252: .getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
253: }
254:
255: ImageIcon imgIcon = new ImageIcon(
256: Marquee.class
257: .getResource("/org/netbeans/modules/visualweb/designer/resources/drag_select.gif")); // TODO get marquee icon
258: // StatusDisplayer_RAVE.getRaveDefault().setPositionLabelIcon(imgIcon);
259:
260: e.consume();
261: }
262: }
263:
264: Rectangle getBounds() {
265: return marqueeBounds;
266: }
267:
268: Point getUnsnappedPosition() {
269: return unsnappedStartPoint;
270: }
271:
272: /** Should the coordinates of the rectangle be snapped to grid? */
273: public void setSnapToGrid(boolean snap) {
274: this .snap = snap;
275: }
276:
277: /** Should a selection operation in the selection manager be attempted
278: * when mouse is released ?*/
279: public void setSelect(boolean select) {
280: this .select = select;
281: }
282:
283: public void setInsertCursor(boolean insertCursor) {
284: this .insertCursor = true;
285: }
286: }
|