001: package com.xoetrope.swing;
002:
003: import java.awt.BorderLayout;
004: import java.awt.Color;
005: import java.awt.Component;
006: import java.awt.Container;
007: import java.awt.Dimension;
008: import java.awt.Graphics;
009: import java.awt.Graphics2D;
010: import java.awt.LayoutManager;
011: import java.awt.Rectangle;
012: import java.awt.event.ActionEvent;
013: import java.awt.event.ActionListener;
014: import java.awt.image.BufferedImage;
015: import java.util.Hashtable;
016: import javax.swing.ButtonGroup;
017: import javax.swing.JComponent;
018: import javax.swing.JToggleButton;
019: import javax.swing.Timer;
020: import net.xoetrope.builder.XuiBuilder;
021: import net.xoetrope.swing.XImageButton;
022: import net.xoetrope.swing.XPanel;
023: import net.xoetrope.xui.XAttributedComponent;
024: import net.xoetrope.xui.XCompositeComponent;
025: import net.xoetrope.xui.XProject;
026: import net.xoetrope.xui.XProjectManager;
027: import net.xoetrope.xui.helper.XuiUtilities;
028:
029: /**
030: * An outlook style roll-up bar. The methods are modelled on the JTabbedPane
031: *
032: * <p> Copyright (c) Xoetrope Ltd., 2001-2006, This software is licensed under
033: * the GNU Public License (GPL), please see license.txt for more details. If
034: * you make commercial use of this software you must purchase a commercial
035: * license from Xoetrope.</p>
036: * <p> $Revision: 1.15 $</p>
037: */
038: public class XRollupBar extends XPanel implements ActionListener,
039: XAttributedComponent, XCompositeComponent {
040: protected int selIdx, lastSelIdx;
041: protected JToggleButton topBtn;
042: protected ButtonGroup buttonGroup;
043: protected XProject currentProject;
044:
045: protected int buttonHeight = 22;
046: protected int minPanelSize = 200;
047: protected int maxPanelSize = Integer.MAX_VALUE;
048:
049: protected boolean antiAlias;
050:
051: protected String buttonClassName = "net.xoetrope.swing.XImageButton";
052: protected boolean allExpandable = false;
053:
054: private JComponent slidingComponent, hidingComponent;
055: private boolean slidingComponentVisiblity;
056: private final long duration = 200L;
057: private double animationOffset;
058: private boolean animating;
059: private boolean isVertical;
060: private boolean slideImages;
061: private boolean overlapButtons;
062: private int maxSharedPanels;
063:
064: /**
065: * Create a new button panel
066: */
067: public XRollupBar() {
068: currentProject = XProjectManager.getCurrentProject();
069: setLayout(new AccordianLayout());
070:
071: setDoubleBuffered(true);
072: selIdx = 0;
073: maxSharedPanels = Integer.MAX_VALUE;
074: }
075:
076: /**
077: * Add a new button.
078: * The add method could not be overloaded so this method adds does the
079: * equivalent.
080: * @param comp the new button component
081: * @return the new component
082: */
083: public Component add(Component comp) {
084: String title = null;
085: String iconFileName = null;
086: String aa = null;
087: boolean visible = true;
088: try {
089: Hashtable attribs = XuiBuilder.getCurrentAttributes();
090: title = XuiUtilities.translate(currentProject,
091: (String) attribs.get("title"));
092: iconFileName = (String) attribs.get("icon");
093: aa = (String) attribs.get("antialias");
094: String s = (String) attribs.get("buttonclass");
095: if ((s != null) && (s.length() > 0))
096: buttonClassName = s;
097:
098: if (!allExpandable && (topBtn != null))
099: visible = false;
100: s = (String) attribs.get("visible");
101: if ((s != null) && (s.length() > 0))
102: visible = s.equals("true");
103: } catch (Exception ex) {
104: }
105:
106: addButton(title, iconFileName, aa, comp, visible);
107: return comp;
108: }
109:
110: /**
111: * Add a new button.
112: * The add method could not be overloaded so this method adds does the
113: * equivalent.
114: * @param comp the new button component
115: * @return the new component
116: */
117: public void add(Component comp, Object constraints) {
118: String title = null;
119: String iconFileName = null;
120: String aa = null;
121: try {
122: Hashtable attribs = XuiBuilder.getCurrentAttributes();
123: title = XuiUtilities.translate(currentProject,
124: (String) attribs.get("title"));
125: iconFileName = (String) attribs.get("icon");
126: aa = (String) attribs.get("antialias");
127: String s = (String) attribs.get("buttonclass");
128: if ((s != null) && (s.length() > 0))
129: buttonClassName = s;
130:
131: /** @todo create a mechanism where by the components can override
132: * properties set for the rollup, without having to specify those
133: * properties for all the children instead of on the rollup */
134: } catch (Exception ex) {
135: }
136:
137: addButton(title, iconFileName, aa, comp, true);
138: }
139:
140: /**
141: * Add a new button.
142: * The add method could not be overloaded so this method adds does the
143: * equivalent.
144: * @param name the name/caption of the button component
145: * @param iconFileName the file name of an icon if one is used, otherwise null
146: * @param aa "true" if the button is antialiased
147: * @param panel the content
148: */
149: private void addButton(String name, String iconFileName, String aa,
150: Component panel, boolean isVisible) {
151: if (!allExpandable && (buttonGroup == null))
152: buttonGroup = new ButtonGroup();
153:
154: JToggleButton newBtn = copyBtn(topBtn);
155: super .add(newBtn);
156:
157: newBtn.setText(name);
158: newBtn.putClientProperty("id", new Integer(getButtonCount()));
159: newBtn.addActionListener(this );
160:
161: if (newBtn instanceof XAttributedComponent) {
162: if (iconFileName != null)
163: ((XAttributedComponent) newBtn).setAttribute("icon",
164: iconFileName);
165: ((XAttributedComponent) newBtn).setAttribute("antialias",
166: aa);
167: }
168:
169: if (topBtn == null)
170: topBtn = newBtn;
171:
172: XRollupPanel rup = new XRollupPanel((JComponent) panel);
173: rup.setVisible(isVisible);
174: super .add(rup);
175: }
176:
177: private int getPanelCount() {
178: return getComponentCount() / 2;
179: }
180:
181: /**
182: * Get the button component at the specified index, skips over the expanded panel
183: * @param index the button index
184: * @return the button component
185: */
186: public JToggleButton getButton(int index) {
187: return (JToggleButton) getComponent(index * 2);
188: }
189:
190: /**
191: * Get a button's background color
192: * @param index the button index
193: * @return the color
194: */
195: public Color getBackgroundAt(int index) {
196: return getButton(index).getBackground();
197: }
198:
199: /**
200: * Get a button's foreground color
201: * @param index the button index
202: * @return the color
203: */
204: public Color getForegroundAt(int index) {
205: return getButton(index).getForeground();
206: }
207:
208: /**
209: * Get the number of buttons
210: * @return the number of buttons
211: */
212: public int getButtonCount() {
213: return getComponentCount() / 2;
214: }
215:
216: /**
217: * Get the index of the selected button
218: * @return the selection index
219: */
220: public int getSelectedIndex() {
221: return selIdx;
222: }
223:
224: /**
225: * Get the title of the button at the specified index
226: * @param index the button index
227: * @return the button text/title
228: */
229: public String getTitleAt(int index) {
230: return getButton(index).getText();
231: }
232:
233: /**
234: * Set the button background color
235: * @param index the button index
236: * @param clr the new colr
237: */
238: public void setBackgroundAt(int index, Color clr) {
239: getButton(index).setBackground(clr);
240: }
241:
242: /**
243: * Set the foreground color
244: * @param index the button index
245: * @param clr the new color
246: */
247: public void setForegroundAt(int index, Color clr) {
248: getComponent(index).setForeground(clr);
249: }
250:
251: /**
252: * Select a button
253: * @param index the button index
254: */
255: public void setSelectedIndex(int index) {
256: // selIdx = index;
257: // JToggleButton comp = getButton( selIdx );
258: // showPanel( comp.getText());
259: }
260:
261: /**
262: * Set a button's title
263: * @param index the button index
264: * @param str the text for the button
265: */
266: public void setTitleAt(int index, String str) {
267: JToggleButton btn = getButton(index);
268: if (btn != null)
269: btn.setText(str);
270: }
271:
272: //-Action listener methods-----------------------------------------------------
273: /**
274: * Invoked when a mouse button has been pressed on a component.
275: * @param e the event
276: */
277: public void actionPerformed(ActionEvent e) {
278: if (animating)
279: return;
280:
281: lastSelIdx = selIdx;
282: JToggleButton comp = (JToggleButton) e.getSource();
283: selIdx = ((Integer) comp.getClientProperty("id")).intValue();
284: if (allExpandable || (selIdx != lastSelIdx)) {
285: JComponent panel = (JComponent) getComponent((selIdx * 2) + 1);
286: JComponent hidingPanel = allExpandable ? null
287: : (JComponent) getComponent((lastSelIdx * 2) + 1);
288: boolean currentState = allExpandable ? !panel.isVisible()
289: : true;
290: comp.setSelected(currentState);
291: slideAll(panel, hidingPanel, currentState);
292: }
293: }
294:
295: private void slideAll(JComponent panel, JComponent hidingPanel,
296: final boolean endState) {
297: animating = true;
298: slidingComponent = panel;
299: hidingComponent = hidingPanel;
300: if (slideImages) {
301: int w = slidingComponent.getWidth();
302: int h = slidingComponent.getHeight();
303: if (isVertical & (h == 0))
304: h = getHeight() - getButtonCount()
305: * getComponent(0).getHeight();
306: else if (w == 0)
307: w = getWidth() - getButtonCount()
308: * getComponent(0).getWidth();
309:
310: if (hidingComponent != null) {
311: w = Math.max(hidingComponent.getWidth(), w);
312: h = Math.max(hidingComponent.getHeight(), h);
313: ((XRollupPanel) hidingComponent).prepare(w, h);
314: }
315: ((XRollupPanel) slidingComponent).prepare(w, h);
316: }
317: slidingComponentVisiblity = slidingComponent.isVisible();
318: if (!slidingComponentVisiblity) {
319: animationOffset = 0.0;
320: slidingComponent.setSize(slidingComponent.getWidth(), 0);
321: slidingComponent.setVisible(true);
322: slidingComponent.revalidate();
323: }
324: final long startTime = System.currentTimeMillis();
325:
326: final Timer slideTimer = new Timer(30, new ActionListener() {
327: public void actionPerformed(ActionEvent e) {
328: double elapsedTime = System.currentTimeMillis()
329: - startTime;
330: animationOffset = elapsedTime / duration;
331: animationOffset = Math.min(1.0, animationOffset);
332: doLayout();
333: if (elapsedTime >= duration)
334: stopSlide((Timer) e.getSource());
335: }
336:
337: public void stopSlide(Timer t) {
338: t.stop();
339:
340: if (!allExpandable) {
341: hidingComponent.setVisible(false);
342: hidingComponent = null;
343: }
344:
345: slidingComponent.setVisible(endState);
346: slidingComponent = null;
347:
348: animating = false;
349:
350: revalidate();
351: doLayout();
352: }
353: });
354: slideTimer.start();
355:
356: }
357:
358: /**
359: * Set one or more attributes of the component.
360: * <OL>
361: * <LI>alignment, value=(Left|Right|Center|Leading|Trailing)</LI>
362: * <LI>imagename, value=the image file name</LI>
363: * <LI>pressed, value=the pressed image file name</LI>
364: * <LI>rollover, value=the rollover image file name</LI>
365: * <LI>icon, value=name of the image</LI>
366: * <LI>iconpressed, value=name of the pressed image</LI>
367: * <LI>iconrollover, value=name of the rollover image</LI>
368: * <LI>tooltip, value=the tooltip text</LI>
369: * <LI>painter, value=the painter class for the image buttons</LI>
370: * <LI>slideImages, value=true to slide images of the panels rather than the
371: * actual panels themselves. In sme case this can give better performance as
372: * each panel does not get layout at ever animatio step</LI>
373: * </OL>
374: * @param attribName the name of the attribute
375: * @param attribValue the value of the attribute
376: * @return 0 for success, non zero otherwise
377: */
378: public int setAttribute(String attribName, Object attribValue) {
379: String attribNameLwr = attribName.toLowerCase();
380: if (attribNameLwr.equals("alignment")
381: || attribNameLwr.equals("icon")
382: || attribNameLwr.equals("iconpressed")
383: || attribNameLwr.equals("iconrollover")
384: || attribNameLwr.equals("imagename")
385: || attribNameLwr.equals("pressed")
386: || attribNameLwr.equals("rollover")
387: || attribNameLwr.equals("disabled")
388: || attribNameLwr.equals("style")
389: || attribNameLwr.equals("painter")) {
390: int numComponents = getComponentCount();
391: for (int i = 0; i < numComponents; i++) {
392: Component comp = getComponent(i);
393: if (comp instanceof XImageButton) {
394: if (attribNameLwr.equals("style"))
395: XuiUtilities.applyStyle(currentProject, comp,
396: (String) attribValue);
397: else
398: ((XImageButton) comp).setAttribute(attribName,
399: attribValue);
400: }
401: }
402: } else if (attribNameLwr.equals("buttonheight"))
403: buttonHeight = Integer.parseInt((String) attribValue);
404: else if (attribNameLwr.equals("antialias")) {
405: antiAlias = attribValue.equals("true");
406: setAntiAlias((String) attribValue);
407: } else if (attribNameLwr.equals("slideimages"))
408: slideImages = attribValue.equals("true");
409: else if (attribNameLwr.equals("vertical"))
410: setIsVertical(attribValue.equals("true"));
411: else if (attribNameLwr.equals("overlapbuttons"))
412: setOverlapButtons(attribValue.equals("true"));
413: else if (attribNameLwr.equals("maxSharedPanels"))
414: setMaxSharedPanels(new Integer((String) attribValue)
415: .intValue());
416: else if (attribNameLwr.equals("state"))
417: setState(((String) attribValue).split(","));
418: else
419: return -1;
420:
421: return 0;
422: }
423:
424: /**
425: * Set the AntiAliasing state. Any buttons contained within the rolloup bar
426: * will have their antialias setting modified by this call.
427: * @param "true" to anti alias the text
428: */
429: public void setAntiAlias(String state) {
430: int numButtons = getButtonCount();
431: for (int i = 0; i < numButtons; i++) {
432: JToggleButton btn = getButton(i);
433: if (btn instanceof XAttributedComponent)
434: ((XAttributedComponent) btn).setAttribute("antialias",
435: state);
436: }
437: }
438:
439: /**
440: * Create a copy of a button
441: */
442: private JToggleButton copyBtn(JToggleButton prototype) {
443: try {
444: JToggleButton newBtn = null;
445: if (prototype == null) {
446: newBtn = (JToggleButton) Class.forName(
447: buttonClassName.trim()).newInstance();
448: newBtn.setSelected(true);
449: } else {
450: newBtn = (JToggleButton) prototype.getClass()
451: .newInstance();
452:
453: newBtn.setSelected(!allExpandable);
454: }
455:
456: if (!allExpandable)
457: buttonGroup.add(newBtn);
458:
459: if (prototype != null) {
460: newBtn.setHorizontalAlignment(prototype
461: .getHorizontalAlignment());
462: if (prototype instanceof XImageButton) {
463: XImageButton newImageButton = (XImageButton) newBtn;
464: XImageButton protoImageButton = (XImageButton) prototype;
465: newImageButton.setImage(currentProject
466: .getImage(protoImageButton.getImageName()));
467: newImageButton.setPressedImage(currentProject
468: .getImage(protoImageButton
469: .getPressedImageName()));
470: newImageButton.setRolloverImage(currentProject
471: .getImage(protoImageButton
472: .getRolloverImageName()));
473: newImageButton.setDisabledImage(currentProject
474: .getImage(protoImageButton
475: .getDisabledImageName()));
476: }
477:
478: newBtn.setPressedIcon(prototype.getPressedIcon());
479: newBtn.setRolloverIcon(prototype.getRolloverIcon());
480: newBtn.setIcon(prototype.getIcon());
481: }
482: return newBtn;
483: } catch (Exception ex) {
484: ex.printStackTrace();
485: }
486:
487: return null;
488: }
489:
490: /**
491: * Does this component allow all of its panel to be visible at once?
492: * @return true if all panels can be made visible
493: */
494: protected boolean isAllExpandable() {
495: return allExpandable;
496: }
497:
498: /**
499: * Set this component to allow all of its panel to be visible at once.
500: * @param allExpandable
501: */
502: protected void setAllExpandable(boolean state) {
503: allExpandable = state;
504: }
505:
506: /**
507: * Get the count of the nested components
508: * @return the component count
509: */
510: public int getContentComponentCount() {
511: return getButtonCount();
512: }
513:
514: /**
515: * Get a nested component
516: * @param the index of the nested component
517: * @return the specified component
518: */
519: public Component getContentComponent(int idx) {
520: return getComponent((idx * 2) + 1);
521: }
522:
523: private Component getSuperComponent(int idx) {
524: return getComponent(idx);
525: }
526:
527: private int getSuperComponentCount() {
528: return getComponentCount();
529: }
530:
531: /**
532: * Set the layout as vertical (one button above another)
533: * @param isVertical
534: */
535: public void setIsVertical(boolean vertical) {
536: isVertical = vertical;
537: if (!isVertical) {
538: int numButtons = getButtonCount();
539: for (int i = 0; i < numButtons; i++) {
540: JComponent comp = getButton(i);
541: if (comp instanceof XImageButton) {
542: ((XImageButton) comp).setVertical(!vertical);
543: comp.putClientProperty("vertical", "true");
544: comp.putClientProperty("verticalOffset", Integer
545: .toString(3 * buttonHeight / 2));
546: }
547: }
548: }
549: }
550:
551: /**
552: * Do the buttons overlap for the adjacent panels when the content is hidden?
553: * @return true if the buttons ovrlap
554: */
555: public boolean isOverlapButtons() {
556: return overlapButtons;
557: }
558:
559: /**
560: * Set the buttons to overlap for the adjacent panels when the content is hidden
561: * @param state the new flag value
562: */
563: public void setOverlapButtons(boolean state) {
564: overlapButtons = state;
565: }
566:
567: /**
568: * Get the maximum number of shared panels
569: * @return the panel count
570: */
571: public int getMaxSharedPanels() {
572: return maxSharedPanels;
573: }
574:
575: /**
576: * Set the maximum number of shared panels (the number of panels that can
577: * occupy a single divider)
578: * @param maxPanels the new max panel count
579: */
580: public void setMaxSharedPanels(int maxPanels) {
581: maxSharedPanels = maxPanels;
582: }
583:
584: public void setState(String[] panelStates) {
585: int numPanels = Math.min(panelStates.length, getPanelCount());
586: for (int i = 0; i < numPanels; i++) {
587: Component comp = getComponent(i * 2 + 1);
588: comp.setVisible("1".equals(panelStates[i])
589: || "visible".equals(panelStates[i]));
590: }
591: }
592:
593: /**
594: * Get the preferred layout size of this component
595: * @return the preferred size
596: */
597: public Dimension getPreferredSize() {
598: return getLayout().preferredLayoutSize(this );
599: }
600:
601: /**
602: * Get the minimum layout size of this component
603: * @return the preferred size
604: */
605: public Dimension getMinimumSize() {
606: return super .getMinimumSize();
607: }
608:
609: /**
610: * Get the minimum layout size of this component
611: * @return the preferred size
612: */
613: public Dimension getMaximumSize() {
614: return super .getMaximumSize();
615: }
616:
617: class XRollupPanel extends JComponent {
618: private BufferedImage bi;
619: private JComponent content;
620:
621: public XRollupPanel(JComponent comp) {
622: super ();
623: content = comp;
624: setLayout(new BorderLayout());
625: add(comp, BorderLayout.CENTER);
626: }
627:
628: public void prepare(int width, int height) {
629: if ((width == 0) || (height == 0)) {
630: bi = null;
631: return;
632: }
633:
634: Rectangle bounds = getBounds();
635: if ((bounds.height == 0) || (bounds.width == 0)) {
636: content.setSize(new Dimension(width, height));
637: content.validate();
638: }
639:
640: bi = new BufferedImage(width, height,
641: BufferedImage.TYPE_INT_RGB);
642: Graphics2D g2d = bi.createGraphics();
643: content.paint(g2d);
644: g2d.dispose();
645:
646: if (bounds.height == 0)
647: content.setBounds(bounds);
648: }
649:
650: public void paintComponent(Graphics g) {
651: if (animating) {
652: Rectangle bounds = getBounds();
653: if (bi != null) {
654: g.drawImage(bi, 0, 0, bounds.width, bounds.height,
655: getBackground(), null);
656: return;
657: }
658: }
659:
660: super .paintComponent(g);
661: }
662:
663: /**
664: * Get the preferred layout size of this component
665: * @return the preferred size
666: */
667: public Dimension getPreferredSize() {
668: return getLayout().preferredLayoutSize(this );
669: }
670:
671: /**
672: * Get the minimum layout size of this component
673: * @return the preferred size
674: */
675: public Dimension getMinimumSize() {
676: return super .getMinimumSize();
677: }
678: }
679:
680: public class AccordianLayout implements LayoutManager {
681: public AccordianLayout() {
682: }
683:
684: /**
685: * If the layout manager uses a per-component string,
686: * adds the component <code>comp</code> to the layout,
687: * associating it
688: * with the string specified by <code>name</code>.
689: *
690: * @param name the string to be associated with the component
691: * @param comp the component to be added
692: */
693: public void addLayoutComponent(String name, Component comp) {
694: }
695:
696: /**
697: * Removes the specified component from the layout.
698: * @param comp the component to be removed
699: */
700: public void removeLayoutComponent(Component comp) {
701: }
702:
703: /**
704: * Calculates the preferred size dimensions for the specified
705: * container, given the components it contains.
706: * @param parent the container to be laid out
707: *
708: * @see #minimumLayoutSize
709: */
710: public Dimension preferredLayoutSize(Container comp) {
711: XRollupBar rollup = (XRollupBar) comp;
712: Container cont = comp.getParent();
713: int w = 0;
714: int h = 0;
715: int numComponents = rollup.getSuperComponentCount();
716: for (int i = 0; i < numComponents; i++) {
717: Component c = rollup.getComponent(i);
718: if (c.isVisible()) {
719: Dimension d = c.getPreferredSize();
720: if (isVertical) {
721: h += Math.min(maxPanelSize,
722: (i % 2 == 0) ? d.height : Math.max(
723: minPanelSize, d.height));
724: w = Math.max(w, d.width);
725: } else {
726: h = Math.max(h, d.height);
727: w += Math.min(maxPanelSize,
728: (i % 2 == 0) ? d.width : Math.max(
729: minPanelSize, d.width));
730: }
731: }
732: }
733:
734: Dimension pd = cont.getSize();
735: return new Dimension(Math.min(w, pd.width), Math.min(h,
736: pd.height));
737: // return new Dimension( parent.getWidth(), (( numComponents - 1 ) * topBtn.getPreferredSize().height ));
738: }
739:
740: /**
741: * Calculates the minimum size dimensions for the specified
742: * container, given the components it contains.
743: * @param parent the component to be laid out
744: * @see #preferredLayoutSize
745: */
746: public Dimension minimumLayoutSize(Container parent) {
747: XRollupBar rollup = (XRollupBar) parent;
748: int numComponents = rollup.getSuperComponentCount();
749: return new Dimension(parent.getWidth(), numComponents
750: * buttonHeight);
751: }
752:
753: private int getPanelSize(Container parent) {
754: int dim = isVertical ? parent.getHeight() : parent
755: .getWidth();
756: XRollupBar rollup = (XRollupBar) parent;
757:
758: int numComponents = rollup.getSuperComponentCount();
759: int numButtons = numComponents / 2;
760: int numVisiblePanels = 0;
761: int numDividers = 0;
762: int buttonSize = isVertical ? topBtn.getPreferredSize().height
763: : topBtn.getPreferredSize().width;
764: int sharedPanelCount = 0;
765: boolean lastPanelHidden = false;
766: for (int i = 0; i < numComponents; i += 2) {
767: if (getComponent(i + 1).isVisible()) {
768: numVisiblePanels++;
769: lastPanelHidden = false;
770: numDividers++;
771: sharedPanelCount = 0;
772: } else if (lastPanelHidden
773: && (sharedPanelCount < maxSharedPanels - 1))
774: sharedPanelCount++;
775: else {
776: lastPanelHidden = true;
777: if ((sharedPanelCount == 0)
778: || (sharedPanelCount >= (maxSharedPanels - 1))) {
779: numDividers++;
780: }
781: sharedPanelCount = 0;
782: }
783: }
784:
785: int panelSizes = 0;
786: if (numVisiblePanels > 0) {
787: if (!overlapButtons)
788: numDividers = numButtons;
789:
790: panelSizes = (dim - buttonSize * numDividers)
791: / numVisiblePanels;
792: }
793:
794: return panelSizes;
795: }
796:
797: /**
798: * Lays out the specified container.
799: * @param parent the container to be laid out
800: */
801: public void layoutContainer(Container parent) {
802: int x = 0;
803: int y = 0;
804: int w = parent.getWidth();
805: int h = parent.getHeight();
806: XRollupBar rollup = (XRollupBar) parent;
807:
808: int numComponents = rollup.getSuperComponentCount();
809: int numButtons = numComponents / 2;
810: int numVisiblePanels = 0;
811: int buttonSize = isVertical ? topBtn.getPreferredSize().height
812: : topBtn.getPreferredSize().width;
813: for (int i = 0; i < numComponents; i += 2) {
814: Component comp = getComponent(i + 1);
815: if (comp.isVisible())
816: numVisiblePanels++;
817: }
818:
819: int panelSizes = getPanelSize(parent);
820: int slidingSize = 0;
821:
822: if (animating && !allExpandable) {
823: panelSizes *= 2;
824: slidingSize = (int) (panelSizes * animationOffset);
825: panelSizes -= slidingSize;
826: } else {
827: if (slidingComponent != null) {
828: if (slidingComponentVisiblity) {
829: slidingSize = (int) (panelSizes * (1.0 - animationOffset));
830: if (numVisiblePanels > 1)
831: panelSizes += (int) (panelSizes * animationOffset)
832: / (numVisiblePanels - 1);
833: } else {
834: // the hidden component has already been shown with a height of 0
835: int availableHeight = panelSizes;
836: slidingSize = (int) (panelSizes * animationOffset);
837: if (numVisiblePanels > 1) {
838: panelSizes = (panelSizes * numVisiblePanels / (numVisiblePanels - 1));
839: availableHeight /= (numVisiblePanels - 1);
840: } else
841: slidingSize = (int) (panelSizes * animationOffset);
842: panelSizes -= (int) (availableHeight * animationOffset);
843: }
844: }
845: }
846:
847: boolean nextCompVisible = true;
848: int newSize = 0;
849: int compY = y;
850: int compX = x;
851: int sharedPanels = 0;
852: int sharedPanelCount = 0;
853: for (int i = 0; i < numComponents; i++) {
854: JComponent comp = (JComponent) rollup
855: .getSuperComponent(i);
856: boolean isButton = ((i % 2) == 0);
857: if (isButton && overlapButtons) {
858: if (sharedPanels >= sharedPanelCount) {
859: sharedPanels = sharedPanelCount = 0;
860: for (int j = i + 1; j < numComponents; j += 2) {
861: if (!rollup.getSuperComponent(j)
862: .isVisible()
863: && (sharedPanelCount < maxSharedPanels))
864: sharedPanelCount++;
865: else
866: break;
867: }
868: }
869: }
870: sharedPanelCount = Math.max(sharedPanelCount, 1);
871:
872: if (comp.isVisible()) {
873: if (comp == slidingComponent)
874: newSize = slidingSize;
875: else if (comp == hidingComponent)
876: newSize = panelSizes;
877: else if (isButton)
878: newSize = buttonSize;
879: else
880: newSize = panelSizes;
881:
882: sharedPanels++;
883: if (isVertical) {
884: int dW = isButton ? w / sharedPanelCount : w;
885: comp.setBounds(isButton ? x : compX, y, dW,
886: newSize);
887: if (!overlapButtons
888: || (sharedPanels >= sharedPanelCount)) {
889: y += newSize;
890: x = compX;
891: } else
892: x += dW;
893: } else {
894: int dH = isButton ? h / sharedPanelCount : h;
895: comp.setBounds(x, isButton ? y : compY,
896: newSize, dH);
897: if (!overlapButtons
898: || (sharedPanels >= sharedPanelCount)) {
899: x += newSize;
900: y = compY;
901: } else
902: y += dH;
903: }
904: }
905:
906: if (!slideImages)
907: comp.revalidate();
908: }
909: parent.repaint();
910: }
911: }
912: }
|