2
* Copyright (c) 2005-2010 Substance 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 Substance 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.substance.internal.utils.combo;
32
import java.awt.Component;
33
import java.awt.Dimension;
34
import java.awt.GraphicsConfiguration;
35
import java.awt.Insets;
36
import java.awt.Point;
37
import java.awt.Rectangle;
38
import java.awt.Toolkit;
40
import javax.swing.JComboBox;
41
import javax.swing.JScrollBar;
42
import javax.swing.ListCellRenderer;
43
import javax.swing.SwingConstants;
44
import javax.swing.SwingUtilities;
45
import javax.swing.plaf.basic.BasicComboPopup;
47
import org.pushingpixels.substance.internal.ui.SubstanceListUI;
48
import org.pushingpixels.substance.internal.utils.SubstanceCoreUtilities;
49
import org.pushingpixels.substance.internal.utils.border.SubstanceBorder;
52
* Combo popup implementation in <b>Substance</b> look-and-feel. This class is
53
* <b>for internal use only</b>.
55
* @author Kirill Grouchnikov
57
public class SubstanceComboPopup extends BasicComboPopup {
60
* Creates combo popup for the specified combobox.
65
public SubstanceComboPopup(JComboBox combo) {
69
this.list.setBackground(combo.getBackground());
75
* @see javax.swing.plaf.basic.BasicComboPopup#configurePopup()
78
protected void configurePopup() {
79
super.configurePopup();
80
setBorder(new SubstanceBorder(new Insets(0, 2, 2, 2)));
84
* Sets the list selection index to the selectedIndex. This method is used
85
* to synchronize the list selection with the combo box selection.
87
* @param selectedIndex
88
* the index to set the list
90
private void setListSelection(int selectedIndex) {
91
if (selectedIndex == -1) {
92
this.list.clearSelection();
94
this.list.setSelectedIndex(selectedIndex);
95
this.list.ensureIndexIsVisible(selectedIndex);
100
* Calculates the upper left location of the popup.
102
* @return The upper left location of the popup.
104
private Point getPopupLocation() {
105
Dimension popupSize = this.comboBox.getSize();
106
Insets insets = this.getInsets();
108
// reduce the width of the scrollpane by the insets so that the popup
109
// is the same width as the combo box.
110
popupSize.setSize(popupSize.width - (insets.right + insets.left), this
111
.getPopupHeightForRowCount(this.comboBox.getMaximumRowCount()));
112
Rectangle popupBounds = this.computePopupBounds(0, this.comboBox
113
.getBounds().height, popupSize.width, popupSize.height);
114
Dimension scrollSize = popupBounds.getSize();
115
Point popupLocation = popupBounds.getLocation();
117
this.scroller.setMaximumSize(scrollSize);
118
this.scroller.setPreferredSize(scrollSize);
119
this.scroller.setMinimumSize(scrollSize);
121
this.list.revalidate();
123
return new Point(popupLocation.x, popupLocation.y);
129
* @see javax.swing.plaf.basic.BasicComboPopup#computePopupBounds(int, int,
133
protected Rectangle computePopupBounds(int px, int py, int pw, int ph) {
134
int popupFlyoutOrientation = SubstanceCoreUtilities
135
.getPopupFlyoutOrientation(this.comboBox);
136
Insets insets = this.getInsets();
139
switch (popupFlyoutOrientation) {
140
case SwingConstants.NORTH:
141
dy = -ph - (int) this.comboBox.getSize().getHeight() - insets.top
144
case SwingConstants.CENTER:
145
dy = -ph / 2 - (int) this.comboBox.getSize().getHeight() / 2
146
- insets.top / 2 - insets.bottom / 2;
148
case SwingConstants.EAST:
149
dx = pw + insets.left + insets.right;
150
dy = -(int) this.comboBox.getSize().getHeight();
152
case SwingConstants.WEST:
153
dx = -pw - insets.left - insets.right;
154
dy = -(int) this.comboBox.getSize().getHeight();
156
Toolkit toolkit = Toolkit.getDefaultToolkit();
157
Rectangle screenBounds;
159
// Calculate the desktop dimensions relative to the combo box.
160
GraphicsConfiguration gc = this.comboBox.getGraphicsConfiguration();
161
Point p = new Point();
162
SwingUtilities.convertPointFromScreen(p, this.comboBox);
164
Insets screenInsets = toolkit.getScreenInsets(gc);
165
screenBounds = gc.getBounds();
166
screenBounds.width -= (screenInsets.left + screenInsets.right);
167
screenBounds.height -= (screenInsets.top + screenInsets.bottom);
168
screenBounds.x += (p.x + screenInsets.left);
169
screenBounds.y += (p.y + screenInsets.top);
171
screenBounds = new Rectangle(p, toolkit.getScreenSize());
174
Rectangle rect = new Rectangle(px + dx, py + dy, pw, ph);
175
if ((py + ph > screenBounds.y + screenBounds.height)
176
&& (ph < screenBounds.height)) {
177
rect.y = -rect.height - insets.top - insets.bottom;
180
// The following has been taken from JGoodies' Looks implementation
181
// for the popup prototype value
182
Object popupPrototypeDisplayValue = SubstanceCoreUtilities
183
.getComboPopupPrototypeDisplayValue(this.comboBox);
184
if (popupPrototypeDisplayValue != null) {
185
ListCellRenderer renderer = this.list.getCellRenderer();
186
Component c = renderer.getListCellRendererComponent(this.list,
187
popupPrototypeDisplayValue, -1, true, true);
188
int npw = c.getPreferredSize().width;
189
boolean hasVerticalScrollBar = this.comboBox.getItemCount() > this.comboBox
190
.getMaximumRowCount();
191
if (hasVerticalScrollBar) {
192
// Add the scrollbar width.
193
JScrollBar verticalBar = this.scroller.getVerticalScrollBar();
194
npw += verticalBar.getPreferredSize().width;
197
pw = Math.max(pw, npw);
207
* @see javax.swing.plaf.basic.BasicComboPopup#hide()
212
SubstanceListUI ui = (SubstanceListUI) this.list.getUI();
213
ui.resetRolloverIndex();
214
// this.list.putClientProperty(SubstanceListUI.ROLLED_OVER_INDEX, null);
217
public JComboBox getCombobox() {
218
return this.comboBox;