001: /*
002: * soapUI, copyright (C) 2004-2007 eviware.com
003: *
004: * soapUI is free software; you can redistribute it and/or modify it under the
005: * terms of version 2.1 of the GNU Lesser General Public License as published by
006: * the Free Software Foundation.
007: *
008: * soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
009: * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
010: * See the GNU Lesser General Public License for more details at gnu.org.
011: */
012:
013: package com.eviware.soapui.ui;
014:
015: import java.awt.BorderLayout;
016: import java.awt.Insets;
017: import java.awt.Point;
018: import java.awt.Rectangle;
019: import java.awt.dnd.Autoscroll;
020: import java.awt.event.ActionEvent;
021: import java.awt.event.KeyAdapter;
022: import java.awt.event.KeyEvent;
023: import java.awt.event.MouseAdapter;
024: import java.awt.event.MouseEvent;
025: import java.util.HashSet;
026: import java.util.Set;
027:
028: import javax.swing.JPanel;
029: import javax.swing.JPopupMenu;
030: import javax.swing.JScrollPane;
031: import javax.swing.JTree;
032: import javax.swing.ToolTipManager;
033: import javax.swing.event.TreeSelectionEvent;
034: import javax.swing.event.TreeSelectionListener;
035: import javax.swing.tree.TreePath;
036: import javax.swing.tree.TreeSelectionModel;
037:
038: import com.eviware.soapui.model.ModelItem;
039: import com.eviware.soapui.model.project.Project;
040: import com.eviware.soapui.model.tree.SoapUITreeModel;
041: import com.eviware.soapui.model.tree.SoapUITreeNode;
042: import com.eviware.soapui.model.tree.SoapUITreeNodeRenderer;
043: import com.eviware.soapui.model.tree.nodes.ProjectTreeNode;
044: import com.eviware.soapui.model.workspace.Workspace;
045: import com.eviware.soapui.support.action.swing.ActionList;
046:
047: /**
048: * The soapUI navigator tree
049: *
050: * @author Ole.Matzura
051: */
052:
053: public class Navigator extends JPanel {
054: private Workspace workspace;
055: private JTree mainTree;
056: private SoapUITreeModel treeModel;
057: private Set<NavigatorListener> listeners = new HashSet<NavigatorListener>();
058:
059: public Navigator(Workspace workspace) {
060: super (new BorderLayout());
061: this .workspace = workspace;
062:
063: buildUI();
064: }
065:
066: private void buildUI() {
067: treeModel = new SoapUITreeModel(workspace);
068:
069: mainTree = new NavigatorTree(treeModel);
070: mainTree.setRootVisible(true);
071: mainTree.setExpandsSelectedPaths(true);
072: mainTree.setToggleClickCount(0);
073: mainTree.addMouseListener(new TreeMouseListener());
074: mainTree
075: .addTreeSelectionListener(new InternalTreeSelectionListener());
076: mainTree.setCellRenderer(new SoapUITreeNodeRenderer());
077: mainTree.setBorder(null);
078: mainTree.getSelectionModel().setSelectionMode(
079: TreeSelectionModel.SINGLE_TREE_SELECTION);
080:
081: mainTree.addKeyListener(new TreeKeyListener());
082:
083: ToolTipManager.sharedInstance().registerComponent(mainTree);
084:
085: add(new JScrollPane(mainTree), BorderLayout.CENTER);
086: }
087:
088: private static class NavigatorTree extends JTree implements
089: Autoscroll {
090: public NavigatorTree(SoapUITreeModel treeModel) {
091: super (treeModel);
092: }
093:
094: private static final int AUTOSCROLL_MARGIN = 12;
095:
096: public void autoscroll(Point pt) {
097: // Figure out which row we’re on.
098: int nRow = getRowForLocation(pt.x, pt.y);
099:
100: // If we are not on a row then ignore this autoscroll request
101: if (nRow < 0)
102: return;
103:
104: Rectangle raOuter = getBounds();
105: // Now decide if the row is at the top of the screen or at the
106: // bottom. We do this to make the previous row (or the next
107: // row) visible as appropriate. If we’re at the absolute top or
108: // bottom, just return the first or last row respectively.
109:
110: nRow = (pt.y + raOuter.y <= AUTOSCROLL_MARGIN) // Is row at top of
111: // screen?
112: ? (nRow <= 0 ? 0 : nRow - 1) // Yes, scroll up one row
113: : (nRow < getRowCount() - 1 ? nRow + 1 : nRow); // No,
114: // scroll
115: // down one
116: // row
117:
118: scrollRowToVisible(nRow);
119: }
120:
121: // Calculate the insets for the *JTREE*, not the viewport
122: // the tree is in. This makes it a bit messy.
123: public Insets getAutoscrollInsets() {
124: Rectangle raOuter = getBounds();
125: Rectangle raInner = getParent().getBounds();
126: return new Insets(
127: raInner.y - raOuter.y + AUTOSCROLL_MARGIN,
128: raInner.x - raOuter.x + AUTOSCROLL_MARGIN,
129: raOuter.height - raInner.height - raInner.y
130: + raOuter.y + AUTOSCROLL_MARGIN,
131: raOuter.width - raInner.width - raInner.x
132: + raOuter.x + AUTOSCROLL_MARGIN);
133: }
134: }
135:
136: public Project getCurrentProject() {
137: TreePath path = mainTree.getSelectionPath();
138: if (path == null)
139: return null;
140:
141: Object node = (Object) path.getLastPathComponent();
142: while (node != null && !(node instanceof ProjectTreeNode)) {
143: path = path.getParentPath();
144: node = (path == null ? null : path.getLastPathComponent());
145: }
146:
147: if (node == null)
148: return null;
149:
150: return ((ProjectTreeNode) node).getProject();
151: }
152:
153: public void addNavigatorListener(NavigatorListener listener) {
154: listeners.add(listener);
155: }
156:
157: public void removeNavigatorListener(NavigatorListener listener) {
158: listeners.remove(listener);
159: }
160:
161: public void selectModelItem(ModelItem modelItem) {
162: TreePath path = treeModel.getPath(modelItem);
163: mainTree.setSelectionPath(path);
164: mainTree.expandPath(path);
165: mainTree.scrollPathToVisible(path);
166: }
167:
168: public TreePath getTreePath(ModelItem modelItem) {
169: return treeModel.getPath(modelItem);
170: }
171:
172: public JTree getMainTree() {
173: return mainTree;
174: }
175:
176: private final class TreeKeyListener extends KeyAdapter {
177: public void keyPressed(KeyEvent e) {
178: TreePath selectionPath = mainTree.getSelectionPath();
179: if (selectionPath != null) {
180: SoapUITreeNode lastPathComponent = (SoapUITreeNode) selectionPath
181: .getLastPathComponent();
182: ActionList actions = lastPathComponent.getActions();
183: if (actions != null) {
184: actions.dispatchKeyEvent(e);
185: }
186: }
187: }
188: }
189:
190: public class InternalTreeSelectionListener implements
191: TreeSelectionListener {
192: public void valueChanged(TreeSelectionEvent e) {
193: Object obj = e.getPath().getLastPathComponent();
194: if (obj instanceof SoapUITreeNode) {
195: SoapUITreeNode treeNode = (SoapUITreeNode) obj;
196:
197: if (!listeners.isEmpty()) {
198: TreePath newPath = e.getNewLeadSelectionPath();
199: NavigatorListener[] array = listeners
200: .toArray(new NavigatorListener[listeners
201: .size()]);
202: for (NavigatorListener listener : array) {
203: listener.nodeSelected(newPath == null ? null
204: : treeNode);
205: }
206: }
207: }
208: }
209: }
210:
211: public class TreeMouseListener extends MouseAdapter {
212: public void mouseClicked(MouseEvent e) {
213: if (e.isPopupTrigger())
214: showPopup(e);
215: else if (e.getClickCount() < 2)
216: return;
217: if (mainTree.getSelectionCount() != 1)
218: return;
219:
220: TreePath path = mainTree.getSelectionPath();
221: if (path == null)
222: return;
223:
224: SoapUITreeNode node = (SoapUITreeNode) path
225: .getLastPathComponent();
226: ActionList actions = node.getActions();
227: if (actions != null)
228: actions.performDefaultAction(new ActionEvent(mainTree,
229: 0, null));
230: }
231:
232: public void mousePressed(MouseEvent e) {
233: if (e.isPopupTrigger())
234: showPopup(e);
235: }
236:
237: public void mouseReleased(MouseEvent e) {
238: if (e.isPopupTrigger())
239: showPopup(e);
240: }
241:
242: private void showPopup(MouseEvent e) {
243: TreePath path = mainTree.getPathForLocation((int) e
244: .getPoint().getX(), (int) e.getPoint().getY());
245: if (path == null)
246: return;
247: SoapUITreeNode node = (SoapUITreeNode) path
248: .getLastPathComponent();
249:
250: JPopupMenu popupMenu = node.getPopup();
251: if (popupMenu == null)
252: return;
253:
254: mainTree.setSelectionPath(path);
255:
256: popupMenu.show(mainTree, e.getX(), e.getY());
257: }
258: }
259:
260: public boolean isVisible(TreePath path) {
261: return mainTree.isVisible(path);
262: }
263:
264: public boolean isExpanded(TreePath path) {
265: return mainTree.isExpanded(path);
266: }
267: }
|