/* This file is part of JFLICKS. JFLICKS is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. JFLICKS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with JFLICKS. If not, see <http://www.gnu.org/licenses/>. */ package org.jflicks.ui.view.fe; import java.awt.Color; import java.awt.Dimension; import java.awt.GridLayout; import java.awt.Font; import java.awt.Insets; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.concurrent.TimeUnit; import javax.swing.AbstractAction; import javax.swing.ImageIcon; import javax.swing.InputMap; import javax.swing.JComponent; import javax.swing.JLayeredPane; import javax.swing.KeyStroke; import javax.swing.SwingConstants; import org.jdesktop.core.animation.timing.Animator; import org.jdesktop.core.animation.timing.KeyFrames; import org.jdesktop.core.animation.timing.PropertySetter; import org.jdesktop.core.animation.timing.TimingTarget; import org.jdesktop.swingx.JXLabel; import org.jdesktop.swingx.JXPanel; import org.jdesktop.swingx.painter.ImagePainter; import org.jdesktop.swingx.painter.MattePainter; import org.jflicks.util.Util; /** * This panel will display an array of JXLabels based upon the given * TextImage objects passed in the constructor. The panel will animate * with zooming fonts and fade ins and fade outs. * * @author Doug Barnum * @version 1.0 */ public class TextImagePanel extends BaseCustomizePanel implements ActionListener { private static final double HGAP = 0.02; private static final double VGAP = 0.02; private static final int ATIME = 250; private static final int RESOLUTION = 10; private ArrayList<ActionListener> actionList = new ArrayList<ActionListener>(); private TextImage[] textImages; private CrossFadePanel backgroundPanel; private JXPanel popupPanel; private JXLabel logoLabel; private MattePainter mattePainter; private JXLabel[] labels; private Animator[] animators; private Animator backgroundAnimator; private ClockPanel clockPanel; private int selectedIndex; private int popupSelectedIndex; private HashMap<TextImage, TextImage[]> childHashMap; private HashMap<TextImage[], JXPanel> panelHashMap; private HashMap<JXPanel, Animator> animatorHashMap; private HashMap<JXPanel, JXLabel[]> labelsHashMap; private ImageIcon rightButtonImageIcon; /** * Constructor with all required arguments. * * @param array The defined TextImage instances to display. * @param logo The logo to display. */ public TextImagePanel(TextImage[] array, BufferedImage logo) { setFocusable(true); requestFocus(); setRightButtonImageIcon( new ImageIcon(getClass().getResource("right_button.png"))); if (logo != null) { JXLabel llabel = new JXLabel(new ImageIcon(logo)); setLogoLabel(llabel); } setTextImages(array); setSelectedIndex(-1); InputMap map = getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); LeftAction leftAction = new LeftAction(); map.put(KeyStroke.getKeyStroke("LEFT"), "left"); getActionMap().put("left", leftAction); RightAction rightAction = new RightAction(); map.put(KeyStroke.getKeyStroke("RIGHT"), "right"); getActionMap().put("right", rightAction); UpAction upAction = new UpAction(); map.put(KeyStroke.getKeyStroke("UP"), "up"); getActionMap().put("up", upAction); DownAction downAction = new DownAction(); map.put(KeyStroke.getKeyStroke("DOWN"), "down"); getActionMap().put("down", downAction); EnterAction enterAction = new EnterAction(this); map.put(KeyStroke.getKeyStroke("ENTER"), "enter"); getActionMap().put("enter", enterAction); } private ImageIcon getRightButtonImageIcon() { return (rightButtonImageIcon); } private void setRightButtonImageIcon(ImageIcon ii) { rightButtonImageIcon = ii; } private HashMap<TextImage, TextImage[]> getChildHashMap() { return (childHashMap); } private void setChildHashMap(HashMap<TextImage, TextImage[]> m) { childHashMap = m; } private void addChild(TextImage child) { HashMap<TextImage, TextImage[]> m = getChildHashMap(); if ((child != null) && (m != null)) { TextImage parent = child.getParentTextImage(); if (parent != null) { TextImage[] array = m.get(parent); if (array != null) { boolean found = false; for (int i = 0; i < array.length; i++) { if (array[i].equals(child)) { found = true; break; } } if (!found) { TextImage[] newarray = new TextImage[array.length + 1]; for (int i = 0; i < array.length; i++) { newarray[i] = array[i]; } newarray[newarray.length - 1] = child; m.put(parent, newarray); } } else { array = new TextImage[1]; array[0] = child; m.put(parent, array); } } } } private TextImage[] getChildren(String s) { TextImage[] result = null; HashMap<TextImage, TextImage[]> m = getChildHashMap(); if ((s != null) && (m != null)) { Iterator<TextImage> iterator = m.keySet().iterator(); while (iterator.hasNext()) { TextImage ti = iterator.next(); if (s.equals(ti.getText())) { result = m.get(ti); break; } } } return (result); } private String[] getChildren() { String[] result = null; HashMap<TextImage, TextImage[]> m = getChildHashMap(); if (m != null) { Collection<TextImage[]> c = m.values(); if (c != null) { ArrayList<String> list = new ArrayList<String>(); Iterator<TextImage[]> iterator = c.iterator(); while (iterator.hasNext()) { TextImage[] array = iterator.next(); if (array != null) { for (int i = 0; i < array.length; i++) { list.add(array[i].getText()); } } } if (list.size() > 0) { result = list.toArray(new String[list.size()]); } } } return (result); } private HashMap<TextImage[], JXPanel> getPanelHashMap() { return (panelHashMap); } private void setPanelHashMap(HashMap<TextImage[], JXPanel> m) { panelHashMap = m; } private void addPanel(TextImage[] array, JXPanel p) { HashMap<TextImage[], JXPanel> m = getPanelHashMap(); if ((array != null) && (p != null) && (m != null)) { m.put(array, p); } } private JXPanel getPanel(TextImage[] array) { JXPanel result = null; HashMap<TextImage[], JXPanel> m = getPanelHashMap(); if ((array != null) && (m != null)) { result = m.get(array); } return (result); } private HashMap<JXPanel, JXLabel[]> getLabelsHashMap() { return (labelsHashMap); } private void setLabelsHashMap(HashMap<JXPanel, JXLabel[]> m) { labelsHashMap = m; } private void addLabels(JXPanel p, JXLabel[] array) { HashMap<JXPanel, JXLabel[]> m = getLabelsHashMap(); if ((p != null) && (array != null) && (m != null)) { m.put(p, array); } } private JXLabel[] getLabels(JXPanel p) { JXLabel[] result = null; HashMap<JXPanel, JXLabel[]> m = getLabelsHashMap(); if ((p != null) && (m != null)) { result = m.get(p); } return (result); } private HashMap<JXPanel, Animator> getAnimatorHashMap() { return (animatorHashMap); } private void setAnimatorHashMap(HashMap<JXPanel, Animator> m) { animatorHashMap = m; } private void addAnimator(JXPanel p, Animator a) { HashMap<JXPanel, Animator> m = getAnimatorHashMap(); if ((p != null) && (a != null) && (m != null)) { m.put(p, a); } } private Animator getAnimator(JXPanel p) { Animator result = null; HashMap<JXPanel, Animator> m = getAnimatorHashMap(); if ((p != null) && (m != null)) { result = m.get(p); } return (result); } /** * Allow access to our defined TextImage array. * * @return An array of TextImage instances. */ public TextImage[] getTextImages() { TextImage[] result = null; if (textImages != null) { result = Arrays.copyOf(textImages, textImages.length); } return (result); } private void setTextImages(TextImage[] array) { textImages = array; } private int getSelectedIndex() { return (selectedIndex); } private void setSelectedIndex(int i) { int old = selectedIndex; selectedIndex = i; update(old, selectedIndex); } private int getPopupSelectedIndex() { return (popupSelectedIndex); } private void setPopupSelectedIndex(int i) { int old = popupSelectedIndex; popupSelectedIndex = i; updatePopup(old, popupSelectedIndex); } private CrossFadePanel getBackgroundPanel() { return (backgroundPanel); } private void setBackgroundPanel(CrossFadePanel p) { backgroundPanel = p; } private JXPanel getPopupPanel() { return (popupPanel); } private void setPopupPanel(JXPanel p) { popupPanel = p; } private JXLabel getLogoLabel() { return (logoLabel); } private void setLogoLabel(JXLabel l) { logoLabel = l; } private MattePainter getMattePainter() { return (mattePainter); } private void setMattePainter(MattePainter p) { mattePainter = p; } private JXLabel[] getLabels() { return (labels); } private void setLabels(JXLabel[] array) { labels = array; } private Animator[] getAnimators() { return (animators); } private void setAnimators(Animator[] array) { animators = array; } private Animator getBackgroundAnimator() { return (backgroundAnimator); } private void setBackgroundAnimator(Animator a) { backgroundAnimator = a; } private ClockPanel getClockPanel() { return (clockPanel); } private void setClockPanel(ClockPanel p) { clockPanel = p; } /** * {@inheritDoc} */ public void performControl() { } /** * {@inheritDoc} */ public void performLayout(Dimension d) { JLayeredPane pane = getLayeredPane(); if ((d != null) && (pane != null)) { // This most likely our screen size... double width = d.getWidth(); double height = d.getHeight(); // Compute our gaps... double hgap = width * HGAP; double vgap = height * VGAP; setChildHashMap(new HashMap<TextImage, TextImage[]>()); setPanelHashMap(new HashMap<TextImage[], JXPanel>()); setAnimatorHashMap(new HashMap<JXPanel, Animator>()); setLabelsHashMap(new HashMap<JXPanel, JXLabel[]>()); TextImage[] tarray = getTextImages(); if ((tarray != null) && (tarray.length > 0)) { ArrayList<JXLabel> list = new ArrayList<JXLabel>(); for (int i = 0; i < tarray.length; i++) { if (tarray[i].getParentTextImage() == null) { JXLabel label = new JXLabel(tarray[i].getText()); label.setFont(getLargeFont()); label.setForeground(getSelectedColor()); label.setHorizontalTextPosition(SwingConstants.CENTER); label.setHorizontalAlignment(SwingConstants.RIGHT); list.add(label); } else { // We have a child. addChild(tarray[i]); } } JXLabel[] labs = list.toArray(new JXLabel[list.size()]); FontEvaluator feval = new FontEvaluator( getMediumFont(), getLargeFont(), getMediumFontSize(), getLargeFontSize()); KeyFrames.Builder<Font> kfb = new KeyFrames.Builder<Font>(); kfb.addFrames(feval.getFonts()); kfb.setEvaluator(feval); KeyFrames<Font> fontFrames = kfb.build(); Animator[] anis = new Animator[tarray.length]; for (int i = 0; i < labs.length; i++) { TimingTarget tt = PropertySetter.getTarget(labs[i], "font", fontFrames); anis[i] = new Animator.Builder().setDuration(ATIME, TimeUnit.MILLISECONDS).setEndBehavior( Animator.EndBehavior.HOLD).addTarget(tt).build(); } setLabels(labs); setAnimators(anis); } ClockPanel clockp = new ClockPanel(getMediumFont(), getInfoColor(), getPanelColor(), (float) getPanelAlpha()); clockp.setOpaque(false); setClockPanel(clockp); // The JXLabels are configured at this point with their large // size. So they need at least that much room to expand. We // can get the size of the label to help us lay them out. JXLabel[] array = getLabels(); double labelMaxWidth = 0.0; double labelMaxHeight = 0.0; for (int i = 0; i < array.length; i++) { Dimension fd = array[i].getPreferredSize(); if (fd != null) { if (fd.getWidth() > labelMaxWidth) { labelMaxWidth = fd.getWidth(); } if (fd.getHeight() > labelMaxHeight) { labelMaxHeight = fd.getHeight(); } } } // We also have to take into account all the submenu items // to make sure the Label won't be too big for the popup panel. double popupPanelWidth = 0.0; String[] kidnames = getChildren(); if (kidnames != null) { for (int i = 0; i < kidnames.length; i++) { JXLabel tmp = new JXLabel(kidnames[i]); tmp.setFont(getSmallFont()); Dimension fd = tmp.getPreferredSize(); if (fd != null) { // Just need to check width... if (fd.getWidth() > popupPanelWidth) { popupPanelWidth = fd.getWidth(); } } } } popupPanelWidth += hgap; // We need to compute the height of the labels that will // go into any popup panel so we can size things properly. double popupLabelHeight = SMALL_FONT_SIZE; JXLabel test = new JXLabel("this is a test"); test.setFont(getSmallFont()); Dimension testdim = test.getPreferredSize(); if (testdim != null) { popupLabelHeight = testdim.getHeight(); } // Compute the width of the "gray panel" where the labels // reside upon. It has to be at least as wide as the largest // label width. double grayPanelWidth = width * 0.3; if (grayPanelWidth < labelMaxWidth) { grayPanelWidth = labelMaxWidth + hgap; } // The total pixels we need in height. double total = (array.length * labelMaxHeight) + ((array.length + 1) * vgap); // For now we support only an amount that "fit". Worry // about scrolling in the future. if (total > height) { throw new RuntimeException("Can't fit buttons..."); } // First define the "gray" area panel which will display // the selections. Color color = getPanelColor(); color = new Color(color.getRed(), color.getGreen(), color.getBlue(), (int) (getPanelAlpha() * 255)); JXPanel panel = new JXPanel(); MattePainter mpainter = new MattePainter(color); panel.setBackgroundPainter(mpainter); setMattePainter(mpainter); panel.setAlpha((float) getPanelAlpha()); panel.setBounds(0, 0, (int) grayPanelWidth, (int) height); pane.add(panel, Integer.valueOf(110)); setBackgroundPainter(mpainter); // Next define the selections and any popup panels. double top = (height - total) / 2.0; for (int i = 0; i < array.length; i++) { array[i].setBounds((int) hgap, (int) top, (int) labelMaxWidth, (int) labelMaxHeight); pane.add(array[i], Integer.valueOf(120)); array[i].setFont(getMediumFont()); array[i].setForeground(getUnselectedColor()); TextImage[] kids = getChildren(array[i].getText()); if (kids != null) { JXLabel right = new JXLabel(getRightButtonImageIcon()); right.setBounds((int) (hgap + labelMaxWidth), (int) top, 32, (int) labelMaxHeight); pane.add(right, Integer.valueOf(120)); // Next is to pre-build this popup panel so we just // have to do it once. Plus we have size info here // that makes it easier to do now. Rectangle r = right.getBounds(); GridLayout gl = new GridLayout(0, 1, 4, 4); JXPanel popup = new JXPanel(gl); popup.setOpaque(false); popup.setAlpha(0.0f); popup.setBackgroundPainter(getMattePainter()); popup.setBounds((int) (r.getX() + 32), (int) r.getY() + 32, (int) popupPanelWidth, (int) ((kids.length * popupLabelHeight) + ((kids.length + 1) * 4))); TimingTarget tt = PropertySetter.getTarget(popup, "alpha", Float.valueOf(0.0f), Float.valueOf((float) getPanelAlpha())); Animator popupAnimator = new Animator.Builder().setDuration(ATIME, TimeUnit.MILLISECONDS).addTarget(tt).build(); addAnimator(popup, popupAnimator); JXLabel[] kidlabels = new JXLabel[kids.length]; for (int j = 0; j < kids.length; j++) { JXLabel kidlabel = new JXLabel(kids[j].getText()); kidlabel.setOpaque(false); kidlabel.setFont(getSmallFont()); kidlabel.setForeground(getUnselectedColor()); popup.add(kidlabel); kidlabels[j] = kidlabel; } addPanel(kids, popup); addLabels(popup, kidlabels); pane.add(popup, Integer.valueOf(130)); } top += (labelMaxHeight + vgap); } // Display the time. ClockPanel cp = getClockPanel(); if (cp != null) { Dimension cpdim = cp.getPreferredSize(); if (cpdim != null) { double x = width - cpdim.getWidth() - hgap - ClockPanel.FUDGE; cp.setBounds((int) x, (int) vgap, (int) (cpdim.getWidth() + ClockPanel.FUDGE), (int) cpdim.getHeight()); pane.add(cp, Integer.valueOf(120)); } } JXLabel llabel = getLogoLabel(); if (llabel != null) { Dimension logodim = llabel.getPreferredSize(); if (logodim != null) { double x = width - logodim.getWidth() - hgap; double y = height - logodim.getHeight() - vgap; llabel.setBounds((int) x, (int) y, (int) logodim.getWidth(), (int) logodim.getHeight()); pane.add(llabel, Integer.valueOf(120)); } } // Make a background panel that makes the fade in of the // background image a little nicer since it has the same // color as the gray panel. //JXPanel backPanel = new JXPanel(); CrossFadePanel backPanel = new CrossFadePanel(); backPanel.setOpaque(false); setBackgroundPanel(backPanel); backPanel.setBounds(0, 0, (int) width, (int) height); pane.add(backPanel, Integer.valueOf(100)); TimingTarget tt = PropertySetter.getTarget(backPanel, "alpha", Float.valueOf(0.0f), Float.valueOf(1.0f)); Animator backAnimator = new Animator.Builder().setDuration(ATIME, TimeUnit.MILLISECONDS).addTarget(tt).build(); setBackgroundAnimator(backAnimator); // Start at the first item. setPopupPanel(null); setSelectedIndex(0); } } /** * Add a listener. * * @param l A given listener. */ public void addActionListener(ActionListener l) { actionList.add(l); } /** * Remove a listener. * * @param l A given listener. */ public void removeActionListener(ActionListener l) { actionList.remove(l); } /** * Send out an action event. * * @param event The event to propagate. */ public void fireActionEvent(ActionEvent event) { processActionEvent(event); } protected synchronized void processActionEvent(ActionEvent event) { for (int i = 0; i < actionList.size(); i++) { ActionListener l = actionList.get(i); l.actionPerformed(event); } } /** * Just propogate all events to our listeners. * * @param event The event to send along. */ public void actionPerformed(ActionEvent event) { fireActionEvent(event); } private void update(int old, int current) { JXLabel[] array = getLabels(); Animator[] anis = getAnimators(); if ((array != null) && (anis != null)) { if ((old >= 0) && (old < array.length)) { if (anis[old].isRunning()) { anis[old].stop(); } array[old].setForeground(getUnselectedColor()); anis[old].startReverse(); } if ((current >= 0) && (current < array.length)) { if (anis[current].isRunning()) { anis[current].stop(); } array[current].setForeground(getSelectedColor()); anis[current].start(); TextImage currentTextImage = getCurrentTextImage(current); if (currentTextImage != null) { BufferedImage bi = currentTextImage.getImage(); if (bi != null) { CrossFadePanel backPanel = getBackgroundPanel(); if (backPanel != null) { bi = ensureSize(backPanel, bi); currentTextImage.setImage(bi); if (isEffects()) { backPanel.setAlpha(0.0f); backPanel.setFromBufferedImage( backPanel.getCurrentBufferedImage()); backPanel.setCurrentBufferedImage(bi); Animator backAnimator = getBackgroundAnimator(); if (backAnimator != null) { if (backAnimator.isRunning()) { backAnimator.stop(); } backAnimator.start(); } } else { backPanel.setAlpha(1.0f); backPanel.setFromBufferedImage(null); backPanel.setCurrentBufferedImage(bi); backPanel.repaint(); } } } } } } } private BufferedImage ensureSize(JXPanel p, BufferedImage bi) { BufferedImage result = bi; if ((p != null) && (bi != null)) { Dimension d = p.getSize(); if (d != null) { if ((d.getWidth() != bi.getWidth()) && (d.getWidth() > 0)) { result = Util.resize(bi, (int) d.getWidth(), (int) d.getHeight()); } } } return (result); } private void updatePopup(int old, int current) { JXPanel popup = getPopupPanel(); if (popup != null) { JXLabel[] array = getLabels(popup); if (array != null) { if ((old >= 0) && (old < array.length)) { array[old].setForeground(getUnselectedColor()); } if ((current >= 0) && (current < array.length)) { array[current].setForeground(getSelectedColor()); } } } } private TextImage getCurrentTextImage(int index) { TextImage result = null; TextImage[] array = getTextImages(); if (array != null) { // The current TextImage is not a 1:1 lookup into the array // of TextImage instances we have. It is only the "root" or // "parent" TextImage instances we have to look for. for (int i = 0; i < array.length; i++) { if (array[i].getParentTextImage() == null) { if (index == 0) { result = array[i]; break; } index--; } } } return (result); } private JXLabel getSelectedLabel() { JXLabel result = null; JXLabel[] array = getLabels(); if (array != null) { int index = getSelectedIndex(); if ((index >= 0) && (index < array.length)) { result = array[index]; } } return (result); } private TextImage[] getSelectedChildren() { TextImage[] result = null; JXLabel[] array = getLabels(); if (array != null) { int index = getSelectedIndex(); if ((index >= 0) && (index < array.length)) { JXLabel l = array[index]; if (l != null) { result = getChildren(l.getText()); } } } return (result); } private void activatePopup() { TextImage[] kids = getSelectedChildren(); JLayeredPane pane = getLayeredPane(); if ((kids != null) && (pane != null)) { JXPanel popup = getPanel(kids); if (popup != null) { setPopupPanel(popup); JXLabel[] labs = getLabels(popup); if (labs != null) { for (int i = 0; i < labs.length; i++) { labs[i].setForeground(getUnselectedColor()); } } setPopupSelectedIndex(0); Animator a = getAnimator(popup); if (a != null) { if (a.isRunning()) { a.stop(); } a.start(); } } } } /** * Deactivate the current popup. */ public void deactivatePopup() { JXPanel popup = getPopupPanel(); if (popup != null) { JLayeredPane pane = getLayeredPane(); if (pane != null) { setPopupPanel(null); setPopupSelectedIndex(-1); Animator a = getAnimator(popup); if (a != null) { if (a.isRunning()) { a.stop(); } a.startReverse(); } } } } /** * The panel is either currently showing a popup menu or it is not. * * @return True is Popup menu is being displayed. */ public boolean isPopup() { return (getPopupPanel() != null); } private boolean isUp() { boolean result = false; if (isPopup()) { JXPanel popup = getPopupPanel(); if (popup != null) { JXLabel[] array = getLabels(popup); if (array != null) { int index = getPopupSelectedIndex() - 1; result = (index >= 0); } } } else { JXLabel[] array = getLabels(); if (array != null) { int index = getSelectedIndex() - 1; result = (index >= 0); } } return (result); } private boolean isDown() { boolean result = false; if (isPopup()) { JXPanel popup = getPopupPanel(); if (popup != null) { JXLabel[] array = getLabels(popup); if (array != null) { int index = getPopupSelectedIndex() + 1; result = (index < array.length); } } } else { JXLabel[] array = getLabels(); if (array != null) { int index = getSelectedIndex() + 1; result = (index < array.length); } } return (result); } private boolean isRight() { boolean result = false; if (!isPopup()) { JXLabel[] array = getLabels(); if (array != null) { int index = getSelectedIndex(); if ((index >= 0) && (index < array.length)) { JXLabel l = array[index]; if (l != null) { TextImage[] kids = getChildren(l.getText()); result = (kids != null) && (getPopupPanel() == null); } } } } return (result); } class LeftAction extends AbstractAction { public LeftAction() { } public void actionPerformed(ActionEvent e) { deactivatePopup(); fireActionEvent(e); } } class RightAction extends AbstractAction { public RightAction() { } public void actionPerformed(ActionEvent e) { if (isRight()) { activatePopup(); } fireActionEvent(e); } } class UpAction extends AbstractAction { public UpAction() { } public void actionPerformed(ActionEvent e) { if (isUp()) { if (isPopup()) { setPopupSelectedIndex(getPopupSelectedIndex() - 1); } else { setSelectedIndex(getSelectedIndex() - 1); } } else { if (isPopup()) { JXPanel popup = getPopupPanel(); if (popup != null) { JXLabel[] array = getLabels(popup); if (array != null) { setPopupSelectedIndex(array.length - 1); } } } else { JXLabel[] array = getLabels(); if (array != null) { setSelectedIndex(array.length - 1); } } } fireActionEvent(e); } } class DownAction extends AbstractAction { public DownAction() { } public void actionPerformed(ActionEvent e) { if (isDown()) { if (isPopup()) { setPopupSelectedIndex(getPopupSelectedIndex() + 1); } else { setSelectedIndex(getSelectedIndex() + 1); } } else { if (isPopup()) { setPopupSelectedIndex(0); } else { setSelectedIndex(0); } } fireActionEvent(e); } } class EnterAction extends AbstractAction { private TextImagePanel textImagePanel; public EnterAction(TextImagePanel tip) { textImagePanel = tip; } public void actionPerformed(ActionEvent e) { JXLabel[] array = getLabels(); if (array != null) { int index = getSelectedIndex(); if ((index >= 0) && (index < array.length)) { TextImage[] kids = getChildren(array[index].getText()); if (kids != null) { // We have a parent selection item. Check first for // a popup activated. JXPanel popup = getPopupPanel(); if (popup != null) { // Ok it's visible... JXLabel[] labs = getLabels(popup); if (labs != null) { int cindex = getPopupSelectedIndex(); if ((cindex >= 0) && (cindex < labs.length)) { String s = array[index].getText() + ":" + labs[cindex].getText(); ActionEvent event = new ActionEvent(textImagePanel, 0, s); fireActionEvent(event); } } } else { // They have selected a parent that has kids // but the kids are not visible. Let's make // them visible. activatePopup(); } } else { // Just a basic selection item. ActionEvent event = new ActionEvent(textImagePanel, 0, array[index].getText()); fireActionEvent(event); } } } fireActionEvent(e); } } }