package filter;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.EventObject;
import java.util.List;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.event.CellEditorListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeCellEditor;
import javax.swing.tree.TreeSelectionModel;
import net.miginfocom.swing.MigLayout;
public class FilterEditorPanel<T> extends JPanel
{
private static final long serialVersionUID = 1L;
private JTree mTree;
private DefaultTreeModel mModel;
private FilterSet<T> mFilterSet;
public FilterEditorPanel( FilterSet<T> filterSet )
{
setLayout( new MigLayout("insets 0 0 0 0", "[grow,fill]", "[grow,fill]") );
mFilterSet = filterSet;
init();
}
private void init()
{
DefaultMutableTreeNode root = new DefaultMutableTreeNode( mFilterSet );
mModel = new DefaultTreeModel( root );
addFilterSet( mFilterSet, root );
mTree = new JTree( mModel );
mTree.setShowsRootHandles( true );
mTree.addMouseListener( new MouseHandler() );
mTree.getSelectionModel().setSelectionMode(
TreeSelectionModel.SINGLE_TREE_SELECTION );
mTree.setCellRenderer( new EditorTreeCellRenderer() );
mTree.setCellEditor( new FilterTreeNodeEditor() );
mTree.setEditable( true );
add( mTree );
}
private void addFilterSet( FilterSet<T> filterSet, DefaultMutableTreeNode parent )
{
List<IFilter<T>> filters = filterSet.getFilters();
/* sort the filters in alphabetical order by name */
Collections.sort( filters, new Comparator<IFilter<?>>()
{
@Override
public int compare( IFilter<?> first, IFilter<?> second )
{
return first.getName().compareTo( second.getName() );
}
});
for( IFilter<T> filter: filters )
{
DefaultMutableTreeNode child = new DefaultMutableTreeNode( filter );
mModel.insertNodeInto( child, parent, parent.getChildCount() );
if( filter instanceof FilterSet )
{
addFilterSet( (FilterSet<T>)filter, child );
}
else if( filter instanceof Filter )
{
addFilter( (Filter<T>)filter, child );
}
}
}
private void addFilter( Filter<T> filter, DefaultMutableTreeNode parent )
{
List<FilterElement<?>> elements = filter.getFilterElements();
Collections.sort( elements, new Comparator<FilterElement<?>>()
{
@Override
public int compare( FilterElement<?> o1, FilterElement<?> o2 )
{
return o1.toString().compareTo( o2.toString() );
}
} );
for( FilterElement<?> element: elements )
{
DefaultMutableTreeNode child = new DefaultMutableTreeNode( element );
mModel.insertNodeInto( child, parent, parent.getChildCount() );
}
}
public class MouseHandler implements MouseListener
{
public MouseHandler()
{
}
@Override
public void mouseClicked( MouseEvent event )
{
if( SwingUtilities.isRightMouseButton( event ) )
{
int row = mTree.getRowForLocation( event.getX(),
event.getY() );
if( row != -1 )
{
mTree.setSelectionRow( row );
Object selectedNode =
mTree.getLastSelectedPathComponent();
if( selectedNode instanceof DefaultMutableTreeNode )
{
final DefaultMutableTreeNode node =
(DefaultMutableTreeNode)selectedNode;
if( node.getChildCount() > 0 )
{
JPopupMenu selectionMenu = new JPopupMenu();
JMenuItem selectAll = new JMenuItem( "Select All" );
selectAll.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent arg0 )
{
setFilterEnabled( mModel, node, true );
}
});
selectionMenu.add( selectAll );
JMenuItem deselectAll = new JMenuItem( "Deselect All" );
deselectAll.addActionListener( new ActionListener()
{
@Override
public void actionPerformed( ActionEvent arg0 )
{
setFilterEnabled( mModel, node, false );
}
});
selectionMenu.add( deselectAll );
selectionMenu.show( mTree,
event.getX(),
event.getY() );
}
}
}
}
}
@Override
public void mousePressed( MouseEvent e ){}
@Override
public void mouseReleased( MouseEvent e ){}
@Override
public void mouseEntered( MouseEvent e ){}
@Override
public void mouseExited( MouseEvent e ){}
}
/**
* Recursively sets the enabled state on all filter node children below the
* specified parent node.
*
* @param model - model containing the tree nodes
* @param node - parent node
* @param enabled - true or false to enable or disable the filters
*/
private void setFilterEnabled( DefaultTreeModel model,
DefaultMutableTreeNode node,
boolean enabled )
{
Object obj = node.getUserObject();
if( obj instanceof FilterSet<?> )
{
((FilterSet<?>)obj).setEnabled( enabled );
}
else if( obj instanceof Filter )
{
((Filter<?>)obj).setEnabled( enabled );
}
else if( obj instanceof FilterElement )
{
((FilterElement<?>)obj).setEnabled( enabled );
}
model.nodeChanged( node );
/* Recursively set the children of this node */
Enumeration<?> children = node.children();
while( children.hasMoreElements() )
{
Object child = children.nextElement();
if( child instanceof DefaultMutableTreeNode )
{
setFilterEnabled( model, (DefaultMutableTreeNode)child, enabled );
}
}
}
public class EditorTreeCellRenderer extends DefaultTreeCellRenderer
{
private static final long serialVersionUID = 1L;
public Component getTreeCellRendererComponent( JTree tree,
Object treeNode,
boolean selected,
boolean expanded,
boolean leaf,
int row,
boolean hasFocus )
{
if( treeNode instanceof DefaultMutableTreeNode )
{
Object userObject = ((DefaultMutableTreeNode)treeNode).getUserObject();
JCheckBox checkBox = null;
if( userObject instanceof IFilter )
{
IFilter<?> filter = (IFilter<?>)userObject;
checkBox = new JCheckBox( filter.getName() );
checkBox.setSelected( filter.isEnabled() );
}
else if( userObject instanceof FilterElement )
{
FilterElement<?> element = (FilterElement<?>)userObject;
checkBox = new JCheckBox( element.getName() );
checkBox.setSelected( element.isEnabled() );
}
if( checkBox != null )
{
if( selected )
{
checkBox.setForeground( getTextSelectionColor() );
checkBox.setBackground( getBackgroundSelectionColor() );
}
else
{
checkBox.setForeground( getTextNonSelectionColor() );
checkBox.setBackground( getBackgroundNonSelectionColor() );
}
return checkBox;
}
}
return super.getTreeCellRendererComponent( tree, treeNode, selected,
expanded, leaf, row, hasFocus );
}
}
public class FilterCheckBox extends JCheckBox
{
private static final long serialVersionUID = 1L;
private IFilter<T> mFilter;
public FilterCheckBox( IFilter<T> filter )
{
super( filter.getName() );
mFilter = filter;
setSelected( mFilter.isEnabled() );
addItemListener( new ItemListener()
{
@Override
public void itemStateChanged( ItemEvent e )
{
mFilter.setEnabled( FilterCheckBox.this.isSelected() );
}
} );
}
}
public class FilterElementCheckBox extends JCheckBox
{
private static final long serialVersionUID = 1L;
private FilterElement<?> mFilter;
public FilterElementCheckBox( FilterElement<?> filter )
{
super( filter.getName() );
mFilter = filter;
setSelected( mFilter.isEnabled() );
addItemListener( new ItemListener()
{
@Override
public void itemStateChanged( ItemEvent arg0 )
{
mFilter.setEnabled( FilterElementCheckBox.this.isSelected() );
}
} );
}
}
public class FilterTreeNodeEditor implements TreeCellEditor
{
@Override
@SuppressWarnings( { "rawtypes", "unchecked" } )
public Component getTreeCellEditorComponent( JTree tree, Object node,
boolean isSelected, boolean expanded, boolean leaf, int row )
{
if( node instanceof DefaultMutableTreeNode )
{
Object userObject = ((DefaultMutableTreeNode)node).getUserObject();
if( userObject instanceof IFilter )
{
return new FilterCheckBox( (IFilter)userObject );
}
else if( userObject instanceof FilterElement )
{
return new FilterElementCheckBox( (FilterElement<?>)userObject );
}
}
return new JLabel( node.toString() );
}
@Override
public void addCellEditorListener( CellEditorListener l ) {}
@Override
public void cancelCellEditing()
{
}
@Override
public Object getCellEditorValue()
{
return null;
}
@Override
public boolean isCellEditable( EventObject anEvent )
{
return true;
}
@Override
public void removeCellEditorListener( CellEditorListener l ) {}
@Override
public boolean shouldSelectCell( EventObject anEvent )
{
return false;
}
@Override
public boolean stopCellEditing()
{
return false;
}
}
}