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.BorderFactory;
29  import javax.swing.JPanel;
30  import javax.swing.JPopupMenu;
31  import javax.swing.JScrollPane;
32  import javax.swing.JTree;
33  import javax.swing.KeyStroke;
34  import javax.swing.ToolTipManager;
35  import javax.swing.event.TreeSelectionEvent;
36  import javax.swing.event.TreeSelectionListener;
37  import javax.swing.tree.TreePath;
38  import javax.swing.tree.TreeSelectionModel;
39  
40  import com.eviware.soapui.model.ModelItem;
41  import com.eviware.soapui.model.project.Project;
42  import com.eviware.soapui.model.tree.SoapUITreeModel;
43  import com.eviware.soapui.model.tree.SoapUITreeNode;
44  import com.eviware.soapui.model.tree.SoapUITreeNodeRenderer;
45  import com.eviware.soapui.model.tree.nodes.ProjectTreeNode;
46  import com.eviware.soapui.model.workspace.Workspace;
47  import com.eviware.soapui.support.UISupport;
48  import com.eviware.soapui.support.action.swing.ActionList;
49  
50  /***
51   * The soapUI navigator tree
52   * 
53   * @author Ole.Matzura
54   */
55  
56  public class Navigator extends JPanel
57  {
58  	private Workspace workspace;
59  	private JTree mainTree;
60  	private SoapUITreeModel treeModel;
61  	private Set<NavigatorListener> listeners = new HashSet<NavigatorListener>();
62  
63  	public Navigator( Workspace workspace )
64  	{
65  		super( new BorderLayout() );
66  		this.workspace = workspace;
67  		
68  		buildUI();
69  	}
70  	
71  	private void buildUI()
72  	{
73  		treeModel = new SoapUITreeModel(workspace);
74  		
75        mainTree = new NavigatorTree( treeModel );
76        mainTree.setRootVisible(true);
77        mainTree.setExpandsSelectedPaths(true);
78        mainTree.setToggleClickCount( 0 );
79        mainTree.addMouseListener(new TreeMouseListener());
80        mainTree.addTreeSelectionListener(new InternalTreeSelectionListener());
81        mainTree.setCellRenderer( new SoapUITreeNodeRenderer() );
82        mainTree.setBorder(null);
83        mainTree.getSelectionModel().setSelectionMode( TreeSelectionModel.SINGLE_TREE_SELECTION );
84        mainTree.addKeyListener( new TreeKeyListener() );
85  //      mainTree.addTreeExpansionListener( new TreeExpansionListener() {
86  //
87  //			public void treeCollapsed( TreeExpansionEvent event )
88  //			{
89  //			}
90  //
91  //			public void treeExpanded( final TreeExpansionEvent event )
92  //			{
93  //				Object treeNode = event.getPath().getLastPathComponent();
94  //				if( treeNode instanceof ProjectTreeNode )
95  //				{
96  //					ProjectTreeNode tn = ( ProjectTreeNode ) treeNode;
97  //					if( !tn.getModelItem().isOpen() && !tn.getModelItem().isDisabled() )
98  //					{
99  //						try
100 //						{
101 //							UISupport.select( workspace.openProject( tn.getModelItem()));
102 //						}
103 //						catch( SoapUIException e )
104 //						{
105 //							UISupport.showErrorMessage( e );
106 //						}
107 //					}
108 //				}
109 //			}} );
110 //      
111       
112       ToolTipManager.sharedInstance().registerComponent(mainTree);
113       
114       add( new JScrollPane( mainTree ), BorderLayout.CENTER );
115       setBorder( BorderFactory.createEmptyBorder( 2, 0, 0, 0 ));
116 	}
117 	
118 	private static class NavigatorTree extends JTree implements Autoscroll
119 	{
120 		public NavigatorTree( SoapUITreeModel treeModel )
121 		{
122 			super( treeModel );
123 		}
124 		
125 		private static final int AUTOSCROLL_MARGIN = 12;
126 
127 		public void autoscroll( Point pt )
128 		{
129 			// Figure out which row we?re on.
130 			int nRow = getRowForLocation( pt.x, pt.y );
131 
132 			// If we are not on a row then ignore this autoscroll request
133 			if( nRow < 0 )
134 				return;
135 
136 			Rectangle raOuter = getBounds();
137 			// Now decide if the row is at the top of the screen or at the
138 			// bottom. We do this to make the previous row (or the next
139 			// row) visible as appropriate. If we?re at the absolute top or
140 			// bottom, just return the first or last row respectively.
141 
142 			nRow = ( pt.y + raOuter.y <= AUTOSCROLL_MARGIN ) // Is row at top of
143 			// screen?
144 			? ( nRow <= 0 ? 0 : nRow - 1 ) // Yes, scroll up one row
145 						: ( nRow < getRowCount() - 1 ? nRow + 1 : nRow ); // No,
146 			// scroll
147 			// down one
148 			// row
149 
150 			scrollRowToVisible( nRow );
151 		}
152 
153 		// Calculate the insets for the *JTREE*, not the viewport
154 		// the tree is in. This makes it a bit messy.
155 		public Insets getAutoscrollInsets()
156 		{
157 			Rectangle raOuter = getBounds();
158 			Rectangle raInner = getParent().getBounds();
159 			return new Insets( raInner.y - raOuter.y + AUTOSCROLL_MARGIN, raInner.x - raOuter.x
160 						+ AUTOSCROLL_MARGIN, raOuter.height - raInner.height - raInner.y + raOuter.y
161 						+ AUTOSCROLL_MARGIN, raOuter.width - raInner.width - raInner.x + raOuter.x
162 						+ AUTOSCROLL_MARGIN );
163 		}
164 	}
165 	
166 	public Project getCurrentProject()
167    {
168       TreePath path = mainTree.getSelectionPath();
169       if( path == null )
170       	return null;
171       
172       Object node = (Object) path.getLastPathComponent();
173       while (node != null && !(node instanceof ProjectTreeNode))
174       {
175          path = path.getParentPath();
176          node = (path == null ? null : path.getLastPathComponent());
177       }
178 
179       if (node == null)
180          return null;
181 
182       return ((ProjectTreeNode) node).getProject();
183    }
184 	
185 	public void addNavigatorListener( NavigatorListener listener )
186 	{
187 		listeners.add( listener );
188 	}
189 	
190 	public void removeNavigatorListener( NavigatorListener listener )
191 	{
192 		listeners.remove( listener );
193 	}
194 	
195 	public void selectModelItem(ModelItem modelItem)
196    {
197       TreePath path = treeModel.getPath( modelItem );
198       mainTree.setSelectionPath( path );
199      	mainTree.expandPath( path );
200       mainTree.scrollPathToVisible( path );
201    }
202 	
203 	public TreePath getTreePath( ModelItem modelItem )
204 	{
205 		return treeModel.getPath( modelItem );
206 	}
207 	
208 	public JTree getMainTree()
209 	{
210 		return mainTree;
211 	}
212 	
213 	public ModelItem getSelectedItem()
214 	{
215 		TreePath path = mainTree.getSelectionPath();
216       if( path == null )
217       	return null;
218       
219      return ((SoapUITreeNode) path.getLastPathComponent()).getModelItem();
220 	}
221 	
222 	private final class TreeKeyListener extends KeyAdapter
223 	{
224 		public void keyPressed(KeyEvent e)
225 		{
226 			TreePath selectionPath = mainTree.getSelectionPath();
227 			if( selectionPath != null )
228 			{
229 				SoapUITreeNode lastPathComponent = (SoapUITreeNode) selectionPath.getLastPathComponent();
230 				ActionList actions = lastPathComponent.getActions();
231 				if( actions != null )
232 				{
233 					actions.dispatchKeyEvent( e );
234 				}
235 				
236 				if( !e.isConsumed() )
237 				{
238 					KeyStroke ks = KeyStroke.getKeyStrokeForEvent( e );
239 					if( ks.equals( UISupport.getKeyStroke( "alt C" )))
240 					{
241 						mainTree.collapsePath( selectionPath );
242 						e.consume();
243 					}
244 					else if( ks.equals( UISupport.getKeyStroke( "alt E" )))
245 					{
246 						mainTree.collapsePath( selectionPath );
247 						int row = mainTree.getSelectionRows()[0];
248 						TreePath nextPath = mainTree.getPathForRow( row+1 );
249 						
250 						TreePath path = mainTree.getPathForRow( row );
251 						while( path != null && !path.equals( nextPath ))
252 						{
253 							mainTree.expandRow( row );
254 							path = mainTree.getPathForRow( ++row );
255 						}
256 					
257 						e.consume();
258 					}
259 				}
260 			}
261 		}
262 	}
263 	
264 	public class InternalTreeSelectionListener implements TreeSelectionListener
265    {
266       public void valueChanged(TreeSelectionEvent e)
267       {
268          Object obj = e.getPath().getLastPathComponent();
269          if (obj instanceof SoapUITreeNode)
270          {
271             SoapUITreeNode treeNode = (SoapUITreeNode) obj;
272 
273             if( !listeners.isEmpty() )
274             {
275             	TreePath newPath = e.getNewLeadSelectionPath();
276 	            NavigatorListener[] array = listeners.toArray( new NavigatorListener[listeners.size()]);
277 	            for( NavigatorListener listener : array )
278 	            {
279 	            	listener.nodeSelected( newPath == null ? null : treeNode );
280 	            }
281             }
282          }
283       }
284    }
285 
286 	public class TreeMouseListener extends MouseAdapter
287    {
288       public void mouseClicked(MouseEvent e)
289       {
290          if (e.isPopupTrigger())
291             showPopup(e);
292          else if (e.getClickCount() < 2)
293             return;
294          if (mainTree.getSelectionCount() != 1)
295             return;
296 
297          int row = mainTree.getRowForLocation( e.getX(), e.getY() );
298          TreePath path = mainTree.getSelectionPath();
299          if( path == null && row == -1 )
300          	return;
301          
302          if( path == null || mainTree.getRowForPath( path ) != row )
303          	mainTree.setSelectionRow( row );
304          
305          SoapUITreeNode node = (SoapUITreeNode) path.getLastPathComponent();
306          ActionList actions = node.getActions();
307          if( actions != null )
308          	actions.performDefaultAction( new ActionEvent( mainTree, 0, null ));
309       }
310 
311       public void mousePressed(MouseEvent e)
312       {
313          if (e.isPopupTrigger())
314             showPopup(e);
315       }
316 
317       public void mouseReleased(MouseEvent e)
318       {
319          if (e.isPopupTrigger())
320             showPopup(e);
321       }
322 
323       private void showPopup(MouseEvent e)
324       {
325          TreePath path = mainTree.getPathForLocation((int) e.getPoint().getX(), (int) e.getPoint().getY());
326          if (path == null)
327             return;
328          SoapUITreeNode node = (SoapUITreeNode) path.getLastPathComponent();
329 
330          JPopupMenu popupMenu = node.getPopup();
331          if (popupMenu == null)
332             return;
333 
334          mainTree.setSelectionPath(path);
335 
336          popupMenu.show(mainTree, e.getX(), e.getY());
337       }
338    }
339 
340 	public boolean isVisible( TreePath path )
341 	{
342 		return mainTree.isVisible( path );
343 	}
344 
345 	public boolean isExpanded( TreePath path )
346 	{
347 		return mainTree.isExpanded( path );
348 	}
349 }