package er.ajax;
import java.math.BigDecimal;
import com.webobjects.appserver.WOComponent;
import com.webobjects.appserver.WOContext;
import com.webobjects.appserver.WODisplayGroup;
import com.webobjects.foundation.NSArray;
import com.webobjects.foundation.NSMutableDictionary;
import er.extensions.foundation.ERXValueUtilities;
/**
* Abstract super class for a navigation bar that can be used with AjaxGrid. Use
* of this is not mandatory, it is provided as a convenience.
* <h3>Example Usage</h3>
* This class has a symbiotic relationship with AjaxGrid. When this nav bar
* changes the data (e.g. batch size, batch displayed) it updates the grid's
* container <b>not</b> its own container. It needs to have the grid tell it to
* update after the grid has refreshed. This allows the AjaxGrid to make any
* needed changes to the display group before the contents of the nav bar are
* updated.
*
* <pre>
* Grid: AjaxGrid {
* configurationData = configData;
* displayGroup = displayGroup;
* afterUpdate = "ajaxGridExampleNavBarUpdate();";
* }
*
* NavBar: AjaxGridExampleNavBar {
* containerID = "ajaxGridExampleNavBar";
* displayGroup = displayGroup;
* configurationData = configData;
* }
* </pre>
*
* <h3>Example Sub-class</h3>
*
* <pre>
* <div class="ajaxGridNavBar">
* <webobject name="NavUpdater">
* <table><tr>
* <td style="text-align:left;"><webobject name="PrevBatch"><<</webobject>
* Page <b><span id="currentBatch"><webobject name="CurrentBatchIndex"/></span></b> of <b><webobject name="BatchCount"/></b>
* <webobject name="NextBatch">>></webobject>
* </td>
* <td style="text-align:center;">
* Number of lines per page: <webobject name="BatchSizes"/><webobject name="UpdateBatchSize"/>
* </td>
* <td style="text-align:right;">
* Displaying <b><webobject name="FirstIndex"/></b> to <b><webobject name="LastIndex"/></b> of <b><webobject name="TotalCount"/></b> entries.
* </td></tr></table>
* <webobject name="BatchSlider"/>
* </webobject name="NavUpdater">
* </div>
* </pre>
*
* <pre>
* NavUpdater: AjaxUpdateContainer {
* id = containerID;
* }
*
* BatchCount: WOString {
* value = displayGroup.batchCount;
* }
*
* BatchSlider: AjaxSlider {
* orientation = "horizontal";
* value = currentBatchIndex;
* minimum = 1;
* maximum = displayGroup.batchCount;
* onChangeServer = updateGridContainer;
* onSlide = "function(v) { $('currentBatch').innerHTML = Math.round(v) }";
* onChange = "function(v) { $('currentBatch').innerHTML = Math.round(v) }";
* }
*
* CurrentBatchIndex : WOString {
* value = displayGroup.currentBatchIndex;
* }
*
* PrevBatch : AjaxUpdateLink {
* action = previousBatch;
* updateContainerID = gridContainerID;
* }
*
* NextBatch : AjaxUpdateLink {
* action = nextBatch;
* updateContainerID = gridContainerID;
* }
*
* BatchSizes: WOPopUpButton {
* list = batchSizes;
* item = batchSize;
* selection = currentBatchSize;
* onChange = updateBatchSizeOnChange;
* }
*
* FirstIndex: WOString {
* value = displayGroup.indexOfFirstDisplayedObject;
* }
*
* LastIndex: WOString {
* value = displayGroup.indexOfLastDisplayedObject;
* }
*
* TotalCount: WOString {
* value = displayGroup.allObjects.count;
* }
*
* UpdateBatchSize: AjaxUpdateLink {
* action = batchSizeUpdated;
* functionName = updateBatchSizeName;
* updateContainerID = gridContainerID;
* }
* </pre>
*
* @binding displayGroup the same WODisplayGroup passed to AjaxGrid
* @binding configurationData the same NSMutableDictionary passed to AjaxGrid
* @binding containerID unique ID for the AjaxUpdateContainer in this component.
*
* @author Chuck Hill
*/
public abstract class AjaxGridNavBar extends WOComponent {
/**
* Do I need to update serialVersionUID?
* See section 5.6 <cite>Type Changes Affecting Serialization</cite> on page 51 of the
* <a href="http://java.sun.com/j2se/1.4/pdf/serial-spec.pdf">Java Object Serialization Spec</a>
*/
private static final long serialVersionUID = 1L;
public static final String CONTAINER_ID_BINDING = "containerID";
public static final String DISPLAY_GROUP_BINDING = "displayGroup";
public static final String CONFIGURATION_DATA_BINDING = "configurationData";
public AjaxGridNavBar(WOContext context) {
super(context);
}
@Override
public boolean isStateless() {
return true;
}
/**
* Ajax action method to select the next batch.
*/
public void nextBatch() {
displayGroup().displayNextBatch();
displayGroup().setSelectedObject(null);
}
/**
* Ajax action method to select the previous batch.
*/
public void previousBatch() {
displayGroup().displayPreviousBatch();
displayGroup().setSelectedObject(null);
}
/**
* Intended to be bound to Ajax slider or selection of batch to display.
*
* @param newValue
* new batch number from AjaxSlider
*/
public void setCurrentBatchIndex(Number newValue) {
// Right now the value returned is a BigDecimal. KVC changes this to an
// int by narrowing, so that 4.9876402 becomes 4.
// If we round this instead, the slider movement is more inutuitive,
// especially with smaller batch sizes.
if (newValue instanceof BigDecimal) {
int roundedIndex = Float.valueOf(((BigDecimal) newValue).floatValue() + 0.5f).intValue();
displayGroup().setCurrentBatchIndex(roundedIndex);
}
else {
displayGroup().setCurrentBatchIndex(newValue.intValue());
}
}
/**
* @return value for AjaxSlider
*/
public int currentBatchIndex() {
return displayGroup().currentBatchIndex();
}
/**
* Returns JavaScript to update the AjaxUpdateContainer identified by
* gridContainerID(). This is intended for use as onChangeServer binding for
* a AjaxSlider.
*
* @return JavaScript calls to update the Ajax grid
*/
public String updateGridContainer() {
return gridContainerID() + "Update(); ";
}
/**
* @return JavaScript for option control to pass selected batch size when
* changed
*/
public String updateBatchSizeOnChange() {
return updateBatchSizeName() + "('batchSize=' + this.value);";
}
/**
* @return unique name for the AjaxUpdateContainer wrapping this
* AjaxGridNavBar
*/
public String updateBatchSizeName() {
return containerID() + "UpdateBatchSize";
}
/**
* Ajax action method for updates to batch size. Grabs batch size from
* request and updates configuration.
*/
public void batchSizeUpdated() {
String batchSizeString = (String) context().request().formValueForKey("batchSize");
int batchSizeIndex = Integer.parseInt(batchSizeString);
configurationData().setObjectForKey(batchSizes().objectAtIndex(batchSizeIndex), AjaxGrid.BATCH_SIZE);
// Keep display group in synch to avoid display update issues
displayGroup().setNumberOfObjectsPerBatch(ERXValueUtilities.intValue(currentBatchSize()));
}
/**
* @return the list of batch sizes to show in the popup
*/
public abstract NSArray batchSizes();
/**
* @return displayGroup().numberOfObjectsPerBatch() as a String for the
* option input
*/
public String currentBatchSize() {
return (String) configurationData().objectForKey(AjaxGrid.BATCH_SIZE);
}
/**
* @return UPDATE_CONTAINER_ID from configurationData(), the update
* container ID from the AjaxGrid
*/
public String gridContainerID() {
return (String) configurationData().objectForKey(AjaxGrid.UPDATE_CONTAINER_ID);
}
/**
* @return TABLE_ID from configurationData(), the table ID from the AjaxGrid
*/
public String tableID() {
return (String) configurationData().objectForKey(AjaxGrid.TABLE_ID);
}
/**
* @return value bound to displayGroup
*/
public WODisplayGroup displayGroup() {
return (WODisplayGroup) valueForBinding(DISPLAY_GROUP_BINDING);
}
/**
* @return value bound to configurationData
*/
public NSMutableDictionary configurationData() {
return (NSMutableDictionary) valueForBinding(CONFIGURATION_DATA_BINDING);
}
/**
* @return value bound to containerID
*/
public String containerID() {
return (String) valueForBinding(CONTAINER_ID_BINDING);
}
}