~ubuntu-branches/debian/stretch/insubstantial/stretch

« back to all changes in this revision

Viewing changes to flamingo/src/main/java/org/pushingpixels/flamingo/api/common/popup/JCommandPopupMenu.java

  • Committer: Package Import Robot
  • Author(s): Felix Natter
  • Date: 2016-01-18 20:58:45 UTC
  • Revision ID: package-import@ubuntu.com-20160118205845-crbmrkda61qsi5qa
Tags: upstream-7.3+dfsg2
ImportĀ upstreamĀ versionĀ 7.3+dfsg2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2005-2010 Flamingo Kirill Grouchnikov. All Rights Reserved.
 
3
 *
 
4
 * Redistribution and use in source and binary forms, with or without 
 
5
 * modification, are permitted provided that the following conditions are met:
 
6
 * 
 
7
 *  o Redistributions of source code must retain the above copyright notice, 
 
8
 *    this list of conditions and the following disclaimer. 
 
9
 *     
 
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. 
 
13
 *     
 
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. 
 
17
 *     
 
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. 
 
29
 */
 
30
package org.pushingpixels.flamingo.api.common.popup;
 
31
 
 
32
import java.awt.Component;
 
33
import java.util.ArrayList;
 
34
import java.util.Collections;
 
35
 
 
36
import javax.swing.*;
 
37
import javax.swing.JPopupMenu.Separator;
 
38
import javax.swing.event.ChangeEvent;
 
39
import javax.swing.event.ChangeListener;
 
40
 
 
41
import org.pushingpixels.flamingo.api.common.*;
 
42
import org.pushingpixels.flamingo.internal.ui.common.popup.BasicCommandPopupMenuUI;
 
43
import org.pushingpixels.flamingo.internal.ui.common.popup.PopupPanelUI;
 
44
 
 
45
/**
 
46
 * Popup menu. Can host any number of command menu buttons added with
 
47
 * {@link #addMenuButton(JCommandMenuButton)} separated with optional
 
48
 * {@link #addMenuSeparator()}. The
 
49
 * {@link #JCommandPopupMenu(JCommandButtonPanel, int, int)} constructor allows
 
50
 * placing a scrollable command button panel in the top part of the popup menu.
 
51
 * 
 
52
 * @author Kirill Grouchnikov
 
53
 */
 
54
public class JCommandPopupMenu extends JPopupPanel {
 
55
        /**
 
56
         * @see #getUIClassID
 
57
         */
 
58
        public static final String uiClassID = "CommandPopupMenuUI";
 
59
 
 
60
        /**
 
61
         * The main button panel. Can be <code>null</code> if this command popup
 
62
         * menu was created with the {@link #JCommandPopupMenu()} constructor.
 
63
         * 
 
64
         * @see #JCommandPopupMenu(JCommandButtonPanel, int, int)
 
65
         * @see #hasCommandButtonPanel()
 
66
         * @see #getMainButtonPanel()
 
67
         */
 
68
        protected JCommandButtonPanel mainButtonPanel;
 
69
 
 
70
        /**
 
71
         * Menu components. This list holds:
 
72
         * <ul>
 
73
         * <li>{@link JCommandMenuButton}s added with
 
74
         * {@link #addMenuButton(JCommandMenuButton)}</li>
 
75
         * <li>{@link JCommandToggleMenuButton}s added with
 
76
         * {@link #addMenuButton(JCommandToggleMenuButton)}</li>
 
77
         * <li>{@link Separator}s added with {@link #addMenuSeparator()}</li>
 
78
         * <li>{@link JPanel}s added by the subclasses with
 
79
         * {@link #addMenuPanel(JPanel)}</li>
 
80
         * </ul>
 
81
         * 
 
82
         * @see #addMenuButton(JCommandMenuButton)
 
83
         * @see #addMenuButton(JCommandToggleMenuButton)
 
84
         * @see #addMenuSeparator()
 
85
         * @see #addMenuPanel(JPanel)
 
86
         * @see #getMenuComponents()
 
87
         */
 
88
        protected java.util.List<Component> menuComponents;
 
89
 
 
90
        /**
 
91
         * Maximum number of button columns visible in the {@link #mainButtonPanel}.
 
92
         * 
 
93
         * @see #JCommandPopupMenu(JCommandButtonPanel, int, int)
 
94
         * @see #getMaxButtonColumns()
 
95
         */
 
96
        protected int maxButtonColumns;
 
97
 
 
98
        /**
 
99
         * Maximum number of button rows visible in the {@link #mainButtonPanel}.
 
100
         * 
 
101
         * @see #JCommandPopupMenu(JCommandButtonPanel, int, int)
 
102
         * @see #getMaxVisibleButtonRows()
 
103
         */
 
104
        protected int maxVisibleButtonRows;
 
105
 
 
106
        /**
 
107
         * Maximum number of menu items visible in this menu. If more buttons are
 
108
         * added with the {@link #addMenuButton(JCommandMenuButton)} and
 
109
         * {@link #addMenuButton(JCommandToggleMenuButton)} APIs, the menu part will
 
110
         * show scroller buttons above the first and below the last menu button. If
 
111
         * the value is negative, there is no limitation on how many menu buttons
 
112
         * are shown, and the entire popup menu can overflow the monitor edges.
 
113
         */
 
114
        protected int maxVisibleMenuButtons;
 
115
 
 
116
        private boolean toDismissOnChildClick;
 
117
 
 
118
        /**
 
119
         * Creates an empty popup menu with no button panel.
 
120
         */
 
121
        public JCommandPopupMenu() {
 
122
                this.menuComponents = new ArrayList<Component>();
 
123
 
 
124
                this.maxVisibleMenuButtons = -1;
 
125
                this.toDismissOnChildClick = true;
 
126
        }
 
127
 
 
128
        /**
 
129
         * Creates a popup menu hosting the specified button panel.
 
130
         * 
 
131
         * @param buttonPanel
 
132
         *            Fully constructed button panel.
 
133
         * @param maxButtonColumns
 
134
         *            Maximum number of button columns visible in
 
135
         *            <code>buttonPanel</code>.
 
136
         * @param maxVisibleButtonRows
 
137
         *            Maximum number of button rows visible in
 
138
         *            <code>buttonPanel</code>.
 
139
         */
 
140
        public JCommandPopupMenu(JCommandButtonPanel buttonPanel,
 
141
                        int maxButtonColumns, int maxVisibleButtonRows) {
 
142
                this();
 
143
 
 
144
                this.mainButtonPanel = buttonPanel;
 
145
                this.maxButtonColumns = maxButtonColumns;
 
146
                this.maxVisibleButtonRows = maxVisibleButtonRows;
 
147
 
 
148
                this.updateUI();
 
149
        }
 
150
 
 
151
        /**
 
152
         * Adds the specified menu button to this menu.
 
153
         * 
 
154
         * @param menuButton
 
155
         *            Menu button to add.
 
156
         */
 
157
        public void addMenuButton(JCommandMenuButton menuButton) {
 
158
                menuButton.setHorizontalAlignment(SwingUtilities.LEFT);
 
159
                this.menuComponents.add(menuButton);
 
160
                this.fireStateChanged();
 
161
        }
 
162
 
 
163
        /**
 
164
         * Adds the specified toggle menu button to this menu.
 
165
         * 
 
166
         * @param menuButton
 
167
         *            Menu button to add.
 
168
         */
 
169
        public void addMenuButton(JCommandToggleMenuButton menuButton) {
 
170
                menuButton.setHorizontalAlignment(SwingUtilities.LEFT);
 
171
                this.menuComponents.add(menuButton);
 
172
                this.fireStateChanged();
 
173
        }
 
174
 
 
175
        /**
 
176
         * Adds a menu separator to this menu.
 
177
         */
 
178
        public void addMenuSeparator() {
 
179
                this.menuComponents.add(new JPopupMenu.Separator());
 
180
                this.fireStateChanged();
 
181
        }
 
182
 
 
183
        /**
 
184
         * Adds a menu panel to this menu.
 
185
         * 
 
186
         * @param menuPanel
 
187
         *            Menu panel to add.
 
188
         */
 
189
        protected void addMenuPanel(JPanel menuPanel) {
 
190
                if (this.maxVisibleMenuButtons > 0) {
 
191
                        throw new IllegalStateException(
 
192
                                        "This method is not supported on menu that contains a command button panel");
 
193
                }
 
194
                this.menuComponents.add(menuPanel);
 
195
                this.fireStateChanged();
 
196
        }
 
197
 
 
198
        /**
 
199
         * Returns indication whether this menu has a command button panel.
 
200
         * 
 
201
         * @return <code>true</code> if this menu has a command button panel,
 
202
         *         <code>false</code> otherwise.
 
203
         * @see #getMainButtonPanel()
 
204
         */
 
205
        public boolean hasCommandButtonPanel() {
 
206
                return (this.mainButtonPanel != null);
 
207
        }
 
208
 
 
209
        /**
 
210
         * Returns the command button panel of this menu. Can return
 
211
         * <code>null</code>.
 
212
         * 
 
213
         * @return The command button panel of this menu.
 
214
         * @see #hasCommandButtonPanel()
 
215
         */
 
216
        public JCommandButtonPanel getMainButtonPanel() {
 
217
                return this.mainButtonPanel;
 
218
        }
 
219
 
 
220
        /**
 
221
         * Returns an unmodifiable list of all the menu components. Can return
 
222
         * <code>null</code>.
 
223
         * 
 
224
         * @return An unmodifiable list of all the menu components
 
225
         */
 
226
        public java.util.List<Component> getMenuComponents() {
 
227
                if (this.menuComponents == null)
 
228
                        return null;
 
229
                return Collections.unmodifiableList(this.menuComponents);
 
230
        }
 
231
 
 
232
        /**
 
233
         * Returns the maximum number of button columns visible in the command
 
234
         * button panel of this menu. If this menu has been created with the
 
235
         * {@link #JCommandPopupMenu()} constructor, zero is returned.
 
236
         * 
 
237
         * @return The maximum number of button columns visible in the command
 
238
         *         button panel of this menu.
 
239
         * @see #JCommandPopupMenu(JCommandButtonPanel, int, int)
 
240
         * @see #getMaxVisibleButtonRows()
 
241
         */
 
242
        public int getMaxButtonColumns() {
 
243
                return this.maxButtonColumns;
 
244
        }
 
245
 
 
246
        /**
 
247
         * Returns the maximum number of button rows visible in the command button
 
248
         * panel of this menu. If this menu has been created with the
 
249
         * {@link #JCommandPopupMenu()} constructor, zero is returned.
 
250
         * 
 
251
         * @return The maximum number of button rows visible in the command button
 
252
         *         panel of this menu.
 
253
         * @see #JCommandPopupMenu(JCommandButtonPanel, int, int)
 
254
         * @see #getMaxButtonColumns()
 
255
         */
 
256
        public int getMaxVisibleButtonRows() {
 
257
                return this.maxVisibleButtonRows;
 
258
        }
 
259
 
 
260
        /**
 
261
         * Returns the maximum number of menu items visible in this menu.
 
262
         * 
 
263
         * @return The maximum number of menu items visible in this menu. If the
 
264
         *         value is negative, there is no limitation on how many menu
 
265
         *         buttons are shown, and the entire popup menu can overflow the
 
266
         *         monitor edges.
 
267
         */
 
268
        public int getMaxVisibleMenuButtons() {
 
269
                return this.maxVisibleMenuButtons;
 
270
        }
 
271
 
 
272
        /**
 
273
         * Sets the maximum number of menu items visible in this menu. If the value
 
274
         * is negative, there is no limitation on how many menu buttons are shown,
 
275
         * and the entire popup menu can overflow the monitor edges.
 
276
         * 
 
277
         * @param maxVisibleMenuButtons
 
278
         *            The new value for the maximum number of menu items visible in
 
279
         *            this menu.
 
280
         */
 
281
        public void setMaxVisibleMenuButtons(int maxVisibleMenuButtons) {
 
282
                for (Component menuComp : this.menuComponents) {
 
283
                        if (menuComp instanceof JPanel) {
 
284
                                throw new IllegalStateException(
 
285
                                                "This method is not supported on menus with panels");
 
286
                        }
 
287
                }
 
288
 
 
289
                int old = this.maxVisibleMenuButtons;
 
290
                this.maxVisibleMenuButtons = maxVisibleMenuButtons;
 
291
 
 
292
                if (old != this.maxVisibleMenuButtons) {
 
293
                        this.firePropertyChange("maxVisibleMenuButtons", old,
 
294
                                        this.maxVisibleMenuButtons);
 
295
                }
 
296
        }
 
297
 
 
298
        @Override
 
299
        public String getUIClassID() {
 
300
                return uiClassID;
 
301
        }
 
302
 
 
303
        @Override
 
304
        public void updateUI() {
 
305
                if (UIManager.get(getUIClassID()) != null) {
 
306
                        setUI((PopupPanelUI) UIManager.getUI(this));
 
307
                } else {
 
308
                        setUI(BasicCommandPopupMenuUI.createUI(this));
 
309
                }
 
310
        }
 
311
 
 
312
        /**
 
313
         * Adds the specified change listener to track changes to this popup menu.
 
314
         * 
 
315
         * @param l
 
316
         *            Change listener to add.
 
317
         * @see #removeChangeListener(ChangeListener)
 
318
         */
 
319
        public void addChangeListener(ChangeListener l) {
 
320
                this.listenerList.add(ChangeListener.class, l);
 
321
        }
 
322
 
 
323
        /**
 
324
         * Removes the specified change listener from tracking changes to this popup
 
325
         * menu.
 
326
         * 
 
327
         * @param l
 
328
         *            Change listener to remove.
 
329
         * @see #addChangeListener(ChangeListener)
 
330
         */
 
331
        public void removeChangeListener(ChangeListener l) {
 
332
                this.listenerList.remove(ChangeListener.class, l);
 
333
        }
 
334
 
 
335
        /**
 
336
         * Notifies all registered listener that the state of this popup menu has
 
337
         * changed.
 
338
         */
 
339
        protected void fireStateChanged() {
 
340
                // Guaranteed to return a non-null array
 
341
                Object[] listeners = this.listenerList.getListenerList();
 
342
                // Process the listeners last to first, notifying
 
343
                // those that are interested in this event
 
344
                ChangeEvent event = new ChangeEvent(this);
 
345
                for (int i = listeners.length - 2; i >= 0; i -= 2) {
 
346
                        if (listeners[i] == ChangeListener.class) {
 
347
                                ((ChangeListener) listeners[i + 1]).stateChanged(event);
 
348
                        }
 
349
                }
 
350
        }
 
351
 
 
352
        public boolean isToDismissOnChildClick() {
 
353
                return toDismissOnChildClick;
 
354
        }
 
355
 
 
356
        public void setToDismissOnChildClick(boolean toDismissOnChildClick) {
 
357
                this.toDismissOnChildClick = toDismissOnChildClick;
 
358
        }
 
359
}