A simple class browser
At JavaOne, Geertjan gave a talk on building an IDE for a specific framework (Wicket). I work on a similar project for an in-house framework. One feature that I thought would be useful is a convenient Java Class selector.
I really like the "Fast Open" selector that you get from the "Navigate...Go To Class" menu item. I looked at the code, and was dismayed to see that it was hard-coded for opening classes, and was not reusable for just selecting a class for another purpose (such as inserting a class reference in an xml file).
So, I sat down to write such a widget, and was pleased to be able to put something pretty featureful together in a couple of hours. I use the MDR API for querying classes.

The list box contains all classes whose classname (without package) starts with the substring in the text field. The list selection is the value returned by the dialog.
Here's a little tour of the code:
public class ClassSelector extends javax.swing.JDialog
{
// the data for the ListModel
private List<JCClass> candidates = new ArrayList<JCClass>();
// an example usage
public static String getFullyQualifiedClassName()
{
ClassSelector cs = new ClassSelector();
cs.setVisible(true);
JCClass c = cs.getSelection();
return c == null ? null : c.getFullName();
}
public ClassSelector()
{
this(WindowManager.getDefault().getMainWindow(), true);
}
public ClassSelector(java.awt.Frame parent, boolean modal)
{
super(parent, modal);
initComponents();
}
public JCClass getSelection()
{
return (JCClass)matchingList.getSelectedValue();
}
private void initComponents()
{
// matisse-generated code here
}
private void matchingListKeyPressed(java.awt.event.KeyEvent evt)
{
// make ENTER work the same as the OK button
if (evt.getKeyCode() == KeyEvent.VK_ENTER)
okButtonActionPerformed(null);
}
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt)
{
matchingList.setSelectedIndex(-1);
dispose();
}
private void okButtonActionPerformed(java.awt.event.ActionEvent evt)
{
dispose();
}
private ListModel createListModel()
{
return new Model();
}
private ListCellRenderer createCellRenderer()
{
return new Renderer();
}
private class Model extends KeyAdapter implements ListModel
{
private List<ListDataListener> listeners = new ArrayList<ListDataListener>();
public Model()
{
classNameField.addKeyListener(this);
}
public int getSize()
{
return candidates.size();
}
public Object getElementAt(int index)
{
return candidates.get(index);
}
public void addListDataListener(ListDataListener l)
{
listeners.add(l);
}
public void removeListDataListener(ListDataListener l)
{
listeners.remove(l);
}
private void fireListChange()
{
ListDataEvent evt = new ListDataEvent(this,
ListDataEvent.CONTENTS_CHANGED, 0, getSize()-1);
for (ListDataListener l : listeners)
{
l.contentsChanged(evt);
}
}
private void refresh()
{
String str = classNameField.getText();
if (str == null || str.trim().length() == 0)
{
// text field is blank, so don't do a query
if (!candidates.isEmpty())
{
candidates.clear();
fireListChange();
}
}
else
{
// clear out the old query results, and do a new query
str = str.trim();
candidates.clear();
JCFinder finder = JCFinderFactory.getDefault().getGlobalFinder();
// TODO: make case insensitive
List<JCClass> classes = finder.findClasses(
null, // don't specify a package
str,
false); // don't require an exact match
candidates.addAll(classes);
fireListChange();
if (!candidates.isEmpty() && matchingList.getSelectedIndex() == -1)
{
// if there's no selection at this point, select the first item
matchingList.setSelectedIndex(0);
}
}
}
/** each time a letter is typed, do a new query */
public void keyReleased(KeyEvent e)
{
refresh();
}
}
private class Renderer implements ListCellRenderer
{
public Component getListCellRendererComponent(
JList list, Object value, int index,
boolean isSelected, boolean cellHasFocus)
{
JCClass c = (JCClass)value;
String str = c.getName() + " (" + c.getPackageName() + ")";
JLabel label = new JLabel(str);
if (isSelected)
{
label.setBackground(Color.BLUE);
label.setForeground(Color.WHITE);
label.setOpaque(true);
}
return label;
}
}
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton cancelButton;
private javax.swing.JTextField classNameField;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel2;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JList matchingList;
private javax.swing.JButton okButton;
// End of variables declaration//GEN-END:variables
}
Neat, eh? The full code is here.
- Login or register to post comments
- Printer-friendly version
- richunger's blog
- 1023 reads





