1 package com.eviware.soapui.support.propertyexpansion.scrollmenu;
2
3 import java.awt.Component;
4 import java.awt.Dimension;
5 import java.awt.event.ActionEvent;
6 import java.awt.event.ActionListener;
7 import java.awt.event.MouseAdapter;
8 import java.awt.event.MouseEvent;
9 import java.awt.event.MouseListener;
10 import java.util.Vector;
11
12 import javax.swing.Action;
13 import javax.swing.JButton;
14 import javax.swing.JComponent;
15 import javax.swing.JMenuItem;
16 import javax.swing.JPopupMenu;
17 import javax.swing.JSeparator;
18 import javax.swing.Timer;
19
20 import com.eviware.soapui.support.UISupport;
21
22 /***
23 * JMenu with the scrolling feature.
24 */
25 public class ScrollablePopup extends JPopupMenu implements ScrollableMenuContainer
26 {
27 /*** How fast the scrolling will happen. */
28 private int scrollSpeed = 20;
29 /*** Handles the scrolling upwards. */
30 private Timer timerUp;
31 /*** Handles the scrolling downwards. */
32 private Timer timerDown;
33 /*** How many items are visible. */
34 private int visibleItems;
35 /***
36 * Menuitem's index which is used to control if up and downbutton are visible
37 * or not.
38 */
39 private int indexVisible = 0;
40 /*** Button to scroll menu upwards. */
41 private JButton upButton;
42 /*** Button to scroll menu downwards. */
43 private JButton downButton;
44 /*** Container to hold submenus. */
45 private Vector<JMenuItem> subMenus = new Vector<JMenuItem>();
46 /*** Height of the screen. */
47 private double screenHeight;
48 /*** Height of the menu. */
49 private double menuHeight;
50 private int headerCount;
51 private int footerCount;
52
53 /***
54 * Creates a new ScrollableMenu object with a given name.
55 * <p>
56 * This also instantiates the timers and buttons. After the buttons are
57 * created they are set invisible.
58 *
59 * @param name
60 * name to be displayed on the JMenu
61 */
62 public ScrollablePopup( String name )
63 {
64 super( name );
65
66 timerUp = new Timer( scrollSpeed, new ActionListener()
67 {
68 public void actionPerformed( ActionEvent evt )
69 {
70 scrollUp();
71 }
72 } );
73 timerDown = new Timer( scrollSpeed, new ActionListener()
74 {
75 public void actionPerformed( ActionEvent evt )
76 {
77 scrollDown();
78 }
79 } );
80
81 screenHeight = 400;
82 createButtons();
83 hideButtons();
84 }
85
86 /***
87 * JMenu's add-method is override to keep track of the added items. If there
88 * are more items that JMenu can display, then the added menuitems will be
89 * invisible. After that downscrolling button will be visible.
90 *
91 * @param menuItem
92 * to be added
93 *
94 * @return added menuitem
95 */
96 public JMenuItem add( JMenuItem menuItem )
97 {
98 add( menuItem, subMenus.size() + headerCount + 1 + ( headerCount == 0 ? 0 : 1 ) );
99 subMenus.add( menuItem );
100
101 menuHeight += menuItem.getPreferredSize().getHeight();
102
103 if( menuHeight > screenHeight )
104 {
105 menuItem.setVisible( false );
106 downButton.setVisible( true );
107 }
108 else
109 {
110 visibleItems++ ;
111 }
112
113 return menuItem;
114 }
115
116 public Component add( Component comp )
117 {
118 if( comp instanceof JMenuItem )
119 return add( ( JMenuItem )comp );
120 else
121 return super.add( comp );
122 }
123
124 public void removeAll()
125 {
126 super.removeAll();
127
128 headerCount = 0;
129 footerCount = 0;
130 menuHeight = 0;
131 indexVisible = 0;
132 visibleItems = 0;
133
134 subMenus.clear();
135
136 add( upButton );
137 add( downButton );
138 }
139
140 /***
141 * When timerUp is started it calls constantly this method to make the JMenu
142 * scroll upwards. When the top of menu is reached then upButton is set
143 * invisible. When scrollUp starts downButton is setVisible.
144 */
145 private void scrollUp()
146 {
147
148
149 if( indexVisible == 0 )
150 {
151 upButton.setVisible( false );
152
153 return;
154 }
155 else
156 {
157 indexVisible-- ;
158 ( ( JComponent )subMenus.get( indexVisible + visibleItems ) ).setVisible( false );
159 ( ( JComponent )subMenus.get( indexVisible ) ).setVisible( true );
160 downButton.setVisible( true );
161 if( indexVisible == 0 )
162 {
163 upButton.setVisible( false );
164 }
165 }
166 }
167
168 /***
169 * When timerDown is started it calls constantly this method to make the
170 * JMenu scroll downwards. When the bottom of menu is reached then downButton
171 * is set invisible. When scrolldown starts upButton is setVisible.
172 */
173 private void scrollDown()
174 {
175
176
177 if( ( indexVisible + visibleItems ) == subMenus.size() )
178 {
179 downButton.setVisible( false );
180
181 return;
182 }
183 else if( ( indexVisible + visibleItems ) > subMenus.size() )
184 {
185 return;
186 }
187 else
188 {
189 try
190 {
191 ( ( JComponent )subMenus.get( indexVisible ) ).setVisible( false );
192 ( ( JComponent )subMenus.get( indexVisible + visibleItems ) ).setVisible( true );
193 upButton.setVisible( true );
194 indexVisible++ ;
195 if( ( indexVisible + visibleItems ) == subMenus.size() )
196 {
197 downButton.setVisible( false );
198 }
199 }
200 catch( Exception eks )
201 {
202 eks.printStackTrace();
203 }
204 }
205 }
206
207 /***
208 * Creates two button: upButton and downButton.
209 */
210 private void createButtons()
211 {
212 upButton = new JButton( UISupport.createImageIcon( "/up_arrow.gif" ) );
213
214 Dimension d = new Dimension( 100, 20 );
215 upButton.setPreferredSize( d );
216 upButton.setBorderPainted( false );
217 upButton.setFocusPainted( false );
218 upButton.setRolloverEnabled( true );
219
220 class Up extends MouseAdapter
221 {
222 /***
223 * When mouse enters over the upbutton, timerUp starts the scrolling
224 * upwards.
225 *
226 * @param e
227 * MouseEvent
228 */
229 public void mouseEntered( MouseEvent e )
230 {
231 try
232 {
233 timerUp.start();
234 }
235 catch( Exception ekas )
236 {
237 }
238 }
239
240 /***
241 * When mouse exites the upbutton, timerUp stops.
242 *
243 * @param e
244 * MouseEvent
245 */
246 public void mouseExited( MouseEvent e )
247 {
248 try
249 {
250 timerUp.stop();
251 }
252 catch( Exception ekas )
253 {
254 }
255 }
256 }
257
258 MouseListener scrollUpListener = new Up();
259 upButton.addMouseListener( scrollUpListener );
260
261 add( upButton );
262 downButton = new JButton( UISupport.createImageIcon( "/down_arrow.gif" ) );
263 downButton.setPreferredSize( d );
264 downButton.setBorderPainted( false );
265 downButton.setFocusPainted( false );
266
267 class Down extends MouseAdapter
268 {
269 /***
270 * When mouse enters over the downbutton, timerDown starts the
271 * scrolling downwards.
272 *
273 * @param e
274 * MouseEvent
275 */
276 public void mouseEntered( MouseEvent e )
277 {
278 try
279 {
280 timerDown.start();
281 }
282 catch( Exception ekas )
283 {
284 }
285 }
286
287 /***
288 * When mouse exites the downbutton, timerDown stops.
289 *
290 * @param e
291 * MouseEvent
292 */
293 public void mouseExited( MouseEvent e )
294 {
295 try
296 {
297 timerDown.stop();
298 }
299 catch( Exception ekas )
300 {
301 }
302 }
303 }
304
305 MouseListener scrollDownListener = new Down();
306 downButton.addMouseListener( scrollDownListener );
307 add( downButton, 1 + subMenus.size() );
308 }
309
310 /***
311 * Hides the scrollButtons.
312 */
313 public void hideButtons()
314 {
315 upButton.setVisible( false );
316 downButton.setVisible( false );
317 }
318
319 public JMenuItem addHeader( JMenuItem header )
320 {
321 add( header, headerCount );
322
323 if( ++headerCount == 1 )
324 add( new JSeparator(), 1 );
325
326 return header;
327 }
328
329 public JMenuItem addHeader( Action action )
330 {
331 return addHeader( new JMenuItem( action ) );
332 }
333
334 public JMenuItem addFooter( JMenuItem footer )
335 {
336 if( footerCount == 0 )
337 add( new JSeparator(), subMenus.size() + headerCount + 2 + ( headerCount == 0 ? 0 : 1 ) );
338
339 add( footer, subMenus.size() + headerCount + footerCount + 3 + ( headerCount == 0 ? 0 : 1 ) );
340 footerCount++ ;
341
342 return footer;
343 }
344
345 public JMenuItem addFooter( Action action )
346 {
347 return addFooter( new JMenuItem( action ) );
348 }
349 }