001: /*
002: * Copyright (c) 2005-2008 Substance Kirill Grouchnikov. All Rights Reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without
005: * modification, are permitted provided that the following conditions are met:
006: *
007: * o Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: *
010: * o Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * o Neither the name of Substance Kirill Grouchnikov nor the names of
015: * its contributors may be used to endorse or promote products derived
016: * from this software without specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
020: * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
021: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
022: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
025: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
026: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
027: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
028: * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029: */
030: package org.jvnet.substance.combo;
031:
032: import java.awt.*;
033:
034: import javax.swing.*;
035: import javax.swing.plaf.basic.BasicComboPopup;
036:
037: import org.jvnet.substance.SubstanceBorder;
038: import org.jvnet.substance.SubstanceListUI;
039: import org.jvnet.substance.utils.SubstanceCoreUtilities;
040:
041: /**
042: * Combo popup implementation in <b>Substance</b> look-and-feel. This class is
043: * <b>for internal use only</b>.
044: *
045: * @author Kirill Grouchnikov
046: */
047: public class SubstanceComboPopup extends BasicComboPopup {
048:
049: /**
050: * Creates combo popup for the specified combobox.
051: *
052: * @param combo
053: * Combobox.
054: */
055: public SubstanceComboPopup(JComboBox combo) {
056: super (combo);
057: // fix for defect 154
058: this .setOpaque(true);
059: this .list.setBackground(combo.getBackground());
060: }
061:
062: /*
063: * (non-Javadoc)
064: *
065: * @see javax.swing.plaf.basic.BasicComboPopup#configurePopup()
066: */
067: @Override
068: protected void configurePopup() {
069: super .configurePopup();
070: setBorder(new SubstanceBorder(new Insets(0, 2, 2, 2)));
071: }
072:
073: /**
074: * Sets the list selection index to the selectedIndex. This method is used
075: * to synchronize the list selection with the combo box selection.
076: *
077: * @param selectedIndex
078: * the index to set the list
079: */
080: private void setListSelection(int selectedIndex) {
081: if (selectedIndex == -1) {
082: this .list.clearSelection();
083: } else {
084: this .list.setSelectedIndex(selectedIndex);
085: this .list.ensureIndexIsVisible(selectedIndex);
086: }
087: }
088:
089: /**
090: * Calculates the upper left location of the popup.
091: *
092: * @return The upper left location of the popup.
093: */
094: private Point getPopupLocation() {
095: Dimension popupSize = this .comboBox.getSize();
096: Insets insets = this .getInsets();
097:
098: // reduce the width of the scrollpane by the insets so that the popup
099: // is the same width as the combo box.
100: popupSize.setSize(popupSize.width
101: - (insets.right + insets.left), this
102: .getPopupHeightForRowCount(this .comboBox
103: .getMaximumRowCount()));
104: Rectangle popupBounds = this .computePopupBounds(0,
105: this .comboBox.getBounds().height, popupSize.width,
106: popupSize.height);
107: Dimension scrollSize = popupBounds.getSize();
108: Point popupLocation = popupBounds.getLocation();
109:
110: this .scroller.setMaximumSize(scrollSize);
111: this .scroller.setPreferredSize(scrollSize);
112: this .scroller.setMinimumSize(scrollSize);
113:
114: this .list.revalidate();
115:
116: return new Point(popupLocation.x, popupLocation.y);
117: }
118:
119: /*
120: * (non-Javadoc)
121: *
122: * @see javax.swing.plaf.basic.BasicComboPopup#computePopupBounds(int, int,
123: * int, int)
124: */
125: @Override
126: protected Rectangle computePopupBounds(int px, int py, int pw,
127: int ph) {
128: int popupFlyoutOrientation = SubstanceCoreUtilities
129: .getPopupFlyoutOrientation(this .comboBox);
130: int dx = 0;
131: int dy = 0;
132: switch (popupFlyoutOrientation) {
133: case SwingConstants.NORTH:
134: dy = -ph - (int) this .comboBox.getSize().getHeight();
135: break;
136: case SwingConstants.CENTER:
137: dy = -ph / 2 - (int) this .comboBox.getSize().getHeight()
138: / 2;
139: break;
140: case SwingConstants.EAST:
141: dx = pw;
142: dy = -(int) this .comboBox.getSize().getHeight();
143: break;
144: case SwingConstants.WEST:
145: dx = -pw;
146: dy = -(int) this .comboBox.getSize().getHeight();
147: }
148: Toolkit toolkit = Toolkit.getDefaultToolkit();
149: Rectangle screenBounds;
150:
151: // Calculate the desktop dimensions relative to the combo box.
152: GraphicsConfiguration gc = this .comboBox
153: .getGraphicsConfiguration();
154: Point p = new Point();
155: SwingUtilities.convertPointFromScreen(p, this .comboBox);
156: if (gc != null) {
157: Insets screenInsets = toolkit.getScreenInsets(gc);
158: screenBounds = gc.getBounds();
159: screenBounds.width -= (screenInsets.left + screenInsets.right);
160: screenBounds.height -= (screenInsets.top + screenInsets.bottom);
161: screenBounds.x += (p.x + screenInsets.left);
162: screenBounds.y += (p.y + screenInsets.top);
163: } else {
164: screenBounds = new Rectangle(p, toolkit.getScreenSize());
165: }
166:
167: Rectangle rect = new Rectangle(px + dx, py + dy, pw, ph);
168: if ((py + ph > screenBounds.y + screenBounds.height)
169: && (ph < screenBounds.height)) {
170: rect.y = -rect.height;
171: }
172:
173: // The following has been taken from JGoodies' Looks implementation
174: // for the popup prototype value
175: Object popupPrototypeDisplayValue = SubstanceCoreUtilities
176: .getComboPopupPrototypeDisplayValue(this .comboBox);
177: if (popupPrototypeDisplayValue != null) {
178: ListCellRenderer renderer = this .list.getCellRenderer();
179: Component c = renderer.getListCellRendererComponent(
180: this .list, popupPrototypeDisplayValue, -1, true,
181: true);
182: int npw = c.getPreferredSize().width;
183: boolean hasVerticalScrollBar = this .comboBox.getItemCount() > this .comboBox
184: .getMaximumRowCount();
185: if (hasVerticalScrollBar) {
186: // Add the scrollbar width.
187: JScrollBar verticalBar = this .scroller
188: .getVerticalScrollBar();
189: npw += verticalBar.getPreferredSize().width;
190: }
191:
192: pw = Math.max(pw, npw);
193: rect.width = pw;
194: }
195:
196: return rect;
197: }
198:
199: /*
200: * (non-Javadoc)
201: *
202: * @see javax.swing.plaf.basic.BasicComboPopup#show()
203: */
204: @Override
205: public void show() {
206: this .setListSelection(this .comboBox.getSelectedIndex());
207:
208: Point location = this .getPopupLocation();
209: this .show(this .comboBox, location.x, location.y);
210: }
211:
212: /*
213: * (non-Javadoc)
214: *
215: * @see javax.swing.plaf.basic.BasicComboPopup#hide()
216: */
217: @Override
218: public void hide() {
219: super .hide();
220: SubstanceListUI ui = (SubstanceListUI) this .list.getUI();
221: ui.resetRolloverIndex();
222: // this.list.putClientProperty(SubstanceListUI.ROLLED_OVER_INDEX, null);
223: }
224:
225: // /* (non-Javadoc)
226: // * @see javax.swing.plaf.basic.BasicComboPopup#createScroller()
227: // */
228: // @Override
229: // protected JScrollPane createScroller() {
230: // JScrollPane scroller = super.createScroller();
231: // ScrollPaneSelector.uninstallScrollPaneSelector(scroller);
232: // return scroller;
233: // }
234:
235: // /*
236: // * (non-Javadoc)
237: // *
238: // * @see javax.swing.plaf.basic.BasicComboPopup#configureScroller()
239: // */
240: // @Override
241: // protected void configureScroller() {
242: // super.configureScroller();
243: // this.scroller.setBorder(new EmptyBorder(0, 1, 0, 1));
244: // }
245: }
|