001: // THIS SOFTWARE IS PROVIDED BY SOFTARIS PTY.LTD. AND OTHER METABOSS
002: // CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
003: // BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
004: // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SOFTARIS PTY.LTD.
005: // OR OTHER METABOSS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
006: // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
007: // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
008: // OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
009: // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
010: // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
011: // EVEN IF SOFTARIS PTY.LTD. OR OTHER METABOSS CONTRIBUTORS ARE ADVISED OF THE
012: // POSSIBILITY OF SUCH DAMAGE.
013: //
014: // Copyright 2000-2005 © Softaris Pty.Ltd. All Rights Reserved.
015: package com.metaboss.applications.designstudio.complexfield;
016:
017: import java.awt.Color;
018: import java.awt.Component;
019: import java.awt.Container;
020: import java.awt.Dimension;
021: import java.awt.Graphics;
022: import java.awt.Insets;
023: import java.awt.LayoutManager;
024: import java.beans.PropertyChangeEvent;
025: import java.beans.PropertyChangeListener;
026: import java.io.Serializable;
027:
028: import javax.swing.CellRendererPane;
029: import javax.swing.ComboBoxEditor;
030: import javax.swing.DefaultButtonModel;
031: import javax.swing.Icon;
032: import javax.swing.JButton;
033: import javax.swing.JComboBox;
034: import javax.swing.JComponent;
035: import javax.swing.JList;
036: import javax.swing.JPanel;
037: import javax.swing.ListCellRenderer;
038: import javax.swing.UIManager;
039: import javax.swing.plaf.ComponentUI;
040: import javax.swing.plaf.basic.BasicComboBoxUI;
041: import javax.swing.plaf.basic.BasicComboPopup;
042: import javax.swing.plaf.basic.ComboPopup;
043: import javax.swing.plaf.metal.MetalComboBoxButton;
044: import javax.swing.plaf.metal.MetalComboBoxEditor;
045: import javax.swing.plaf.metal.MetalComboBoxUI;
046: import javax.swing.plaf.metal.MetalLookAndFeel;
047:
048: import com.jgoodies.plaf.LookUtils;
049: import com.jgoodies.plaf.plastic.PlasticComboBoxUI;
050: import com.jgoodies.plaf.plastic.PlasticLookAndFeel;
051: import com.metaboss.applications.designstudio.BaseUserObject;
052:
053: public class ComplexBoxUI extends MetalComboBoxUI {
054: protected ComboPopup createPopup() {
055: return new DataTypePopUp(comboBox);
056: }
057:
058: public static ComponentUI createUI(JComponent b) {
059: return new PlasticComboBoxUI();
060: }
061:
062: /**
063: * Creates the editor that is to be used in editable combo boxes.
064: * This method only gets called if a custom editor has not already
065: * been installed in the JComboBox.
066: */
067: protected ComboBoxEditor createEditor() {
068: return new MetalComboBoxEditor.UIResource();
069: }
070:
071: public Dimension getMinimumSize(JComponent c) {
072: if (!isMinimumSizeDirty) {
073: return new Dimension(cachedMinimumSize);
074: }
075:
076: Dimension size = null;
077:
078: if (!comboBox.isEditable() && arrowButton != null
079: && arrowButton instanceof MetalComboBoxButton) {
080:
081: PlasticComboBoxButton button = (PlasticComboBoxButton) arrowButton;
082: Insets buttonInsets = button.getInsets();
083: Insets insets = comboBox.getInsets();
084:
085: size = getDisplaySize();
086:
087: /*
088: * The next line will lead to good results if used with standard renderers;
089: * In case, a custom renderer is used, it may use a different height,
090: * and we can't help much.
091: */
092: size.height += LookUtils.isLowRes ? 0 : 2;
093:
094: size.width += insets.left + insets.right;
095: size.width += buttonInsets.left + buttonInsets.right;
096: size.width += buttonInsets.right
097: + button.getComboIcon().getIconWidth();
098: size.height += insets.top + insets.bottom;
099: size.height += buttonInsets.top + buttonInsets.bottom;
100:
101: } else if (comboBox.isEditable() && arrowButton != null
102: && editor != null) {
103:
104: // Includes the text editor border and inner margin
105: size = getDisplaySize();
106:
107: // Since the button is positioned besides the editor,
108: // do not add the buttons margin to the height.
109:
110: Insets insets = comboBox.getInsets();
111: size.height += insets.top + insets.bottom;
112: } else {
113: size = super .getMinimumSize(c);
114: }
115:
116: size.height += 4; //???
117:
118: cachedMinimumSize.setSize(size.width, size.height);
119: isMinimumSizeDirty = false;
120:
121: return new Dimension(cachedMinimumSize);
122: }
123:
124: /**
125: * Creates and answers the arrow button that is to be used in the combo box.<p>
126: *
127: * Overridden to use a button that can have a pseudo 3D effect.
128: */
129: protected JButton createArrowButton() {
130: return new PlasticComboBoxButton(comboBox,
131: new ComboBoxButtonIcon(), comboBox.isEditable(),
132: currentValuePane, listBox);
133: }
134:
135: /**
136: * Creates a layout manager for managing the components which
137: * make up the combo box.<p>
138: *
139: * Overriden to use a layout that has a fixed width arrow button.
140: *
141: * @return an instance of a layout manager
142: */
143: protected LayoutManager createLayoutManager() {
144: return new PlasticComboBoxLayoutManager();
145: }
146:
147: /**
148: * This layout manager handles the 'standard' layout of combo boxes.
149: * It puts the arrow button to the right and the editor to the left.
150: * If there is no editor it still keeps the arrow button to the right.
151: *
152: * Overriden to use a fixed arrow button width.
153: */
154: private class PlasticComboBoxLayoutManager extends
155: MetalComboBoxUI.MetalComboBoxLayoutManager {
156: public void layoutContainer(Container parent) {
157: JComboBox cb = (JComboBox) parent;
158:
159: // Use superclass behavior if the combobox is not editable.
160: if (!cb.isEditable()) {
161: super .layoutContainer(parent);
162: /*if (arrowButton != null)
163: {
164: Rectangle lRect = arrowButton.getBounds();
165: lRect.x = lRect.x - 10;
166: arrowButton.setBounds(lRect);
167:
168: lRect = parent.getBounds();
169: lRect.x = lRect.x + 10;
170: parent.setBounds(lRect);
171: }*/
172: return;
173: }
174:
175: int width = cb.getWidth();
176: int height = cb.getHeight();
177:
178: Insets insets = getInsets();
179: int buttonWidth = UIManager.getInt("ScrollBar.width");
180: int buttonHeight = height - (insets.top + insets.bottom);
181:
182: if (arrowButton != null) {
183: if (cb.getComponentOrientation().isLeftToRight()) {
184: arrowButton.setBounds(width
185: - (insets.right + 2 * buttonWidth),
186: insets.top, buttonWidth, buttonHeight);
187: } else {
188: arrowButton.setBounds(insets.left, insets.top,
189: buttonWidth, buttonHeight);
190: }
191: }
192: if (editor != null) {
193: editor.setBounds(rectangleForCurrentValue());
194: }
195: }
196: }
197:
198: // Required if we have a combobox button that does not extend MetalComboBoxButton
199: public PropertyChangeListener createPropertyChangeListener() {
200: return new PlasticPropertyChangeListener();
201: }
202:
203: // Overriden to use PlasticComboBoxButton instead of a MetalComboBoxButton.
204: // Required if we have a combobox button that does not extend MetalComboBoxButton
205: private class PlasticPropertyChangeListener extends
206: BasicComboBoxUI.PropertyChangeHandler {
207:
208: public void propertyChange(PropertyChangeEvent e) {
209: super .propertyChange(e);
210: String propertyName = e.getPropertyName();
211:
212: if (propertyName.equals("editable")) {
213: PlasticComboBoxButton button = (PlasticComboBoxButton) arrowButton;
214: button.setIconOnly(comboBox.isEditable());
215: comboBox.repaint();
216: } else if (propertyName.equals("background")) {
217: Color color = (Color) e.getNewValue();
218: arrowButton.setBackground(color);
219: listBox.setBackground(color);
220:
221: } else if (propertyName.equals("foreground")) {
222: Color color = (Color) e.getNewValue();
223: arrowButton.setForeground(color);
224: listBox.setForeground(color);
225: }
226: }
227: }
228:
229: public class DataTypePopUp extends BasicComboPopup {
230: public DataTypePopUp(JComboBox combo) {
231: super (combo);
232: }
233:
234: public void show() {
235: ComplexSelectDialog lDialog = ((ComplexBox) comboBox)
236: .createSelectDialog();
237: if (lDialog != null) {
238: Object lObject = comboBox.getSelectedItem();
239: if (lObject != null
240: && lObject instanceof BaseUserObject)
241: lDialog.setSelectedObject((BaseUserObject) lObject);
242: if (lDialog.getModalResult() == ComplexSelectDialog.MR_OK) {
243: BaseUserObject lUserObject = lDialog
244: .getSelectedObject();
245: if (lUserObject != null)
246: ((ComplexBox) comboBox)
247: .setSelectedModelElement(lUserObject
248: .getBOObject());
249: else
250: ((ComplexBox) comboBox)
251: .setSelectedModelElement(null);
252: }
253:
254: arrowButton.getModel().setArmed(false);
255: arrowButton.getModel().setPressed(false);
256: } else
257: super .show();
258: }
259: }
260:
261: final class PlasticComboBoxButton extends JButton {
262:
263: private static final int LEFT_INSET = 2;
264: private static final int RIGHT_INSET = 3;
265:
266: private final JList listBox;
267: private final CellRendererPane rendererPane;
268:
269: private JComboBox comboBox;
270: private Icon comboIcon;
271: protected boolean iconOnly = false;
272: private boolean borderPaintsFocus;
273:
274: /**
275: * Constructs a <code>PlasticComboBoxButton</code>.
276: */
277: PlasticComboBoxButton(JComboBox comboBox, Icon comboIcon,
278: boolean iconOnly, CellRendererPane rendererPane,
279: JList listBox) {
280: super ("");
281: setModel(new DefaultButtonModel() {
282: public void setArmed(boolean armed) {
283: super .setArmed(isPressed() || armed);
284: }
285: });
286: this .comboBox = comboBox;
287: this .comboIcon = comboIcon;
288: this .iconOnly = iconOnly;
289: this .rendererPane = rendererPane;
290: this .listBox = listBox;
291: setEnabled(comboBox.isEnabled());
292: setRequestFocusEnabled(comboBox.isEnabled());
293: setBorder(UIManager.getBorder("ComboBox.arrowButtonBorder"));
294: setMargin(new Insets(0, LEFT_INSET, 0, RIGHT_INSET));
295: borderPaintsFocus = Boolean.TRUE.equals(UIManager
296: .get("ComboBox.borderPaintsFocus"));
297: }
298:
299: public JComboBox getComboBox() {
300: return comboBox;
301: }
302:
303: public void setComboBox(JComboBox cb) {
304: comboBox = cb;
305: }
306:
307: public Icon getComboIcon() {
308: return comboIcon;
309: }
310:
311: public void setComboIcon(Icon i) {
312: comboIcon = i;
313: }
314:
315: public boolean isIconOnly() {
316: return iconOnly;
317: }
318:
319: public void setIconOnly(boolean b) {
320: iconOnly = b;
321: }
322:
323: /*public boolean isFocusTraversable() {
324: return LookUtils.IS_BEFORE_14 &&
325: (!comboBox.isEditable()) && comboBox.isEnabled();
326: }*/
327:
328: public void setEnabled(boolean enabled) {
329: super .setEnabled(enabled);
330: // Set the background and foreground to the combobox colors.
331: if (enabled) {
332: setBackground(comboBox.getBackground());
333: setForeground(comboBox.getForeground());
334: } else {
335: setBackground(UIManager
336: .getColor("ComboBox.disabledBackground"));
337: setForeground(UIManager
338: .getColor("ComboBox.disabledForeground"));
339: }
340: }
341:
342: /**
343: * Checks and answers if we should paint a pseudo 3D effect.
344: */
345: private boolean is3D() {
346: /*if (PlasticUtils.force3D(comboBox))
347: return true;
348: if (PlasticUtils.forceFlat(comboBox))
349: return false;
350: return PlasticUtils.is3D("ComboBox.");*/
351: return false;
352: }
353:
354: /**
355: * Paints the component; honors the 3D settings and
356: * tries to switch the renderer component to transparent.
357: */
358: public void paintComponent(Graphics g) {
359: super .paintComponent(g);
360: boolean leftToRight = true;// PlasticUtils.isLeftToRight(comboBox);
361:
362: Insets insets = getInsets();
363:
364: int width = getWidth() - (insets.left + insets.right);
365: int height = getHeight() - (insets.top + insets.bottom);
366:
367: if (height <= 0 || width <= 0) {
368: return;
369: }
370:
371: int left = insets.left;
372: int top = insets.top;
373: int right = left + (width - 1);
374:
375: int iconWidth = 0;
376: int iconLeft = (leftToRight) ? right : left;
377:
378: // Paint the icon
379: if (comboIcon != null) {
380: iconWidth = comboIcon.getIconWidth();
381: int iconHeight = comboIcon.getIconHeight();
382: int iconTop;
383:
384: if (iconOnly) {
385: iconLeft = (getWidth() - iconWidth) / 2;
386: iconTop = (getHeight() - iconHeight) / 2;
387: } else {
388: if (leftToRight) {
389: iconLeft = (left + (width - 1)) - iconWidth;
390: } else {
391: iconLeft = left;
392: }
393: iconTop = (getHeight() - iconHeight) / 2;
394: }
395:
396: comboIcon.paintIcon(this , g, iconLeft, iconTop);
397:
398: }
399:
400: // Let the renderer paint
401: if (!iconOnly && comboBox != null) {
402: ListCellRenderer renderer = comboBox.getRenderer();
403: boolean renderPressed = getModel().isPressed();
404: Component c = renderer.getListCellRendererComponent(
405: listBox, comboBox.getSelectedItem(), -1,
406: renderPressed, false);
407: c.setFont(rendererPane.getFont());
408:
409: if (model.isArmed() && model.isPressed()) {
410: if (isOpaque()) {
411: c.setBackground(UIManager
412: .getColor("Button.select"));
413: }
414: c.setForeground(comboBox.getForeground());
415: } else if (!comboBox.isEnabled()) {
416: if (isOpaque()) {
417: c
418: .setBackground(UIManager
419: .getColor("ComboBox.disabledBackground"));
420: }
421: c.setForeground(UIManager
422: .getColor("ComboBox.disabledForeground"));
423: } else {
424: c.setForeground(comboBox.getForeground());
425: c.setBackground(comboBox.getBackground());
426: }
427:
428: int cWidth = width - (insets.right + iconWidth);
429:
430: // Fix for 4238829: should lay out the JPanel.
431: boolean shouldValidate = c instanceof JPanel;
432: int x = leftToRight ? left : left + iconWidth;
433: int myHeight = getHeight() - LEFT_INSET - RIGHT_INSET
434: - (LookUtils.IS_BEFORE_14 ? 2 : 1);
435:
436: if (!is3D()) {
437: rendererPane.paintComponent(g, c, this , x, top + 1,
438: cWidth, myHeight, shouldValidate);
439: } else if (!(c instanceof JComponent)) {
440: rendererPane.paintComponent(g, c, this , x, top + 1,
441: cWidth, myHeight, shouldValidate);
442: //LookUtils.log("Custom renderer detected: " + c);
443: //LookUtils.log("Custom renderer superclass: " + c.getClass().getSuperclass().getName());
444: } else {
445: // In case, we are in 3D mode _and_ have a JComponent renderer,
446: // store the opaque state, set it to transparent, paint, then restore.
447: JComponent component = (JComponent) c;
448: boolean hasBeenOpaque = component.isOpaque();
449: component.setOpaque(false);
450: rendererPane.paintComponent(g, c, this , x, top + 1,
451: cWidth, myHeight, shouldValidate);
452: component.setOpaque(hasBeenOpaque);
453: }
454: }
455:
456: if (comboIcon != null) {
457: // Paint the focus
458: boolean hasFocus = LookUtils.IS_BEFORE_14 ? hasFocus()
459: : comboBox.hasFocus();
460: if (!borderPaintsFocus && hasFocus) {
461: g.setColor(PlasticLookAndFeel.getFocusColor());
462: int x = LEFT_INSET;
463: int y = LEFT_INSET;
464: int w = getWidth() - LEFT_INSET - RIGHT_INSET;
465: int h = getHeight() - LEFT_INSET - RIGHT_INSET;
466: g.drawRect(x, y, w - 1, h - 1);
467: }
468: }
469:
470: }
471:
472: }
473:
474: private static class ComboBoxButtonIcon implements Icon,
475: Serializable {
476:
477: public void paintIcon(Component c, Graphics g, int x, int y) {
478: JComponent component = (JComponent) c;
479: int iconWidth = getIconWidth();
480:
481: g.translate(x, y);
482:
483: g.setColor(component.isEnabled() ? MetalLookAndFeel
484: .getControlInfo() : MetalLookAndFeel
485: .getControlShadow());
486: g.drawLine(0, 0, iconWidth - 1, 0);
487: g.drawLine(1, 1, 1 + (iconWidth - 3), 1);
488: g.drawLine(2, 2, 2 + (iconWidth - 5), 2);
489: g.drawLine(3, 3, 3 + (iconWidth - 7), 3);
490:
491: /*
492: int startY = (((h + 1) - arrowHeight) / 2) + arrowHeight - 1;
493: int startX = (w / 2);
494:
495: // System.out.println( "startX2 :" + startX + " startY2 :"+startY);
496:
497: for (int line = 0; line < arrowHeight; line++) {
498: g.drawLine(
499: startX - line,
500: startY - line,
501: startX + line + 1,
502: startY - line);
503: }*/
504: g.translate(-x, -y);
505: }
506:
507: public int getIconWidth() {
508: return 8;
509: }
510:
511: public int getIconHeight() {
512: return 4;
513: }
514: }
515: }
|