2
* Copyright (c) 2005-2010 Flamingo Kirill Grouchnikov. All Rights Reserved.
4
* Redistribution and use in source and binary forms, with or without
5
* modification, are permitted provided that the following conditions are met:
7
* o Redistributions of source code must retain the above copyright notice,
8
* this list of conditions and the following disclaimer.
10
* o Redistributions in binary form must reproduce the above copyright notice,
11
* this list of conditions and the following disclaimer in the documentation
12
* and/or other materials provided with the distribution.
14
* o Neither the name of Flamingo Kirill Grouchnikov nor the names of
15
* its contributors may be used to endorse or promote products derived
16
* from this software without specific prior written permission.
18
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
22
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
27
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
package org.pushingpixels.flamingo.api.common.popup;
32
import java.awt.Component;
33
import java.awt.event.ComponentEvent;
36
import javax.swing.JComponent;
37
import javax.swing.Popup;
38
import javax.swing.event.EventListenerList;
40
import org.pushingpixels.flamingo.api.common.JCommandButton;
43
* Manager for showing and hiding {@link JPopupPanel}s.
45
* @author Kirill Grouchnikov
47
public class PopupPanelManager {
49
* Listener on showing and hiding the popup panels.
51
* @author Kirill Grouchnikov
53
public static interface PopupListener extends EventListener {
55
* Fired when a popup panel has been shown.
60
void popupShown(PopupEvent event);
63
* Fired when a popup panel has been hidden.
68
void popupHidden(PopupEvent event);
74
* @author Kirill Grouchnikov
76
public static class PopupEvent extends ComponentEvent {
78
* ID of "popup shown" event.
80
public static final int POPUP_SHOWN = 100;
83
* ID of "popup hidden" event.
85
public static final int POPUP_HIDDEN = 101;
88
* The popup originator component.
90
private JComponent popupOriginator;
93
* Creates a new popup event.
99
* @param popupOriginator
100
* Popup originator component.
102
public PopupEvent(JPopupPanel source, int id, JComponent popupOriginator) {
104
this.popupOriginator = popupOriginator;
108
* Returns the popup originator component.
110
* @return Popup originator component.
112
public JComponent getPopupOriginator() {
113
return this.popupOriginator;
118
* List of all registered listeners.
120
protected EventListenerList listenerList = new EventListenerList();
123
* The singleton instance of popup panel manager.
125
private static final PopupPanelManager instance = new PopupPanelManager();
128
* Information on a single showing popup.
130
* @author Kirill Grouchnikov
132
public static class PopupInfo {
136
private JPopupPanel popupPanel;
139
* The originating component.
141
private JComponent popupOriginator;
144
* Creates a new information object.
146
* @param popupOriginator
147
* The originating component.
151
public PopupInfo(JComponent popupOriginator, JPopupPanel popupPanel) {
152
this.popupOriginator = popupOriginator;
153
this.popupPanel = popupPanel;
157
* Returns the popup panel.
159
* @return The popup panel.
161
public JPopupPanel getPopupPanel() {
162
return this.popupPanel;
166
* Returns the originating component.
168
* @return The originating component.
170
public JComponent getPopupOriginator() {
171
return this.popupOriginator;
176
* Returns the default popup panel manager.
178
* @return a PopupPanelManager object
180
public static PopupPanelManager defaultManager() {
185
* All currently shown popup panels.
187
protected LinkedList<PopupInfo> shownPath = new LinkedList<PopupInfo>();
190
* Map of all popup panels and associated {@link Popup} objects.
192
protected Map<JPopupPanel, Popup> popupPanels = new HashMap<JPopupPanel, Popup>();
195
* Adds new popup to the tracking structures.
197
* @param popupOriginator
198
* The originating component.
201
* @param popupInitiator
202
* The initiator of the popup.
204
public void addPopup(JComponent popupOriginator, Popup popup,
205
JPopupPanel popupInitiator) {
206
popupPanels.put(popupInitiator, popup);
207
shownPath.addLast(new PopupInfo(popupOriginator, popupInitiator));
209
if (popupOriginator instanceof JCommandButton) {
210
((JCommandButton) popupOriginator).getPopupModel().setPopupShowing(
213
this.firePopupShown(popupInitiator, popupOriginator);
217
* Hides the last shown popup panel.
219
public void hideLastPopup() {
220
if (shownPath.size() == 0)
222
PopupInfo last = shownPath.removeLast();
223
Popup popup = popupPanels.get(last.popupPanel);
225
popupPanels.remove(last.popupPanel);
226
if (last.popupOriginator instanceof JCommandButton) {
227
((JCommandButton) last.popupOriginator).getPopupModel()
228
.setPopupShowing(false);
231
// KeyTipManager.defaultManager().showChainBefore(last.popupPanel);
232
this.firePopupHidden(last.popupPanel, last.popupOriginator);
236
* Hides all popup panels based on the specified component. We find the
237
* first ancestor of the specified component that is popup panel, and close
238
* all popup panels that were open from that popup panel. If the specified
239
* component is <code>null</code>, all popup panels are closed.
244
public void hidePopups(Component comp) {
245
// System.out.println("Hiding all popups");
247
// throw new Exception();
249
// catch (Exception exc) {
250
// exc.printStackTrace(System.out);
251
// System.out.println("At " + System.currentTimeMillis() + "\n");
253
boolean foundAndDismissed = false;
256
// find JPopupGallery parent of the component
258
if (c instanceof JPopupPanel) {
259
foundAndDismissed = true;
260
// And close all popups that were opened
261
// from the found popup panel
262
while (shownPath.size() > 0) {
263
if (shownPath.getLast().popupPanel == c)
265
PopupInfo last = shownPath.removeLast();
266
Popup popup = popupPanels.get(last.popupPanel);
268
if (last.popupOriginator instanceof JCommandButton) {
269
((JCommandButton) last.popupOriginator)
270
.getPopupModel().setPopupShowing(false);
272
this.firePopupHidden(last.popupPanel,
273
last.popupOriginator);
274
popupPanels.remove(last.popupPanel);
280
if (!foundAndDismissed || (comp == null)) {
281
while (shownPath.size() > 0) {
282
PopupInfo last = shownPath.removeLast();
283
Popup popup = popupPanels.get(last.popupPanel);
285
if (last.popupOriginator instanceof JCommandButton) {
286
((JCommandButton) last.popupOriginator).getPopupModel()
287
.setPopupShowing(false);
289
this.firePopupHidden(last.popupPanel, last.popupOriginator);
290
popupPanels.remove(last.popupPanel);
296
* Returns all currently shown popup panels.
298
* @return All currently shown popup panels.
300
public List<PopupInfo> getShownPath() {
301
List<PopupInfo> toReturn = new ArrayList<PopupInfo>();
302
for (PopupInfo pInfo : this.shownPath)
308
* Adds the specified popup listener.
313
public void addPopupListener(PopupListener l) {
314
this.listenerList.add(PopupListener.class, l);
318
* Removes the specified popup listener.
321
* Listener to remove.
323
public void removePopupListener(PopupListener l) {
324
this.listenerList.remove(PopupListener.class, l);
328
* Fires an event on showing the specified popup panel.
331
* Popup panel that was shown.
332
* @param popupOriginator
333
* The originating component.
335
protected void firePopupShown(JPopupPanel panel, JComponent popupOriginator) {
336
// Guaranteed to return a non-null array
337
Object[] listeners = listenerList.getListenerList();
338
PopupEvent popupEvent = new PopupEvent(panel, PopupEvent.POPUP_SHOWN,
340
// Process the listeners last to first, notifying
341
// those that are interested in this event
342
for (int i = listeners.length - 2; i >= 0; i -= 2) {
343
if (listeners[i] == PopupListener.class) {
344
((PopupListener) listeners[i + 1]).popupShown(popupEvent);
350
* Fires an event on hiding the specified popup panel.
353
* Popup panel that was hidden.
354
* @param popupOriginator
355
* The originating component.
357
protected void firePopupHidden(JPopupPanel panel, JComponent popupOriginator) {
358
// Guaranteed to return a non-null array
359
Object[] listeners = listenerList.getListenerList();
360
PopupEvent popupEvent = new PopupEvent(panel, PopupEvent.POPUP_HIDDEN,
362
// Process the listeners last to first, notifying
363
// those that are interested in this event
364
for (int i = listeners.length - 2; i >= 0; i -= 2) {
365
if (listeners[i] == PopupListener.class) {
366
((PopupListener) listeners[i + 1]).popupHidden(popupEvent);