[Schmitzm-commits] r1190 - in trunk: src/schmitzm/geotools/gui src/skrueger/swing src_junit/schmitzm/io src_junit/schmitzm/swing

scm-commit@wald.intevation.org scm-commit at wald.intevation.org
Sat Oct 30 00:03:21 CEST 2010


Author: alfonx
Date: 2010-10-30 00:03:19 +0200 (Sat, 30 Oct 2010)
New Revision: 1190

Added:
   trunk/src/skrueger/swing/FilterTableKeyListener.java
Modified:
   trunk/src/schmitzm/geotools/gui/SelectableFeatureTablePane.java
   trunk/src_junit/schmitzm/io/IOUtilTest.java
   trunk/src_junit/schmitzm/swing/TestingUtil.java
Log:
Added new FilterTableKeyListener, which connects a JTextField with any JTable and allows to filter the list by content. The input is converted to OR. A timer can be set that delays(collects) the update of the JTable.

Modified: trunk/src/schmitzm/geotools/gui/SelectableFeatureTablePane.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/SelectableFeatureTablePane.java	2010-10-28 09:47:06 UTC (rev 1189)
+++ trunk/src/schmitzm/geotools/gui/SelectableFeatureTablePane.java	2010-10-29 22:03:19 UTC (rev 1190)
@@ -30,7 +30,6 @@
 package schmitzm.geotools.gui;
 
 import java.awt.BorderLayout;
-import java.awt.Component;
 import java.awt.Cursor;
 import java.awt.Dimension;
 import java.awt.event.ActionEvent;
@@ -45,22 +44,26 @@
 import javax.swing.JScrollBar;
 import javax.swing.JScrollPane;
 import javax.swing.JTable;
+import javax.swing.JTextField;
 import javax.swing.JToolBar;
 import javax.swing.RowSorter.SortKey;
 import javax.swing.SortOrder;
 import javax.swing.event.ListSelectionEvent;
 import javax.swing.event.ListSelectionListener;
 
+import net.miginfocom.swing.MigLayout;
+
 import org.geotools.feature.FeatureCollection;
 
 import schmitzm.geotools.feature.FeatureUtil;
 import schmitzm.swing.table.SelectionTableModel;
+import skrueger.swing.FilterTableKeyListener;
 
 /**
  * Extends the {@link FeatureTablePane} with buttons and functionality to select
- * lines. Can be configured to set the regions on an external a {@link SelectableXMapPane}
- * . Can be configured to show a simple preview {@link SelectableXMapPane} to the left of
- * the table.
+ * lines. Can be configured to set the regions on an external a
+ * {@link SelectableXMapPane} . Can be configured to show a simple preview
+ * {@link SelectableXMapPane} to the left of the table.
  * 
  * @author Stefan A. Tzeggai
  * 
@@ -70,53 +73,55 @@
 	public static final ImageIcon ICON_SELECTION_INVERT = new ImageIcon(
 			SelectableFeatureTablePane.class
 					.getResource("resource/icons/mActionInvertSelection.png"));
-	
+
 	public static final ImageIcon ICON_SELECTED_TO_TOP = new ImageIcon(
 			SelectableFeatureTablePane.class
 					.getResource("resource/icons/mActionSelectedToTop.png"));
-	
+
 	public static final ImageIcon ICON_UNSELECT = new ImageIcon(
 			SelectableFeatureTablePane.class
 					.getResource("resource/icons/mActionUnselectAttributes.png"));
-	
+
 	public static final ImageIcon ICON_ZOOM_TO_SELECTED = new ImageIcon(
 			SelectableFeatureTablePane.class
 					.getResource("resource/icons/mActionZoomToSelected.png"));
-	
-	
+
 	private final SelectableXMapPane externalMapPane;
-	
+
 	private JLabel statusLabel;
 
-    /**
-     * @param fc
-     *            {@link FeatureCollection} that holds the data.
-     * @param geomPreview
-     *            If <code>true</code>, a preview {@link SelectableXMapPane} is attached
-     *            to the left of the table.
-     * @param externalMapPane
-     *            <code>null</code> if this component is NOT linked to an
-     *            external JMapPane. If mapPane == <code>null</code>, the
-     *            "ZoomToSelection" Button is automatically disabled. If a
-     *            {@link SelectableXMapPane} is passed, the "ZoomToSelectedFeature"
-     *            function will be enabled.
-     */
-    public SelectableFeatureTablePane(FeatureCollection fc, boolean geomPreview, SelectableXMapPane externalMapPane) {
-      this(new FeatureCollectionTableModel(fc), geomPreview, externalMapPane);
-    }
+	private JPanel sarchPanel;
 
-    /**
+	/**
+	 * @param fc
+	 *            {@link FeatureCollection} that holds the data.
+	 * @param geomPreview
+	 *            If <code>true</code>, a preview {@link SelectableXMapPane} is
+	 *            attached to the left of the table.
+	 * @param externalMapPane
+	 *            <code>null</code> if this component is NOT linked to an
+	 *            external JMapPane. If mapPane == <code>null</code>, the
+	 *            "ZoomToSelection" Button is automatically disabled. If a
+	 *            {@link SelectableXMapPane} is passed, the
+	 *            "ZoomToSelectedFeature" function will be enabled.
+	 */
+	public SelectableFeatureTablePane(FeatureCollection fc,
+			boolean geomPreview, SelectableXMapPane externalMapPane) {
+		this(new FeatureCollectionTableModel(fc), geomPreview, externalMapPane);
+	}
+
+	/**
 	 * @param model
 	 *            {@link FeatureCollectionTableModel} that holds the data.
 	 * @param geomPreview
-	 *            If <code>true</code>, a preview {@link SelectableXMapPane} is attached
-	 *            to the left of the table.
+	 *            If <code>true</code>, a preview {@link SelectableXMapPane} is
+	 *            attached to the left of the table.
 	 * @param externalMapPane
 	 *            <code>null</code> if this component is NOT linked to an
 	 *            external JMapPane. If mapPane == <code>null</code>, the
 	 *            "ZoomToSelection" Button is automatically disabled. If a
-	 *            {@link SelectableXMapPane} is passed, the "ZoomToSelectedFeature"
-	 *            function will be enabled.
+	 *            {@link SelectableXMapPane} is passed, the
+	 *            "ZoomToSelectedFeature" function will be enabled.
 	 */
 	public SelectableFeatureTablePane(FeatureCollectionTableModel model,
 			boolean geomPreview, SelectableXMapPane externalMapPane) {
@@ -130,7 +135,9 @@
 			newPanelArroundTable.add(splitPane.getRightComponent(),
 					BorderLayout.CENTER);
 			splitPane.setRightComponent(newPanelArroundTable);
-			splitPane.setDividerLocation(0.33); // SK: Does have no effect because the JSplitPane is not yet rendered.
+			splitPane.setDividerLocation(0.33); // SK: Does have no effect
+												// because the JSplitPane is not
+												// yet rendered.
 		} else {
 			newPanelArroundTable.add(getComponent(0), BorderLayout.CENTER);
 			removeAll();
@@ -139,78 +146,106 @@
 
 		// Change the sizes
 		mapPane.setPreferredSize(new Dimension(200, 300));
-		
+
 		featuresTable.getParent().setPreferredSize(new Dimension(400, 300));
-	    featuresTable.setAutoResizeMode( JTable.AUTO_RESIZE_OFF );
+		featuresTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
 
-	    // In the NORTH, the ToolBar and a JLabel presenting the total and selected number of features is displayed
+		// In the NORTH, the ToolBar and a JLabel presenting the total and
+		// selected number of features is displayed
 		JPanel north = new JPanel(new BorderLayout());
 		north.add(getToolBar(), BorderLayout.WEST);
 		north.add(getStatusLabel(), BorderLayout.EAST);
 		newPanelArroundTable.add(north, BorderLayout.NORTH);
 		newPanelArroundTable.add(getSearchBar(), BorderLayout.SOUTH);
-		
-		featuresTable.getSelectionModel().addListSelectionListener( new ListSelectionListener(){
 
-			@Override
-			public void valueChanged(ListSelectionEvent e) {
-				if (!e.getValueIsAdjusting()){
-					getStatusLabel();
-				}
-			}
-			
-		});
+		featuresTable.getSelectionModel().addListSelectionListener(
+				new ListSelectionListener() {
+
+					@Override
+					public void valueChanged(ListSelectionEvent e) {
+						if (!e.getValueIsAdjusting()) {
+							getStatusLabel();
+						}
+					}
+
+				});
 	}
 
 	/**
-	 * After calling the super-method the table model is encapsulated in
-	 * a {@link SelectionTableModel} to show a selection column.
+	 * After calling the super-method the table model is encapsulated in a
+	 * {@link SelectionTableModel} to show a selection column.
 	 */
-    @Override
-    protected void initGUI(boolean geomPreview) {
-      super.initGUI(geomPreview);
-      // Reset the table model to show a selection column
-      featuresTable.setModel( new SelectionTableModel(featuresTableModel, featuresTable) );
-      // Because SortableJTable is used, the first col is always a checkbox.
-      // TODO: How wide is a CheckBox in differnet L'n'F s?
-      int selCol = featuresTable.convertColumnIndexToModel(0);
-      featuresTable.getColumnModel().getColumn(selCol).setMaxWidth(17);
-    }
-    
-    /**
-	 * This Label present something like "40 of 56 Polygons selected". It is lazily constructed. Later calls will only update the existing label.  
+	@Override
+	protected void initGUI(boolean geomPreview) {
+		super.initGUI(geomPreview);
+		// Reset the table model to show a selection column
+		featuresTable.setModel(new SelectionTableModel(featuresTableModel,
+				featuresTable));
+		// Because SortableJTable is used, the first col is always a checkbox.
+		// TODO: How wide is a CheckBox in differnet L'n'F s?
+		int selCol = featuresTable.convertColumnIndexToModel(0);
+		featuresTable.getColumnModel().getColumn(selCol).setMaxWidth(17);
+	}
+
+	/**
+	 * This Label present something like "40 of 56 Polygons selected". It is
+	 * lazily constructed. Later calls will only update the existing label.
 	 */
 	private JLabel getStatusLabel() {
-		if (statusLabel == null){
+		if (statusLabel == null) {
 			statusLabel = new JLabel();
 		}
-		
+
 		int selectedAnz = getSelectedFeatures().size();
-		
-		// TODO Cache totalAnz and localizedGeometryTypeName. Do not recalc all the time!  
+
+		// TODO Cache totalAnz and localizedGeometryTypeName. Do not recalc all
+		// the time!
 		int totalAnz = getFeatureCollection().size();
-		
+
 		String localizedGeometryTypeName = "rows";
-		
-		switch ( FeatureUtil.getGeometryForm(getFeatureCollection()) ){
+
+		switch (FeatureUtil.getGeometryForm(getFeatureCollection())) {
 		case LINE:
-			localizedGeometryTypeName = GeotoolsGUIUtil.R("schmitzm.geotools.gui.SelectableFeatureTablePane.selectionStatus.lines");
+			localizedGeometryTypeName = GeotoolsGUIUtil
+					.R("schmitzm.geotools.gui.SelectableFeatureTablePane.selectionStatus.lines");
 			break;
 		case POLYGON:
-			localizedGeometryTypeName = GeotoolsGUIUtil.R("schmitzm.geotools.gui.SelectableFeatureTablePane.selectionStatus.polygons");
+			localizedGeometryTypeName = GeotoolsGUIUtil
+					.R("schmitzm.geotools.gui.SelectableFeatureTablePane.selectionStatus.polygons");
 			break;
 		case POINT:
-			localizedGeometryTypeName = GeotoolsGUIUtil.R("schmitzm.geotools.gui.SelectableFeatureTablePane.selectionStatus.points");
+			localizedGeometryTypeName = GeotoolsGUIUtil
+					.R("schmitzm.geotools.gui.SelectableFeatureTablePane.selectionStatus.points");
 			break;
 		}
-		
-		statusLabel.setText( GeotoolsGUIUtil.R("schmitzm.geotools.gui.SelectableFeatureTablePane.selectionStatus", selectedAnz, totalAnz,localizedGeometryTypeName));
-		
+
+		statusLabel
+				.setText(GeotoolsGUIUtil
+						.R("schmitzm.geotools.gui.SelectableFeatureTablePane.selectionStatus",
+								selectedAnz, totalAnz,
+								localizedGeometryTypeName));
+
 		return statusLabel;
 	}
 
-	private Component getSearchBar() {
-		return new JLabel(""); // TODO Add ability to search here!
+	/**
+	 * Adding the ability to search all Field. The Key events are collected evry
+	 * 1000ms for fast typers ;-).
+	 */
+	private JPanel getSearchBar() {
+		if (sarchPanel == null) {
+			sarchPanel = new JPanel(new MigLayout("", "[grow]"));
+			sarchPanel.add(new JLabel("Filter:"), "align right");
+			JTextField filtertextField = new JTextField();
+
+			// The constructor adds itself to the textfield
+			// Use 1000ms delay, in case the table is large...
+			new FilterTableKeyListener(getTable(), 1000, filtertextField);
+
+			sarchPanel.add(filtertextField, " growx , align right");
+
+		}
+		return sarchPanel;
 	}
 
 	/**
@@ -218,9 +253,9 @@
 	 */
 	protected JToolBar getToolBar() {
 		JToolBar toolBar = new JToolBar();
-		
-		toolBar.setFloatable(false); // Sorry Martin ;-) 
 
+		toolBar.setFloatable(false); // Sorry Martin ;-)
+
 		/**
 		 * Add an Action to clear the selection
 		 */
@@ -262,7 +297,7 @@
 				keys.add(0, sortKey);
 
 				featuresTable.getRowSorter().setSortKeys(keys);
-				
+
 				// Move the scrollbars to the top
 				JScrollPane scrollPane = getFeaturesTableScrollPane();
 				JScrollBar verticalScrollBar = scrollPane
@@ -272,7 +307,6 @@
 				verticalScrollBar.setValue(verticalScrollBar.getMinimum());
 				horizontalScrollBar.setValue(horizontalScrollBar.getMinimum());
 
-
 				// A bug? Sorting only works from the second time on..
 				if (isFirstClick) {
 					isFirstClick = false;
@@ -298,16 +332,16 @@
 			public void actionPerformed(ActionEvent e) {
 
 				setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
-				
+
 				featuresTable.getSelectionModel().setValueIsAdjusting(true);
-				
+
 				for (int i = 0; i < featuresTable.getModel().getRowCount(); i++) {
 					if (featuresTable.getSelectionModel().isSelectedIndex(i)) {
-					  featuresTable.getSelectionModel().removeSelectionInterval(
+						featuresTable.getSelectionModel()
+								.removeSelectionInterval(i, i);
+					} else {
+						featuresTable.getSelectionModel().addSelectionInterval(
 								i, i);
-					} else {
-					  featuresTable.getSelectionModel().addSelectionInterval(i,
-								i);
 					}
 				}
 				featuresTable.getSelectionModel().setValueIsAdjusting(false);

Added: trunk/src/skrueger/swing/FilterTableKeyListener.java
===================================================================
--- trunk/src/skrueger/swing/FilterTableKeyListener.java	2010-10-28 09:47:06 UTC (rev 1189)
+++ trunk/src/skrueger/swing/FilterTableKeyListener.java	2010-10-29 22:03:19 UTC (rev 1190)
@@ -0,0 +1,110 @@
+package skrueger.swing;
+
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.regex.Pattern;
+
+import javax.swing.JTable;
+import javax.swing.JTextField;
+import javax.swing.RowFilter;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.table.TableRowSorter;
+
+/**
+ * Connects a {@link JTextField} with a {@link JTable} to filter the data. The
+ * column it should filter are given as indices on construction.
+ * 
+ */
+public class FilterTableKeyListener extends KeyAdapter {
+
+	private final JTable table;
+	private final int[] indices;
+	private final JTextField jTextField;
+	private Timer setRowFilterTimer;
+
+	/**
+	 * Collects key events for 300ms, The constructor adds itself the the
+	 * {@link JTextField}!
+	 * 
+	 * @param table
+	 * @param jTextField
+	 * @param indices
+	 */
+	public FilterTableKeyListener(JTable table, JTextField jTextField,
+			int... indices) {
+		this(table, 300, jTextField, indices);
+	}
+
+	/**
+	 * The constructor adds itself the the {@link JTextField}!
+	 * 
+	 * @param table
+	 * @param jTextField
+	 * @param waitToUpdateGuiMs
+	 *            ms to wait until the table rowSorter is changed.
+	 * @param indices
+	 */
+	public FilterTableKeyListener(JTable table, long waitToUpdateGuiMs,
+			JTextField jTextField, int... indices) {
+		this.table = table;
+		this.jTextField = jTextField;
+		this.indices = indices;
+
+		jTextField.addKeyListener(this);
+	}
+
+	@Override
+	public void keyReleased(KeyEvent e) {
+		String text = jTextField.getText();
+		newFilterForTable(
+				(TableRowSorter<AbstractTableModel>) table.getRowSorter(),
+				text, indices);
+	}
+
+	/**
+	 * When a key is released, filter for the table is updated
+	 */
+	private void newFilterForTable(
+			final TableRowSorter<AbstractTableModel> sorter, String text,
+			int... indices) {
+		// System.out.println("\n" + text);
+
+		String filter = "";
+		String[] split = text.trim().split("\\s");
+		for (String s : split) {
+			if (s.trim().isEmpty())
+				continue;
+			s = Pattern.quote(s);
+			s = s.substring(2, s.length() - 2);
+			filter += "|.*" + s + ".*";
+		}
+		if (filter.length() > 0)
+			filter = filter.substring(1);
+
+		// If current expression doesn't parse, don't update.
+		try {
+			// System.out.println(filter);
+			final RowFilter<AbstractTableModel, Object> rf = RowFilter
+					.regexFilter("(?i)" + filter, indices);
+			if (setRowFilterTimer != null)
+				setRowFilterTimer.cancel();
+			setRowFilterTimer = new Timer("Set rowFilter for JTable");
+			setRowFilterTimer.schedule(new TimerTask() {
+
+				@Override
+				public void run() {
+					sorter.setRowFilter(rf);
+				}
+			}, 300);
+
+			return;
+		} catch (java.util.regex.PatternSyntaxException e) {
+			return;
+		}
+
+		// sorter.setRowFilter(null);
+	}
+
+}


Property changes on: trunk/src/skrueger/swing/FilterTableKeyListener.java
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Id URL
Name: svn:eol-style
   + native

Modified: trunk/src_junit/schmitzm/io/IOUtilTest.java
===================================================================
--- trunk/src_junit/schmitzm/io/IOUtilTest.java	2010-10-28 09:47:06 UTC (rev 1189)
+++ trunk/src_junit/schmitzm/io/IOUtilTest.java	2010-10-29 22:03:19 UTC (rev 1190)
@@ -1,6 +1,7 @@
 package schmitzm.io;
 
-import static org.junit.Assert.*;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
 import java.io.File;

Modified: trunk/src_junit/schmitzm/swing/TestingUtil.java
===================================================================
--- trunk/src_junit/schmitzm/swing/TestingUtil.java	2010-10-28 09:47:06 UTC (rev 1189)
+++ trunk/src_junit/schmitzm/swing/TestingUtil.java	2010-10-29 22:03:19 UTC (rev 1190)
@@ -1,5 +1,7 @@
 package schmitzm.swing;
 
+import static org.junit.Assert.assertTrue;
+
 import java.awt.Color;
 import java.awt.Component;
 import java.awt.Dialog.ModalExclusionType;
@@ -44,8 +46,6 @@
 import schmitzm.geotools.io.GeoImportUtil;
 import schmitzm.io.IOUtil;
 import schmitzm.lang.LangUtil;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
 /**
  * Helpers to test Swing applications in general. <br/>
  * If not set to @Ignore, HUDSON will complain



More information about the Schmitzm-commits mailing list