SWF-646 - Improve the SelectionTrackingActionListener to work with any iterator type of component that works with a DataModel.

This commit is contained in:
Jeremy Grelle
2008-04-23 19:27:38 +00:00
parent f1e476997b
commit 0949ccbb96
2 changed files with 135 additions and 17 deletions

View File

@@ -15,6 +15,8 @@
*/ */
package org.springframework.faces.model; package org.springframework.faces.model;
import java.lang.reflect.Method;
import javax.faces.component.UIComponent; import javax.faces.component.UIComponent;
import javax.faces.component.UIData; import javax.faces.component.UIData;
import javax.faces.component.UIViewRoot; import javax.faces.component.UIViewRoot;
@@ -25,14 +27,16 @@ import javax.faces.event.ActionListener;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.faces.webflow.FlowActionListener; import org.springframework.faces.webflow.FlowActionListener;
import org.springframework.util.ReflectionUtils;
/** /**
* Custom {@link ActionListener} that inspects the {@link UIComponent} that signaled the current {@link ActionEvent} to * Custom {@link ActionListener} that inspects the {@link UIComponent} that signaled the current {@link ActionEvent} to
* determine whether it is a child of a {@link UIData} component that uses a {@link SelectionAware} data model * determine whether it is a child of any iterator type of component (such as {@link UIData}) that uses a
* implementation. If a containing SelectionAware model is found, the row containing the event-signaling component * {@link SelectionAware} data model implementation. If a containing SelectionAware model is found, the row containing
* instance will be selected. This enables convenient access to the selected model state at any time through EL * the event-signaling component instance will be selected. This enables convenient access to the selected model state
* expressions such as #{model.selectedRow.id} without having to rely on the whether or not the current row index is * at any time through EL expressions such as #{model.selectedRow.id} without having to rely on the whether or not the
* pointing to the desired row as it would need to be to use an expression such as #{model.rowData.id} * current row index is pointing to the desired row as it would need to be to use an expression such as
* #{model.rowData.id}
* *
* @author Jeremy Grelle * @author Jeremy Grelle
*/ */
@@ -52,23 +56,23 @@ public class SelectionTrackingActionListener implements ActionListener {
} }
private void trackSelection(UIComponent component) { private void trackSelection(UIComponent component) {
// Find parent UIData instance if it exists // Find parent component with a SelectionAware model if it exists
UIData table = null;
UIComponent currentComponent = component; UIComponent currentComponent = component;
while (!(currentComponent.getParent() instanceof UIViewRoot)) { while (!(currentComponent.getParent() instanceof UIViewRoot)) {
if (currentComponent.getParent() instanceof UIData) { UIComponent parent = currentComponent.getParent();
table = (UIData) currentComponent.getParent(); Method valueAccessor = ReflectionUtils.findMethod(parent.getClass(), "getValue");
break; if (valueAccessor != null) {
Object value = ReflectionUtils.invokeMethod(valueAccessor, parent);
if (value != null && value instanceof SelectionAware) {
((SelectionAware) value).setSelected(true);
if (logger.isDebugEnabled()) {
logger.debug("Row selection has been set on the current SelectionAware data model.");
}
break;
}
} }
currentComponent = currentComponent.getParent(); currentComponent = currentComponent.getParent();
} }
if (table != null && table.getValue() instanceof SelectionAware) {
SelectionAware selectableModel = (SelectionAware) table.getValue();
selectableModel.setSelected(true);
if (logger.isDebugEnabled()) {
logger.debug("Row selection has been set on the current SelectionAware data model.");
}
}
} }
} }

View File

@@ -0,0 +1,114 @@
package org.springframework.faces.model;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import javax.faces.component.UIColumn;
import javax.faces.component.UICommand;
import javax.faces.component.UIData;
import javax.faces.component.UIViewRoot;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.ActionEvent;
import javax.faces.event.ActionListener;
import org.springframework.util.ReflectionUtils;
import com.sun.facelets.component.UIRepeat;
import junit.framework.TestCase;
public class SelectionTrackingActionListenerTests extends TestCase {
/**
* The JSF view to simulate
*/
private UIViewRoot viewToTest;
/**
* The list of row data objects to
*/
private OneSelectionTrackingListDataModel dataModel;
/**
* The delegate action listener that should be called
*/
private TestDelegateActionListener delegateListener = new TestDelegateActionListener();
/**
* The class under test
*/
private ActionListener selectionTrackingListener = new SelectionTrackingActionListener(delegateListener);
public void setUp() {
viewToTest = new UIViewRoot();
List rows = new ArrayList();
rows.add(new TestRowData());
rows.add(new TestRowData());
rows.add(new TestRowData());
dataModel = new OneSelectionTrackingListDataModel(rows);
}
public void testProcessActionWithUIData() {
UIData dataTable = new UIData();
dataTable.setValue(dataModel);
UIColumn column = new UIColumn();
UICommand commandButton = new UICommand();
column.getChildren().add(commandButton);
dataTable.getChildren().add(column);
viewToTest.getChildren().add(dataTable);
dataTable.setRowIndex(1);
ActionEvent event = new ActionEvent(commandButton);
selectionTrackingListener.processAction(event);
assertTrue(dataModel.isCurrentRowSelected());
assertSame(dataModel.getSelectedRow(), dataModel.getRowData());
assertTrue(delegateListener.processedEvent);
dataModel.setRowIndex(2);
assertFalse(dataModel.isCurrentRowSelected());
assertTrue(dataModel.getSelectedRow() != dataModel.getRowData());
}
public void testProcessActionWithUIRepeat() {
UIRepeat uiRepeat = new UIRepeat();
uiRepeat.setValue(dataModel);
UICommand commandButton = new UICommand();
uiRepeat.getChildren().add(commandButton);
viewToTest.getChildren().add(uiRepeat);
Method indexMutator = ReflectionUtils.findMethod(UIRepeat.class, "setIndex", new Class[] { int.class });
indexMutator.setAccessible(true);
ReflectionUtils.invokeMethod(indexMutator, uiRepeat, new Object[] { new Integer(1) });
ActionEvent event = new ActionEvent(commandButton);
selectionTrackingListener.processAction(event);
assertTrue(dataModel.isCurrentRowSelected());
assertSame(dataModel.getSelectedRow(), dataModel.getRowData());
assertTrue(delegateListener.processedEvent);
ReflectionUtils.invokeMethod(indexMutator, uiRepeat, new Object[] { new Integer(2) });
assertFalse(dataModel.isCurrentRowSelected());
assertTrue(dataModel.getSelectedRow() != dataModel.getRowData());
}
private class TestRowData {
}
private class TestDelegateActionListener implements ActionListener {
public boolean processedEvent = false;
public void processAction(ActionEvent event) throws AbortProcessingException {
processedEvent = true;
}
}
}