/*==========================================================================*\
| $Id: WCTreeModelRepetition.java,v 1.2 2011/11/08 14:05:23 aallowat Exp $
|*-------------------------------------------------------------------------*|
| Copyright (C) 2011 Virginia Tech
|
| This file is part of Web-CAT.
|
| Web-CAT is free software; you can redistribute it and/or modify
| it under the terms of the GNU Affero General Public License as published
| by the Free Software Foundation; either version 3 of the License, or
| (at your option) any later version.
|
| Web-CAT is distributed in the hope that it will be useful,
| but WITHOUT ANY WARRANTY; without even the implied warranty of
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
| GNU General Public License for more details.
|
| You should have received a copy of the GNU Affero General Public License
| along with Web-CAT; if not, see <http://www.gnu.org/licenses/>.
\*==========================================================================*/
package org.webcat.ui;
import com.webobjects.appserver.WOActionResults;
import com.webobjects.appserver.WOApplication;
import com.webobjects.appserver.WOAssociation;
import com.webobjects.appserver.WOComponent;
import com.webobjects.appserver.WOContext;
import com.webobjects.appserver.WOElement;
import com.webobjects.appserver.WORequest;
import com.webobjects.appserver.WOResponse;
import com.webobjects.appserver._private.WODynamicElementCreationException;
import com.webobjects.appserver._private.WODynamicGroup;
import com.webobjects.appserver._private.WOShared;
import com.webobjects.foundation.NSArray;
import com.webobjects.foundation.NSDictionary;
import com.webobjects.foundation.NSLog;
import com.webobjects.foundation.NSLog.Logger;
import java.util.Iterator;
import java.util.List;
import java.util.Stack;
//-------------------------------------------------------------------------
/**
* A dynamic element similar to {@code WORepetition} that "flattens" a tree
* model and provides iteration for its elements in a hierarchical manner.
*
* @author Tony Allevato
* @author Last changed by $Author: aallowat $
* @version $Revision: 1.2 $, $Date: 2011/11/08 14:05:23 $
*/
public class WCTreeModelRepetition extends WODynamicGroup
{
//~ Constructors ..........................................................
// ----------------------------------------------------------
public WCTreeModelRepetition(String aName, NSDictionary someAssociations,
WOElement template)
{
super(null, null, template);
this._treeModel = ((WOAssociation) someAssociations.objectForKey("treeModel"));
this._item = ((WOAssociation) someAssociations.objectForKey("item"));
this._index = ((WOAssociation) someAssociations.objectForKey("index"));
this._indexPath = ((WOAssociation) someAssociations.objectForKey("indexPath"));
if (this._treeModel == null)
throw new WODynamicElementCreationException("<"
+ super.getClass().getName()
+ "> Missing 'treeModel' attribute.");
if ((this._treeModel != null) && (this._item == null))
throw new WODynamicElementCreationException("<"
+ super.getClass().getName()
+ "> Missing 'item' attribute with 'treeModel' attribute.");
if ((this._item != null) && (!(this._item.isValueSettable())))
throw new WODynamicElementCreationException("<"
+ super.getClass().getName()
+ "> Illegal read-only 'item' attribute.");
if ((this._index != null) && (!(this._index.isValueSettable())))
throw new WODynamicElementCreationException("<"
+ super.getClass().getName()
+ "> Illegal read-only 'index' attribute.");
if ((this._indexPath != null) && (!(this._indexPath.isValueSettable())))
throw new WODynamicElementCreationException("<"
+ super.getClass().getName()
+ "> Illegal read-only 'indexPath' attribute.");
}
// ----------------------------------------------------------
public String toString()
{
return "<WCTreeModelRepetition iterator: "
+ ((this._treeModel != null) ? this._treeModel.toString() : "null")
+ " item: "
+ ((this._item != null) ? this._item.toString() : "null")
+ " index: "
+ ((this._index != null) ? this._index.toString() : "null")
+ " indexPath: "
+ ((this._indexPath != null) ? this._indexPath.toString() : "null")
+ ">";
}
// ----------------------------------------------------------
public WCIndexPath _prepareForIterationWithIndex(int anIndex,
WCTreeModel<?> model, Stack<TreePosition> treeStack,
WCIndexPath lastIndexPath, WOContext aContext,
WOComponent aComponent)
{
TreePosition newValue = null;
newValue = treeStack.pop();
if (this._item != null)
{
pushChildrenOfItem(model, newValue.item, newValue.indexPath,
treeStack);
this._item._setValueNoValidation(newValue.item, aComponent);
if (this._indexPath != null)
{
this._indexPath._setValueNoValidation(newValue.indexPath,
aComponent);
}
}
if (this._index != null)
{
Integer aNumber = WOShared.unsignedIntNumber(anIndex);
this._index._setValueNoValidation(aNumber, aComponent);
}
if (lastIndexPath != null)
{
_removeIndexPathFromElementID(aContext, lastIndexPath);
}
_appendIndexPathToElementID(aContext, newValue.indexPath);
return newValue.indexPath;
}
// ----------------------------------------------------------
private void _appendIndexPathToElementID(WOContext context,
WCIndexPath indexPath)
{
context.appendElementIDComponent(
indexPath.toString().replace('.', '_'));
}
// ----------------------------------------------------------
private void _removeIndexPathFromElementID(WOContext context,
WCIndexPath indexPath)
{
context.deleteLastElementIDComponent();
}
// ----------------------------------------------------------
public void _cleanupAfterIteration(WOContext aContext,
WCIndexPath lastIndexPath, WOComponent aComponent, int count)
{
if (this._item != null)
{
this._item._setValueNoValidation(null, aComponent);
}
if (this._indexPath != null)
{
this._indexPath._setValueNoValidation(null, aComponent);
}
if (this._index != null)
{
Integer aNumber = WOShared.unsignedIntNumber(count);
this._index._setValueNoValidation(aNumber, aComponent);
}
if (lastIndexPath != null)
{
_removeIndexPathFromElementID(aContext, lastIndexPath);
}
}
// ----------------------------------------------------------
public void takeValuesFromRequest(WORequest aRequest, WOContext aContext)
{
int anIndex = 0;
WOComponent aComponent = aContext.component();
WCTreeModel<?> aModel = null;
if (this._treeModel != null)
{
Object aValue = this._treeModel.valueInComponent(aComponent);
if (aValue instanceof WCTreeModel)
{
aModel = (WCTreeModel<?>) aValue;
}
else
{
throw new IllegalArgumentException(
"<"
+ super.getClass().getName()
+ "> Evaluating 'treeModel' binding returned a "
+ aValue.getClass().getName()
+ " when it should return a WCTreeModel.");
}
}
Stack<TreePosition> stack = new Stack<TreePosition>();
pushChildrenOfItem(aModel, null, new WCIndexPath(), stack);
WCIndexPath lastIndexPath = null;
while (!stack.isEmpty())
{
lastIndexPath = _prepareForIterationWithIndex(anIndex, aModel,
stack, lastIndexPath, aContext, aComponent);
anIndex++;
super.takeValuesFromRequest(aRequest, aContext);
}
_cleanupAfterIteration(aContext, lastIndexPath, aComponent, anIndex);
}
// ----------------------------------------------------------
private static class TreePosition
{
public TreePosition(WCIndexPath indexPath, Object item)
{
this.indexPath = indexPath;
this.item = item;
}
public WCIndexPath indexPath;
public Object item;
}
// ----------------------------------------------------------
private static void pushChildrenOfItem(WCTreeModel model, Object item,
WCIndexPath indexPath, Stack<TreePosition> stack)
{
if (model.objectHasArrangedChildren(item))
{
NSArray children = model.arrangedChildrenOfObject(item);
if (children != null)
{
for (int i = children.count() - 1; i >= 0; i--)
{
stack.push(new TreePosition(
indexPath.indexPathByAddingIndex(i),
children.objectAtIndex(i)));
}
}
}
}
// ----------------------------------------------------------
static String _indexStringForSenderAndElement(String aSenderId,
String anElementId)
{
String anIndexString = null;
int aLength = anElementId.length();
int aStartIndex = aLength + 1;
int anEndIndex = aSenderId.indexOf('.', aStartIndex);
if (anEndIndex < 0)
{
anIndexString = aSenderId.substring(aStartIndex);
}
else
{
anIndexString = aSenderId.substring(aStartIndex, anEndIndex);
}
return anIndexString;
}
// ----------------------------------------------------------
static String _indexOfChosenItemForRequestInContext(WORequest aRequest,
WOContext aContext)
{
String anIndexString = null;
String aSenderId = aContext.senderID();
String anElementId = aContext.elementID();
if (aSenderId.startsWith(anElementId))
{
int anElementIdLength = anElementId.length();
if ((aSenderId.length() > anElementIdLength)
&& (aSenderId.charAt(anElementIdLength) == '.'))
{
anIndexString = _indexStringForSenderAndElement(aSenderId,
anElementId);
}
}
return anIndexString;
}
// ----------------------------------------------------------
public WOActionResults invokeAction(WORequest aRequest, WOContext aContext)
{
WOComponent aComponent = aContext.component();
WOActionResults aResponsePage = null;
String anIndexString = _indexOfChosenItemForRequestInContext(aRequest,
aContext);
if (anIndexString != null)
{
WCIndexPath indexPath = new WCIndexPath(
anIndexString.replace('_', '.'));
if (this._treeModel != null)
{
Object aValue = this._treeModel.valueInComponent(aComponent);
Object item = null;
if (aValue != null)
{
if (aValue instanceof WCTreeModel)
{
WCTreeModel<?> aModel = (WCTreeModel<?>) aValue;
item = aModel.objectAtIndexPath(indexPath);
}
else
{
throw new IllegalArgumentException(
"<"
+ super.getClass().getName()
+ "> Evaluating 'treeModel' binding returned a "
+ aValue.getClass().getName()
+ " when it should return a WCTreeModel.");
}
if (this._item != null)
{
this._item._setValueNoValidation(item, aComponent);
}
}
}
/* if (this._index != null)
{
Integer aNumber = WOShared.unsignedIntNumber(anIndex);
this._index._setValueNoValidation(aNumber, aComponent);
}*/
aContext.appendElementIDComponent(anIndexString);
aResponsePage = super.invokeAction(aRequest, aContext);
aContext.deleteLastElementIDComponent();
}
else
{
WCTreeModel<?> aModel = null;
int anIndex = 0;
if (this._treeModel != null)
{
Object aValue = this._treeModel.valueInComponent(aComponent);
if (aValue != null)
{
if (aValue instanceof WCTreeModel)
{
aModel = (WCTreeModel<?>) aValue;
}
else
{
throw new IllegalArgumentException(
"<"
+ super.getClass().getName()
+ "> Evaluating 'treeModel' binding returned a "
+ aValue.getClass().getName()
+ " when it should return a WCTreeModel.");
}
}
}
Stack<TreePosition> stack = new Stack<TreePosition>();
pushChildrenOfItem(aModel, null, new WCIndexPath(), stack);
WCIndexPath lastIndexPath = null;
while (!stack.isEmpty() && aResponsePage == null)
{
lastIndexPath = _prepareForIterationWithIndex(anIndex, aModel,
stack, lastIndexPath, aContext, aComponent);
anIndex++;
aResponsePage = super.invokeAction(aRequest, aContext);
}
if (anIndex > 0)
{
_cleanupAfterIteration(aContext, lastIndexPath, aComponent,
anIndex);
}
}
return aResponsePage;
}
// ----------------------------------------------------------
public void appendToResponse(WOResponse aResponse, WOContext aContext)
{
int anIndex = 0;
WOComponent aComponent = aContext.component();
WCTreeModel<?> aModel = null;
if (this._treeModel != null)
{
Object aValue = this._treeModel.valueInComponent(aComponent);
if (aValue != null)
{
if (aValue instanceof WCTreeModel)
{
aModel = (WCTreeModel<?>) aValue;
}
else
{
throw new IllegalArgumentException(
"<"
+ super.getClass()
+ "> Evaluating 'treeModel' binding returned a "
+ aValue.getClass().getName()
+ " when it should return a WCTreeModel.");
}
}
}
Stack<TreePosition> stack = new Stack<TreePosition>();
pushChildrenOfItem(aModel, null, new WCIndexPath(), stack);
WCIndexPath lastIndexPath = null;
while (!stack.isEmpty())
{
lastIndexPath = _prepareForIterationWithIndex(anIndex, aModel,
stack, lastIndexPath, aContext, aComponent);
anIndex++;
super.appendToResponse(aResponse, aContext);
}
_cleanupAfterIteration(aContext, lastIndexPath, aComponent, anIndex);
}
//~ Static/instance variables .............................................
private WOAssociation _treeModel;
private WOAssociation _item;
private WOAssociation _index;
private WOAssociation _indexPath;
}