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: * If you wish your version of this file to be governed by only the CDDL
025: * or only the GPL Version 2, indicate your decision by adding
026: * "[Contributor] elects to include this software in this distribution
027: * under the [CDDL or GPL Version 2] license." If you do not indicate a
028: * single choice of license, a recipient has the option to distribute
029: * your version of this file under either the CDDL, the GPL Version 2 or
030: * to extend the choice of license to its licensees as provided above.
031: * However, if you add GPL Version 2 code and therefore, elected the GPL
032: * Version 2 license, then the option applies only if the new code is
033: * made subject to such option by the copyright holder.
034: *
035: * Contributor(s):
036: *
037: * Portions Copyrighted 2008 Sun Microsystems, Inc.
038: */
039: package org.netbeans.jellytools.widgets;
040:
041: import java.awt.BorderLayout;
042: import java.awt.Dimension;
043: import java.awt.Frame;
044: import java.awt.Point;
045: import java.awt.Toolkit;
046: import java.awt.event.ActionEvent;
047: import java.awt.event.ActionListener;
048: import java.awt.event.MouseEvent;
049: import javax.swing.JComponent;
050: import javax.swing.JDialog;
051: import javax.swing.JFrame;
052: import javax.swing.JMenuItem;
053: import javax.swing.JPopupMenu;
054: import javax.swing.SwingUtilities;
055: import org.netbeans.api.visual.action.ActionFactory;
056: import org.netbeans.api.visual.action.ConnectProvider;
057: import org.netbeans.api.visual.action.ConnectorState;
058: import org.netbeans.api.visual.action.PopupMenuProvider;
059: import org.netbeans.api.visual.action.ReconnectProvider;
060: import org.netbeans.api.visual.action.WidgetAction;
061: import org.netbeans.api.visual.action.WidgetAction.WidgetMouseEvent;
062: import org.netbeans.api.visual.anchor.AnchorFactory;
063: import org.netbeans.api.visual.anchor.AnchorShape;
064: import org.netbeans.api.visual.anchor.PointShape;
065: import org.netbeans.api.visual.border.BorderFactory;
066: import org.netbeans.api.visual.graph.GraphScene;
067: import org.netbeans.api.visual.widget.ConnectionWidget;
068: import org.netbeans.api.visual.widget.LabelWidget;
069: import org.netbeans.api.visual.widget.LayerWidget;
070: import org.netbeans.api.visual.widget.Scene;
071: import org.netbeans.api.visual.widget.Widget;
072: import org.openide.windows.TopComponent;
073:
074: /**
075: *
076: * @author Jiri Skrivanek
077: */
078: public class Utils {
079:
080: /** Shows given Scene wrapped in TopComponent and JFrame.
081: * @param scene Scene to be shown
082: * @return TopComponent instance where scene resides
083: */
084: public static TopComponent showScene(Scene scene) {
085: JComponent sceneView = scene.getView();
086: if (sceneView == null) {
087: sceneView = scene.createView();
088: }
089: int width = 450, height = 250;
090: JFrame frame = new JFrame("Test Scene");
091: TopComponent tc = new TopComponent();
092: tc.setLayout(new BorderLayout());
093: tc.add(sceneView);
094: frame.add(tc);
095: frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
096: Dimension screenSize = java.awt.Toolkit.getDefaultToolkit()
097: .getScreenSize();
098: frame.setBounds((screenSize.width - width) / 2,
099: (screenSize.height - height) / 2, width, height);
100: frame.setVisible(true);
101: return tc;
102: }
103:
104: /** Creates test scene and shows it
105: * @param args arguments
106: */
107: public static void main(String[] args) {
108: if (SwingUtilities.isEventDispatchThread()) {
109: showScene(new TestScene());
110: } else {
111: SwingUtilities.invokeLater(new Runnable() {
112:
113: public void run() {
114: showScene(new TestScene());
115: }
116: });
117: }
118: }
119:
120: /** Creates test scene with 2 LabelWidgets and one movable widget. */
121: public static class TestScene extends GraphScene.StringGraph {
122:
123: private LayerWidget mainLayer = new LayerWidget(this );
124: private LayerWidget connectionLayer = new LayerWidget(this );
125: private LayerWidget interractionLayer = new LayerWidget(this );
126: private WidgetAction createAction = new SceneCreateAction();
127: private WidgetAction moveAction = ActionFactory
128: .createMoveAction();
129: private WidgetAction connectAction = ActionFactory
130: .createConnectAction(interractionLayer,
131: new SceneConnectProvider());
132: private WidgetAction reconnectAction = ActionFactory
133: .createReconnectAction(new SceneReconnectProvider());
134: private long nodeCounter = 0;
135: private long edgeCounter = 0;
136:
137: public TestScene() {
138: addChild(mainLayer);
139: addChild(connectionLayer);
140: addChild(interractionLayer);
141: getActions().addAction(createAction);
142: //mainLayer.addChild(new LabelWidget(this, "Click on background to create a node. Drag a node to create a connection."));
143: // do not change label nor location because it is hard coded in test cases
144: //addNode("Label 0").setPreferredLocation(new Point(100, 100));
145: Widget label0Widget = addNode("Label 0");
146: label0Widget.setPreferredLocation(new Point(100, 100));
147: label0Widget
148: .getActions()
149: .addAction(
150: ActionFactory
151: .createPopupMenuAction(new MyPopupProvider()));
152: label0Widget.getActions().addAction(new LabelAction());
153: Widget label1Widget = addNode("Label 1");
154: label1Widget.setPreferredLocation(new Point(300, 100));
155: LabelWidget movableWidget = new LabelWidget(this ,
156: "Movable Widget");
157: movableWidget.setPreferredLocation(new Point(100, 150));
158: movableWidget.getActions().addAction(moveAction);
159: addChild(movableWidget);
160: }
161:
162: protected Widget attachNodeWidget(String node) {
163: LabelWidget label = new LabelWidget(this , node);
164: label.setBorder(BorderFactory.createLineBorder(4));
165: label.getActions().addAction(createObjectHoverAction());
166: // label.getActions ().addAction (createSelectAction ());
167: label.getActions().addAction(connectAction);
168: mainLayer.addChild(label);
169: return label;
170: }
171:
172: protected Widget attachEdgeWidget(String edge) {
173: ConnectionWidget connection = new ConnectionWidget(this );
174: connection
175: .setTargetAnchorShape(AnchorShape.TRIANGLE_FILLED);
176: connection.setEndPointShape(PointShape.SQUARE_FILLED_BIG);
177: connection.getActions()
178: .addAction(createObjectHoverAction());
179: connection.getActions().addAction(createSelectAction());
180: connection.getActions().addAction(reconnectAction);
181: connectionLayer.addChild(connection);
182: return connection;
183: }
184:
185: protected void attachEdgeSourceAnchor(String edge,
186: String oldSourceNode, String sourceNode) {
187: Widget w = sourceNode != null ? findWidget(sourceNode)
188: : null;
189: ((ConnectionWidget) findWidget(edge))
190: .setSourceAnchor(AnchorFactory
191: .createRectangularAnchor(w));
192: }
193:
194: protected void attachEdgeTargetAnchor(String edge,
195: String oldTargetNode, String targetNode) {
196: Widget w = targetNode != null ? findWidget(targetNode)
197: : null;
198: ((ConnectionWidget) findWidget(edge))
199: .setTargetAnchor(AnchorFactory
200: .createRectangularAnchor(w));
201: }
202:
203: private class SceneCreateAction extends WidgetAction.Adapter {
204:
205: @Override
206: public State mousePressed(Widget widget,
207: WidgetMouseEvent event) {
208: if (event.getClickCount() == 1) {
209: if (event.getButton() == MouseEvent.BUTTON1
210: || event.getButton() == MouseEvent.BUTTON2) {
211: addNode("node" + nodeCounter++)
212: .setPreferredLocation(
213: widget
214: .convertLocalToScene(event
215: .getPoint()));
216: return State.CONSUMED;
217: }
218: }
219: return State.REJECTED;
220: }
221: }
222:
223: private class SceneConnectProvider implements ConnectProvider {
224:
225: private String source = null;
226: private String target = null;
227:
228: public boolean isSourceWidget(Widget sourceWidget) {
229: Object object = findObject(sourceWidget);
230: source = isNode(object) ? (String) object : null;
231: return source != null;
232: }
233:
234: public ConnectorState isTargetWidget(Widget sourceWidget,
235: Widget targetWidget) {
236: Object object = findObject(targetWidget);
237: target = isNode(object) ? (String) object : null;
238: if (target != null) {
239: return !source.equals(target) ? ConnectorState.ACCEPT
240: : ConnectorState.REJECT_AND_STOP;
241: }
242: return object != null ? ConnectorState.REJECT_AND_STOP
243: : ConnectorState.REJECT;
244: }
245:
246: public boolean hasCustomTargetWidgetResolver(Scene scene) {
247: return false;
248: }
249:
250: public Widget resolveTargetWidget(Scene scene,
251: Point sceneLocation) {
252: return null;
253: }
254:
255: public void createConnection(Widget sourceWidget,
256: Widget targetWidget) {
257: String edge = "edge" + edgeCounter++;
258: addEdge(edge);
259: setEdgeSource(edge, source);
260: setEdgeTarget(edge, target);
261: }
262: }
263:
264: private class SceneReconnectProvider implements
265: ReconnectProvider {
266:
267: String edge;
268: String originalNode;
269: String replacementNode;
270:
271: public void reconnectingStarted(
272: ConnectionWidget connectionWidget,
273: boolean reconnectingSource) {
274: }
275:
276: public void reconnectingFinished(
277: ConnectionWidget connectionWidget,
278: boolean reconnectingSource) {
279: }
280:
281: public boolean isSourceReconnectable(
282: ConnectionWidget connectionWidget) {
283: Object object = findObject(connectionWidget);
284: edge = isEdge(object) ? (String) object : null;
285: originalNode = edge != null ? getEdgeSource(edge)
286: : null;
287: return originalNode != null;
288: }
289:
290: public boolean isTargetReconnectable(
291: ConnectionWidget connectionWidget) {
292: Object object = findObject(connectionWidget);
293: edge = isEdge(object) ? (String) object : null;
294: originalNode = edge != null ? getEdgeTarget(edge)
295: : null;
296: return originalNode != null;
297: }
298:
299: public ConnectorState isReplacementWidget(
300: ConnectionWidget connectionWidget,
301: Widget replacementWidget, boolean reconnectingSource) {
302: Object object = findObject(replacementWidget);
303: replacementNode = isNode(object) ? (String) object
304: : null;
305: if (replacementNode != null) {
306: return ConnectorState.ACCEPT;
307: }
308: return object != null ? ConnectorState.REJECT_AND_STOP
309: : ConnectorState.REJECT;
310: }
311:
312: public boolean hasCustomReplacementWidgetResolver(
313: Scene scene) {
314: return false;
315: }
316:
317: public Widget resolveReplacementWidget(Scene scene,
318: Point sceneLocation) {
319: return null;
320: }
321:
322: public void reconnect(ConnectionWidget connectionWidget,
323: Widget replacementWidget, boolean reconnectingSource) {
324: if (replacementWidget == null) {
325: removeEdge(edge);
326: } else if (reconnectingSource) {
327: setEdgeSource(edge, replacementNode);
328: } else {
329: setEdgeTarget(edge, replacementNode);
330: }
331: }
332: }
333:
334: private static class MyPopupProvider implements
335: PopupMenuProvider, ActionListener {
336:
337: private static final String OPEN_ACTION = "openAction";
338: private static final String MODAL_ACTION = "modalAction";
339: private static final int WIDTH = 100;
340: private static final int HEIGHT = 100;
341: private JPopupMenu menu;
342:
343: public MyPopupProvider() {
344: menu = new JPopupMenu("Popup menu");
345: JMenuItem item;
346:
347: item = new JMenuItem("Open");
348: item.setActionCommand(OPEN_ACTION);
349: item.addActionListener(this );
350: menu.add(item);
351:
352: item = new JMenuItem("Modal");
353: item.setActionCommand(MODAL_ACTION);
354: item.addActionListener(this );
355: menu.add(item);
356:
357: }
358:
359: public JPopupMenu getPopupMenu(Widget widget,
360: Point localLocation) {
361: return menu;
362: }
363:
364: public void actionPerformed(ActionEvent e) {
365: if (OPEN_ACTION.equals(e.getActionCommand())) {
366: JDialog dialog = new JDialog((Frame) null, "Open");
367: Dimension screenSize = Toolkit.getDefaultToolkit()
368: .getScreenSize();
369: dialog.setBounds((screenSize.width - WIDTH) / 2,
370: (screenSize.height - HEIGHT) / 2, WIDTH,
371: HEIGHT);
372: dialog.setVisible(true);
373: } else if (MODAL_ACTION.equals(e.getActionCommand())) {
374: JDialog dialog = new JDialog((Frame) null, "Modal",
375: true);
376: Dimension screenSize = Toolkit.getDefaultToolkit()
377: .getScreenSize();
378: dialog.setBounds((screenSize.width - WIDTH) / 2,
379: (screenSize.height - HEIGHT) / 2, WIDTH,
380: HEIGHT);
381: dialog.setVisible(true);
382: }
383: }
384: }
385:
386: private class LabelAction extends WidgetAction.Adapter {
387:
388: private static final int WIDTH = 100;
389: private static final int HEIGHT = 100;
390:
391: @Override
392: public State mouseClicked(Widget widget,
393: WidgetMouseEvent event) {
394: if (event.getButton() == MouseEvent.BUTTON1) {
395: JDialog dialog = new JDialog((Frame) null,
396: "Mouse Clicked " + event.getClickCount());
397: Dimension screenSize = Toolkit.getDefaultToolkit()
398: .getScreenSize();
399: dialog.setBounds((screenSize.width - WIDTH) / 2,
400: (screenSize.height - HEIGHT) / 2, WIDTH,
401: HEIGHT);
402: dialog.setVisible(true);
403: return State.CONSUMED;
404: }
405: return State.REJECTED;
406: }
407: }
408: }
409: }
|