/* Copyright 1996-2008 Ariba, Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. $Id: //ariba/platform/ui/widgets/ariba/ui/outline/OutlineRepetition.java#4 $ */ package ariba.ui.outline; import java.util.List; import ariba.util.core.ListUtil; import ariba.util.core.Assert; import ariba.util.fieldvalue.OrderedList; import ariba.ui.aribaweb.core.AWComponent; import ariba.ui.aribaweb.core.AWBindingNames; import ariba.ui.aribaweb.core.AWRequestContext; import ariba.ui.aribaweb.core.AWBinding; import ariba.ui.aribaweb.core.AWResponseGenerating; public final class OutlineRepetition extends AWComponent { protected AWBinding _childrenBinding; protected AWBinding _hasChildrenBinding; protected AWBinding _selectedObjectBinding; protected AWBinding _selectionPathBinding; protected AWBinding _expandCurrentItem; protected AWBinding _showExpansionControl; public AWBinding _fullList; protected int _maxLevels; protected boolean _expandAll; protected OutlineState _outlineState; protected int _start, _end; // state for currentItem protected Object _currentItem; protected boolean _isExpanded; public boolean _hasChildren; protected boolean _hideImages; protected Object _currentItemChildren; // OrderedList protected boolean _useCachedChildren; // long-term (cross phase) state public static OutlineRepetition currentInstance (AWComponent currentComponent) { return (OutlineRepetition)currentComponent.env().peek("awxOutlineRepetition"); } public boolean isStateless () { return false; } public void init () { _hasChildrenBinding = bindingForName(BindingNames.hasChildren); _childrenBinding = bindingForName(BindingNames.children); _selectionPathBinding = bindingForName(BindingNames.selectionPath); _selectedObjectBinding = bindingForName(BindingNames.selectedObject); _maxLevels = hasBinding(BindingNames.maxLevels) ? intValueForBinding(BindingNames.maxLevels) : 0; _expandCurrentItem = bindingForName(BindingNames.expandCurrentItem); _showExpansionControl = bindingForName(BindingNames.showExpansionControl); _fullList = bindingForName("fullList"); // create an outline state if we don't have one _outlineState = (OutlineState)valueForBinding(BindingNames.outlineState); if (_outlineState == null) { // create it and push it _outlineState = new OutlineState(); setValueForBinding(_outlineState, BindingNames.outlineState); } // create a selection path if we don't have one if (valueForBinding(_selectionPathBinding) == null) { // create it and push it setSelectionPath(_outlineState.expansionPath()); } } protected void checkBindings () { OutlineState outlineState = (OutlineState)valueForBinding(BindingNames.outlineState); if (outlineState != null) _outlineState = outlineState; if (_selectionPathBinding != null) { _outlineState.setExpansionPath((List)valueForBinding(_selectionPathBinding)); } if (_selectedObjectBinding != null) { _outlineState.setSelectedObject(valueForBinding(_selectedObjectBinding)); } _expandAll = booleanValueForBinding(BindingNames.expandAll) || requestContext().isPrintMode(); _hideImages = requestContext().isExportMode(); } protected void accumulateList (List all, Object currSubList) { if (currSubList == null) return; incrementNestingLevel(); OrderedList orderedListClassExtension = OrderedList.get(currSubList); int count = orderedListClassExtension.size(currSubList); for (int i=0; i<count; i++) { Object currObj = orderedListClassExtension.elementAt(currSubList, i); all.add(currObj); setCurrentItem(currObj); if (isExpanded()) { accumulateList(all, currentItemChildren()); } } decrementNestingLevel(); } /** Used to arm DataTable / DisplayGroup with the full extend of the list to enable scroll faulting */ protected void pushFullList () { // Todo: can we tell if we changed? if (_fullList != null) { _useCachedChildren = false; _outlineState._index = -1; List all = ListUtil.list(); accumulateList(all, rootList()); setValueForBinding(all, _fullList); _useCachedChildren = true; } } void prepareForPhase () { _outlineState._index = -1; _start = hasBinding(BindingNames.start) ? intValueForBinding(BindingNames.start) : 0; _end = hasBinding(BindingNames.count) ? intValueForBinding(BindingNames.count) : Integer.MAX_VALUE; } public void applyValues(AWRequestContext requestContext, AWComponent component) { prepareForPhase(); super.applyValues(requestContext, this); } public AWResponseGenerating invokeAction(AWRequestContext requestContext, AWComponent component) { prepareForPhase(); return super.invokeAction(requestContext, this); } public void renderResponse(AWRequestContext requestContext, AWComponent component) { // check for external changes to bindings checkBindings(); pushFullList(); prepareForPhase(); // note: don't need to do for other phases - it must come back to -1 // after each phase to preserve nesting balance. // -1 rather than 0 since we preincrement the nesting level in // OutlineInnerRepetition _outlineState._nestingLevel = -1; super.renderResponse(requestContext, component); Assert.that((_outlineState._nestingLevel==-1), "Nesting level unbalanced"); } public Object rootList () { // force it through outline state so that we sort it return _outlineState.displayListForChildren(null, valueForBinding(BindingNames.list)); } public void setCurrentItem (Object item) { _currentItem = item; // cache it // maintain a stack representing the current object path if (_outlineState._currentPath == null) { _outlineState._currentPath = ListUtil.list(); } while (_outlineState._currentPath.size() > _outlineState._nestingLevel+1) { ListUtil.removeLastElement(_outlineState._currentPath); } if (_outlineState._nestingLevel >= _outlineState._currentPath.size()) { _outlineState._currentPath.add(item); } else { _outlineState._currentPath.set(_outlineState._nestingLevel, item); } // push our item setValueForBinding(item, AWBindingNames.item); _currentItemChildren = null; // invalidate for lazy recalc // recalculate // if they don't have a hasChildren binding, use $^children!=null _hasChildren = (_hasChildrenBinding != null) ? booleanValueForBinding(_hasChildrenBinding) : (currentItemChildrenCount() > 0); if (_expandAll) { _isExpanded = _hasChildren; } else { _isExpanded = _hasChildren && (_outlineState.isExpanded(_currentItem) || (_expandCurrentItem != null && booleanValueForBinding(_expandCurrentItem))); } if (_isExpanded && (_maxLevels != 0) && (_outlineState._nestingLevel >= _maxLevels)) { _isExpanded = false; } } public Object currentItem () { return _currentItem; } public Object currentItemChildren () { // compute lazily if (_currentItemChildren == null) { if (_useCachedChildren) { _currentItemChildren = _outlineState.lookupListForParent(_currentItem); } else { _currentItemChildren = _outlineState.displayListForChildren(_currentItem, valueForBinding(_childrenBinding)); } } return _currentItemChildren; } public int currentItemChildrenCount () { Object children = currentItemChildren(); return (children == null) ? 0 : OrderedList.get(children).size(children); } public boolean isExpanded () { return _isExpanded; } /* Called by OutlineInnerRepetition to determine whether the current item should be rendered or skipped (i.e. is it in the start<->end renderable range */ public boolean shouldRender () { int index = _outlineState._index; return ((index >= _start) && (index < _end)); } public Object selectedObject () { // for the moment, the tail of the path return _outlineState.selectedObject(); } public void setSelectedObject (Object object) { _outlineState.setSelectedObject(object); setValueForBinding(object, BindingNames.selectedObject); } public AWComponent toggleExpansion () { _outlineState.toggleExpansion(_outlineState._currentPath); setValueForBinding(_outlineState.expansionPath(), BindingNames.selectionPath); setSelectedObject(_currentItem); return null; } public void setSelectionPath (List path) { _outlineState.setExpansionPath(path); setValueForBinding(_outlineState.expansionPath(), BindingNames.selectionPath); } public int nestingLevel () { return _outlineState._nestingLevel; } public void incrementNestingLevel () { _outlineState._nestingLevel++; } public void decrementNestingLevel () { _outlineState._nestingLevel--; } public boolean hideImages () { return _hideImages || ((_showExpansionControl != null) && !booleanValueForBinding(_showExpansionControl)); } public void incrementOutlineIndex() { _outlineState._index++; setValueForBinding(_outlineState._index, BindingNames.outlineIndex); // System.out.println("index: " + _outlineState._index); } }