<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">package usda.weru.util;

//TODO: figure out a way not to use protected Sun classes
import com.sun.java.swing.plaf.motif.MotifComboBoxUI;
import com.sun.java.swing.plaf.windows.WindowsComboBoxUI;

import java.awt.Color;
import javax.swing.event.PopupMenuListener;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.plaf.basic.ComboPopup;
import javax.swing.plaf.metal.MetalComboBoxUI;
import javax.swing.border.EmptyBorder;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Point;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.Map;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JList;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.event.TreeExpansionListener;
import javax.swing.event.TreeWillExpandListener;
import javax.swing.plaf.ComboBoxUI;
import javax.swing.plaf.basic.BasicComboBoxUI;
import javax.swing.tree.*;
import org.apache.log4j.Logger;
import usda.weru.mcrew.MCREWWindow;
import usda.weru.weps.Weps;

/**
 *
 * @author maxerdwien
 */
public class WepsTreeComboBox extends JComponent {

    private static final long serialVersionUID = 1L;

    private static final Logger LOGGER = Logger.getLogger(WepsTreeComboBox.class);

    /**
     *
     */
    public static final String PROP_MODEL = "model";

    /**
     *
     */
    public static final String PROP_SELECTED_ITEM = "selectedItem";

    /**
     *
     */
    protected JComboBox&lt;Object&gt; c_comboBox = null;

    /**
     *
     */
    protected JTree c_tree = null;

    /**
     *
     */
    protected LazyLoadingTreeController c_treeController;

    /**
     *
     */
    protected Object c_selectedItem;

    /**
     *
     */
    protected boolean c_selectOnLossOfFocus = false;
    
    private boolean closeAll = false;

    /**
     *
     */
    protected Map&lt;Object, TreePath&gt; c_pathCache;

    /**
     *
     */
    public WepsTreeComboBox() {
        setLayout(new BorderLayout());
        initializeComboBox();
        initializeTree();

    }

    /**
     *
     * @param model
     */
    public WepsTreeComboBox(TreeModel model) {
        this();
        setModel(model);
    }

    /**
     *
     * @param root
     */
    public WepsTreeComboBox(TreeNode root) {
        this(new DefaultTreeModel(root));
    }

    private void initializeComboBox() {
        c_comboBox = new JComboBox&lt;Object&gt;() {
            private static final long serialVersionUID = 1L;

            @Override
            public void updateUI() {
                super.updateUI();
                ComboBoxUI cui = (ComboBoxUI) UIManager.getUI(this);
                if (cui instanceof MetalComboBoxUI) {
                    cui = new MetalTreeComboBoxUI();
                } else if (cui instanceof MotifComboBoxUI) {
                    cui = new MotifTreeComboBoxUI();
                } else if (cui instanceof WindowsComboBoxUI) {
                    cui = new WindowsTreeComboBoxUI();
                }
                setUI(cui);

            }
        };

        c_comboBox.setMaximumRowCount(14);

        add(c_comboBox);
    }

    private void initializeTree() {
        c_tree = new JTree();
        c_treeController = new LazyLoadingTreeController(c_tree);

        c_tree.setVisibleRowCount(8);
        c_tree.setShowsRootHandles(true);
    }

    /**
     *
     * @return
     */
    public JTree getTree() {
        return c_tree;
    }

    /**
     *
     * @return
     */
    public JComboBox&lt;Object&gt; getComboBox() {
        return c_comboBox;
    }

    /**
     *
     * @param model
     */
    public void setModel(TreeModel model) {
        TreeModel old = c_tree.getModel();
        c_pathCache = null;
        c_tree.setModel(model);
        firePropertyChange(PROP_MODEL, old, c_tree.getModel());
    }

    /**
     *
     * @return
     */
    public TreeModel getModel() {
        return c_tree.getModel();
    }

    /**
     *
     * @param item
     */
    protected void setComboSelectedItem(Object item) {
        c_comboBox.removeAllItems();
        c_comboBox.addItem(item);
        c_comboBox.setSelectedItem(item);
    }

    /**
     *
     * @param path
     */
    protected void setTreeSelectedPath(TreePath path) {
        c_tree.setSelectionPath(path);
    }

    /**
     *
     * @param item
     */
    protected void setSelectedItem(Object item) {
        c_selectedItem = item;
        firePropertyChange(PROP_SELECTED_ITEM, null, c_selectedItem);
    }

    /**
     *
     * @param path
     */
    public void setSelectedPath(TreePath path) {
        if (path != null) {
            Object item = path.getLastPathComponent();
            setTreeSelectedPath(path);
            setComboSelectedItem(item);
            setSelectedItem(item);
        } else {
            c_tree.setSelectionRow(-1);
            c_comboBox.removeAllItems();
            setSelectedItem(null);
        }
    }

    /**
     *
     * @return
     */
    public Object getSelectedItem() {
        return c_selectedItem;
    }

    /**
     *
     * @param select
     */
    public void setSelectOnLossOfFocus(boolean select) {
        c_selectOnLossOfFocus = select;
    }

    /**
     *
     * @param cursor
     */
    @Override
    public void setCursor(Cursor cursor) {
        super.setCursor(cursor);
        c_tree.setCursor(cursor);
        c_comboBox.setCursor(cursor);
    }

    /**
     *
     * @param enabled
     */
    @Override
    public void setEnabled(boolean enabled) {
        super.setEnabled(enabled);
        c_tree.setEnabled(enabled);
        c_comboBox.setEnabled(enabled);
    }

    //pass through methods
    /**
     *
     * @param rootVisible
     */
    public void setRootVisible(boolean rootVisible) {
        c_tree.setRootVisible(rootVisible);
    }

    /**
     *
     * @return
     */
    public boolean isRootVisible() {
        return c_tree.isRootVisible();
    }

    /**
     *
     * @return
     */
    public boolean isPopupVisible() {
        return c_comboBox.isPopupVisible();
    }

    /**
     *
     * @param visible
     */
    public void setPopupVisible(boolean visible) {
        c_comboBox.setPopupVisible(visible);
    }

    /**
     *
     */
    public void showPopup() {
        c_comboBox.showPopup();
        if(closeAll &amp;&amp; ConfigData.isToCollapse())
        {
            for(int index = 0; index &lt; c_tree.getRowCount(); index ++)
            { 
                TreePath path = c_tree.getPathForRow(index);
                if(((FileTreeNode) path.getLastPathComponent()).c_file.getAbsolutePath().endsWith(".zip")) continue;
                c_tree.collapseRow(index);
            }
        }
    }

    public void setToClose(boolean input)
    {
        closeAll = input;
    }
    
    /**
     *
     */
    public void hidePopup() {
        c_comboBox.hidePopup();
    }

    /**
     *
     * @param bg
     */
    @Override
    public void setBackground(Color bg) {
        super.setBackground(bg);
        c_comboBox.setBackground(bg);
        c_tree.setBackground(bg);
    }

    /**
     *
     * @param fg
     */
    @Override
    public void setForeground(Color fg) {
        super.setForeground(fg);
        c_comboBox.setForeground(fg);
        c_tree.setForeground(fg);
    }

    class TreePopup implements ComboPopup, MouseMotionListener, MouseListener, KeyListener,
            PopupMenuListener, TreeExpansionListener, TreeWillExpandListener, FocusListener {

        protected JScrollPane c_scroller;
        protected JComboBox&lt;?&gt; c_comboBox;
        protected JPopupMenu c_popup;
        protected boolean c_mouseInside = false;
        
        // required for the ComboPopup interface, this class does nothing with it but return it.
        protected final JList&lt;?&gt; list = new JList&lt;&gt;();

        public TreePopup(JComboBox&lt;?&gt; comboBox) {
            c_comboBox = comboBox;
            initializePopup();
        }

        protected void initializePopup() {
            c_scroller = new JScrollPane();

            //never show the horizontal scrollbar, the popup will automagically resize through updatePopup();
            c_scroller.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);

            c_popup = new JPopupMenu();
            c_popup.setLightWeightPopupEnabled(false);
            c_popup.setLayout(new BorderLayout());
            c_popup.setBorder(new EmptyBorder(0, 0, 0, 0));
            c_popup.addPopupMenuListener(this);
            c_popup.add(c_scroller);
            c_popup.pack();

        }

        protected void updatePopup() {
            int comboWidth = c_comboBox.getWidth() + 1;
            int popupWidth = (int) c_tree.getPreferredSize().getWidth();
            int width = Math.max(comboWidth, popupWidth);

            int height = (int) c_tree.getPreferredScrollableViewportSize().getHeight() * 2;

            c_popup.setPopupSize(width, height);
            Container parent = c_comboBox.getParent();
            while(parent != null)
            {
                if(parent instanceof Weps) break;
                if(parent instanceof MCREWWindow) break;
                parent = parent.getParent();
            }
            
            //Get the top left corner of WEPS or MCREW
            Point orig = parent.getLocationOnScreen();
            //Find the halfway point
            int half  = parent.getBounds().height / 2;
            //Get the combobox location
            Point other = c_comboBox.getLocationOnScreen();
            //find out if the point is lower than the halfway mark.
            int place = other.y - orig.y;
            if(place &gt; half) verticalOffset = other.y - height;
            else verticalOffset = other.y + 25;
            
            
            //prevent loss of focus
            c_tree.requestFocusInWindow();

        }

        int verticalOffset;
        
        @Override
        public void show() {
            c_scroller.setViewportView(c_tree);

            //make sure we're the correct size
            updatePopup();

            if (c_comboBox.isShowing()) {
                c_popup.show(c_comboBox, 0, c_comboBox.getHeight());
            } else {
                LOGGER.warn("Can't show popup. Parent not shiowing.");
                return;
            }

            TreePath path = c_tree.getSelectionPath();
            if (path != null) {
                c_tree.setSelectionPath(path);
            } else {
                c_tree.setSelectionRow(0);
            }

            //scroll to the currently selected node
            c_tree.scrollPathToVisible(path);

            c_tree.addTreeExpansionListener(this);
            c_tree.addTreeWillExpandListener(this);
            c_tree.addMouseListener(this);
            c_tree.addKeyListener(this);
            c_tree.addFocusListener(this);

            //show the popup
            c_popup.setVisible(true);

            //make sure we have focus
            c_tree.requestFocus();
            
            c_popup.setLocation(c_comboBox.getLocationOnScreen().x, verticalOffset);
        }

        @Override
        public void hide() {
            c_popup.setVisible(false);

            //cleanup listeners
            c_tree.removeTreeExpansionListener(this);
            c_tree.removeTreeWillExpandListener(this);
            c_tree.removeMouseListener(this);
            c_tree.removeKeyListener(this);
            c_tree.removeFocusListener(this);

        }

        @Override
        public JList&lt;?&gt; getList() {
            return list;
        }

        @Override
        public MouseListener getMouseListener() {
            return this;
        }

        @Override
        public MouseMotionListener getMouseMotionListener() {
            return this;
        }

        @Override
        public KeyListener getKeyListener() {
            return this;
        }

        @Override
        public boolean isVisible() {
            return c_popup.isVisible();
        }

        @Override
        public void uninstallingUI() {
            c_popup.removePopupMenuListener(this);
        }

        // MouseListener
        @Override
        public void mousePressed(MouseEvent e) {
        }

        @Override
        public void mouseReleased(MouseEvent e) {
        }

        // something else registered for MousePressed
        @Override
        public void mouseClicked(MouseEvent e) {
            WepsTreeComboBox.this.processEvent(e);
            if (e.getSource().equals(c_tree)) {
                //tree event
                TreePath path = c_tree.getPathForLocation(e.getX(), e.getY());
                if (path != null) {
                    Object o = path.getLastPathComponent();
                    if (o != null &amp;&amp; c_tree.getModel().isLeaf(o)) {
                        //user clicked a leaf, select it!
                        setComboSelectedItem(o);
                        setSelectedItem(o);
                        hide();
                    }
                }

            } else {
                //combo box
                if (e.getClickCount() &gt; 1) {
                    return;
                }
                if (!SwingUtilities.isLeftMouseButton(e)) {
                    return;
                }
                if (!c_comboBox.isEnabled()) {
                    return;
                }
                if (c_comboBox.isEditable()) {
                    c_comboBox.getEditor().getEditorComponent().requestFocusInWindow();
                } else {
                    c_comboBox.requestFocusInWindow();
                }
                togglePopup();
            }
        }

        @Override
        public void mouseEntered(MouseEvent e) {
            if (e.getSource().equals(c_tree)) {
                c_mouseInside = true;
            }
        }

        @Override
        public void mouseExited(MouseEvent e) {
            if (e.getSource().equals(c_tree)) {
                c_mouseInside = false;
            }
        }

        // MouseMotionListener
        @Override
        public void mouseDragged(MouseEvent e) {
        }

        @Override
        public void mouseMoved(MouseEvent e) {
        }

        @Override
        public void keyPressed(KeyEvent e) {
        }

        @Override
        public void keyTyped(KeyEvent e) {
        }

        @Override
        public void keyReleased(KeyEvent e) {
            if (e.getSource().equals(c_tree)) {
                if (e.getKeyCode() == KeyEvent.VK_ENTER) {
                    TreePath path = c_tree.getSelectionPath();
                    if (path != null) {
                        Object o = path.getLastPathComponent();
                        if (o != null &amp;&amp; c_tree.getModel().isLeaf(o)) {
                            //user clicked a leaf, select it!
                            setComboSelectedItem(o);
                            setSelectedItem(o);
                            hide();
                        }
                    }
                }
            }
        }

        @Override
        public void focusGained(FocusEvent e) {

        }

        @Override
        public void focusLost(FocusEvent e) {
            if (c_selectOnLossOfFocus) {
                TreePath path = c_tree.getSelectionPath();
                if (path != null) {
                    Object o = path.getLastPathComponent();
                    if (o != null &amp;&amp; c_tree.getModel().isLeaf(o)) {
                        //user clicked a leaf, select it!
                        setComboSelectedItem(o);
                        setSelectedItem(o);
                    }
                }
                hide();
            }
        }

        /**
         * Variables hideNext and mouseInside are used to
         * hide the popupMenu by clicking the mouse in the JComboBox
         */
        @Override
        public void popupMenuCanceled(PopupMenuEvent e) {
        }

        @Override
        public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {

        }

        @Override
        public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
        }

        protected void togglePopup() {
            if (isVisible()) {
                hide();
            } else {
                show();
            }
        }

        @Override
        public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException {
            //begin loading the kids, so show a friendly wait cursor
            c_tree.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
        }

        @Override
        public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException {
            //do nothing
        }

        @Override
        public void treeExpanded(TreeExpansionEvent event) {
            //done loading the kids
            c_tree.setCursor(Cursor.getDefaultCursor());

            //resize
            updatePopup();
        }

        @Override
        public void treeCollapsed(TreeExpansionEvent event) {
            //resize
            updatePopup();
        }
    }

    //special ui classes for creating the popup, it's an ugly hack.
    class MetalTreeComboBoxUI extends MetalComboBoxUI {

        @Override
        protected ComboPopup createPopup() {
            return new TreePopup(comboBox);
        }
    }

    class WindowsTreeComboBoxUI extends WindowsComboBoxUI {

        @Override
        protected ComboPopup createPopup() {
            return new TreePopup(comboBox);
        }
    }

    class MotifTreeComboBoxUI extends MotifComboBoxUI {

        private static final long serialVersionUID = 1L;

        @Override
        protected ComboPopup createPopup() {
            return new TreePopup(comboBox);
        }
    }

    class BacicTreeComboBoxUI extends BasicComboBoxUI {

        @Override
        protected ComboPopup createPopup() {
            return new TreePopup(comboBox);
        }
    }
}
</pre></body></html>