Author: nbelaevski
Date: 2008-03-27 22:56:01 -0400 (Thu, 27 Mar 2008)
New Revision: 7340
Added:
trunk/framework/api/src/main/java/org/richfaces/model/ConvertableKeyModel.java
Modified:
trunk/framework/api/src/main/java/org/richfaces/model/AbstractTreeDataModel.java
trunk/framework/api/src/main/java/org/richfaces/model/CacheableTreeDataModel.java
trunk/framework/api/src/main/java/org/richfaces/model/ClassicTreeDataModel.java
trunk/framework/api/src/main/java/org/richfaces/model/ListRowKey.java
trunk/framework/api/src/main/java/org/richfaces/model/MapDataModel.java
trunk/framework/api/src/main/java/org/richfaces/model/SequenceDataModel.java
trunk/framework/api/src/main/java/org/richfaces/model/StackingTreeModel.java
trunk/framework/api/src/main/java/org/richfaces/model/SwingTreeDataModel.java
trunk/framework/api/src/main/java/org/richfaces/model/TreeDataModel.java
Log:
http://jira.jboss.com/jira/browse/RF-2812
Modified:
trunk/framework/api/src/main/java/org/richfaces/model/AbstractTreeDataModel.java
===================================================================
---
trunk/framework/api/src/main/java/org/richfaces/model/AbstractTreeDataModel.java 2008-03-27
20:46:35 UTC (rev 7339)
+++
trunk/framework/api/src/main/java/org/richfaces/model/AbstractTreeDataModel.java 2008-03-28
02:56:01 UTC (rev 7340)
@@ -24,7 +24,9 @@
import java.io.IOException;
import javax.faces.component.NamingContainer;
+import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
+import javax.faces.convert.Converter;
import org.ajax4jsf.model.DataVisitor;
import org.ajax4jsf.model.ExtendedDataModel;
@@ -124,4 +126,7 @@
}
public abstract TreeNode getTreeNode();
+
+ public abstract Object convertToKey(FacesContext context, String keyString,
+ UIComponent component, Converter converter);
}
Modified:
trunk/framework/api/src/main/java/org/richfaces/model/CacheableTreeDataModel.java
===================================================================
---
trunk/framework/api/src/main/java/org/richfaces/model/CacheableTreeDataModel.java 2008-03-27
20:46:35 UTC (rev 7339)
+++
trunk/framework/api/src/main/java/org/richfaces/model/CacheableTreeDataModel.java 2008-03-28
02:56:01 UTC (rev 7340)
@@ -23,7 +23,9 @@
import java.io.IOException;
+import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
+import javax.faces.convert.Converter;
import org.ajax4jsf.model.DataVisitor;
import org.ajax4jsf.model.Range;
@@ -135,4 +137,8 @@
protected abstract void setDefaultNodeData(T node, Object data);
+ @Override
+ public Object convertToKey(FacesContext context, String keyString, UIComponent
component, Converter converter) {
+ return treeDataModel.convertToKey(context, keyString, component, converter);
+ }
}
Modified: trunk/framework/api/src/main/java/org/richfaces/model/ClassicTreeDataModel.java
===================================================================
---
trunk/framework/api/src/main/java/org/richfaces/model/ClassicTreeDataModel.java 2008-03-27
20:46:35 UTC (rev 7339)
+++
trunk/framework/api/src/main/java/org/richfaces/model/ClassicTreeDataModel.java 2008-03-28
02:56:01 UTC (rev 7340)
@@ -21,6 +21,15 @@
package org.richfaces.model;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map.Entry;
+
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.convert.Converter;
+
/**
* {@link TreeDataModel} implementation for classic {@link TreeNode} instances
*
@@ -44,4 +53,40 @@
throw new IllegalStateException(
"No tree element available or row key not set!");
}
+
+ @Override
+ public Object convertToKey(FacesContext context, String keyString, UIComponent
component, Converter converter) {
+ String[] strings = ListRowKey.fromString(keyString);
+ List<Object> list = new ArrayList<Object>(strings.length);
+ TreeNode node = (TreeNode) getWrappedData();
+
+ for (int i = 0; i < strings.length; i++) {
+ String key = strings[i];
+ TreeNode<?> child = node.getChild(key);
+ if (child != null) {
+ node = child;
+ list.add(key);
+ } else {
+ boolean found = false;
+ Iterator<Entry<Object, TreeNode>> children = node.getChildren();
+
+ while (children.hasNext() && !found) {
+ Entry<Object, TreeNode> entry = children.next();
+ Object keyObject = entry.getKey();
+ if (key.equals(keyObject.toString())) {
+ node = entry.getValue();
+ list.add(keyObject);
+ found = true;
+ }
+ }
+
+ if (!found) {
+ return null;
+ }
+ }
+ }
+
+ return new ListRowKey<Object>(list);
+ }
+
}
Added: trunk/framework/api/src/main/java/org/richfaces/model/ConvertableKeyModel.java
===================================================================
--- trunk/framework/api/src/main/java/org/richfaces/model/ConvertableKeyModel.java
(rev 0)
+++
trunk/framework/api/src/main/java/org/richfaces/model/ConvertableKeyModel.java 2008-03-28
02:56:01 UTC (rev 7340)
@@ -0,0 +1,51 @@
+/**
+ * License Agreement.
+ *
+ * JBoss RichFaces - Ajax4jsf Component Library
+ *
+ * Copyright (C) 2007 Exadel, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation.
+ *
+ * This library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+package org.richfaces.model;
+
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.convert.Converter;
+
+/**
+ * Models that can handle keys conversion should implement this interface
+ *
+ * For internal use only
+ *
+ * @author Nick Belaevski
+ * @since 3.2
+ */
+
+public interface ConvertableKeyModel {
+
+ /**
+ * Converts {@link String} to model object key
+ *
+ * @param context
+ * @param key
+ * @param component
+ * @param converter
+ * @return
+ */
+ public Object getKeyAsObject(FacesContext context, String key,
+ UIComponent component, Converter converter);
+
+}
Modified: trunk/framework/api/src/main/java/org/richfaces/model/ListRowKey.java
===================================================================
--- trunk/framework/api/src/main/java/org/richfaces/model/ListRowKey.java 2008-03-27
20:46:35 UTC (rev 7339)
+++ trunk/framework/api/src/main/java/org/richfaces/model/ListRowKey.java 2008-03-28
02:56:01 UTC (rev 7340)
@@ -22,9 +22,12 @@
package org.richfaces.model;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
+import javax.faces.component.NamingContainer;
+
/**
* Default {@link TreeRowKey} implementation based on {@link ArrayList}
* @author Nick Belaevski - nbelaevski(a)exadel.com
@@ -148,28 +151,42 @@
}
}
+ private void appendSegment(StringBuilder builder, String segment) {
+ StringBuilder escapedSubPath = new StringBuilder();
+ for (int i = 0; i < segment.length(); i++) {
+ char ch = segment.charAt(i);
+
+ //escape
+ if (AbstractTreeDataModel.SEPARATOR == ch || ListRowKey.SEPARATOR_ESCAPE_CHAR == ch)
{
+ escapedSubPath.append(ListRowKey.SEPARATOR_ESCAPE_CHAR);
+ }
+
+ escapedSubPath.append(ch);
+ }
+
+ builder.append(escapedSubPath.toString());
+ }
+
public String getPath() {
- StringBuffer result = new StringBuffer();
+ StringBuilder result = new StringBuilder();
Iterator<T> iterator = path.iterator();
boolean hasNext = iterator.hasNext();
-
+
while (hasNext) {
- String pathSegment = iterator.next().toString();
-
- StringBuffer escapedSubPath = new StringBuffer();
- for (int i = 0; i < pathSegment.length(); i++) {
- char ch = pathSegment.charAt(i);
-
- //escape
- if (AbstractTreeDataModel.SEPARATOR == ch || ListRowKey.SEPARATOR_ESCAPE_CHAR == ch)
{
- escapedSubPath.append(ListRowKey.SEPARATOR_ESCAPE_CHAR);
+ T segment = iterator.next();
+ if (segment instanceof CompositeKey) {
+ CompositeKey compositeKey = (CompositeKey) segment;
+ Iterator keySegments = compositeKey.getKeySegments();
+ while (keySegments.hasNext()) {
+ appendSegment(result, keySegments.next().toString());
+ if (keySegments.hasNext()) {
+ result.append(AbstractTreeDataModel.SEPARATOR);
}
+ }
+ } else {
+ appendSegment(result, segment.toString());
+ }
- escapedSubPath.append(ch);
- }
-
- result.append(escapedSubPath.toString());
-
hasNext = iterator.hasNext();
if (hasNext) {
@@ -195,4 +212,25 @@
public T get(int i) {
return path.get(i);
}
+
+ private static final String SEPARATOR = "(?<!" +
ListRowKey.SEPARATOR_ESCAPE_CHAR + ")\\"
+ + NamingContainer.SEPARATOR_CHAR;
+
+ public static String[] fromString(String keyString) {
+ String[] split = keyString.split(SEPARATOR);
+ for (int i = 0; i < split.length; i++) {
+ //TODO exception if not escaped properly
+ split[i] = split[i].replaceAll("_(:|_)", "$1");
+ }
+
+ return split;
+ }
+
+ public static interface CompositeKey {
+ public Iterator getKeySegments();
+ }
+
+ public static void main(String[] args) {
+ System.out.println(Arrays.toString(fromString("test_:abc:123:a__b")));
+ }
}
Modified: trunk/framework/api/src/main/java/org/richfaces/model/MapDataModel.java
===================================================================
--- trunk/framework/api/src/main/java/org/richfaces/model/MapDataModel.java 2008-03-27
20:46:35 UTC (rev 7339)
+++ trunk/framework/api/src/main/java/org/richfaces/model/MapDataModel.java 2008-03-28
02:56:01 UTC (rev 7340)
@@ -10,8 +10,11 @@
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
+import java.util.Map.Entry;
+import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
+import javax.faces.convert.Converter;
import org.ajax4jsf.model.DataVisitor;
import org.ajax4jsf.model.ExtendedDataModel;
@@ -24,7 +27,7 @@
*
* @author Nick Belaevski mailto:nbelaevski@exadel.com created 30.07.2007
*/
-public class MapDataModel extends ExtendedDataModel {
+public class MapDataModel extends ExtendedDataModel implements ConvertableKeyModel {
private Map<Object, Object> map;
private Object rowKey;
@@ -199,4 +202,22 @@
}
}
+ public Object getKeyAsObject(FacesContext context, String key, UIComponent component,
Converter converter) {
+ if (this.map != null) {
+ if (this.map.containsKey(key)) {
+ return key;
+ } else {
+ Set<Entry<Object,Object>> set = this.map.entrySet();
+ for (Entry<Object, Object> entry : set) {
+ Object keyObject = entry.getKey();
+ if (key.equals(keyObject.toString())) {
+ return keyObject;
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
}
Modified: trunk/framework/api/src/main/java/org/richfaces/model/SequenceDataModel.java
===================================================================
---
trunk/framework/api/src/main/java/org/richfaces/model/SequenceDataModel.java 2008-03-27
20:46:35 UTC (rev 7339)
+++
trunk/framework/api/src/main/java/org/richfaces/model/SequenceDataModel.java 2008-03-28
02:56:01 UTC (rev 7340)
@@ -12,7 +12,9 @@
import java.util.Iterator;
import java.util.List;
+import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
+import javax.faces.convert.Converter;
import org.ajax4jsf.model.DataVisitor;
import org.ajax4jsf.model.ExtendedDataModel;
@@ -27,7 +29,7 @@
* created 30.07.2007
*
*/
-public class SequenceDataModel extends ExtendedDataModel {
+public class SequenceDataModel extends ExtendedDataModel implements ConvertableKeyModel
{
private Object wrappedData;
private List list;
@@ -140,4 +142,13 @@
this.list = null;
}
}
+
+ public Object getKeyAsObject(FacesContext context, String keyString, UIComponent
component, Converter converter) {
+ int key = Integer.parseInt(keyString);
+ if (key >= 0 && this.list != null && key < this.list.size())
{
+ return key;
+ } else {
+ return null;
+ }
+ }
}
Modified: trunk/framework/api/src/main/java/org/richfaces/model/StackingTreeModel.java
===================================================================
---
trunk/framework/api/src/main/java/org/richfaces/model/StackingTreeModel.java 2008-03-27
20:46:35 UTC (rev 7339)
+++
trunk/framework/api/src/main/java/org/richfaces/model/StackingTreeModel.java 2008-03-28
02:56:01 UTC (rev 7340)
@@ -5,18 +5,24 @@
import java.io.IOException;
import java.io.Serializable;
+import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
+import java.util.List;
import java.util.Map;
+import java.util.NoSuchElementException;
+import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
+import javax.faces.convert.Converter;
import org.ajax4jsf.model.DataVisitor;
import org.ajax4jsf.model.ExtendedDataModel;
import org.ajax4jsf.model.Range;
import org.apache.commons.collections.Predicate;
import org.apache.commons.collections.iterators.FilterIterator;
+import org.richfaces.model.ListRowKey.CompositeKey;
import org.w3c.dom.NamedNodeMap;
/**
@@ -123,6 +129,8 @@
leaveModel(getRoot().stackEntries.iterator(), null, context);
return null;
}
+
+ //TODO what's here?
}
if (keyIterator != null && keyIterator.hasNext()) {
@@ -503,7 +511,7 @@
*
* @author Nick Belaevski
*/
- protected static class Key implements Serializable {
+ protected static class Key implements Serializable, CompositeKey {
/**
*
*/
@@ -551,6 +559,103 @@
return false;
return true;
}
+
+ static enum IteratorState {
+ INITIAL {
+ @Override
+ protected boolean hasNext(Key arg0) {
+ return true;
+ }
+
+ @Override
+ protected Object next(Key arg0) {
+ throw new IllegalStateException();
+ }
+
+ @Override
+ protected IteratorState nextState() {
+ return ID;
+ }
+ },
+
+ ID {
+ @Override
+ protected boolean hasNext(Key arg0) {
+ return true;
+ }
+
+ @Override
+ protected Object next(Key arg0) {
+ return arg0.modelId;
+ }
+
+ @Override
+ protected IteratorState nextState() {
+ return KEY;
+ }
+ },
+
+ KEY {
+ @Override
+ protected boolean hasNext(Key arg0) {
+ return false;
+ }
+
+ @Override
+ protected Object next(Key arg0) {
+ return arg0.modelKey;
+ }
+
+ @Override
+ protected IteratorState nextState() {
+ return DONE;
+ }
+ },
+
+ DONE {
+ @Override
+ protected boolean hasNext(Key arg0) {
+ return false;
+ }
+
+ @Override
+ protected Object next(Key arg0) {
+ throw new NoSuchElementException();
+ }
+
+ @Override
+ protected IteratorState nextState() {
+ return DONE;
+ }
+ };
+
+ protected abstract boolean hasNext(Key key);
+
+ protected abstract Object next(Key key);
+
+ protected abstract IteratorState nextState();
+ };
+
+ public Iterator getKeySegments() {
+
+ return new Iterator<Object>() {
+ IteratorState state = IteratorState.INITIAL;
+
+ public boolean hasNext() {
+ return state.hasNext(Key.this);
+ }
+
+ public Object next() {
+ state = state.nextState();
+ return state.next(Key.this);
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+
+ };
+ }
}
protected boolean isActiveData() {
@@ -583,4 +688,47 @@
public void setWrappedData(Object data) {
throw new UnsupportedOperationException();
}
+
+ @Override
+ public Object convertToKey(FacesContext context, String keyString,
+ UIComponent component, Converter converter) {
+
+ //force model leave
+ setRowKey(null);
+
+ String[] strings = ListRowKey.fromString(keyString);
+ int l = strings.length / 2;
+ List<Object> list = new ArrayList<Object>(l);
+ StackingTreeModel model = getRoot();
+
+ for (int i = 0; i < l; i++) {
+ int idx = i*2;
+
+ String modelId = strings[idx];
+ model = model.getInternalModelById(modelId);
+ if (model.isActive()) {
+ Object key = model.convert(context, strings[idx + 1], component, converter);
+ if (key == null) {
+ return null;
+ }
+
+ list.add(new Key(modelId, key));
+
+ if (!model.setupModel(key, context) || !model.isActiveData()) {
+ return null;
+ }
+ } else {
+ return null;
+ }
+ }
+
+ return new ListRowKey<Object>(list);
+ }
+
+ protected Object convert(FacesContext context, String string,
+ UIComponent component, Converter converter) {
+
+ ConvertableKeyModel convertable = (ConvertableKeyModel) getDataModel();
+ return convertable.getKeyAsObject(context, string, component, converter);
+ }
}
Modified: trunk/framework/api/src/main/java/org/richfaces/model/SwingTreeDataModel.java
===================================================================
---
trunk/framework/api/src/main/java/org/richfaces/model/SwingTreeDataModel.java 2008-03-27
20:46:35 UTC (rev 7339)
+++
trunk/framework/api/src/main/java/org/richfaces/model/SwingTreeDataModel.java 2008-03-28
02:56:01 UTC (rev 7340)
@@ -21,9 +21,14 @@
package org.richfaces.model;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
+import java.util.List;
+import javax.faces.component.UIComponent;
+import javax.faces.context.FacesContext;
+import javax.faces.convert.Converter;
import javax.swing.tree.TreeNode;
/**
@@ -77,4 +82,30 @@
super.setWrappedData(data);
}
+
+
+ @Override
+ public Object convertToKey(FacesContext context, String keyString, UIComponent
component, Converter converter) {
+ String[] strings = ListRowKey.fromString(keyString);
+ List<Integer> list = new ArrayList<Integer>(strings.length);
+ TreeNode node = this.treeNode;
+
+ if (node != null) {
+ TreeDataModelNodeAdaptor<TreeNode> adaptor = getNodeAdaptor();
+
+ for (int i = 0; i < strings.length; i++) {
+ int key = Integer.parseInt(strings[i]);
+
+ node = adaptor.getChild(node, key);
+ if (node != null) {
+ list.add(key);
+ } else {
+ return null;
+ }
+ }
+ }
+
+ return new ListRowKey<Integer>(list);
+ }
+
}
Modified: trunk/framework/api/src/main/java/org/richfaces/model/TreeDataModel.java
===================================================================
--- trunk/framework/api/src/main/java/org/richfaces/model/TreeDataModel.java 2008-03-27
20:46:35 UTC (rev 7339)
+++ trunk/framework/api/src/main/java/org/richfaces/model/TreeDataModel.java 2008-03-28
02:56:01 UTC (rev 7340)
@@ -36,7 +36,7 @@
* @author Nick Belaevski - nbelaevski(a)exadel.com created 16.11.2006
*
*/
-public class TreeDataModel<T> extends AbstractTreeDataModel {
+public abstract class TreeDataModel<T> extends AbstractTreeDataModel {
private Object wrappedData;
private Class<T> clazz;