View Javadoc

1   /*
2    *  soapUI, copyright (C) 2004-2007 eviware.com 
3    *
4    *  soapUI is free software; you can redistribute it and/or modify it under the 
5    *  terms of version 2.1 of the GNU Lesser General Public License as published by 
6    *  the Free Software Foundation.
7    *
8    *  soapUI is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
9    *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
10   *  See the GNU Lesser General Public License for more details at gnu.org.
11   */
12  
13  package com.eviware.soapui.ui;
14  
15  import java.awt.BorderLayout;
16  import java.awt.Insets;
17  import java.awt.Point;
18  import java.awt.Rectangle;
19  import java.awt.dnd.Autoscroll;
20  import java.awt.event.ActionEvent;
21  import java.awt.event.KeyAdapter;
22  import java.awt.event.KeyEvent;
23  import java.awt.event.MouseAdapter;
24  import java.awt.event.MouseEvent;
25  import java.util.HashSet;
26  import java.util.Set;
27  
28  import javax.swing.JPanel;
29  import javax.swing.JPopupMenu;
30  import javax.swing.JScrollPane;
31  import javax.swing.JTree;
32  import javax.swing.ToolTipManager;
33  import javax.swing.event.TreeSelectionEvent;
34  import javax.swing.event.TreeSelectionListener;
35  import javax.swing.tree.TreePath;
36  import javax.swing.tree.TreeSelectionModel;
37  
38  import com.eviware.soapui.model.ModelItem;
39  import com.eviware.soapui.model.project.Project;
40  import com.eviware.soapui.model.tree.SoapUITreeModel;
41  import com.eviware.soapui.model.tree.SoapUITreeNode;
42  import com.eviware.soapui.model.tree.SoapUITreeNodeRenderer;
43  import com.eviware.soapui.model.tree.nodes.ProjectTreeNode;
44  import com.eviware.soapui.model.workspace.Workspace;
45  import com.eviware.soapui.support.action.swing.ActionList;
46  
47  /***
48   * The soapUI navigator tree
49   * 
50   * @author Ole.Matzura
51   */
52  
53  public class Navigator extends JPanel
54  {
55  	private Workspace workspace;
56  	private JTree mainTree;
57  	private SoapUITreeModel treeModel;
58  	private Set<NavigatorListener> listeners = new HashSet<NavigatorListener>();
59  
60  	public Navigator( Workspace workspace )
61  	{
62  		super( new BorderLayout() );
63  		this.workspace = workspace;
64  		
65  		buildUI();
66  	}
67  	
68  	private void buildUI()
69  	{
70  		treeModel = new SoapUITreeModel(workspace);
71  		
72        mainTree = new NavigatorTree( treeModel );
73        mainTree.setRootVisible(true);
74        mainTree.setExpandsSelectedPaths(true);
75        mainTree.setToggleClickCount( 0 );
76        mainTree.addMouseListener(new TreeMouseListener());
77        mainTree.addTreeSelectionListener(new InternalTreeSelectionListener());
78        mainTree.setCellRenderer( new SoapUITreeNodeRenderer() );
79        mainTree.setBorder(null);
80        mainTree.getSelectionModel().setSelectionMode( TreeSelectionModel.SINGLE_TREE_SELECTION );
81        
82        mainTree.addKeyListener( new TreeKeyListener() );
83        
84        ToolTipManager.sharedInstance().registerComponent(mainTree);
85        
86        add( new JScrollPane( mainTree ), BorderLayout.CENTER );
87  	}
88  	
89  	private static class NavigatorTree extends JTree implements Autoscroll
90  	{
91  		public NavigatorTree( SoapUITreeModel treeModel )
92  		{
93  			super( treeModel );
94  		}
95  		
96  		private static final int AUTOSCROLL_MARGIN = 12;
97  
98  		public void autoscroll( Point pt )
99  		{
100 			// Figure out which row we?re on.
101 			int nRow = getRowForLocation( pt.x, pt.y );
102 
103 			// If we are not on a row then ignore this autoscroll request
104 			if( nRow < 0 )
105 				return;
106 
107 			Rectangle raOuter = getBounds();
108 			// Now decide if the row is at the top of the screen or at the
109 			// bottom. We do this to make the previous row (or the next
110 			// row) visible as appropriate. If we?re at the absolute top or
111 			// bottom, just return the first or last row respectively.
112 
113 			nRow = ( pt.y + raOuter.y <= AUTOSCROLL_MARGIN ) // Is row at top of
114 			// screen?
115 			? ( nRow <= 0 ? 0 : nRow - 1 ) // Yes, scroll up one row
116 						: ( nRow < getRowCount() - 1 ? nRow + 1 : nRow ); // No,
117 			// scroll
118 			// down one
119 			// row
120 
121 			scrollRowToVisible( nRow );
122 		}
123 
124 		// Calculate the insets for the *JTREE*, not the viewport
125 		// the tree is in. This makes it a bit messy.
126 		public Insets getAutoscrollInsets()
127 		{
128 			Rectangle raOuter = getBounds();
129 			Rectangle raInner = getParent().getBounds();
130 			return new Insets( raInner.y - raOuter.y + AUTOSCROLL_MARGIN, raInner.x - raOuter.x
131 						+ AUTOSCROLL_MARGIN, raOuter.height - raInner.height - raInner.y + raOuter.y
132 						+ AUTOSCROLL_MARGIN, raOuter.width - raInner.width - raInner.x + raOuter.x
133 						+ AUTOSCROLL_MARGIN );
134 		}
135 	}
136 	
137 	public Project getCurrentProject()
138    {
139       TreePath path = mainTree.getSelectionPath();
140       if( path == null )
141       	return null;
142       
143       Object node = (Object) path.getLastPathComponent();
144       while (node != null && !(node instanceof ProjectTreeNode))
145       {
146          path = path.getParentPath();
147          node = (path == null ? null : path.getLastPathComponent());
148       }
149 
150       if (node == null)
151          return null;
152 
153       return ((ProjectTreeNode) node).getProject();
154    }
155 	
156 	public void addNavigatorListener( NavigatorListener listener )
157 	{
158 		listeners.add( listener );
159 	}
160 	
161 	public void removeNavigatorListener( NavigatorListener listener )
162 	{
163 		listeners.remove( listener );
164 	}
165 	
166 	public void selectModelItem(ModelItem modelItem)
167    {
168       TreePath path = treeModel.getPath( modelItem );
169       mainTree.setSelectionPath( path );
170      	mainTree.expandPath( path );
171       mainTree.scrollPathToVisible( path );
172    }
173 	
174 	public TreePath getTreePath( ModelItem modelItem )
175 	{
176 		return treeModel.getPath( modelItem );
177 	}
178 	
179 	public JTree getMainTree()
180 	{
181 		return mainTree;
182 	}
183 	
184 	private final class TreeKeyListener extends KeyAdapter
185 	{
186 		public void keyPressed(KeyEvent e)
187 		{
188 			TreePath selectionPath = mainTree.getSelectionPath();
189 			if( selectionPath != null )
190 			{
191 				SoapUITreeNode lastPathComponent = (SoapUITreeNode) selectionPath.getLastPathComponent();
192 				ActionList actions = lastPathComponent.getActions();
193 				if( actions != null )
194 				{
195 					actions.dispatchKeyEvent( e );
196 				}
197 			}
198 		}
199 	}
200 	
201 	public class InternalTreeSelectionListener implements TreeSelectionListener
202    {
203       public void valueChanged(TreeSelectionEvent e)
204       {
205          Object obj = e.getPath().getLastPathComponent();
206          if (obj instanceof SoapUITreeNode)
207          {
208             SoapUITreeNode treeNode = (SoapUITreeNode) obj;
209 
210             if( !listeners.isEmpty() )
211             {
212             	TreePath newPath = e.getNewLeadSelectionPath();
213 	            NavigatorListener[] array = listeners.toArray( new NavigatorListener[listeners.size()]);
214 	            for( NavigatorListener listener : array )
215 	            {
216 	            	listener.nodeSelected( newPath == null ? null : treeNode );
217 	            }
218             }
219          }
220       }
221    }
222 
223 	public class TreeMouseListener extends MouseAdapter
224    {
225       public void mouseClicked(MouseEvent e)
226       {
227          if (e.isPopupTrigger())
228             showPopup(e);
229          else if (e.getClickCount() < 2)
230             return;
231          if (mainTree.getSelectionCount() != 1)
232             return;
233 
234          TreePath path = mainTree.getSelectionPath();
235          if( path == null )
236          	return;
237          
238          SoapUITreeNode node = (SoapUITreeNode) path.getLastPathComponent();
239          ActionList actions = node.getActions();
240          if( actions != null )
241          	actions.performDefaultAction( new ActionEvent( mainTree, 0, null ));
242       }
243 
244       public void mousePressed(MouseEvent e)
245       {
246          if (e.isPopupTrigger())
247             showPopup(e);
248       }
249 
250       public void mouseReleased(MouseEvent e)
251       {
252          if (e.isPopupTrigger())
253             showPopup(e);
254       }
255 
256       private void showPopup(MouseEvent e)
257       {
258          TreePath path = mainTree.getPathForLocation((int) e.getPoint().getX(), (int) e.getPoint().getY());
259          if (path == null)
260             return;
261          SoapUITreeNode node = (SoapUITreeNode) path.getLastPathComponent();
262 
263          JPopupMenu popupMenu = node.getPopup();
264          if (popupMenu == null)
265             return;
266 
267          mainTree.setSelectionPath(path);
268 
269          popupMenu.show(mainTree, e.getX(), e.getY());
270       }
271    }
272 
273 	public boolean isVisible( TreePath path )
274 	{
275 		return mainTree.isVisible( path );
276 	}
277 
278 	public boolean isExpanded( TreePath path )
279 	{
280 		return mainTree.isExpanded( path );
281 	}
282 }