kramerd 29 Posting Pro in Training

I have a complex UI with little screen real estate, so I'm trying to allow users to manage contents of a combo box using a right-click context menu. But I'm having trouble getting the combo box's drop down list to appear at the same time as the pop-up menu. I've created a small program with just the relevant code to show where I've gotten so far. If anyone knows how to get the pop-up menu to appear on top of the combo box's drop-down list, I'd sure appreciate the help.

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.lang.reflect.Field;
import java.util.ArrayList;

import javax.swing.AbstractListModel;
import javax.swing.ComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.plaf.basic.BasicComboBoxUI;
import javax.swing.plaf.basic.BasicComboPopup;

public class ComboBoxTest {
	private static final String[] names = {
		"Tom", "John", "Harry", "Sally", "Mary", "Jennifer"
	};
	
	private MyComboBoxModel model;
	private JComboBox comboBox;
	private JPopupMenu popupMenu;
	
	public ComboBoxTest() {
		// create frame
	    JFrame frame = new JFrame("ComboBox Test Program");
	    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

	    // create pop-up menu for combo box
	    popupMenu = new JPopupMenu();
	    JMenuItem mi1 = new JMenuItem("Move Up");
	    mi1.addActionListener(new MoveUpAction());
	    JMenuItem mi2 = new JMenuItem("Move Down");
	    mi2.addActionListener(new MoveDownAction());
	    JMenuItem mi3 = new JMenuItem("Delete Item");
	    mi3.addActionListener(new DeleteItemAction());
            popupMenu.add(mi1);
            popupMenu.add(mi2);
            popupMenu.add(mi3);

	    // create data model for combo box
	    ArrayList<String> nameList = new ArrayList<String>();
	    for (String name : names) {
	    	nameList.add(name);
	    }
	    model = new MyComboBoxModel(nameList);

	    // create the combo box itself
	    comboBox = new JComboBox(model);
	    comboBox.setSelectedIndex(0);
	    comboBox.setEditable(true);
	    
	    // add right-click context menu to combo box's drop-down list
	    addPopupMouseListener(comboBox, new MyMouseListener());
	    
	    // add it to the frame
	    JPanel top = new JPanel();
	    top.add(comboBox);
	    frame.add(top, BorderLayout.NORTH);
	    frame.setSize(300, 225);
	    frame.setVisible(true);
	}
	
	/*
	 * Add a mouse listener to a JComboBox's pop up menu,
	 * adapted from code found on the web here:
	 * http://engin-tekin.blogspot.com/2009/10/hrefhttpkfd.html
	 */
	private static void addPopupMouseListener(JComboBox box, MouseListener ml) {  
		try {  
			Field popupInBasicComboBoxUI = BasicComboBoxUI.class.getDeclaredField("popup");  
			popupInBasicComboBoxUI.setAccessible(true);  
			BasicComboPopup popup = (BasicComboPopup) popupInBasicComboBoxUI.get(box.getUI());  

			Field scrollerInBasicComboPopup = BasicComboPopup.class.getDeclaredField("scroller");  
			scrollerInBasicComboPopup.setAccessible(true);  
			JScrollPane scroller = (JScrollPane) scrollerInBasicComboPopup.get(popup);  

			scroller.getViewport().getView().addMouseListener(ml);  
		}  
		catch (NoSuchFieldException e) {  
			e.printStackTrace();  
		}  
		catch (IllegalAccessException e) {  
			e.printStackTrace();  
		}  
	}  

	public class MoveUpAction implements ActionListener {
		public void actionPerformed(ActionEvent e) {
			String sel = (String)comboBox.getSelectedItem();
			System.out.println("Move up " + sel);
			model.moveUp(sel);
		}
	}

	public class MoveDownAction implements ActionListener {
		public void actionPerformed(ActionEvent e) {
			String sel = (String)comboBox.getSelectedItem();
			System.out.println("Move down " + sel);
			model.moveDown(sel);
		}
	}

	public class DeleteItemAction implements ActionListener {
		public void actionPerformed(ActionEvent e) {
			String sel = (String)comboBox.getSelectedItem();
			System.out.println("Delete " + sel);
			model.delete(sel);
		}
	}
	
	public class MyMouseListener extends MouseAdapter {
		public void mouseReleased(MouseEvent me) {
			if (me.isPopupTrigger()) {
				final MouseEvent e = me;
				SwingUtilities.invokeLater(new Runnable() {
					public void run() {
						// make the drop down combo box list stay visible
						comboBox.showPopup();
						int x = e.getX();
						int y = e.getY();
						popupMenu.show(e.getComponent(), x, y);
					}
				});
			}
		}
	}

	public static void main(String args[]) {
		new ComboBoxTest();
	}
	
}

class MyComboBoxModel extends AbstractListModel implements ComboBoxModel {
	private Object selectedItem;

	private ArrayList<String> arrayList;

	public MyComboBoxModel(ArrayList<String> list) {
		arrayList = list;
	}

	public Object getSelectedItem() {
		return selectedItem;
	}

	public void setSelectedItem(Object newValue) {
		selectedItem = newValue;
	}

	public int getSize() {
		return arrayList.size();
	}

	public Object getElementAt(int i) {
		return arrayList.get(i);
	}

	/**
	 * Move the specified item up in the list.
	 * If the item is already at the top, this will
	 * move it to the bottom.
	 * @param item the item to move
	 */
	public void moveUp(String item) {
		int place = arrayList.indexOf(item);
		if (place >= 0) {
			arrayList.remove(place);
			if (place > 0)
				arrayList.add(place-1, item);
			else
				arrayList.add(item);
		}
	}

	/**
	 * Move the specified item down in the list.
	 * If the item is already at the bottom, this
	 * will move it to the top.
	 * @param item the item to move
	 */
	public void moveDown(String item) {
		int place = arrayList.indexOf(item);
		if (place >= 0) {
			arrayList.remove(place);
			if (place < arrayList.size())
				arrayList.add(place+1, item);
			else
				arrayList.add(0, item);
		}
	}
	
	/**
	 * Remove the specified item from the list
	 * @param item the item to remove
	 */
	public void delete(String item) {
		arrayList.remove(item);
	}
}