1
2
3
4
5
6
7
8
9
10
11
12
13 package com.eviware.soapui.ui;
14
15 import java.awt.BorderLayout;
16 import java.awt.Component;
17 import java.awt.Insets;
18 import java.awt.Point;
19 import java.awt.Rectangle;
20 import java.awt.dnd.Autoscroll;
21 import java.awt.event.ActionEvent;
22 import java.awt.event.KeyAdapter;
23 import java.awt.event.KeyEvent;
24 import java.awt.event.MouseAdapter;
25 import java.awt.event.MouseEvent;
26 import java.util.Enumeration;
27 import java.util.HashSet;
28 import java.util.Set;
29
30 import javax.swing.AbstractAction;
31 import javax.swing.BorderFactory;
32 import javax.swing.JPanel;
33 import javax.swing.JPopupMenu;
34 import javax.swing.JScrollPane;
35 import javax.swing.JToggleButton;
36 import javax.swing.JTree;
37 import javax.swing.KeyStroke;
38 import javax.swing.ToolTipManager;
39 import javax.swing.event.TreeSelectionEvent;
40 import javax.swing.event.TreeSelectionListener;
41 import javax.swing.tree.TreePath;
42 import javax.swing.tree.TreeSelectionModel;
43
44 import com.eviware.soapui.model.ModelItem;
45 import com.eviware.soapui.model.project.Project;
46 import com.eviware.soapui.model.tree.SoapUITreeModel;
47 import com.eviware.soapui.model.tree.SoapUITreeNode;
48 import com.eviware.soapui.model.tree.SoapUITreeNodeRenderer;
49 import com.eviware.soapui.model.tree.nodes.ProjectTreeNode;
50 import com.eviware.soapui.model.workspace.Workspace;
51 import com.eviware.soapui.support.UISupport;
52 import com.eviware.soapui.support.action.swing.ActionList;
53 import com.eviware.soapui.support.components.JXToolBar;
54
55 /***
56 * The soapUI navigator tree
57 *
58 * @author Ole.Matzura
59 */
60
61 public class Navigator extends JPanel
62 {
63 private Workspace workspace;
64 private JTree mainTree;
65 private SoapUITreeModel treeModel;
66 private Set<NavigatorListener> listeners = new HashSet<NavigatorListener>();
67
68 public Navigator( Workspace workspace )
69 {
70 super( new BorderLayout() );
71 this.workspace = workspace;
72
73 buildUI();
74 }
75
76 private void buildUI()
77 {
78 treeModel = new SoapUITreeModel(workspace);
79
80 mainTree = new NavigatorTree( treeModel );
81 mainTree.setRootVisible(true);
82 mainTree.setExpandsSelectedPaths(true);
83 mainTree.setToggleClickCount( 0 );
84 mainTree.addMouseListener(new TreeMouseListener());
85 mainTree.addTreeSelectionListener(new InternalTreeSelectionListener());
86 mainTree.setCellRenderer( new SoapUITreeNodeRenderer() );
87 mainTree.setBorder(null);
88 mainTree.getSelectionModel().setSelectionMode( TreeSelectionModel.SINGLE_TREE_SELECTION );
89 mainTree.addKeyListener( new TreeKeyListener() );
90
91 ToolTipManager.sharedInstance().registerComponent(mainTree);
92
93 add( new JScrollPane( mainTree ), BorderLayout.CENTER );
94 add( buildToolbar(), BorderLayout.NORTH );
95 setBorder( BorderFactory.createEmptyBorder( 0, 0, 0, 0 ));
96 }
97
98 private Component buildToolbar()
99 {
100 JXToolBar toolbar = UISupport.createSmallToolbar();
101
102 JToggleButton toggleButton = new JToggleButton( new TogglePropertiesAction( ));
103 toggleButton.setToolTipText( "Toggles displaying of Test Properties in tree" );
104 toggleButton.setSize( 10, 12 );
105 toolbar.addFixed( toggleButton );
106 toolbar.addGlue();
107
108 return toolbar;
109 }
110
111 private static class NavigatorTree extends JTree implements Autoscroll
112 {
113 public NavigatorTree( SoapUITreeModel treeModel )
114 {
115 super( treeModel );
116 }
117
118 private static final int AUTOSCROLL_MARGIN = 12;
119
120 public void autoscroll( Point pt )
121 {
122
123 int nRow = getRowForLocation( pt.x, pt.y );
124
125
126 if( nRow < 0 )
127 return;
128
129 Rectangle raOuter = getBounds();
130
131
132
133
134
135 nRow = ( pt.y + raOuter.y <= AUTOSCROLL_MARGIN )
136
137 ? ( nRow <= 0 ? 0 : nRow - 1 )
138 : ( nRow < getRowCount() - 1 ? nRow + 1 : nRow );
139
140
141
142
143 scrollRowToVisible( nRow );
144 }
145
146
147
148 public Insets getAutoscrollInsets()
149 {
150 Rectangle raOuter = getBounds();
151 Rectangle raInner = getParent().getBounds();
152 return new Insets( raInner.y - raOuter.y + AUTOSCROLL_MARGIN, raInner.x - raOuter.x
153 + AUTOSCROLL_MARGIN, raOuter.height - raInner.height - raInner.y + raOuter.y
154 + AUTOSCROLL_MARGIN, raOuter.width - raInner.width - raInner.x + raOuter.x
155 + AUTOSCROLL_MARGIN );
156 }
157 }
158
159 public Project getCurrentProject()
160 {
161 TreePath path = mainTree.getSelectionPath();
162 if( path == null )
163 return null;
164
165 Object node = (Object) path.getLastPathComponent();
166 while (node != null && !(node instanceof ProjectTreeNode))
167 {
168 path = path.getParentPath();
169 node = (path == null ? null : path.getLastPathComponent());
170 }
171
172 if (node == null)
173 return null;
174
175 return ((ProjectTreeNode) node).getProject();
176 }
177
178 public void addNavigatorListener( NavigatorListener listener )
179 {
180 listeners.add( listener );
181 }
182
183 public void removeNavigatorListener( NavigatorListener listener )
184 {
185 listeners.remove( listener );
186 }
187
188 public void selectModelItem(ModelItem modelItem)
189 {
190 TreePath path = treeModel.getPath( modelItem );
191 mainTree.setSelectionPath( path );
192 mainTree.expandPath( path );
193 mainTree.scrollPathToVisible( path );
194 }
195
196 public TreePath getTreePath( ModelItem modelItem )
197 {
198 return treeModel.getPath( modelItem );
199 }
200
201 public JTree getMainTree()
202 {
203 return mainTree;
204 }
205
206 public ModelItem getSelectedItem()
207 {
208 TreePath path = mainTree.getSelectionPath();
209 if( path == null )
210 return null;
211
212 return ((SoapUITreeNode) path.getLastPathComponent()).getModelItem();
213 }
214
215 private final class TreeKeyListener extends KeyAdapter
216 {
217 public void keyPressed(KeyEvent e)
218 {
219 TreePath selectionPath = mainTree.getSelectionPath();
220 if( selectionPath != null )
221 {
222 SoapUITreeNode lastPathComponent = (SoapUITreeNode) selectionPath.getLastPathComponent();
223 ActionList actions = lastPathComponent.getActions();
224 if( actions != null )
225 {
226 actions.dispatchKeyEvent( e );
227 }
228
229 if( !e.isConsumed() )
230 {
231 KeyStroke ks = KeyStroke.getKeyStrokeForEvent( e );
232 if( ks.equals( UISupport.getKeyStroke( "alt C" )))
233 {
234 mainTree.collapsePath( selectionPath );
235 e.consume();
236 }
237 else if( ks.equals( UISupport.getKeyStroke( "alt E" )))
238 {
239 mainTree.collapsePath( selectionPath );
240 int row = mainTree.getSelectionRows()[0];
241 TreePath nextPath = mainTree.getPathForRow( row+1 );
242
243 TreePath path = mainTree.getPathForRow( row );
244 while( path != null && !path.equals( nextPath ))
245 {
246 mainTree.expandRow( row );
247 path = mainTree.getPathForRow( ++row );
248 }
249
250 e.consume();
251 }
252 }
253 }
254 }
255 }
256
257 public class InternalTreeSelectionListener implements TreeSelectionListener
258 {
259 public void valueChanged(TreeSelectionEvent e)
260 {
261 Object obj = e.getPath().getLastPathComponent();
262 if (obj instanceof SoapUITreeNode)
263 {
264 SoapUITreeNode treeNode = (SoapUITreeNode) obj;
265
266 if( !listeners.isEmpty() )
267 {
268 TreePath newPath = e.getNewLeadSelectionPath();
269 NavigatorListener[] array = listeners.toArray( new NavigatorListener[listeners.size()]);
270 for( NavigatorListener listener : array )
271 {
272 listener.nodeSelected( newPath == null ? null : treeNode );
273 }
274 }
275 }
276 }
277 }
278
279 public class TreeMouseListener extends MouseAdapter
280 {
281 public void mouseClicked(MouseEvent e)
282 {
283 if (e.isPopupTrigger())
284 showPopup(e);
285 else if (e.getClickCount() < 2)
286 return;
287 if (mainTree.getSelectionCount() != 1)
288 return;
289
290 int row = mainTree.getRowForLocation( e.getX(), e.getY() );
291 TreePath path = mainTree.getSelectionPath();
292 if( path == null && row == -1 )
293 return;
294
295 if( path == null || mainTree.getRowForPath( path ) != row )
296 mainTree.setSelectionRow( row );
297
298 SoapUITreeNode node = (SoapUITreeNode) path.getLastPathComponent();
299 ActionList actions = node.getActions();
300 if( actions != null )
301 actions.performDefaultAction( new ActionEvent( mainTree, 0, null ));
302 }
303
304 public void mousePressed(MouseEvent e)
305 {
306 if (e.isPopupTrigger())
307 showPopup(e);
308 }
309
310 public void mouseReleased(MouseEvent e)
311 {
312 if (e.isPopupTrigger())
313 showPopup(e);
314 }
315
316 private void showPopup(MouseEvent e)
317 {
318 TreePath path = mainTree.getPathForLocation((int) e.getPoint().getX(), (int) e.getPoint().getY());
319 if (path == null)
320 return;
321 SoapUITreeNode node = (SoapUITreeNode) path.getLastPathComponent();
322
323 JPopupMenu popupMenu = node.getPopup();
324 if (popupMenu == null)
325 return;
326
327 mainTree.setSelectionPath(path);
328
329 popupMenu.show(mainTree, e.getX(), e.getY());
330 }
331 }
332
333 public boolean isVisible( TreePath path )
334 {
335 return mainTree.isVisible( path );
336 }
337
338 public boolean isExpanded( TreePath path )
339 {
340 return mainTree.isExpanded( path );
341 }
342
343 private class TogglePropertiesAction extends AbstractAction
344 {
345 public TogglePropertiesAction()
346 {
347 putValue( SMALL_ICON, UISupport.createImageIcon( "/toggle_properties.gif" ));
348 }
349
350 public void actionPerformed( ActionEvent e )
351 {
352 Enumeration<TreePath> expandedDescendants = mainTree.getExpandedDescendants( getTreePath( workspace ) );
353 TreePath selectionPath = mainTree.getSelectionPath();
354
355 treeModel.setShowProperties( !treeModel.isShowProperties() );
356
357 while( expandedDescendants != null && expandedDescendants.hasMoreElements() )
358 {
359 mainTree.expandPath( expandedDescendants.nextElement() );
360 }
361
362 if( selectionPath != null )
363 mainTree.setSelectionPath( selectionPath );
364 }
365 }
366 }