1
2
3
4
5
6
7
8
9
10
11
12
13 package com.eviware.soapui.support.components;
14
15 import java.awt.BorderLayout;
16 import java.awt.Component;
17 import java.awt.event.ActionEvent;
18 import java.util.HashMap;
19 import java.util.Map;
20
21 import javax.swing.AbstractAction;
22 import javax.swing.AbstractListModel;
23 import javax.swing.BorderFactory;
24 import javax.swing.DefaultListCellRenderer;
25 import javax.swing.DefaultListModel;
26 import javax.swing.JComponent;
27 import javax.swing.JLabel;
28 import javax.swing.JList;
29 import javax.swing.JPanel;
30 import javax.swing.JPopupMenu;
31 import javax.swing.JScrollPane;
32 import javax.swing.SwingUtilities;
33 import javax.swing.event.ListDataEvent;
34 import javax.swing.event.ListSelectionEvent;
35 import javax.swing.event.ListSelectionListener;
36 import javax.swing.event.TreeModelEvent;
37 import javax.swing.event.TreeModelListener;
38 import javax.swing.tree.TreePath;
39
40 import com.eviware.soapui.SoapUI;
41 import com.eviware.soapui.model.ModelItem;
42 import com.eviware.soapui.model.tree.SoapUITreeNode;
43 import com.eviware.soapui.model.tree.nodes.support.EmptyModelItem;
44 import com.eviware.soapui.support.ListDataListenerAdapter;
45 import com.eviware.soapui.support.UISupport;
46 import com.eviware.soapui.support.swing.ModelItemListMouseListener;
47 import com.eviware.soapui.support.types.StringList;
48 import com.eviware.soapui.ui.support.DefaultDesktopPanel;
49
50 public class ModelItemListDesktopPanel extends DefaultDesktopPanel
51 {
52 private final ModelItem[] modelItems;
53 private JList list;
54 private ItemsListModel listModel;
55 private InternalTreeModelListener treeModelListener;
56 private Map<ModelItem, StringList> detailInfo = new HashMap<ModelItem, StringList>();
57 private JList detailList;
58 private DetailsListModel detailListModel;
59
60 public ModelItemListDesktopPanel( String title, String description, ModelItem[] modelItems )
61 {
62 super( title, description, new JPanel( new BorderLayout() ) );
63 this.modelItems = modelItems;
64
65 buildUI();
66
67 treeModelListener = new InternalTreeModelListener();
68 SoapUI.getNavigator().getMainTree().getModel().addTreeModelListener( treeModelListener );
69 }
70
71 public void addDetails( ModelItem modelItem, String details )
72 {
73 if( !detailInfo.containsKey( modelItem ) )
74 detailInfo.put( modelItem, new StringList() );
75
76 detailInfo.get( modelItem ).add( details );
77 }
78
79 private void buildUI()
80 {
81 JPanel p = ( JPanel )getComponent();
82
83 p.add( UISupport.buildDescription( getTitle(), getDescription(), null ), BorderLayout.NORTH );
84 p.add( buildModelItemList(), BorderLayout.CENTER );
85 }
86
87 @Override
88 public boolean onClose( boolean canCancel )
89 {
90 SoapUI.getNavigator().getMainTree().getModel().removeTreeModelListener( treeModelListener );
91 return super.onClose( canCancel );
92 }
93
94 private Component buildModelItemList()
95 {
96 listModel = new ItemsListModel( modelItems );
97
98 list = new JList( listModel );
99 list.setCellRenderer( new ItemListCellRenderer() );
100 ModelItemListMouseListener modelItemListMouseListener = new ModelItemListMouseListener();
101 JPopupMenu popupMenu = new JPopupMenu();
102 popupMenu.add( new RemoveAction() );
103 popupMenu.add( new HighlightAction() );
104
105 modelItemListMouseListener.setPopupMenu( popupMenu );
106 list.addMouseListener( modelItemListMouseListener );
107 listModel.addListDataListener( new ListDataListenerAdapter()
108 {
109
110 @Override
111 public void intervalRemoved( ListDataEvent e )
112 {
113 if( listModel.isEmpty() )
114 {
115 SwingUtilities.invokeLater( new Runnable()
116 {
117
118 public void run()
119 {
120 SoapUI.getDesktop().closeDesktopPanel( ModelItemListDesktopPanel.this );
121 }
122 } );
123 }
124 }
125 } );
126
127 list.addListSelectionListener( new ListSelectionListener()
128 {
129
130 public void valueChanged( ListSelectionEvent e )
131 {
132 detailListModel.refresh();
133 }
134 } );
135
136 JInspectorPanelImpl inspectorPanel = new JInspectorPanelImpl( new JScrollPane( list ) );
137 inspectorPanel.addInspector( new JComponentInspector<JComponent>( buildDetails(), "Details",
138 "Shows detailed information for the selected item", true ) );
139
140 return inspectorPanel;
141 }
142
143 private JComponent buildDetails()
144 {
145 detailListModel = new DetailsListModel();
146 detailList = new JList( detailListModel );
147 return new JScrollPane( detailList );
148 }
149
150 private class DetailsListModel extends AbstractListModel
151 {
152 public Object getElementAt( int index )
153 {
154 ModelItem modelItem = ( ModelItem )list.getSelectedValue();
155 if( modelItem == null || !detailInfo.containsKey( modelItem ) )
156 return null;
157 else
158 return detailInfo.get( modelItem ).get( index );
159 }
160
161 public void refresh()
162 {
163 fireContentsChanged( this, 0, getSize() - 1 );
164 }
165
166 public int getSize()
167 {
168 ModelItem modelItem = ( ModelItem )list.getSelectedValue();
169 if( modelItem == null || !detailInfo.containsKey( modelItem ) )
170 return 0;
171 else
172 return detailInfo.get( modelItem ).size();
173 }
174 }
175
176 private class ItemsListModel extends DefaultListModel
177 {
178 public ItemsListModel( ModelItem[] modelItems )
179 {
180 for( ModelItem item : modelItems )
181 addElement( item );
182 }
183
184 public void nodesChanged()
185 {
186 fireContentsChanged( this, 0, getSize() - 1 );
187 }
188 }
189
190 private class RemoveAction extends AbstractAction
191 {
192 public RemoveAction()
193 {
194 super( "Remove" );
195 putValue( SHORT_DESCRIPTION, "Removes this item from the list" );
196 }
197
198 public void actionPerformed( ActionEvent e )
199 {
200 int ix = list.getSelectedIndex();
201 if( ix != -1 && UISupport.confirm( "Remove selected item from list?", "Remove Item" ) )
202 listModel.remove( ix );
203 }
204 }
205
206 private class HighlightAction extends AbstractAction
207 {
208 public HighlightAction()
209 {
210 super( "Select in Tree" );
211 putValue( SHORT_DESCRIPTION, "Selects this node in the Navigator Tree" );
212 }
213
214 public void actionPerformed( ActionEvent e )
215 {
216 int ix = list.getSelectedIndex();
217 if( ix != -1 )
218 UISupport.select( ( ModelItem )listModel.getElementAt( ix ) );
219 }
220 }
221
222 private final class InternalTreeModelListener implements TreeModelListener
223 {
224 public void treeNodesChanged( TreeModelEvent e )
225 {
226 listModel.nodesChanged();
227 }
228
229 public void treeNodesInserted( TreeModelEvent e )
230 {
231 }
232
233 public void treeNodesRemoved( TreeModelEvent e )
234 {
235 SwingUtilities.invokeLater( new Runnable()
236 {
237
238 public void run()
239 {
240 for( int c = 0; c < listModel.getSize(); c++ )
241 {
242 if( SoapUI.getNavigator().getTreePath( ( ModelItem )listModel.elementAt( c ) ) == null )
243 {
244 listModel.remove( c );
245 c-- ;
246 }
247 }
248 }
249 } );
250 }
251
252 public void treeStructureChanged( TreeModelEvent e )
253 {
254 }
255 }
256
257 private class ItemListCellRenderer extends DefaultListCellRenderer
258 {
259 public Component getListCellRendererComponent( JList list, Object value, int index, boolean isSelected,
260 boolean cellHasFocus )
261 {
262 JLabel label = ( JLabel )super.getListCellRendererComponent( list, value, index, isSelected, cellHasFocus );
263
264 if( value instanceof ModelItem )
265 {
266 ModelItem item = ( ModelItem )value;
267 TreePath treePath = SoapUI.getNavigator().getTreePath( item );
268
269 if( treePath == null )
270 {
271 if( !( item instanceof EmptyModelItem ) )
272 {
273
274
275 }
276
277 label.setText( "<removed>" );
278 label.setToolTipText( null );
279 }
280 else
281 {
282 String str = item.getName() + " [";
283
284 for( int c = 1; c < treePath.getPathCount(); c++ )
285 {
286 SoapUITreeNode comp = ( SoapUITreeNode )treePath.getPathComponent( c );
287 if( comp.getModelItem() instanceof EmptyModelItem )
288 continue;
289
290 if( c > 1 )
291 str += " - ";
292
293 str += comp.toString();
294 }
295
296 str += "]";
297
298 label.setText( str );
299 label.setToolTipText( item.getDescription() );
300 }
301
302 label.setIcon( item.getIcon() );
303 label.setBorder( BorderFactory.createEmptyBorder( 2, 2, 2, 2 ) );
304 }
305
306 return label;
307 }
308 }
309 }