Author: nbelaevski
Date: 2010-11-18 13:50:06 -0500 (Thu, 18 Nov 2010)
New Revision: 20107
Added:
trunk/core/api/src/main/java/org/richfaces/component/ComponentPredicates.java
trunk/examples/iteration-demo/src/main/java/org/richfaces/demo/LazyTreeNode.java
trunk/ui/iteration/api/src/main/java/org/richfaces/model/TreeDataVisitor.java
trunk/ui/iteration/ui/src/main/config/
trunk/ui/iteration/ui/src/main/config/faces-config.xml
trunk/ui/iteration/ui/src/main/java/org/richfaces/event/MethodExpressionTreeSelectionChangeListener.java
trunk/ui/iteration/ui/src/main/java/org/richfaces/event/MethodExpressionTreeToggleListener.java
trunk/ui/iteration/ui/src/main/java/org/richfaces/model/TreeSequenceKeyModel.java
trunk/ui/iteration/ui/src/main/java/org/richfaces/view/
trunk/ui/iteration/ui/src/main/java/org/richfaces/view/facelets/
trunk/ui/iteration/ui/src/main/java/org/richfaces/view/facelets/TreeHandler.java
trunk/ui/iteration/ui/src/main/java/org/richfaces/view/facelets/TreeNodeHandler.java
trunk/ui/iteration/ui/src/main/java/org/richfaces/view/facelets/TreeSelectionChangeListenerExpressionMetadata.java
trunk/ui/iteration/ui/src/main/java/org/richfaces/view/facelets/TreeToggleListenerExpressionMetadata.java
Modified:
trunk/cdk/generator/src/main/java/org/richfaces/cdk/xmlconfig/model/EventBean.java
trunk/cdk/generator/src/main/resources/META-INF/templates/listenerTagHandler.ftl
trunk/examples/iteration-demo/src/main/java/org/richfaces/demo/TreeBean.java
trunk/examples/iteration-demo/src/main/webapp/tree.xhtml
trunk/ui/common/ui/src/main/java/org/richfaces/renderkit/RenderKitUtils.java
trunk/ui/common/ui/src/test/java/org/richfaces/renderkit/RenderKitUtilsMocksTest.java
trunk/ui/iteration/api/src/main/java/org/richfaces/event/TreeSelectionChangeEvent.java
trunk/ui/iteration/api/src/main/java/org/richfaces/event/TreeSelectionChangeListener.java
trunk/ui/iteration/api/src/main/java/org/richfaces/event/TreeSelectionChangeSource.java
trunk/ui/iteration/api/src/main/java/org/richfaces/event/TreeToggleListener.java
trunk/ui/iteration/api/src/main/java/org/richfaces/event/TreeToggleSource.java
trunk/ui/iteration/api/src/main/java/org/richfaces/model/TreeDataModel.java
trunk/ui/iteration/ui/src/main/java/org/richfaces/component/AbstractTree.java
trunk/ui/iteration/ui/src/main/java/org/richfaces/component/AbstractTreeNode.java
trunk/ui/iteration/ui/src/main/java/org/richfaces/component/TreeRange.java
trunk/ui/iteration/ui/src/main/java/org/richfaces/model/ExtendedTreeDataModelImpl.java
trunk/ui/iteration/ui/src/main/java/org/richfaces/model/SequenceRowKey.java
trunk/ui/iteration/ui/src/main/java/org/richfaces/model/SequenceRowKeyIterator.java
trunk/ui/iteration/ui/src/main/java/org/richfaces/model/SwingTreeNodeDataModelImpl.java
trunk/ui/iteration/ui/src/main/java/org/richfaces/renderkit/TreeEncoderBase.java
trunk/ui/iteration/ui/src/main/java/org/richfaces/renderkit/TreeEncoderFull.java
trunk/ui/iteration/ui/src/main/java/org/richfaces/renderkit/TreeEncoderPartial.java
trunk/ui/iteration/ui/src/main/java/org/richfaces/renderkit/TreeRendererBase.java
trunk/ui/iteration/ui/src/main/java/org/richfaces/renderkit/TreeRenderingContext.java
trunk/ui/iteration/ui/src/main/resources/META-INF/resources/org.richfaces/tree.js
trunk/ui/iteration/ui/src/main/templates/tree.template.xml
trunk/ui/iteration/ui/src/main/templates/treeNode.template.xml
trunk/ui/validator/ui/src/main/java/org/richfaces/renderkit/html/ClientAndAjaxScript.java
Log:
Rest of tree work merged manually from GIT
Modified:
trunk/cdk/generator/src/main/java/org/richfaces/cdk/xmlconfig/model/EventBean.java
===================================================================
---
trunk/cdk/generator/src/main/java/org/richfaces/cdk/xmlconfig/model/EventBean.java 2010-11-18
17:10:13 UTC (rev 20106)
+++
trunk/cdk/generator/src/main/java/org/richfaces/cdk/xmlconfig/model/EventBean.java 2010-11-18
18:50:06 UTC (rev 20107)
@@ -48,6 +48,7 @@
private ClassName sourceInterface;
private ClassName type;
private List<TagModel> tags = Lists.newArrayList();
+ private String listenerMethod;
/**
* <p class="changed_added_4_0"></p>
@@ -165,4 +166,19 @@
public void setTags(List<TagModel> tags) {
this.tags = tags;
}
+
+ /**
+ * @return the listenerMethod
+ */
+ @XmlElement(name = "listener-method", namespace =
ComponentLibrary.CDK_EXTENSIONS_NAMESPACE)
+ public String getListenerMethod() {
+ return listenerMethod;
+ }
+
+ /**
+ * @param listenerMethod the listenerMethod to set
+ */
+ public void setListenerMethod(String listenerMethod) {
+ this.listenerMethod = listenerMethod;
+ }
}
Modified:
trunk/cdk/generator/src/main/resources/META-INF/templates/listenerTagHandler.ftl
===================================================================
---
trunk/cdk/generator/src/main/resources/META-INF/templates/listenerTagHandler.ftl 2010-11-18
17:10:13 UTC (rev 20106)
+++
trunk/cdk/generator/src/main/resources/META-INF/templates/listenerTagHandler.ftl 2010-11-18
18:50:06 UTC (rev 20107)
@@ -98,7 +98,7 @@
private TagAttribute listenerMethod;
- public TestListenerHandler(TagConfig config) {
+ public ${tag.targetClass.simpleName}(TagConfig config) {
super(config);
this.binding = this.getAttribute("binding");
Added: trunk/core/api/src/main/java/org/richfaces/component/ComponentPredicates.java
===================================================================
--- trunk/core/api/src/main/java/org/richfaces/component/ComponentPredicates.java
(rev 0)
+++
trunk/core/api/src/main/java/org/richfaces/component/ComponentPredicates.java 2010-11-18
18:50:06 UTC (rev 20107)
@@ -0,0 +1,45 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.component;
+
+import javax.faces.component.UIComponent;
+
+import com.google.common.base.Predicate;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public final class ComponentPredicates {
+
+ private static final Predicate<UIComponent> IS_RENDERED = new
Predicate<UIComponent>() {
+ public boolean apply(UIComponent input) {
+ return input.isRendered();
+ };
+ };
+
+ private ComponentPredicates() {}
+
+ public static Predicate<UIComponent> isRendered() {
+ return IS_RENDERED;
+ }
+}
Added: trunk/examples/iteration-demo/src/main/java/org/richfaces/demo/LazyTreeNode.java
===================================================================
--- trunk/examples/iteration-demo/src/main/java/org/richfaces/demo/LazyTreeNode.java
(rev 0)
+++
trunk/examples/iteration-demo/src/main/java/org/richfaces/demo/LazyTreeNode.java 2010-11-18
18:50:06 UTC (rev 20107)
@@ -0,0 +1,112 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.demo;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+
+import javax.swing.tree.TreeNode;
+
+import com.google.common.collect.Iterators;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public class LazyTreeNode implements TreeNode, Serializable {
+
+ private static final long serialVersionUID = 7222747310505408841L;
+
+ private TreeNode srcNode;
+
+ private LazyTreeNode parentNode;
+
+ private List<LazyTreeNode> children = null;
+
+ public LazyTreeNode(LazyTreeNode parentNode, TreeNode srcNode) {
+ super();
+ this.parentNode = parentNode;
+ this.srcNode = srcNode;
+ }
+
+ public LazyTreeNode(TreeNode srcNode) {
+ this(null, srcNode);
+ }
+
+ private void initializeChildren() {
+ if (children != null) {
+ return;
+ }
+
+ children = new ArrayList<LazyTreeNode>();
+
+ Enumeration srcChildren = srcNode.children();
+ while (srcChildren.hasMoreElements()) {
+ TreeNode srcChild = (TreeNode) srcChildren.nextElement();
+ children.add(new LazyTreeNode(this, srcChild));
+ }
+ }
+
+ public TreeNode getChildAt(int childIndex) {
+ initializeChildren();
+
+ return children.get(childIndex);
+ }
+
+ public int getChildCount() {
+ initializeChildren();
+
+ return children.size();
+ }
+
+ public TreeNode getParent() {
+ return parentNode;
+ }
+
+ public int getIndex(TreeNode node) {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean getAllowsChildren() {
+ return true;
+ }
+
+ public boolean isLeaf() {
+ if (children == null) {
+ return false;
+ }
+
+ return children.isEmpty();
+ }
+
+ public Enumeration children() {
+ initializeChildren();
+
+ return Iterators.asEnumeration(children.iterator());
+ }
+
+ public TreeNode getWrappedNode() {
+ return srcNode;
+ }
+}
Modified: trunk/examples/iteration-demo/src/main/java/org/richfaces/demo/TreeBean.java
===================================================================
---
trunk/examples/iteration-demo/src/main/java/org/richfaces/demo/TreeBean.java 2010-11-18
17:10:13 UTC (rev 20106)
+++
trunk/examples/iteration-demo/src/main/java/org/richfaces/demo/TreeBean.java 2010-11-18
18:50:06 UTC (rev 20107)
@@ -22,6 +22,7 @@
package org.richfaces.demo;
import java.io.Serializable;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -30,10 +31,18 @@
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;
+import javax.faces.event.AbortProcessingException;
import javax.faces.event.AjaxBehaviorEvent;
+import javax.faces.event.FacesEvent;
import javax.swing.tree.TreeNode;
+import org.richfaces.component.AbstractTree;
+import org.richfaces.component.AbstractTreeNode;
import org.richfaces.component.SwitchType;
+import org.richfaces.event.TreeSelectionChangeEvent;
+import org.richfaces.event.TreeSelectionChangeListener;
+import org.richfaces.event.TreeToggleEvent;
+import org.richfaces.event.TreeToggleListener;
import org.richfaces.log.LogFactory;
import org.richfaces.log.Logger;
@@ -45,28 +54,98 @@
@SessionScoped
public class TreeBean implements Serializable {
+ public static final class SelectionChangeHandler implements
TreeSelectionChangeListener {
+
+ private boolean fromExpression = false;
+
+ public SelectionChangeHandler() {
+ }
+
+ public SelectionChangeHandler(boolean fromExpression) {
+ super();
+ this.fromExpression = fromExpression;
+ }
+
+ public void processSelectionChange(TreeSelectionChangeEvent event) throws
AbortProcessingException {
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+
+ facesContext.addMessage(getTree(event).getBaseClientId(facesContext),
createEventMessage(event, fromExpression));
+ }
+
+ }
+
+ public static final class ToggleHandler implements TreeToggleListener {
+
+ private boolean fromExpression = false;
+
+ public ToggleHandler() {
+ }
+
+ public ToggleHandler(boolean fromExpression) {
+ super();
+ this.fromExpression = fromExpression;
+ }
+
+ public void processToggle(TreeToggleEvent event) throws AbortProcessingException
{
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+ facesContext.addMessage(getTree(event).getBaseClientId(facesContext),
createEventMessage(event, fromExpression));
+ }
+
+ }
+
private static final long serialVersionUID = 3368885134614548497L;
private static final Logger LOGGER = LogFactory.getLogger(TreeBean.class);
private List<TreeNode> rootNodes;
+ private List<TreeNode> lazyRootNodes;
+
private SwitchType toggleType = SwitchType.DEFAULT;
private SwitchType selectionType = SwitchType.client;
- private Object nodeData;
-
private boolean showCustomClasses = true;
private Collection<Object> selection = new TracingSet<Object>();
+
+ private String toggleNodeEvent = "";
+ private static Object staticGetNodeData() {
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+ return facesContext.getApplication().evaluateExpressionGet(facesContext,
"#{node}", Object.class);
+ }
+
+ private static FacesMessage createEventMessage(FacesEvent event, boolean
fromExpression) {
+ String summary = event + (fromExpression ? " called from attribute" :
" called from tag") + ", data: " + staticGetNodeData();
+ return new FacesMessage(summary);
+ }
+
+ private static AbstractTree getTree(FacesEvent event) {
+ if (event.getComponent() instanceof AbstractTree) {
+ return (AbstractTree) event.getComponent();
+ }
+
+ return ((AbstractTreeNode) event.getComponent()).findTreeComponent();
+ }
+
+ private List<TreeNode> createLazyNodes(List<TreeNode> nodes) {
+ List<TreeNode> result = new ArrayList<TreeNode>(nodes.size());
+
+ for (TreeNode srcNode : nodes) {
+ result.add(new LazyTreeNode(srcNode));
+ }
+
+ return result;
+ }
+
@PostConstruct
public void init() {
try {
TreeNodeParser parser = new TreeNodeParser();
parser.parse(TreeBean.class.getResource("plants.xml"));
rootNodes = parser.getRootNodes();
+ lazyRootNodes = createLazyNodes(rootNodes);
} catch (Exception e) {
LOGGER.error(e.getMessage(), e);
}
@@ -76,6 +155,10 @@
return rootNodes;
}
+ public List<TreeNode> getLazyRootNodes() {
+ return lazyRootNodes;
+ }
+
public SwitchType[] getTypes() {
return SwitchType.values();
}
@@ -97,8 +180,7 @@
}
public Object getNodeData() {
- FacesContext facesContext = FacesContext.getCurrentInstance();
- return facesContext.getApplication().evaluateExpressionGet(facesContext,
"#{node}", Object.class);
+ return staticGetNodeData();
}
public Collection<Object> getSelection() {
@@ -131,4 +213,22 @@
FacesContext facesContext = FacesContext.getCurrentInstance();
facesContext.addMessage(event.getComponent().getClientId(facesContext), new
FacesMessage("Selection changed, source is: " + event.getSource()));
}
+
+ public void processSelectionChange(TreeSelectionChangeEvent event) {
+ new SelectionChangeHandler(true).processSelectionChange(event);
+ }
+
+ public void processToggle(TreeToggleEvent event) {
+ new ToggleHandler(true).processToggle(event);
+ }
+
+ public String getToggleNodeEvent() {
+ return toggleNodeEvent;
+ }
+
+ public void setToggleNodeEvent(String toggleNodeEvent) {
+ this.toggleNodeEvent = toggleNodeEvent;
+ }
+
+
}
Modified: trunk/examples/iteration-demo/src/main/webapp/tree.xhtml
===================================================================
--- trunk/examples/iteration-demo/src/main/webapp/tree.xhtml 2010-11-18 17:10:13 UTC (rev
20106)
+++ trunk/examples/iteration-demo/src/main/webapp/tree.xhtml 2010-11-18 18:50:06 UTC (rev
20107)
@@ -53,6 +53,20 @@
+ '[' + nodeData + ']:\n ' + treeNode.getId() + ' became ' +
getNodeStateString(treeNode));
}
+ function handleBeforeNodeToggle(event, isTreeNodeLevel) {
+ var treeNode = RichFaces.$(event.target);
+ return confirm('Tree' + (isTreeNodeLevel ? ' node ' : ' ') +
'asks: really toggle node ' + treeNode.getId() + '?');
+ }
+
+ function handleBeforeNodeSelect(event) {
+ var treeNode = RichFaces.$(event.target);
+
+ var oldSelectionString = nodesArrayToString(event.rf.data.oldSelection);
+ var newSelectionString = nodesArrayToString(event.rf.data.newSelection);
+
+ return confirm('Selection will be changed from: [' + oldSelectionString +
'] to: [' + newSelectionString + ']');
+ }
+
function handleNodeSelect(event) {
var treeNode = RichFaces.$(event.target);
@@ -75,6 +89,15 @@
</h:selectOneRadio>
Show custom classes: <h:selectBooleanCheckbox
value="#{treeBean.showCustomClasses}" onclick="submit()" />
+
+ <br />
+ Toggle node event:
+ <h:selectOneMenu value="#{treeBean.toggleNodeEvent}"
onchange="submit()">
+ <f:selectItem itemLabel="none" itemValue="" />
+ <f:selectItem itemLabel="click" itemValue="click" />
+ <f:selectItem itemLabel="mouseenter" itemValue="mouseenter"
/>
+ <f:selectItem itemLabel="dblclick" itemValue="dblclick" />
+ </h:selectOneMenu>
</h:form>
<h:form id="form">
@@ -125,9 +148,12 @@
<it:tree id="clientSideEventsTree" var="node"
value="#{treeBean.rootNodes}"
selectionType="#{treeBean.selectionType}"
toggleType="#{treeBean.toggleType}"
onnodetoggle="handleNodeToggle("#{node.data}", event,
false)"
- onselectionchange="handleNodeSelect(event)">
+ onselectionchange="handleNodeSelect(event)"
+ onbeforeselectionchange="return handleBeforeNodeSelect(event)"
+ onbeforenodetoggle="return handleBeforeNodeToggle(event, false)">
- <it:treeNode ontoggle="handleNodeToggle("#{node.data}",
event, true)">
+ <it:treeNode ontoggle="handleNodeToggle("#{node.data}",
event, true)"
+ onbeforetoggle="return handleBeforeNodeToggle(event, true)">
#{node.data}
</it:treeNode>
</it:tree>
@@ -149,6 +175,43 @@
</it:treeNode>
</it:tree>
+ Lazy loaded tree:
+ <it:tree id="lazyLoadedTree" var="node"
value="#{treeBean.lazyRootNodes}"
+ selectionType="#{treeBean.selectionType}"
toggleType="#{treeBean.toggleType}">
+
+ <it:treeNode>
+ #{node.wrappedNode.data}
+ </it:treeNode>
+ </it:tree>
+
+ <a4j:outputPanel ajaxRendered="true">
+ <h:messages for="serverListenersTree" />
+ </a4j:outputPanel>
+
+ Server listeners test:
+ <it:tree id="serverListenersTree" var="node"
value="#{treeBean.rootNodes}"
+ selectionType="#{treeBean.selectionType}"
toggleType="#{treeBean.toggleType}"
+ selectionChangeListener="#{treeBean.processSelectionChange}"
+ toggleListener="#{treeBean.processToggle}">
+
+ <it:treeSelectionChangeListener
type="org.richfaces.demo.TreeBean$SelectionChangeHandler" />
+ <it:treeToggleListener type="org.richfaces.demo.TreeBean$ToggleHandler"
/>
+
+ <it:treeNode toggleListener="#{treeBean.processToggle}">
+ <it:treeToggleListener type="org.richfaces.demo.TreeBean$ToggleHandler"
/>
+
+ #{node.data}
+ </it:treeNode>
+ </it:tree>
+
+ Toggle node event:
+ <it:tree toggleNodeEvent="#{treeBean.toggleNodeEvent}"
var="node" value="#{treeBean.rootNodes}"
+ selectionType="#{treeBean.selectionType}"
toggleType="#{treeBean.toggleType}">
+ <it:treeNode>
+ #{node.data}
+ </it:treeNode>
+ </it:tree>
+
<a4j:log />
</h:form>
</h:body>
Modified: trunk/ui/common/ui/src/main/java/org/richfaces/renderkit/RenderKitUtils.java
===================================================================
---
trunk/ui/common/ui/src/main/java/org/richfaces/renderkit/RenderKitUtils.java 2010-11-18
17:10:13 UTC (rev 20106)
+++
trunk/ui/common/ui/src/main/java/org/richfaces/renderkit/RenderKitUtils.java 2010-11-18
18:50:06 UTC (rev 20107)
@@ -299,7 +299,7 @@
}
if (isChained) {
- result.insert(0, "jsf.util.chain(this, event, ");
+ result.insert(0, "return jsf.util.chain(this, event, ");
result.append(")");
}
@@ -715,6 +715,39 @@
return context.getExternalContext().encodeResourceURL(value);
}
+ public static Object getFirstNonEmptyAttribute(String attributeName, UIComponent
component) {
+ Object attributeValue = component.getAttributes().get(attributeName);
+
+ return !isEmpty(attributeValue) ? attributeValue : null;
+ }
+
+ public static Object getFirstNonEmptyAttribute(String attributeName, UIComponent
componentA, UIComponent componentB) {
+ Object attributeValue = componentA.getAttributes().get(attributeName);
+
+ if (!isEmpty(attributeValue)) {
+ return attributeValue;
+ }
+
+ attributeValue = componentB.getAttributes().get(attributeName);
+
+ if (!isEmpty(attributeValue)) {
+ return attributeValue;
+ }
+
+ return null;
+ }
+
+ public static Object getFirstNonEmptyAttribute(String attributeName, UIComponent...
components) {
+ for (UIComponent component : components) {
+ Object attributeValue = component.getAttributes().get(attributeName);
+ if (!isEmpty(attributeValue)) {
+ return attributeValue;
+ }
+ }
+
+ return null;
+ }
+
@SuppressWarnings("serial")
public static final class Attributes extends TreeSet<ComponentAttribute> {
Modified:
trunk/ui/common/ui/src/test/java/org/richfaces/renderkit/RenderKitUtilsMocksTest.java
===================================================================
---
trunk/ui/common/ui/src/test/java/org/richfaces/renderkit/RenderKitUtilsMocksTest.java 2010-11-18
17:10:13 UTC (rev 20106)
+++
trunk/ui/common/ui/src/test/java/org/richfaces/renderkit/RenderKitUtilsMocksTest.java 2010-11-18
18:50:06 UTC (rev 20107)
@@ -199,10 +199,10 @@
ClientBehaviorHolder behaviorHolder = createMockClientBehaviorHolder();
UIComponent component = (UIComponent) behaviorHolder;
- responseWriter.writeAttribute(eq("onkeypress"),
eq("jsf.util.chain(this, event,
'alert(keypress)','prompt(keypress)')"),
+ responseWriter.writeAttribute(eq("onkeypress"), eq("return
jsf.util.chain(this, event, 'alert(keypress)','prompt(keypress)')"),
EasyMock.<String>isNull());
responseWriter.writeAttribute(eq("onclick"),
- eq("jsf.util.chain(this, event,
'alert(click)','prompt(action1)','prompt(action2)')"),
EasyMock.<String>isNull());
+ eq("return jsf.util.chain(this, event,
'alert(click)','prompt(action1)','prompt(action2)')"),
EasyMock.<String>isNull());
responseWriter.writeAttribute(eq("onmousemove"),
eq("alert(mousemove)"), EasyMock.<String>isNull());
responseWriter.writeAttribute(eq("oncontextmenu"),
eq("prompt(contextmenu)"), EasyMock.<String>isNull());
@@ -249,7 +249,7 @@
componentAttributes.put("disabled", Boolean.FALSE);
UIComponent component = setupBehaviorsTestForDisabledComponent();
- responseWriter.writeAttribute(eq("onclick"),
eq("jsf.util.chain(this, event,
'alert(click)','prompt(action1)')"),
+ responseWriter.writeAttribute(eq("onclick"), eq("return
jsf.util.chain(this, event, 'alert(click)','prompt(action1)')"),
EasyMock.<String>isNull());
responseWriter.writeAttribute(eq("onmousemove"),
eq("alert(mousemove)"), EasyMock.<String>isNull());
Modified:
trunk/ui/iteration/api/src/main/java/org/richfaces/event/TreeSelectionChangeEvent.java
===================================================================
---
trunk/ui/iteration/api/src/main/java/org/richfaces/event/TreeSelectionChangeEvent.java 2010-11-18
17:10:13 UTC (rev 20106)
+++
trunk/ui/iteration/api/src/main/java/org/richfaces/event/TreeSelectionChangeEvent.java 2010-11-18
18:50:06 UTC (rev 20107)
@@ -53,7 +53,7 @@
@Override
public void processListener(FacesListener listener) {
- ((TreeSelectionChangeListener) listener).processSelection(this);
+ ((TreeSelectionChangeListener) listener).processSelectionChange(this);
}
public Collection<Object> getOldSelection() {
Modified:
trunk/ui/iteration/api/src/main/java/org/richfaces/event/TreeSelectionChangeListener.java
===================================================================
---
trunk/ui/iteration/api/src/main/java/org/richfaces/event/TreeSelectionChangeListener.java 2010-11-18
17:10:13 UTC (rev 20106)
+++
trunk/ui/iteration/api/src/main/java/org/richfaces/event/TreeSelectionChangeListener.java 2010-11-18
18:50:06 UTC (rev 20107)
@@ -21,6 +21,7 @@
*/
package org.richfaces.event;
+import javax.faces.event.AbortProcessingException;
import javax.faces.event.FacesListener;
/**
@@ -29,6 +30,6 @@
*/
public interface TreeSelectionChangeListener extends FacesListener {
- public void processSelection(TreeSelectionChangeEvent event);
+ public void processSelectionChange(TreeSelectionChangeEvent event) throws
AbortProcessingException;
}
Modified:
trunk/ui/iteration/api/src/main/java/org/richfaces/event/TreeSelectionChangeSource.java
===================================================================
---
trunk/ui/iteration/api/src/main/java/org/richfaces/event/TreeSelectionChangeSource.java 2010-11-18
17:10:13 UTC (rev 20106)
+++
trunk/ui/iteration/api/src/main/java/org/richfaces/event/TreeSelectionChangeSource.java 2010-11-18
18:50:06 UTC (rev 20107)
@@ -27,8 +27,8 @@
*/
public interface TreeSelectionChangeSource {
- public void addSelectionChangeListener(TreeSelectionChangeListener listener);
+ public void addTreeSelectionChangeListener(TreeSelectionChangeListener listener);
- public void removeSelectionchangeListener(TreeSelectionChangeListener listener);
+ public void removeTreeSelectionChangeListener(TreeSelectionChangeListener listener);
}
Modified:
trunk/ui/iteration/api/src/main/java/org/richfaces/event/TreeToggleListener.java
===================================================================
---
trunk/ui/iteration/api/src/main/java/org/richfaces/event/TreeToggleListener.java 2010-11-18
17:10:13 UTC (rev 20106)
+++
trunk/ui/iteration/api/src/main/java/org/richfaces/event/TreeToggleListener.java 2010-11-18
18:50:06 UTC (rev 20107)
@@ -21,6 +21,7 @@
*/
package org.richfaces.event;
+import javax.faces.event.AbortProcessingException;
import javax.faces.event.FacesListener;
/**
@@ -29,6 +30,6 @@
*/
public interface TreeToggleListener extends FacesListener {
- public void processToggle(TreeToggleEvent event);
+ public void processToggle(TreeToggleEvent event) throws AbortProcessingException;
}
Modified: trunk/ui/iteration/api/src/main/java/org/richfaces/event/TreeToggleSource.java
===================================================================
---
trunk/ui/iteration/api/src/main/java/org/richfaces/event/TreeToggleSource.java 2010-11-18
17:10:13 UTC (rev 20106)
+++
trunk/ui/iteration/api/src/main/java/org/richfaces/event/TreeToggleSource.java 2010-11-18
18:50:06 UTC (rev 20107)
@@ -27,8 +27,8 @@
*/
public interface TreeToggleSource {
- public void addToggleListener(TreeToggleListener listener);
+ public void addTreeToggleListener(TreeToggleListener listener);
- public void removeToggleListener(TreeToggleListener listener);
+ public void removeTreeToggleListener(TreeToggleListener listener);
}
Modified: trunk/ui/iteration/api/src/main/java/org/richfaces/model/TreeDataModel.java
===================================================================
--- trunk/ui/iteration/api/src/main/java/org/richfaces/model/TreeDataModel.java 2010-11-18
17:10:13 UTC (rev 20106)
+++ trunk/ui/iteration/api/src/main/java/org/richfaces/model/TreeDataModel.java 2010-11-18
18:50:06 UTC (rev 20107)
@@ -21,8 +21,11 @@
*/
package org.richfaces.model;
-import java.util.Iterator;
+import javax.faces.context.FacesContext;
+import org.ajax4jsf.model.DataVisitor;
+import org.ajax4jsf.model.Range;
+
/**
* @author Nick Belaevski
*
@@ -36,10 +39,16 @@
public boolean isDataAvailable();
+ public boolean isLeaf();
+
public E getData();
- public Iterator<Object> getChildrenRowKeysIterator(Object rowKey);
+ public void walk(FacesContext context, DataVisitor visitor, Range range, Object
argument);
+
+ public void enterNode(DataVisitor visitor);
+ public void exitNode(DataVisitor visitor);
+
public Object getParentRowKey(Object rowKey);
public Object getWrappedData();
Added: trunk/ui/iteration/api/src/main/java/org/richfaces/model/TreeDataVisitor.java
===================================================================
--- trunk/ui/iteration/api/src/main/java/org/richfaces/model/TreeDataVisitor.java
(rev 0)
+++
trunk/ui/iteration/api/src/main/java/org/richfaces/model/TreeDataVisitor.java 2010-11-18
18:50:06 UTC (rev 20107)
@@ -0,0 +1,36 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.model;
+
+import org.ajax4jsf.model.DataVisitor;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public interface TreeDataVisitor extends DataVisitor {
+
+ public void enterNode();
+
+ public void exitNode();
+
+}
Added: trunk/ui/iteration/ui/src/main/config/faces-config.xml
===================================================================
--- trunk/ui/iteration/ui/src/main/config/faces-config.xml (rev
0)
+++ trunk/ui/iteration/ui/src/main/config/faces-config.xml 2010-11-18 18:50:06 UTC (rev
20107)
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<faces-config
xmlns="http://java.sun.com/xml/ns/javaee"
+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"
+
xmlns:cdk="http://jboss.org/schema/richfaces/cdk/extensions"
+ version="2.0">
+
+ <faces-config-extension>
+ <cdk:faces-event>
+
<cdk:event-class>org.richfaces.event.TreeToggleEvent</cdk:event-class>
+
<cdk:listener-class>org.richfaces.event.TreeToggleListener</cdk:listener-class>
+
<cdk:source-class>org.richfaces.event.TreeToggleSource</cdk:source-class>
+ <cdk:listener-method>processToggle</cdk:listener-method>
+ <cdk:tag>
+ <cdk:tag-name>treeToggleListener</cdk:tag-name>
+ <cdk:tag-type>Facelets</cdk:tag-type>
+
<cdk:handler-class>org.richfaces.view.facelets.TreeToggleListenerHandler</cdk:handler-class>
+ <cdk:generate>true</cdk:generate>
+ </cdk:tag>
+ </cdk:faces-event>
+
+ <cdk:faces-event>
+
<cdk:event-class>org.richfaces.event.TreeSelectionChangeEvent</cdk:event-class>
+
<cdk:listener-class>org.richfaces.event.TreeSelectionChangeListener</cdk:listener-class>
+
<cdk:source-class>org.richfaces.event.TreeSelectionChangeSource</cdk:source-class>
+
<cdk:listener-method>processSelectionChange</cdk:listener-method>
+ <cdk:tag>
+ <cdk:tag-name>treeSelectionChangeListener</cdk:tag-name>
+ <cdk:tag-type>Facelets</cdk:tag-type>
+
<cdk:handler-class>org.richfaces.view.facelets.TreeSelectionChangeListenerHandler</cdk:handler-class>
+ <cdk:generate>true</cdk:generate>
+ </cdk:tag>
+ </cdk:faces-event>
+ </faces-config-extension>
+
+</faces-config>
Modified: trunk/ui/iteration/ui/src/main/java/org/richfaces/component/AbstractTree.java
===================================================================
---
trunk/ui/iteration/ui/src/main/java/org/richfaces/component/AbstractTree.java 2010-11-18
17:10:13 UTC (rev 20106)
+++
trunk/ui/iteration/ui/src/main/java/org/richfaces/component/AbstractTree.java 2010-11-18
18:50:06 UTC (rev 20107)
@@ -26,9 +26,14 @@
import java.util.HashSet;
import java.util.Iterator;
+import javax.el.ELContext;
+import javax.el.ELException;
+import javax.el.MethodExpression;
import javax.el.ValueExpression;
import javax.faces.application.Application;
+import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
+import javax.faces.component.UpdateModelException;
import javax.faces.component.html.HtmlOutputText;
import javax.faces.component.visit.VisitCallback;
import javax.faces.component.visit.VisitContext;
@@ -36,22 +41,34 @@
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.event.AbortProcessingException;
+import javax.faces.event.ExceptionQueuedEvent;
+import javax.faces.event.ExceptionQueuedEventContext;
import javax.faces.event.FacesEvent;
+import javax.faces.event.PhaseId;
import javax.swing.tree.TreeNode;
import org.ajax4jsf.model.DataComponentState;
import org.ajax4jsf.model.ExtendedDataModel;
import org.ajax4jsf.model.Range;
+import org.richfaces.application.MessageFactory;
+import org.richfaces.application.ServiceTracker;
+import org.richfaces.appplication.FacesMessages;
import org.richfaces.cdk.annotations.Attribute;
import org.richfaces.cdk.annotations.EventName;
import org.richfaces.cdk.annotations.JsfComponent;
import org.richfaces.cdk.annotations.JsfRenderer;
+import org.richfaces.cdk.annotations.Signature;
import org.richfaces.cdk.annotations.Tag;
+import org.richfaces.component.util.MessageUtil;
import org.richfaces.context.ExtendedVisitContext;
import org.richfaces.context.ExtendedVisitContextMode;
import org.richfaces.convert.SequenceRowKeyConverter;
import org.richfaces.event.TreeSelectionChangeEvent;
import org.richfaces.event.TreeSelectionChangeListener;
+import org.richfaces.event.TreeSelectionChangeSource;
+import org.richfaces.event.TreeToggleEvent;
+import org.richfaces.event.TreeToggleListener;
+import org.richfaces.event.TreeToggleSource;
import org.richfaces.model.ExtendedTreeDataModelImpl;
import org.richfaces.model.SwingTreeNodeDataModelImpl;
import org.richfaces.model.TreeDataModel;
@@ -69,22 +86,22 @@
@JsfComponent(
type = AbstractTree.COMPONENT_TYPE,
family = AbstractTree.COMPONENT_FAMILY,
- tag = @Tag(name = "tree"),
+ tag = @Tag(name = "tree", handler =
"org.richfaces.view.facelets.TreeHandler"),
renderer = @JsfRenderer(type = "org.richfaces.TreeRenderer"),
attributes = {"events-props.xml", "core-props.xml",
"i18n-props.xml"}
)
-public abstract class AbstractTree extends UIDataAdaptor implements
MetaComponentResolver, MetaComponentEncoder {
+public abstract class AbstractTree extends UIDataAdaptor implements
MetaComponentResolver, MetaComponentEncoder, TreeSelectionChangeSource, TreeToggleSource
{
public static final String COMPONENT_TYPE = "org.richfaces.Tree";
public static final String COMPONENT_FAMILY = "org.richfaces.Tree";
public static final String SELECTION_META_COMPONENT_ID = "selection";
-
+
private static final String DEFAULT_TREE_NODE_CREATED = AbstractTree.class.getName()
+ ":DEFAULT_TREE_NODE_CREATED";
-
+
private static final class MatchingTreeNodePredicate implements
Predicate<UIComponent> {
-
+
private String type;
public MatchingTreeNodePredicate(String type) {
@@ -96,20 +113,16 @@
if (!(input instanceof AbstractTreeNode)) {
return false;
}
-
- if (!input.isRendered()) {
- return false;
- }
-
+
String nodeType = ((AbstractTreeNode) input).getType();
if (type == null && nodeType == null) {
return true;
}
-
+
return type != null && type.equals(nodeType);
}
};
-
+
private static final Converter ROW_KEY_CONVERTER = new SequenceRowKeyConverter();
/**
@@ -126,6 +139,12 @@
selection
}
+ @Attribute(generate = false, signature = @Signature(returnType = Void.class,
parameters = TreeSelectionChangeEvent.class))
+ private MethodExpression selectionChangeListener;
+
+ @Attribute(generate = false, signature = @Signature(returnType = Void.class,
parameters = TreeToggleListener.class))
+ private MethodExpression toggleListener;
+
public AbstractTree() {
setKeepSaved(true);
setRendererType("org.richfaces.TreeRenderer");
@@ -136,44 +155,52 @@
public abstract boolean isImmediate();
public abstract String getIconLeaf();
-
+
public abstract String getIconExpanded();
-
+
public abstract String getIconCollapsed();
public abstract String getNodeClass();
-
+
public abstract String getHandleClass();
-
+
public abstract String getIconClass();
-
+
public abstract String getLabelClass();
-
+
@Attribute(events = @EventName("nodetoggle"))
public abstract String getOnnodetoggle();
-
+
+ @Attribute(events = @EventName("beforenodetoggle"))
+ public abstract String getOnbeforenodetoggle();
+
@Attribute(events = @EventName("selectionchange"))
public abstract String getOnselectionchange();
-
+
+ @Attribute(events = @EventName("beforeselectionchange"))
+ public abstract String getOnbeforeselectionchange();
+
@Attribute(defaultValue = "SwitchType.DEFAULT")
public abstract SwitchType getToggleType();
@Attribute(defaultValue = "SwitchType.client")
public abstract SwitchType getSelectionType();
-
+
public abstract String getNodeType();
+
+ public abstract String getToggleNodeEvent();
@Override
public String getFamily() {
return COMPONENT_FAMILY;
}
-
+
public Collection<Object> getSelection() {
@SuppressWarnings("unchecked")
Collection<Object> selection = (Collection<Object>)
getStateHelper().eval(PropertyKeys.selection);
if (selection == null) {
selection = new HashSet<Object>();
-
+
ValueExpression ve = getValueExpression(PropertyKeys.selection.toString());
if (ve != null) {
ve.setValue(getFacesContext().getELContext(), selection);
@@ -181,14 +208,14 @@
getStateHelper().put(PropertyKeys.selection, selection);
}
}
-
+
return selection;
}
-
+
public void setSelection(Collection<Object> selection) {
getStateHelper().put(PropertyKeys.selection, selection);
}
-
+
@Override
protected ExtendedDataModel<?> createExtendedDataModel() {
ExtendedTreeDataModelImpl<?> model = new
ExtendedTreeDataModelImpl<TreeNode>(new SwingTreeNodeDataModelImpl());
@@ -211,41 +238,42 @@
return converter;
}
- public Iterator<Object> getChildrenRowKeysIterator(FacesContext faces, Object
rowKey) {
- TreeDataModel<?> dataModel = (TreeDataModel<?>)
getExtendedDataModel();
- return dataModel.getChildrenRowKeysIterator(rowKey);
- }
-
public AbstractTreeNode findTreeNodeComponent() {
FacesContext facesContext = getFacesContext();
-
+
String nodeType = getNodeType();
- Iterator<UIComponent> iterator = Iterators.filter(getChildren().iterator(),
+ Iterator<UIComponent> matchingNodes =
Iterators.filter(getChildren().iterator(),
new MatchingTreeNodePredicate(nodeType));
-
- if (iterator.hasNext()) {
- return (AbstractTreeNode) iterator.next();
+
+ boolean hasNodes = matchingNodes.hasNext();
+ if (hasNodes) {
+ Iterator<UIComponent> renderedTreeNodes =
Iterators.filter(matchingNodes, ComponentPredicates.isRendered());
+ if (renderedTreeNodes.hasNext()) {
+ return (AbstractTreeNode) renderedTreeNodes.next();
+ } else {
+ return null;
+ }
}
if (Strings.isNullOrEmpty(nodeType)) {
if (getAttributes().put(DEFAULT_TREE_NODE_CREATED, Boolean.TRUE) != null) {
return null;
}
-
+
Application application = facesContext.getApplication();
AbstractTreeNode treeNode = (AbstractTreeNode)
application.createComponent(AbstractTreeNode.COMPONENT_TYPE);
treeNode.setId("__defaultTreeNode");
-
+
getChildren().add(treeNode);
-
+
UIComponent text =
application.createComponent(HtmlOutputText.COMPONENT_TYPE);
text.setValueExpression("value",
application.getExpressionFactory().createValueExpression(facesContext.getELContext(),
"#{" + getVar() + "}", String.class));
treeNode.getChildren().add(text);
-
+
return treeNode;
}
-
+
return null;
}
@@ -255,28 +283,83 @@
if (event instanceof TreeSelectionChangeEvent) {
TreeSelectionChangeEvent selectionEvent = (TreeSelectionChangeEvent) event;
-
+
final Collection<Object> newSelection =
selectionEvent.getNewSelection();
Collection<Object> selectionCollection = getSelection();
-
+
Iterables.removeIf(selectionCollection, new Predicate<Object>() {
public boolean apply(Object input) {
return !newSelection.contains(input);
};
});
-
+
if (!newSelection.isEmpty()) {
Iterables.addAll(selectionCollection, newSelection);
}
+ } else if (event instanceof TreeToggleEvent) {
+ TreeToggleEvent toggleEvent = (TreeToggleEvent) event;
+ AbstractTreeNode treeNodeComponent = findTreeNodeComponent();
+
+ boolean newExpandedValue = toggleEvent.isExpanded();
+
+ FacesContext context = getFacesContext();
+ ValueExpression expression =
getValueExpression(AbstractTreeNode.PropertyKeys.expanded.toString());
+ if (expression != null) {
+ ELContext elContext = context.getELContext();
+ Exception caught = null;
+ FacesMessage message = null;
+ try {
+ expression.setValue(elContext, newExpandedValue);
+ } catch (ELException e) {
+ caught = e;
+ String messageStr = e.getMessage();
+ Throwable result = e.getCause();
+ while (null != result &&
+ result.getClass().isAssignableFrom(ELException.class)) {
+ messageStr = result.getMessage();
+ result = result.getCause();
+ }
+ if (null == messageStr) {
+ MessageFactory messageFactory =
ServiceTracker.getService(MessageFactory.class);
+ message =
+ messageFactory.createMessage(context,
FacesMessages.UIINPUT_UPDATE,
+ MessageUtil.getLabel(context, this));
+ } else {
+ message = new FacesMessage(FacesMessage.SEVERITY_ERROR,
+ messageStr,
+ messageStr);
+ }
+ } catch (Exception e) {
+ caught = e;
+ MessageFactory messageFactory =
ServiceTracker.getService(MessageFactory.class);
+ message =
+ messageFactory.createMessage(context,
FacesMessages.UIINPUT_UPDATE,
+ MessageUtil.getLabel(context, this));
+ }
+ if (caught != null) {
+ assert(message != null);
+ UpdateModelException toQueue = new UpdateModelException(message,
caught);
+ ExceptionQueuedEventContext eventContext =
+ new ExceptionQueuedEventContext(context,
+ toQueue,
+ this,
+ PhaseId.UPDATE_MODEL_VALUES);
+ context.getApplication().publishEvent(context,
+ ExceptionQueuedEvent.class,
+ eventContext);
+ }
+ } else {
+ treeNodeComponent.setExpanded(newExpandedValue);
+ }
}
}
-
+
@Override
protected boolean visitFixedChildren(VisitContext visitContext, VisitCallback
callback) {
if (visitContext instanceof ExtendedVisitContext) {
ExtendedVisitContext extendedVisitContext = (ExtendedVisitContext)
visitContext;
-
+
if (ExtendedVisitContextMode.RENDER == extendedVisitContext.getVisitMode())
{
VisitResult result =
extendedVisitContext.invokeMetaComponentVisitCallback(this, callback,
SELECTION_META_COMPONENT_ID);
if (result != VisitResult.ACCEPT) {
@@ -287,7 +370,7 @@
return super.visitFixedChildren(visitContext, callback);
}
-
+
void decodeMetaComponent(FacesContext context, String metaComponentId) {
((MetaComponentRenderer) getRenderer(context)).decodeMetaComponent(context, this,
metaComponentId);
}
@@ -295,15 +378,15 @@
public void encodeMetaComponent(FacesContext context, String metaComponentId) throws
IOException {
((MetaComponentRenderer) getRenderer(context)).encodeMetaComponent(context, this,
metaComponentId);
}
-
+
public String resolveClientId(FacesContext facesContext, UIComponent
contextComponent, String metaComponentId) {
if (SELECTION_META_COMPONENT_ID.equals(metaComponentId)) {
return getClientId(facesContext) +
MetaComponentResolver.META_COMPONENT_SEPARATOR_CHAR + metaComponentId;
}
-
+
return null;
}
-
+
public String substituteUnresolvedClientId(FacesContext facesContext, UIComponent
contextComponent,
String metaComponentId) {
@@ -319,35 +402,58 @@
return Iterators.<UIComponent>emptyIterator();
}
}
-
+
@Override
public DataComponentState getComponentState() {
return new TreeComponentState();
}
- public void addSelectionChangeListener(TreeSelectionChangeListener listener) {
+ public void addTreeSelectionChangeListener(TreeSelectionChangeListener listener) {
addFacesListener(listener);
}
- public TreeSelectionChangeListener[] getSelectionChangeListeners() {
+ @Attribute(hidden = true)
+ public TreeSelectionChangeListener[] getTreeSelectionChangeListeners() {
return (TreeSelectionChangeListener[])
getFacesListeners(TreeSelectionChangeListener.class);
}
-
- public void removeSelectionChangeListener(TreeSelectionChangeListener listener) {
+
+ public void removeTreeSelectionChangeListener(TreeSelectionChangeListener listener)
{
removeFacesListener(listener);
}
+ public void addTreeToggleListener(TreeToggleListener listener) {
+ addFacesListener(listener);
+ }
+
@Attribute(hidden = true)
+ public TreeToggleListener[] getTreeToggleListeners() {
+ return (TreeToggleListener[]) getFacesListeners(TreeToggleListener.class);
+ }
+
+ public void removeTreeToggleListener(TreeToggleListener listener) {
+ removeFacesListener(listener);
+ }
+
+ @Attribute(hidden = true)
public boolean isExpanded() {
if (getRowKey() == null) {
return true;
}
-
+
AbstractTreeNode treeNode = findTreeNodeComponent();
if (treeNode == null) {
return false;
}
-
+
return treeNode.isExpanded();
}
+
+ @Attribute(hidden = true)
+ public boolean isLeaf() {
+ if (getRowKey() == null) {
+ return false;
+ }
+
+ return ((TreeDataModel<?>) getExtendedDataModel()).isLeaf();
+ }
}
Modified:
trunk/ui/iteration/ui/src/main/java/org/richfaces/component/AbstractTreeNode.java
===================================================================
---
trunk/ui/iteration/ui/src/main/java/org/richfaces/component/AbstractTreeNode.java 2010-11-18
17:10:13 UTC (rev 20106)
+++
trunk/ui/iteration/ui/src/main/java/org/richfaces/component/AbstractTreeNode.java 2010-11-18
18:50:06 UTC (rev 20107)
@@ -23,37 +23,30 @@
import java.io.IOException;
-import javax.el.ELContext;
-import javax.el.ELException;
+import javax.el.MethodExpression;
import javax.el.ValueExpression;
-import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.component.UIComponentBase;
-import javax.faces.component.UpdateModelException;
import javax.faces.component.visit.VisitCallback;
import javax.faces.component.visit.VisitContext;
import javax.faces.component.visit.VisitResult;
import javax.faces.context.FacesContext;
import javax.faces.event.AbortProcessingException;
-import javax.faces.event.ExceptionQueuedEvent;
-import javax.faces.event.ExceptionQueuedEventContext;
import javax.faces.event.FacesEvent;
import javax.faces.event.PhaseId;
import org.ajax4jsf.component.IterationStateHolder;
-import org.richfaces.application.MessageFactory;
-import org.richfaces.application.ServiceTracker;
-import org.richfaces.appplication.FacesMessages;
import org.richfaces.cdk.annotations.Attribute;
import org.richfaces.cdk.annotations.EventName;
import org.richfaces.cdk.annotations.JsfComponent;
import org.richfaces.cdk.annotations.JsfRenderer;
+import org.richfaces.cdk.annotations.Signature;
import org.richfaces.cdk.annotations.Tag;
-import org.richfaces.component.util.MessageUtil;
import org.richfaces.context.ExtendedVisitContext;
import org.richfaces.context.ExtendedVisitContextMode;
import org.richfaces.event.TreeToggleEvent;
import org.richfaces.event.TreeToggleListener;
+import org.richfaces.event.TreeToggleSource;
import org.richfaces.renderkit.MetaComponentRenderer;
/**
@@ -63,11 +56,11 @@
@JsfComponent(
type = AbstractTreeNode.COMPONENT_TYPE,
family = AbstractTreeNode.COMPONENT_FAMILY,
- tag = @Tag(name = "treeNode"),
+ tag = @Tag(name = "treeNode", handler =
"org.richfaces.view.facelets.TreeNodeHandler"),
renderer = @JsfRenderer(type = "org.richfaces.TreeNodeRenderer"),
attributes = {"events-props.xml", "core-props.xml",
"i18n-props.xml"}
)
-public abstract class AbstractTreeNode extends UIComponentBase implements
MetaComponentResolver, MetaComponentEncoder, IterationStateHolder {
+public abstract class AbstractTreeNode extends UIComponentBase implements
MetaComponentResolver, MetaComponentEncoder, IterationStateHolder, TreeToggleSource {
public static final String COMPONENT_TYPE = "org.richfaces.TreeNode";
@@ -75,10 +68,13 @@
public static final String SUBTREE_META_COMPONENT_ID = "subtree";
- private enum PropertyKeys {
+ enum PropertyKeys {
expanded
}
+ @Attribute(generate = false, signature = @Signature(returnType = Void.class,
parameters = TreeToggleEvent.class))
+ private MethodExpression toggleListener;
+
public AbstractTreeNode() {
setRendererType("org.richfaces.TreeNodeRenderer");
}
@@ -108,6 +104,9 @@
@Attribute(events = @EventName("toggle"))
public abstract String getOntoggle();
+ @Attribute(events = @EventName("beforetoggle"))
+ public abstract String getOnbeforetoggle();
+
protected Boolean getLocalExpandedValue(FacesContext facesContext) {
return (Boolean) getStateHelper().get(PropertyKeys.expanded);
}
@@ -166,69 +165,20 @@
if (event instanceof TreeToggleEvent) {
TreeToggleEvent toggleEvent = (TreeToggleEvent) event;
- boolean newExpandedValue = toggleEvent.isExpanded();
-
- FacesContext context = getFacesContext();
- ValueExpression expression =
getValueExpression(PropertyKeys.expanded.toString());
- if (expression != null) {
- ELContext elContext = context.getELContext();
- Exception caught = null;
- FacesMessage message = null;
- try {
- expression.setValue(elContext, newExpandedValue);
- } catch (ELException e) {
- caught = e;
- String messageStr = e.getMessage();
- Throwable result = e.getCause();
- while (null != result &&
- result.getClass().isAssignableFrom(ELException.class)) {
- messageStr = result.getMessage();
- result = result.getCause();
- }
- if (null == messageStr) {
- MessageFactory messageFactory =
ServiceTracker.getService(MessageFactory.class);
- message =
- messageFactory.createMessage(context,
FacesMessages.UIINPUT_UPDATE,
- MessageUtil.getLabel(context, this));
- } else {
- message = new FacesMessage(FacesMessage.SEVERITY_ERROR,
- messageStr,
- messageStr);
- }
- } catch (Exception e) {
- caught = e;
- MessageFactory messageFactory =
ServiceTracker.getService(MessageFactory.class);
- message =
- messageFactory.createMessage(context,
FacesMessages.UIINPUT_UPDATE,
- MessageUtil.getLabel(context, this));
- }
- if (caught != null) {
- assert(message != null);
- UpdateModelException toQueue = new UpdateModelException(message,
caught);
- ExceptionQueuedEventContext eventContext =
- new ExceptionQueuedEventContext(context,
- toQueue,
- this,
- PhaseId.UPDATE_MODEL_VALUES);
- context.getApplication().publishEvent(context,
- ExceptionQueuedEvent.class,
- eventContext);
- }
- } else {
- setExpanded(newExpandedValue);
- }
+ new TreeToggleEvent(findTreeComponent(), toggleEvent.isExpanded()).queue();
}
}
- public void addToggleListener(TreeToggleListener listener) {
+ public void addTreeToggleListener(TreeToggleListener listener) {
addFacesListener(listener);
}
+ @Attribute(hidden = true)
public TreeToggleListener[] getTreeToggleListeners() {
return (TreeToggleListener[]) getFacesListeners(TreeToggleListener.class);
}
- public void removeToggleListener(TreeToggleListener listener) {
+ public void removeTreeToggleListener(TreeToggleListener listener) {
removeFacesListener(listener);
}
Modified: trunk/ui/iteration/ui/src/main/java/org/richfaces/component/TreeRange.java
===================================================================
--- trunk/ui/iteration/ui/src/main/java/org/richfaces/component/TreeRange.java 2010-11-18
17:10:13 UTC (rev 20106)
+++ trunk/ui/iteration/ui/src/main/java/org/richfaces/component/TreeRange.java 2010-11-18
18:50:06 UTC (rev 20107)
@@ -50,8 +50,7 @@
return true;
}
- tree.setRowKey(facesContext, rowKey);
- return tree.isExpanded();
+ return !tree.isLeaf() && tree.isExpanded();
}
}
Added:
trunk/ui/iteration/ui/src/main/java/org/richfaces/event/MethodExpressionTreeSelectionChangeListener.java
===================================================================
---
trunk/ui/iteration/ui/src/main/java/org/richfaces/event/MethodExpressionTreeSelectionChangeListener.java
(rev 0)
+++
trunk/ui/iteration/ui/src/main/java/org/richfaces/event/MethodExpressionTreeSelectionChangeListener.java 2010-11-18
18:50:06 UTC (rev 20107)
@@ -0,0 +1,50 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.event;
+
+import javax.el.MethodExpression;
+import javax.faces.event.AbortProcessingException;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public class MethodExpressionTreeSelectionChangeListener extends
MethodExpressionEventListener implements TreeSelectionChangeListener {
+
+ public MethodExpressionTreeSelectionChangeListener() {
+ super();
+ }
+
+ public MethodExpressionTreeSelectionChangeListener(MethodExpression
methodExprOneArg,
+ MethodExpression methodExprZeroArg) {
+ super(methodExprOneArg, methodExprZeroArg);
+ }
+
+ public MethodExpressionTreeSelectionChangeListener(MethodExpression
methodExpressionOneArg) {
+ super(methodExpressionOneArg);
+ }
+
+ public void processSelectionChange(TreeSelectionChangeEvent event) throws
AbortProcessingException {
+ processEvent(event);
+ }
+
+}
Added:
trunk/ui/iteration/ui/src/main/java/org/richfaces/event/MethodExpressionTreeToggleListener.java
===================================================================
---
trunk/ui/iteration/ui/src/main/java/org/richfaces/event/MethodExpressionTreeToggleListener.java
(rev 0)
+++
trunk/ui/iteration/ui/src/main/java/org/richfaces/event/MethodExpressionTreeToggleListener.java 2010-11-18
18:50:06 UTC (rev 20107)
@@ -0,0 +1,49 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.event;
+
+import javax.el.MethodExpression;
+import javax.faces.event.AbortProcessingException;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public class MethodExpressionTreeToggleListener extends MethodExpressionEventListener
implements TreeToggleListener {
+
+ public MethodExpressionTreeToggleListener() {
+ super();
+ }
+
+ public MethodExpressionTreeToggleListener(MethodExpression methodExprOneArg,
MethodExpression methodExprZeroArg) {
+ super(methodExprOneArg, methodExprZeroArg);
+ }
+
+ public MethodExpressionTreeToggleListener(MethodExpression methodExpressionOneArg) {
+ super(methodExpressionOneArg);
+ }
+
+ public void processToggle(TreeToggleEvent event) throws AbortProcessingException {
+ processEvent(event);
+ }
+
+}
Modified:
trunk/ui/iteration/ui/src/main/java/org/richfaces/model/ExtendedTreeDataModelImpl.java
===================================================================
---
trunk/ui/iteration/ui/src/main/java/org/richfaces/model/ExtendedTreeDataModelImpl.java 2010-11-18
17:10:13 UTC (rev 20106)
+++
trunk/ui/iteration/ui/src/main/java/org/richfaces/model/ExtendedTreeDataModelImpl.java 2010-11-18
18:50:06 UTC (rev 20107)
@@ -21,15 +21,11 @@
*/
package org.richfaces.model;
-import java.util.Iterator;
-
import javax.faces.context.FacesContext;
-import org.ajax4jsf.model.DataVisitResult;
import org.ajax4jsf.model.DataVisitor;
import org.ajax4jsf.model.ExtendedDataModel;
import org.ajax4jsf.model.Range;
-import org.richfaces.component.TreeRange;
/**
* @author Nick Belaevski
@@ -52,10 +48,6 @@
return wrappedModel.getData();
}
- public Iterator<Object> getChildrenRowKeysIterator(Object rowKey) {
- return wrappedModel.getChildrenRowKeysIterator(rowKey);
- }
-
public Object getParentRowKey(Object rowKey) {
throw new UnsupportedOperationException();
}
@@ -70,31 +62,11 @@
return wrappedModel.getRowKey();
}
- protected void walk(FacesContext context, DataVisitor visitor, Range range, Object
argument, Iterator<Object> keysIterator) {
- while (keysIterator.hasNext()) {
- Object object = (Object) keysIterator.next();
-
- DataVisitResult visitResult = visitor.process(context, object, argument);
- if (visitResult == DataVisitResult.CONTINUE) {
- if (((TreeRange) range).shouldIterateChildren(object)) {
- Iterator<Object> childrenIterator =
getChildrenRowKeysIterator(object);
- walk(context, visitor, range, argument, childrenIterator);
- }
- }
- }
- }
-
@Override
public void walk(FacesContext context, DataVisitor visitor, Range range, Object
argument) {
- TreeRange treeRange = (TreeRange) range;
- if (treeRange.shouldIterateChildren(null)) {
- setRowKey(null);
- DataVisitResult visitResult = visitor.process(context, null, argument);
- if (visitResult == DataVisitResult.CONTINUE) {
- Iterator<Object> iterator = getChildrenRowKeysIterator(null);
- walk(context, visitor, range, argument, iterator);
- }
- }
+ wrappedModel.enterNode(visitor);
+ wrappedModel.walk(context, visitor, range, argument);
+ wrappedModel.exitNode(visitor);
}
@Override
@@ -131,5 +103,31 @@
wrappedModel.setWrappedData(data);
}
+ /* (non-Javadoc)
+ * @see org.richfaces.model.TreeDataModel#isLeaf()
+ */
+ public boolean isLeaf() {
+ // TODO Auto-generated method stub
+ return wrappedModel.isLeaf();
+ }
+ /* (non-Javadoc)
+ * @see org.richfaces.model.TreeDataModel#enterNode(org.ajax4jsf.model.DataVisitor)
+ */
+ public void enterNode(DataVisitor visitor) {
+ // TODO Auto-generated method stub
+
+ wrappedModel.enterNode(visitor);
+ }
+
+ /* (non-Javadoc)
+ * @see org.richfaces.model.TreeDataModel#exitNode(org.ajax4jsf.model.DataVisitor)
+ */
+ public void exitNode(DataVisitor visitor) {
+ // TODO Auto-generated method stub
+
+ wrappedModel.exitNode(visitor);
+ }
+
+
}
Modified: trunk/ui/iteration/ui/src/main/java/org/richfaces/model/SequenceRowKey.java
===================================================================
--- trunk/ui/iteration/ui/src/main/java/org/richfaces/model/SequenceRowKey.java 2010-11-18
17:10:13 UTC (rev 20106)
+++ trunk/ui/iteration/ui/src/main/java/org/richfaces/model/SequenceRowKey.java 2010-11-18
18:50:06 UTC (rev 20107)
@@ -49,6 +49,24 @@
return new SequenceRowKey<T>(ObjectArrays.concat(simpleKeys, segment));
}
+ public T getLastKeySegment() {
+ if (simpleKeys.length == 0) {
+ return null;
+ }
+
+ return simpleKeys[simpleKeys.length - 1];
+ }
+
+ public SequenceRowKey<T> getParent() {
+ if (simpleKeys.length == 0) {
+ return null;
+ }
+
+ T[] parentSimpleKeys = ObjectArrays.newArray(simpleKeys, simpleKeys.length - 1);
+ System.arraycopy(simpleKeys, 0, parentSimpleKeys, 0, parentSimpleKeys.length);
+ return new SequenceRowKey<T>(parentSimpleKeys);
+ }
+
@Override
public int hashCode() {
final int prime = 31;
Modified:
trunk/ui/iteration/ui/src/main/java/org/richfaces/model/SequenceRowKeyIterator.java
===================================================================
---
trunk/ui/iteration/ui/src/main/java/org/richfaces/model/SequenceRowKeyIterator.java 2010-11-18
17:10:13 UTC (rev 20106)
+++
trunk/ui/iteration/ui/src/main/java/org/richfaces/model/SequenceRowKeyIterator.java 2010-11-18
18:50:06 UTC (rev 20107)
@@ -23,25 +23,29 @@
import java.util.Iterator;
+import com.google.common.base.Objects;
+import com.google.common.base.Objects.ToStringHelper;
+
/**
* @author Nick Belaevski
*
*/
-public class SequenceRowKeyIterator<T> implements Iterator<Object> {
+public abstract class SequenceRowKeyIterator<K, T> implements
Iterator<Object> {
- private int counter = 0;
+ private SequenceRowKey<K> baseKey;
- private SequenceRowKey<Integer> baseKey;
-
private Iterator<T> itr;
private T element;
- private SequenceRowKey<Integer> elementKey;
+ private SequenceRowKey<K> elementKey;
+
+ private T baseElement;
- public SequenceRowKeyIterator(SequenceRowKey<Integer> baseKey,
Iterator<T> itr) {
+ public SequenceRowKeyIterator(SequenceRowKey<K> baseKey, T baseElement,
Iterator<T> itr) {
super();
this.baseKey = baseKey;
+ this.baseElement = baseElement;
this.itr = itr;
}
@@ -49,10 +53,17 @@
return itr.hasNext();
}
+ protected abstract K nextKey();
+
public Object next() {
element = itr.next();
- elementKey = baseKey.append(counter++);
+ if (baseKey != null) {
+ elementKey = baseKey.append(nextKey());
+ } else {
+ elementKey = new SequenceRowKey<K>(nextKey());
+ }
+
return elementKey;
}
@@ -60,7 +71,15 @@
return element;
}
- public SequenceRowKey<Integer> getElementKey() {
+ public SequenceRowKey<K> getBaseKey() {
+ return baseKey;
+ }
+
+ public T getBaseElement() {
+ return baseElement;
+ }
+
+ public SequenceRowKey<K> getElementKey() {
return elementKey;
}
@@ -68,4 +87,12 @@
throw new UnsupportedOperationException();
}
+ @Override
+ public String toString() {
+ ToStringHelper helper = Objects.toStringHelper(this);
+
+ helper.add("element", element).add("elementKey",
elementKey);
+
+ return helper.toString();
+ }
}
Modified:
trunk/ui/iteration/ui/src/main/java/org/richfaces/model/SwingTreeNodeDataModelImpl.java
===================================================================
---
trunk/ui/iteration/ui/src/main/java/org/richfaces/model/SwingTreeNodeDataModelImpl.java 2010-11-18
17:10:13 UTC (rev 20106)
+++
trunk/ui/iteration/ui/src/main/java/org/richfaces/model/SwingTreeNodeDataModelImpl.java 2010-11-18
18:50:06 UTC (rev 20107)
@@ -36,13 +36,46 @@
* @author Nick Belaevski
*
*/
-public class SwingTreeNodeDataModelImpl implements TreeDataModel<TreeNode> {
+public class SwingTreeNodeDataModelImpl extends TreeSequenceKeyModel<Integer,
TreeNode> {
/**
* @author Nick Belaevski
*
*/
+ private static final class SwingTreeNodeRowKeyIterator extends
SequenceRowKeyIterator<Integer, TreeNode> {
+
+ private int counter = 0;
+
+ /**
+ * @param baseKey
+ * @param baseElement
+ * @param itr
+ */
+ private SwingTreeNodeRowKeyIterator(SequenceRowKey<Integer> baseKey,
TreeNode baseElement,
+ Iterator<TreeNode> itr) {
+ super(baseKey, baseElement, itr);
+ }
+
+ @Override
+ protected Integer nextKey() {
+ return counter++;
+ }
+ }
+
+
+ /**
+ * @author Nick Belaevski
+ *
+ */
private final class FakeRootNode implements TreeNode {
+
+ private Collection<TreeNode> wrappedData;
+
+ public FakeRootNode(Collection<TreeNode> wrappedData) {
+ super();
+ this.wrappedData = wrappedData;
+ }
+
public boolean isLeaf() {
return !wrappedData.isEmpty();
}
@@ -86,21 +119,13 @@
return Iterators.asEnumeration(wrappedData.iterator());
}
+
+ public Collection<TreeNode> getWrappedData() {
+ return wrappedData;
+ }
}
- private static final SequenceRowKey<Integer> EMPTY_SEQUENCE_ROW_KEY = new
SequenceRowKey<Integer>();
-
- private Collection<TreeNode> wrappedData = null;
-
- private TreeNode fakeRootNode = new FakeRootNode();
-
- private TreeNode selectedNode;
-
- private SequenceRowKey<Integer> selectedRowKey;
-
- private Iterator<TreeNode> findChildren(SequenceRowKey<Integer>
compositeKey) {
- TreeNode treeNode = findNode(compositeKey);
-
+ private Iterator<TreeNode> safeGetChildren(SequenceRowKey<Integer> key,
TreeNode treeNode) {
if (treeNode == null) {
return Iterators.emptyIterator();
}
@@ -108,72 +133,48 @@
return Iterators.forEnumeration((Enumeration<TreeNode>)
treeNode.children());
}
- private TreeNode findNode(SequenceRowKey<Integer> compositeKey) {
- if (compositeKey == null) {
- return null;
+
+ public Object getParentRowKey(Object rowKey) {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isLeaf() {
+ if (!isDataAvailable()) {
+ throw new IllegalStateException();
}
- TreeNode result = fakeRootNode;
+ TreeNode treeNode = getData();
- for (Integer simpleKey : compositeKey.getSimpleKeys()) {
- int idx = simpleKey.intValue();
-
- if (idx < result.getChildCount()) {
- result = result.getChildAt(idx);
- } else {
- result = null;
- break;
- }
- }
-
- return result;
+ return !treeNode.getAllowsChildren() || treeNode.isLeaf();
}
-
- public void setRowKey(Object key) {
- this.selectedRowKey = (SequenceRowKey<Integer>) key;
- this.selectedNode = findNode(selectedRowKey);
- }
- public Object getRowKey() {
- return selectedRowKey;
+ public void setWrappedData(Object data) {
+ setRootNode(new FakeRootNode((Collection<TreeNode>) data));
}
-
- private SequenceRowKey<Integer> castKeyAndWrapNull(Object rowKey) {
- if (rowKey == null) {
- return EMPTY_SEQUENCE_ROW_KEY;
+
+ public Collection<TreeNode> getWrappedData() {
+ FakeRootNode rootNode = (FakeRootNode) getRootNode();
+ if (rootNode == null) {
+ return null;
}
-
- return (SequenceRowKey<Integer>) rowKey;
+ return rootNode.getWrappedData();
}
-
- public Iterator<Object> getChildrenRowKeysIterator(Object rowKey) {
- SequenceRowKey<Integer> sequenceKey = castKeyAndWrapNull(rowKey);
- Iterator<TreeNode> itr = findChildren(sequenceKey);
-
- return new SequenceRowKeyIterator<TreeNode>(sequenceKey, itr);
- }
- public TreeNode getData() {
- if (!isDataAvailable()) {
- throw new IllegalArgumentException();
+ @Override
+ protected TreeNode findChild(TreeNode parent, Integer simpleKey) {
+ int idx = simpleKey.intValue();
+ if (idx >= 0 && idx < parent.getChildCount()) {
+ return parent.getChildAt(idx);
}
- return selectedNode;
+ return null;
}
- public Object getParentRowKey(Object rowKey) {
- throw new UnsupportedOperationException();
- }
- public boolean isDataAvailable() {
- return selectedRowKey == null || selectedNode != null;
+ @Override
+ protected SequenceRowKeyIterator<Integer, TreeNode>
createChildrenIterator(SequenceRowKey<Integer> baseKey,
+ TreeNode value) {
+
+ return new SwingTreeNodeRowKeyIterator(baseKey, value, safeGetChildren(baseKey,
value));
}
-
- public Object getWrappedData() {
- return wrappedData;
- }
-
- public void setWrappedData(Object wrappedData) {
- this.wrappedData = (Collection<TreeNode>) wrappedData;
- }
}
Added: trunk/ui/iteration/ui/src/main/java/org/richfaces/model/TreeSequenceKeyModel.java
===================================================================
--- trunk/ui/iteration/ui/src/main/java/org/richfaces/model/TreeSequenceKeyModel.java
(rev 0)
+++
trunk/ui/iteration/ui/src/main/java/org/richfaces/model/TreeSequenceKeyModel.java 2010-11-18
18:50:06 UTC (rev 20107)
@@ -0,0 +1,168 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.model;
+
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.ListIterator;
+
+import javax.faces.context.FacesContext;
+
+import org.ajax4jsf.model.DataVisitor;
+import org.ajax4jsf.model.Range;
+import org.richfaces.component.TreeRange;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public abstract class TreeSequenceKeyModel<K, V> implements TreeDataModel<V>
{
+
+ private V rootNode;
+
+ private V currentData;
+
+ private SequenceRowKey<K> currentRowKey;
+
+ private LinkedList<SequenceRowKeyIterator<K, V>> keysStack = new
LinkedList<SequenceRowKeyIterator<K, V>>();
+
+ public SequenceRowKey<K> getRowKey() {
+ return currentRowKey;
+ }
+
+ public void setRowKey(Object rowKey) {
+ this.currentRowKey = (SequenceRowKey<K>) rowKey;
+ this.currentData = findData(currentRowKey);
+ }
+
+ public boolean isDataAvailable() {
+ return currentRowKey == null || currentData != null;
+ }
+
+ public abstract boolean isLeaf();
+
+ public V getData() {
+ if (!isDataAvailable()) {
+ throw new IllegalArgumentException();
+ }
+
+ return currentData;
+ }
+
+ protected boolean isRootNodeKey(SequenceRowKey<K> key) {
+ return key == null || key.getLastKeySegment() == null;
+ }
+
+ protected V findData(SequenceRowKey<K> key) {
+ if (key == null) {
+ return rootNode;
+ }
+
+ if (!keysStack.isEmpty()) {
+ ListIterator<SequenceRowKeyIterator<K, V>> listIterator =
keysStack.listIterator(keysStack.size());
+
+ while (listIterator.hasPrevious()) {
+ SequenceRowKeyIterator<K, V> previous = listIterator.previous();
+
+ V baseNode = null;
+
+ SequenceRowKey<K> baseKey = previous.getBaseKey();
+ if (isRootNodeKey(baseKey) && isRootNodeKey(key.getParent())) {
+ baseNode = rootNode;
+ } else if (baseKey.equals(key.getParent())) {
+ baseNode = previous.getBaseElement();
+ }
+
+ if (baseNode == null) {
+ continue;
+ }
+
+ return findChild(baseNode, key.getLastKeySegment());
+ }
+ }
+
+ V result = rootNode;
+
+ for (K simpleKey : key.getSimpleKeys()) {
+ result = findChild(result, simpleKey);
+
+ if (result == null) {
+ break;
+ }
+ }
+
+ return result;
+ }
+
+ protected abstract V findChild(V parent, K simpleKey);
+
+ protected abstract SequenceRowKeyIterator<K, V>
createChildrenIterator(SequenceRowKey<K> baseKey, V value);
+
+ public void enterNode(DataVisitor visitor) {
+ SequenceRowKey<K> sequenceKey = getRowKey();
+ V data = findData(sequenceKey);
+
+ keysStack.addLast(createChildrenIterator(sequenceKey, data));
+
+ if (visitor instanceof TreeDataVisitor) {
+ ((TreeDataVisitor) visitor).enterNode();
+ }
+ }
+
+ public void walk(FacesContext context, DataVisitor visitor, Range range, Object
argument) {
+ if (getRowKey() != null) {
+ visitor.process(context, getRowKey(), argument);
+ }
+
+ TreeRange treeRange = (TreeRange) range;
+
+ if (treeRange.shouldIterateChildren(getRowKey())) {
+ enterNode(visitor);
+ Iterator<Object> keysIterator = keysStack.getLast();
+ while (keysIterator.hasNext()) {
+ Object key = (Object) keysIterator.next();
+ setRowKey(key);
+ walk(context, visitor, range, argument);
+ }
+ exitNode(visitor);
+ }
+ }
+
+ public void exitNode(DataVisitor visitor) {
+ if (visitor instanceof TreeDataVisitor) {
+ ((TreeDataVisitor) visitor).exitNode();
+ }
+
+ keysStack.removeLast();
+ }
+
+ public abstract Object getParentRowKey(Object rowKey);
+
+ protected V getRootNode() {
+ return rootNode;
+ }
+
+ protected void setRootNode(V rootNode) {
+ this.rootNode = rootNode;
+ }
+
+}
Modified:
trunk/ui/iteration/ui/src/main/java/org/richfaces/renderkit/TreeEncoderBase.java
===================================================================
---
trunk/ui/iteration/ui/src/main/java/org/richfaces/renderkit/TreeEncoderBase.java 2010-11-18
17:10:13 UTC (rev 20106)
+++
trunk/ui/iteration/ui/src/main/java/org/richfaces/renderkit/TreeEncoderBase.java 2010-11-18
18:50:06 UTC (rev 20107)
@@ -22,111 +22,138 @@
package org.richfaces.renderkit;
import java.io.IOException;
-import java.util.Iterator;
import java.util.LinkedList;
+import javax.faces.FacesException;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import org.ajax4jsf.context.AjaxContext;
import org.ajax4jsf.javascript.JSFunction;
+import org.ajax4jsf.model.DataVisitResult;
import org.richfaces.component.AbstractTree;
import org.richfaces.component.AbstractTreeNode;
-import org.richfaces.component.TreeRange;
import org.richfaces.component.util.HtmlUtil;
+import org.richfaces.model.TreeDataVisitor;
import org.richfaces.renderkit.TreeRendererBase.QueuedData;
-import com.google.common.base.Predicate;
-import com.google.common.collect.Iterators;
-import com.google.common.collect.UnmodifiableIterator;
+abstract class TreeEncoderBase implements TreeDataVisitor {
-abstract class TreeEncoderBase {
+ static final String TREE_NODE_STATE_ATTRIBUTE = "__treeNodeState";
- static final String TREE_NODE_STATE_ATTRIBUTE = "__treeNodeState";
-
protected final FacesContext context;
-
+
protected final ResponseWriter responseWriter;
-
+
protected final AbstractTree tree;
- private TreeRange treeRange;
-
- private LinkedList<QueuedData> queuedData = new
LinkedList<QueuedData>();
-
+ private LinkedList<QueuedData> queuedDataList = new
LinkedList<QueuedData>();
+
+ private QueuedData queuedData;
+
public TreeEncoderBase(FacesContext context, AbstractTree tree) {
super();
this.context = context;
this.responseWriter = context.getResponseWriter();
this.tree = tree;
-
- this.treeRange = (TreeRange) tree.getComponentState().getRange();
}
- protected void encodeTree(Iterator<Object> childrenIterator) throws IOException
{
- Predicate<Object> renderedTreeNodeKeyPredicate = new
Predicate<Object>() {
- public boolean apply(Object input) {
- tree.setRowKey(input);
-
- if (!tree.isRowAvailable()) {
- return false;
+ protected void encodeTree() throws IOException {
+ tree.walk(context, this, null);
+ }
+
+ protected void flushNode() throws IOException {
+ if (!queuedData.isEncoded()) {
+ tree.setRowKey(context, queuedData.getRowKey());
+
+ TreeNodeState state;
+ if (tree.isLeaf()) {
+ state = TreeNodeState.leaf;
+ } else {
+ if (queuedData.isVisited()) {
+ state = TreeNodeState.leaf;
+ } else {
+ state = TreeNodeState.collapsed;
}
-
- return tree.findTreeNodeComponent() != null;
}
- };
+
+ writeTreeNodeStartElement(state);
+ }
+
+ writeTreeNodeEndElement();
+ }
+
+ protected void flushParentNode() throws IOException {
+ if (queuedDataList.isEmpty()) {
+ return;
+ }
- UnmodifiableIterator<Object> filteredIterator =
Iterators.filter(childrenIterator, renderedTreeNodeKeyPredicate);
- while (filteredIterator.hasNext()) {
- Object rowKey = filteredIterator.next();
+ QueuedData data = queuedDataList.getLast();
+ if (!data.isEncoded()) {
+ data.setEncoded(true);
+ tree.setRowKey(context, data.getRowKey());
- encodeTreeNode(rowKey, !filteredIterator.hasNext());
+ writeTreeNodeStartElement(tree.isExpanded() ? TreeNodeState.expanded :
TreeNodeState.collapsed);
}
}
- protected void encodeTreeNode(Object rowKey, boolean isLastNode) throws IOException
{
- if (!queuedData.isEmpty()) {
- QueuedData data = queuedData.getLast();
- if (!data.isEncoded()) {
- tree.setRowKey(context, data.getRowKey());
-
- writeTreeNodeStartElement(data.isExpanded() ? TreeNodeState.expanded :
TreeNodeState.collapsed, data.isLastNode());
-
- data.setEncoded(true);
+ public void enterNode() {
+ if (queuedData != null) {
+ queuedData.makeVisited();
+ queuedDataList.add(queuedData);
+ queuedData = null;
+ }
+ }
+
+ public DataVisitResult process(FacesContext context, Object rowKey, Object argument)
{
+ try {
+ if (queuedData != null) {
+ flushNode();
+ queuedData = null;
+ } else {
+ flushParentNode();
}
+ } catch (IOException e) {
+ throw new FacesException(e.getMessage(), e);
}
-
- tree.setRowKey(context, rowKey);
- boolean expanded = tree.isExpanded();
- queuedData.add(new QueuedData(rowKey, isLastNode, expanded));
-
- boolean iterateChildren = treeRange.shouldIterateChildren(rowKey);
-
- if (iterateChildren) {
- encodeTree(tree.getChildrenRowKeysIterator(context, rowKey));
+ if (rowKey != null) {
+ tree.setRowKey(context, rowKey);
+
+ if (tree.isRowAvailable() && tree.findTreeNodeComponent() != null) {
+ queuedData = new QueuedData(rowKey);
+ }
}
- QueuedData data = queuedData.removeLast();
- if (!data.isEncoded()) {
- TreeNodeState nodeState = iterateChildren ? TreeNodeState.leaf :
TreeNodeState.collapsed;
- writeTreeNodeStartElement(nodeState, data.isLastNode());
+ return DataVisitResult.CONTINUE;
+ }
+
+ public void exitNode() {
+ try {
+ if (queuedData != null) {
+ flushNode();
+ queuedData = null;
+ }
+
+ if (!queuedDataList.isEmpty()) {
+ queuedData = queuedDataList.removeLast();
+ }
+ } catch (IOException e) {
+ throw new FacesException(e.getMessage(), e);
}
-
- writeTreeNodeEndElement();
}
-
- protected void writeTreeNodeStartElement(TreeNodeState nodeState, boolean isLast)
throws IOException {
+
+ protected void writeTreeNodeStartElement(TreeNodeState nodeState) throws IOException
{
AbstractTreeNode treeNodeComponent = tree.findTreeNodeComponent();
context.getAttributes().put(TREE_NODE_STATE_ATTRIBUTE, nodeState);
-
+
responseWriter.startElement(HtmlConstants.DIV_ELEM, tree);
responseWriter.writeAttribute(HtmlConstants.CLASS_ATTRIBUTE,
- HtmlUtil.concatClasses("rf-tr-nd", isLast ?
"rf-tr-nd-last" : null, nodeState.getNodeClass()),
+ HtmlUtil.concatClasses("rf-tr-nd", nodeState.getNodeClass()),
null);
responseWriter.writeAttribute(HtmlConstants.ID_ATTRIBUTE,
treeNodeComponent.getClientId(context), null);
-
+
emitClientToggleEvent(treeNodeComponent, nodeState);
treeNodeComponent.encodeAll(context);
}
@@ -136,12 +163,12 @@
}
public abstract void encode() throws IOException;
-
+
private void emitClientToggleEvent(AbstractTreeNode treeNode, TreeNodeState
nodeState) {
if
(treeNode.getClientId(context).equals(context.getAttributes().get(TreeNodeRendererBase.AJAX_TOGGLED_NODE_ATTRIBUTE)))
{
TreeNodeState submittedState = ((Boolean)
(context.getAttributes().get(TreeNodeRendererBase.AJAX_TOGGLED_NODE_STATE_ATTRIBUTE)))
? TreeNodeState.expanded : TreeNodeState.collapsed;
-
+
if (submittedState == nodeState || nodeState == TreeNodeState.leaf) {
AjaxContext ajaxContext = AjaxContext.getCurrentInstance(context);
ajaxContext.appendOncomplete(new
JSFunction("RichFaces.ui.TreeNode.emitToggleEvent",
treeNode.getClientId(context)));
Modified:
trunk/ui/iteration/ui/src/main/java/org/richfaces/renderkit/TreeEncoderFull.java
===================================================================
---
trunk/ui/iteration/ui/src/main/java/org/richfaces/renderkit/TreeEncoderFull.java 2010-11-18
17:10:13 UTC (rev 20106)
+++
trunk/ui/iteration/ui/src/main/java/org/richfaces/renderkit/TreeEncoderFull.java 2010-11-18
18:50:06 UTC (rev 20107)
@@ -38,7 +38,8 @@
public void encode() throws java.io.IOException {
Object initialRowKey = tree.getRowKey();
try {
- encodeTree(tree.getChildrenRowKeysIterator(context, null));
+ tree.setRowKey(context, null);
+ encodeTree();
} finally {
try {
tree.setRowKey(context, initialRowKey);
Modified:
trunk/ui/iteration/ui/src/main/java/org/richfaces/renderkit/TreeEncoderPartial.java
===================================================================
---
trunk/ui/iteration/ui/src/main/java/org/richfaces/renderkit/TreeEncoderPartial.java 2010-11-18
17:10:13 UTC (rev 20106)
+++
trunk/ui/iteration/ui/src/main/java/org/richfaces/renderkit/TreeEncoderPartial.java 2010-11-18
18:50:06 UTC (rev 20107)
@@ -63,8 +63,9 @@
Object initialRowKey = tree.getRowKey();
try {
TreeRenderingContext.create(context, tree);
-
- encodeTreeNode(rowKey, true);
+ tree.setRowKey(context, rowKey);
+
+ encodeTree();
prw.endUpdate();
Modified:
trunk/ui/iteration/ui/src/main/java/org/richfaces/renderkit/TreeRendererBase.java
===================================================================
---
trunk/ui/iteration/ui/src/main/java/org/richfaces/renderkit/TreeRendererBase.java 2010-11-18
17:10:13 UTC (rev 20106)
+++
trunk/ui/iteration/ui/src/main/java/org/richfaces/renderkit/TreeRendererBase.java 2010-11-18
18:50:06 UTC (rev 20107)
@@ -88,16 +88,12 @@
private Object rowKey;
- private boolean lastNode;
-
- private boolean expanded;
-
private boolean encoded;
- public QueuedData(Object rowKey, boolean lastNode, boolean expanded) {
+ private boolean visited;
+
+ public QueuedData(Object rowKey) {
this.rowKey = rowKey;
- this.lastNode = lastNode;
- this.expanded = expanded;
}
public void setEncoded(boolean encoded) {
@@ -112,12 +108,12 @@
return rowKey;
}
- public boolean isLastNode() {
- return lastNode;
+ public boolean isVisited() {
+ return visited;
}
-
- public boolean isExpanded() {
- return expanded;
+
+ public void makeVisited() {
+ visited = true;
}
}
@@ -216,7 +212,7 @@
writer.startEval();
JSFunction function = new JSFunction("RichFaces.$",
component.getClientId(context));
- writer.write(function.toScript() + ".__updateSelection();");
+ writer.write(function.toScript() +
".__updateSelectionFromInput();");
writer.endEval();
} else {
Modified:
trunk/ui/iteration/ui/src/main/java/org/richfaces/renderkit/TreeRenderingContext.java
===================================================================
---
trunk/ui/iteration/ui/src/main/java/org/richfaces/renderkit/TreeRenderingContext.java 2010-11-18
17:10:13 UTC (rev 20106)
+++
trunk/ui/iteration/ui/src/main/java/org/richfaces/renderkit/TreeRenderingContext.java 2010-11-18
18:50:06 UTC (rev 20107)
@@ -49,12 +49,20 @@
private static final ComponentAttribute ONNODETOGGLE_ATTRIBUTE = new
ComponentAttribute("onnodetoggle").setEventNames("nodetoggle");
+ private static final ComponentAttribute ONBEFORETOGGLE_ATTRIBUTE = new
ComponentAttribute("onbeforetoggle").setEventNames("beforetoggle");
+
+ private static final ComponentAttribute ONBEFORENODETOGGLE_ATTRIBUTE = new
ComponentAttribute("onbeforenodetoggle").setEventNames("beforenodetoggle");
+
public static final class Handlers extends ScriptStringBase {
private String toggleHandler;
private String nodeToggleHandler;
+ private String beforeToggleHandler;
+
+ private String beforeNodeToggleHandler;
+
protected Object chain(String firstHandler, String secondHandler) {
if (isNullOrEmpty(firstHandler) && isNullOrEmpty(secondHandler)) {
return null;
@@ -68,7 +76,7 @@
return firstHandler;
}
- return new JSFunction("jsf.util.chain", JSReference.THIS,
JSReference.EVENT, firstHandler, secondHandler).toScript();
+ return new JSFunction("return jsf.util.chain", JSReference.THIS,
JSReference.EVENT, firstHandler, secondHandler).toScript();
}
public void setToggleHandler(String toggleHandler) {
@@ -79,17 +87,49 @@
return toggleHandler;
}
+ public void setNodeToggleHandler(String nodeToggleHandler) {
+ this.nodeToggleHandler = nodeToggleHandler;
+ }
+
public String getNodeToggleHandler() {
return nodeToggleHandler;
}
- public void setNodeToggleHandler(String nodeToggleHandler) {
- this.nodeToggleHandler = nodeToggleHandler;
+ public void setBeforeToggleHandler(String beforeToggleHandler) {
+ this.beforeToggleHandler = beforeToggleHandler;
}
-
+
+ public String getBeforeToggleHandler() {
+ return beforeToggleHandler;
+ }
+
+ public void setBeforeNodeToggleHandler(String beforeNodeToggleHandler) {
+ this.beforeNodeToggleHandler = beforeNodeToggleHandler;
+ }
+
+ public String getBeforeNodeToggleHandler() {
+ return beforeNodeToggleHandler;
+ }
+
public void appendScript(Appendable target) throws IOException {
- Object chain = chain(toggleHandler, nodeToggleHandler);
- ScriptUtils.appendScript(target, chain);
+ Object chainedToggleHandler = chain(toggleHandler, nodeToggleHandler);
+ Object chainedBeforeToggleHandler = chain(beforeToggleHandler,
beforeNodeToggleHandler);
+
+ if (chainedToggleHandler != null || chainedBeforeToggleHandler != null) {
+ Map<String,Object> map = new HashMap<String, Object>(2);
+
+ if (chainedToggleHandler != null) {
+ map.put("th", chainedToggleHandler);
+ }
+
+ if (chainedBeforeToggleHandler != null) {
+ map.put("bth", chainedBeforeToggleHandler);
+ }
+
+ ScriptUtils.appendScript(target, map);
+ } else {
+ ScriptUtils.appendScript(target, null);
+ }
}
}
@@ -145,10 +185,20 @@
getOrCreateHandlers(relativeClientId).setToggleHandler(toggleHandler);
}
+ String beforeToggleHandler = (String)
RenderKitUtils.getAttributeAndBehaviorsValue(context, treeNode,
ONBEFORETOGGLE_ATTRIBUTE);
+ if (!isNullOrEmpty(beforeToggleHandler)) {
+
getOrCreateHandlers(relativeClientId).setBeforeToggleHandler(beforeToggleHandler);
+ }
+
String nodeToggleHandler = (String)
RenderKitUtils.getAttributeAndBehaviorsValue(context, tree, ONNODETOGGLE_ATTRIBUTE);
if (!isNullOrEmpty(nodeToggleHandler)) {
getOrCreateHandlers(relativeClientId).setNodeToggleHandler(nodeToggleHandler);
}
+
+ String beforeNodeToggleHandler = (String)
RenderKitUtils.getAttributeAndBehaviorsValue(context, tree,
ONBEFORENODETOGGLE_ATTRIBUTE);
+ if (!isNullOrEmpty(beforeNodeToggleHandler)) {
+
getOrCreateHandlers(relativeClientId).setBeforeNodeToggleHandler(beforeNodeToggleHandler);
+ }
}
}
Added: trunk/ui/iteration/ui/src/main/java/org/richfaces/view/facelets/TreeHandler.java
===================================================================
--- trunk/ui/iteration/ui/src/main/java/org/richfaces/view/facelets/TreeHandler.java
(rev 0)
+++
trunk/ui/iteration/ui/src/main/java/org/richfaces/view/facelets/TreeHandler.java 2010-11-18
18:50:06 UTC (rev 20107)
@@ -0,0 +1,66 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.view.facelets;
+
+import javax.faces.view.facelets.ComponentConfig;
+import javax.faces.view.facelets.ComponentHandler;
+import javax.faces.view.facelets.MetaRule;
+import javax.faces.view.facelets.MetaRuleset;
+import javax.faces.view.facelets.Metadata;
+import javax.faces.view.facelets.MetadataTarget;
+import javax.faces.view.facelets.TagAttribute;
+
+import org.richfaces.component.AbstractTree;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public class TreeHandler extends ComponentHandler {
+
+ private static final MetaRule RULE = new MetaRule() {
+
+ @Override
+ public Metadata applyRule(String name, TagAttribute attribute, MetadataTarget
meta) {
+ if (meta.isTargetInstanceOf(AbstractTree.class)) {
+ if ("selectionChangeListener".equals(name)) {
+ return new TreeSelectionChangeListenerExpressionMetadata(attribute);
+ } else if ("toggleListener".equals(name)) {
+ return new TreeToggleListenerExpressionMetadata(attribute);
+ }
+
+ }
+ return null;
+ }
+ };
+
+ public TreeHandler(ComponentConfig config) {
+ super(config);
+ }
+
+ @Override
+ protected MetaRuleset createMetaRuleset(Class type) {
+ MetaRuleset metaRuleset = super.createMetaRuleset(type);
+ metaRuleset.addRule(RULE);
+ return metaRuleset;
+ }
+}
Added:
trunk/ui/iteration/ui/src/main/java/org/richfaces/view/facelets/TreeNodeHandler.java
===================================================================
--- trunk/ui/iteration/ui/src/main/java/org/richfaces/view/facelets/TreeNodeHandler.java
(rev 0)
+++
trunk/ui/iteration/ui/src/main/java/org/richfaces/view/facelets/TreeNodeHandler.java 2010-11-18
18:50:06 UTC (rev 20107)
@@ -0,0 +1,63 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, Red Hat, Inc. and individual contributors
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site:
http://www.fsf.org.
+ */
+package org.richfaces.view.facelets;
+
+import javax.faces.view.facelets.ComponentConfig;
+import javax.faces.view.facelets.ComponentHandler;
+import javax.faces.view.facelets.MetaRule;
+import javax.faces.view.facelets.MetaRuleset;
+import javax.faces.view.facelets.Metadata;
+import javax.faces.view.facelets.MetadataTarget;
+import javax.faces.view.facelets.TagAttribute;
+
+import org.richfaces.component.AbstractTreeNode;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+public class TreeNodeHandler extends ComponentHandler {
+
+ private static final MetaRule RULE = new MetaRule() {
+
+ @Override
+ public Metadata applyRule(String name, TagAttribute attribute, MetadataTarget
meta) {
+ if (meta.isTargetInstanceOf(AbstractTreeNode.class)) {
+ if ("toggleListener".equals(name)) {
+ return new TreeToggleListenerExpressionMetadata(attribute);
+ }
+ }
+ return null;
+ }
+ };
+
+ public TreeNodeHandler(ComponentConfig config) {
+ super(config);
+ }
+
+ @Override
+ protected MetaRuleset createMetaRuleset(Class type) {
+ MetaRuleset metaRuleset = super.createMetaRuleset(type);
+ metaRuleset.addRule(RULE);
+ return metaRuleset;
+ }
+}
Added:
trunk/ui/iteration/ui/src/main/java/org/richfaces/view/facelets/TreeSelectionChangeListenerExpressionMetadata.java
===================================================================
---
trunk/ui/iteration/ui/src/main/java/org/richfaces/view/facelets/TreeSelectionChangeListenerExpressionMetadata.java
(rev 0)
+++
trunk/ui/iteration/ui/src/main/java/org/richfaces/view/facelets/TreeSelectionChangeListenerExpressionMetadata.java 2010-11-18
18:50:06 UTC (rev 20107)
@@ -0,0 +1,31 @@
+package org.richfaces.view.facelets;
+
+import javax.faces.view.facelets.FaceletContext;
+import javax.faces.view.facelets.Metadata;
+import javax.faces.view.facelets.TagAttribute;
+
+import org.richfaces.event.MethodExpressionTreeSelectionChangeListener;
+import org.richfaces.event.TreeSelectionChangeEvent;
+import org.richfaces.event.TreeSelectionChangeSource;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+final class TreeSelectionChangeListenerExpressionMetadata extends Metadata {
+
+ private static final Class<?>[] SIGNATURE = new Class[] {
TreeSelectionChangeEvent.class };
+
+ private final TagAttribute attr;
+
+ TreeSelectionChangeListenerExpressionMetadata(TagAttribute attr) {
+ this.attr = attr;
+ }
+
+ @Override
+ public void applyMetadata(FaceletContext ctx, Object instance) {
+ ((TreeSelectionChangeSource) instance).addTreeSelectionChangeListener(new
MethodExpressionTreeSelectionChangeListener(
+ this.attr.getMethodExpression(ctx, null, SIGNATURE)));
+ }
+
+}
\ No newline at end of file
Added:
trunk/ui/iteration/ui/src/main/java/org/richfaces/view/facelets/TreeToggleListenerExpressionMetadata.java
===================================================================
---
trunk/ui/iteration/ui/src/main/java/org/richfaces/view/facelets/TreeToggleListenerExpressionMetadata.java
(rev 0)
+++
trunk/ui/iteration/ui/src/main/java/org/richfaces/view/facelets/TreeToggleListenerExpressionMetadata.java 2010-11-18
18:50:06 UTC (rev 20107)
@@ -0,0 +1,31 @@
+package org.richfaces.view.facelets;
+
+import javax.faces.view.facelets.FaceletContext;
+import javax.faces.view.facelets.Metadata;
+import javax.faces.view.facelets.TagAttribute;
+
+import org.richfaces.event.MethodExpressionTreeToggleListener;
+import org.richfaces.event.TreeToggleEvent;
+import org.richfaces.event.TreeToggleSource;
+
+/**
+ * @author Nick Belaevski
+ *
+ */
+final class TreeToggleListenerExpressionMetadata extends Metadata {
+
+ private static final Class<?>[] SIGNATURE = new Class[] { TreeToggleEvent.class
};
+
+ private final TagAttribute attr;
+
+ TreeToggleListenerExpressionMetadata(TagAttribute attr) {
+ this.attr = attr;
+ }
+
+ @Override
+ public void applyMetadata(FaceletContext ctx, Object instance) {
+ ((TreeToggleSource) instance).addTreeToggleListener(new
MethodExpressionTreeToggleListener(this.attr
+ .getMethodExpression(ctx, null, SIGNATURE)));
+ }
+
+}
\ No newline at end of file
Modified:
trunk/ui/iteration/ui/src/main/resources/META-INF/resources/org.richfaces/tree.js
===================================================================
---
trunk/ui/iteration/ui/src/main/resources/META-INF/resources/org.richfaces/tree.js 2010-11-18
17:10:13 UTC (rev 20106)
+++
trunk/ui/iteration/ui/src/main/resources/META-INF/resources/org.richfaces/tree.js 2010-11-18
18:50:06 UTC (rev 20107)
@@ -46,15 +46,21 @@
this.__initializeChildren(commonOptions);
- var __toggleHandler = (commonOptions.clientEventHandlers ||
{})[this.getId().substring(commonOptions.treeId.length)];
+ var handlers = (commonOptions.clientEventHandlers ||
{})[this.getId().substring(commonOptions.treeId.length)] || {};
- if (__toggleHandler) {
- richfaces.Event.bind(this.__rootElt, "toggle", new
Function("event", __toggleHandler));
+ if (handlers.bth) {
+ richfaces.Event.bind(this.__rootElt, "beforetoggle", new
Function("event", handlers.bth));
}
+
+ if (handlers.th) {
+ richfaces.Event.bind(this.__rootElt, "toggle", new
Function("event", handlers.th));
+ }
+
+ this.__addLastNodeClass();
},
destroy: function() {
- this.$super.destroy.call(this);
+ richfaces.BaseComponent.prototype.destroy.call(this);
if (this.parent) {
this.parent.removeChild(this);
@@ -75,6 +81,12 @@
});
},
+ __addLastNodeClass: function() {
+ if (this.__rootElt.next("div").length == 0) {
+ this.__rootElt.addClass("rf-tr-nd-last");
+ }
+ },
+
__getHandle: function() {
return this.__rootElt.find(" > .rf-trn:first > .rf-trn-hnd:first");
},
@@ -163,13 +175,22 @@
},
+ __fireBeforeToggleEvent: function() {
+ return richfaces.Event.callHandler(this.__rootElt, "beforetoggle");
+ },
+
__fireToggleEvent: function() {
- richfaces.Event.fire(this.__rootElt, "toggle");
+ richfaces.Event.callHandler(this.__rootElt, "toggle");
},
__changeToggleState: function(newState) {
if (!this.isLeaf()) {
if (newState ^ this.isExpanded()) {
+
+ if (this.__fireBeforeToggleEvent() === false) {
+ return;
+ }
+
var tree = this.getTree();
switch (tree.getToggleType()) {
@@ -234,10 +255,6 @@
var opts = commonOptions || {};
- if (node.nextAll(".rf-tr-nd:first").length != 0) {
- node.removeClass("rf-tr-nd-last");
- }
-
var parent = node.parent(".rf-tr-nd, .rf-tr");
var idx = node.prevAll(".rf-tr-nd").length;
@@ -247,7 +264,7 @@
var newChild = new richfaces.ui.TreeNode(node[0], opts);
parentNode.addChild(newChild, idx);
- parentNode.getTree().__updateSelection();
+ parentNode.getTree().__updateSelectionFromInput();
};
richfaces.ui.TreeNode.emitToggleEvent = function(nodeId) {
@@ -291,31 +308,52 @@
this.__ajaxSubmitFunction = new Function("event", "source",
"params", options.ajaxSubmitFunction);
}
+ if (options.onbeforeselectionchange) {
+ richfaces.Event.bind(this.__treeRootElt, "beforeselectionchange", new
Function("event", options.onbeforeselectionchange));
+ }
+
if (options.onselectionchange) {
richfaces.Event.bind(this.__treeRootElt, "selectionchange", new
Function("event", options.onselectionchange));
}
+ this.__toggleNodeEvent = options.toggleNodeEvent;
+ if (this.__toggleNodeEvent) {
+ this.__treeRootElt.delegate(".rf-trn", this.__toggleNodeEvent, this,
this.__nodeToggleActivated);
+ }
+ if (!this.__toggleNodeEvent || this.__toggleNodeEvent != 'click') {
+ this.__treeRootElt.delegate(".rf-trn-hnd", "click", this,
this.__nodeToggleActivated);
+ }
+
+ this.__treeRootElt.delegate(".rf-trn-cnt", "mousedown", this,
this.__nodeSelectionActivated);
+
this.__selectionInput = $(" > .rf-tr-sel-inp", this.__treeRootElt);
+ this.__selection = new richfaces.ui.TreeNodeSet(this.__selectionInput.val());
- this.__treeRootElt.delegate(".rf-trn-hnd", "click", this,
this.__itemHandleClicked);
- this.__treeRootElt.delegate(".rf-trn-cnt", "mousedown", this,
this.__itemContentClicked);
-
- this.__updateSelection();
+ $(document).ready($.proxy(this.__updateSelectionFromInput, this));
},
+ __addLastNodeClass: function() {
+ //stub function overriding parent class method
+ },
+
destroy: function() {
- this.$super.destroy.call(this);
+ richfaces.ui.TreeNode.prototype.destroy.call(this);
- this.__treeRootElt.undelegate(".rf-trn-hnd", "click",
this.__itemHandleClicked);
- this.__treeRootElt.undelegate(".rf-trn-cnt", "mousedown",
this.__itemContentClicked);
+ if (this.__toggleNodeEvent) {
+ this.__treeRootElt.undelegate(".rf-trn", this.__toggleNodeEvent, this,
this.__nodeToggleActivated);
+ }
+ if (!this.__toggleNodeEvent || this.__toggleNodeEvent != 'click') {
+ this.__treeRootElt.undelegate(".rf-trn-hnd", "click", this,
this.__nodeToggleActivated);
+ }
+
+ this.__treeRootElt.undelegate(".rf-trn-cnt", "mousedown",
this.__nodeSelectionActivated);
this.__treeRootElt = null;
- this.__itemContentClickedHandler = null;
this.__selectionInput = null;
this.__ajaxSubmitFunction = null;
},
- __itemHandleClicked: function(event) {
+ __nodeToggleActivated: function(event) {
var theTree = event.data;
if (isEventForAnotherTree(theTree, this)) {
return;
@@ -325,7 +363,7 @@
treeNode.toggle();
},
- __itemContentClicked: function(event) {
+ __nodeSelectionActivated: function(event) {
var theTree = event.data;
if (isEventForAnotherTree(theTree, this)) {
return;
@@ -365,68 +403,119 @@
return this;
},
- __bindFocusHandler: function(elt) {
- elt.mousedown(this.__itemContentClickedHandler);
- },
-
__isSelected: function(node) {
- return this.__selectedNodeId == node.getId();
+ return this.__selection.contains(node);
},
- __handleSelectionChange: function() {
+ __handleSelectionChange: function(newSelection) {
+ var eventData = {
+ oldSelection: this.__selection.getNodes(),
+ newSelection: newSelection.getNodes()
+ };
+
+ if (richfaces.Event.callHandler(this.__treeRootElt, "beforeselectionchange",
eventData) === false) {
+ return;
+ }
+
+ this.__selectionInput.val(newSelection.toString());
+
if (this.getSelectionType() == 'client') {
- this.__updateSelection();
+ this.__updateSelection(newSelection);
} else {
this.__ajaxSubmitFunction(null, this.getId());
}
},
__toggleSelection: function(node) {
- if (this.__isSelected(node)) {
- this.__selectionInput.val("");
- } else {
- this.__selectionInput.val(node.getId());
- }
-
- this.__handleSelectionChange();
+ var newSelection = this.__selection.cloneAndToggle(node);
+ this.__handleSelectionChange(newSelection);
},
__addToSelection: function(node) {
- this.__selectionInput.val(node.getId());
-
- this.__handleSelectionChange();
+ var newSelection = this.__selection.cloneAndAdd(node);
+ this.__handleSelectionChange(newSelection);
},
- __updateSelection: function() {
- var oldSelection = new Array();
- var newSelection = new Array();
+ __updateSelectionFromInput: function() {
+ this.__updateSelection(new richfaces.ui.TreeNodeSet(this.__selectionInput.val()));
+ },
+
+ __updateSelection: function(newSelection) {
+
+ var oldSelection = this.__selection;
- var oldSelectionId = this.__selectedNodeId;
- var newSelectionId = this.__selectionInput.val();
-
- if (oldSelectionId == newSelectionId) {
- return;
+ oldSelection.each(function() {this.__setSelected(false)});
+ newSelection.each(function() {this.__setSelected(true)});
+
+ if (oldSelection.getNodeString() != newSelection.getNodeString()) {
+ richfaces.Event.callHandler(this.__treeRootElt, "selectionchange", {
+ oldSelection: oldSelection.getNodes(),
+ newSelection: newSelection.getNodes()
+ });
}
- if (oldSelectionId) {
- var oldSelectionNode = richfaces.$(oldSelectionId);
- if (oldSelectionNode) {
- oldSelectionNode.__setSelected(false);
- oldSelection.push(oldSelectionNode);
+ this.__selection = newSelection;
+ }
+ });
+
+ richfaces.ui.TreeNodeSet = function() {
+ this.init.apply(this, arguments);
+ };
+
+ //TODO - that's a single-node set, implement multi-node support!
+ $.extend(richfaces.ui.TreeNodeSet.prototype, {
+
+ init: function(nodeId) {
+ this.__nodeId = nodeId;
+ },
+
+ contains: function(node) {
+ if (node.getId) {
+ return this.__nodeId == node.getId();
+ } else {
+ return this.__nodeId == node;
+ }
+ },
+
+ getNodeString: function() {
+ return this.__nodeId;
+ },
+
+ toString: function() {
+ return this.getNodeString();
+ },
+
+ getNodes: function() {
+ if (this.__nodeId) {
+ var node = richfaces.$(this.__nodeId);
+ if (node) {
+ return [node];
+ } else {
+ return null;
}
}
- if (newSelectionId) {
- var newSelectionNode = richfaces.$(newSelectionId);
- if (newSelectionNode) {
- newSelectionNode.__setSelected(true);
- newSelection.push(newSelectionNode);
- }
+ return [];
+ },
+
+ cloneAndAdd: function(node) {
+ return new richfaces.ui.TreeNodeSet(node.getId());
+ },
+
+ cloneAndToggle: function(node) {
+ var nodeId;
+ if (this.contains(node)) {
+ nodeId = "";
+ } else {
+ nodeId = node.getId();
}
-
- this.__selectedNodeId = newSelectionId;
- richfaces.Event.fire(this.__treeRootElt, "selectionchange", {oldSelection:
oldSelection, newSelection: newSelection});
+
+ return new richfaces.ui.TreeNodeSet(nodeId);
+ },
+
+ each: function(callback) {
+ $.each(this.getNodes() || [], callback);
}
});
-
+
}(jQuery, RichFaces));
\ No newline at end of file
Modified: trunk/ui/iteration/ui/src/main/templates/tree.template.xml
===================================================================
--- trunk/ui/iteration/ui/src/main/templates/tree.template.xml 2010-11-18 17:10:13 UTC
(rev 20106)
+++ trunk/ui/iteration/ui/src/main/templates/tree.template.xml 2010-11-18 18:50:06 UTC
(rev 20107)
@@ -44,7 +44,7 @@
<cdk:scriptOption attributes="toggleType"
defaultValue="SwitchType.DEFAULT" />
<cdk:scriptOption name="selectionType"
value="#{getSelectionMode(facesContext, component)}"
defaultValue="SwitchType.client" />
<cdk:scriptOption name="ajaxSubmitFunction"
value="#{getAjaxSubmitFunction(facesContext, component)}" />
- <cdk:scriptOption attributes="onselectionchange" />
+ <cdk:scriptOption attributes="onselectionchange
onbeforeselectionchange toggleNodeEvent" />
<cdk:scriptOption variables="clientEventHandlers" />
</cdk:scriptObject>
Modified: trunk/ui/iteration/ui/src/main/templates/treeNode.template.xml
===================================================================
--- trunk/ui/iteration/ui/src/main/templates/treeNode.template.xml 2010-11-18 17:10:13 UTC
(rev 20106)
+++ trunk/ui/iteration/ui/src/main/templates/treeNode.template.xml 2010-11-18 18:50:06 UTC
(rev 20107)
@@ -21,17 +21,16 @@
<cc:implementation>
<cdk:object name="nodeState"
value="#{getNodeState(facesContext)}"
type="org.richfaces.renderkit.TreeNodeState" />
+ <cdk:object name="tree"
value="#{getTreeComponent(component)}" type="UIComponent" />
<cdk:call expression="addClientEventHandlers(facesContext,
component)" />
- <cdk:call expression="addClientEventHandlers(facesContext,
component)" />
-
<div class="#{concatClasses('rf-trn',
component.attributes['styleClass'],
tree.attributes['nodeClass'])}">
<span class="#{concatClasses(nodeState.handleClass,
component.attributes['handleClass'],
tree.attributes['handleClass'])}"></span>
<span class="rf-trn-cnt">
<cdk:call expression="encodeIcon(facesContext, component)"
/>
- <span class="#{concatClasses('rf-trn-lbl',
component.attributes['labelClass'])}">
+ <span class="#{concatClasses('rf-trn-lbl',
component.attributes['labelClass'],
tree.attributes['labelClass'])}">
<cdk:body />
</span>
</span>
Modified:
trunk/ui/validator/ui/src/main/java/org/richfaces/renderkit/html/ClientAndAjaxScript.java
===================================================================
---
trunk/ui/validator/ui/src/main/java/org/richfaces/renderkit/html/ClientAndAjaxScript.java 2010-11-18
17:10:13 UTC (rev 20106)
+++
trunk/ui/validator/ui/src/main/java/org/richfaces/renderkit/html/ClientAndAjaxScript.java 2010-11-18
18:50:06 UTC (rev 20107)
@@ -18,7 +18,7 @@
}
- protected void finishValidation(StringBuffer body) {
+ protected void finishValidation(StringBuilder body) {
// AJAX callback
body.append("if(!").append(DISABLE_AJAX).append("){\n");
body.append(ajaxScript).append(EOL).append("}\n");