Author: lfryc(a)redhat.com
Date: 2010-07-10 14:12:55 -0400 (Sat, 10 Jul 2010)
New Revision: 17818
Modified:
root/tests/metamer/trunk/src/main/java/org/richfaces/testapp/Attributes.java
root/tests/metamer/trunk/src/main/java/org/richfaces/testapp/bean/A4JCommandLinkBean.java
root/tests/metamer/trunk/src/main/resources/org/richfaces/testapp/bean/A4JCommandLinkBean.properties
root/tests/metamer/trunk/src/main/webapp/components/a4jCommandLink/simple.xhtml
root/tests/metamer/trunk/src/main/webapp/templates/template.xhtml
Log:
https://jira.jboss.org/jira/browse/RFPL-466
* list of attributes refactored - shows checkboxes, radio buttons and input boxes
* table with attributes styled
Modified: root/tests/metamer/trunk/src/main/java/org/richfaces/testapp/Attributes.java
===================================================================
---
root/tests/metamer/trunk/src/main/java/org/richfaces/testapp/Attributes.java 2010-07-10
18:11:56 UTC (rev 17817)
+++
root/tests/metamer/trunk/src/main/java/org/richfaces/testapp/Attributes.java 2010-07-10
18:12:55 UTC (rev 17818)
@@ -25,21 +25,27 @@
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.Set;
import java.util.TreeMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import javax.el.ELContext;
import javax.el.MethodExpression;
+import javax.faces.bean.ManagedBean;
import javax.faces.component.UIComponentBase;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
+import javax.faces.model.SelectItem;
import org.jboss.el.ExpressionFactoryImpl;
import org.slf4j.Logger;
@@ -54,9 +60,16 @@
public class Attributes implements Map<String, Object> {
private Logger logger;
+ // K - name of a component attribute, V - value of the component attribute
private Map<String, Object> attributes;
+ // K - name of a component attribute, V - type of the component attribute
+ private Map<String, Class<?>> attributesTypes;
+ // K - name of a component attribute, V - help for the component attribute
private Map<String, String> helpMap;
- private Set<String> excludeSet;
+ // K - name of a component attribute, V - select items used on page to select value
for the attribute
+ private Map<String, List<SelectItem>> attributesSelectOptions;
+ // class object of managed bean
+ private Class<?> beanClass;
/**
* Constructor for class Attributes.
@@ -70,6 +83,8 @@
logger = LoggerFactory.getLogger(Attributes.class);
logger.info("creating attributes map for " + componentClass);
+ this.beanClass = beanClass;
+
PropertyDescriptor[] descriptors = null;
try {
descriptors =
Introspector.getBeanInfo(componentClass).getPropertyDescriptors();
@@ -80,28 +95,30 @@
}
attributes = new TreeMap<String, Object>();
+ attributesTypes = new TreeMap<String, Class<?>>();
// not all attributes of given class are needed
- excludeSet = getExcludeSet();
+ Set<String> excludeSet = getExcludeSet();
+ // create list of all attributes and their types
for (PropertyDescriptor descriptor : descriptors) {
if (!excludeSet.contains(descriptor.getName())) {
attributes.put(descriptor.getName(), null);
+ attributesTypes.put(descriptor.getName(), descriptor.getPropertyType());
}
}
logger.info(attributes.keySet().toString());
- helpMap = loadHelp(beanClass);
+ helpMap = loadHelp();
+ attributesSelectOptions = loadSelectOptions();
}
/**
- * Loads help for given managed bean.
+ * Loads help.
*
- * @param beanClass
- * class object of a managed bean
* @return map where key is attribute's name and value is help for this
attribute
*/
- private Map<String, String> loadHelp(Class<?> beanClass) {
+ private Map<String, String> loadHelp() {
ResourceBundle rb = ResourceBundle.getBundle(beanClass.getName());
Enumeration<String> keys = rb.getKeys();
String key = null;
@@ -109,8 +126,8 @@
while (keys.hasMoreElements()) {
key = keys.nextElement();
- if (key.startsWith("help.")) {
- result.put(key.replaceFirst("help.", ""),
rb.getString(key));
+ if (key.startsWith("testapp.help.")) {
+ result.put(key.replaceFirst("testapp.help.", ""),
rb.getString(key));
}
}
@@ -118,6 +135,41 @@
}
/**
+ * Loads select options used on the page for selecting attribute value.
+ *
+ * @return map where key is attribute's name and value is list of select items
usable to select attribute value
+ */
+ private Map<String, List<SelectItem>> loadSelectOptions() {
+ ResourceBundle rb = ResourceBundle.getBundle(beanClass.getName());
+ Enumeration<String> keys = rb.getKeys();
+ String key = null;
+ Map<String, List<SelectItem>> result = new HashMap<String,
List<SelectItem>>();
+
+ // e.g. attr.action.toUpperCaseAction
+ Pattern pattern = Pattern.compile("(.*)\\.(.*)\\.(.*)");
+ Matcher matcher = null;
+ SelectItem item = null;
+
+ while (keys.hasMoreElements()) {
+ key = keys.nextElement();
+ if (key.startsWith("attr.")) {
+ matcher = pattern.matcher(key);
+ matcher.find();
+
+ if (result.get(matcher.group(2)) == null) {
+ result.put(matcher.group(2), new ArrayList<SelectItem>());
+ }
+
+ item = new SelectItem(rb.getString(key), matcher.group(3));
+ result.get(matcher.group(2)).add(item);
+
+ }
+ }
+
+ return result;
+ }
+
+ /**
* {@inheritDoc}
*/
public void clear() {
@@ -208,10 +260,6 @@
* @return set containing all attributes of a JSF component that cannot/shouldn't
be set on page.
*/
private Set<String> getExcludeSet() {
- if (excludeSet != null) {
- return excludeSet;
- }
-
Set<String> set = new HashSet<String>();
set.add("attributes");
@@ -259,7 +307,7 @@
* @return description of an attribute
*/
public String getHelp(String attribute) {
- String help = helpMap.get(attribute);
+ String help = helpMap.get(attribute);
return help;
}
@@ -279,6 +327,14 @@
}
/**
+ * {@inheritDoc}
+ */
+ public Object putAttributeClass(String key, Class<?> value) {
+
+ return attributesTypes.put(key, value);
+ }
+
+ /**
* An action for tested JSF component. Can be modified dynamically.
*
* @return outcome of an action or null if no navigation should be performed
@@ -288,12 +344,21 @@
MethodExpression method = null;
String outcome = (String) attributes.get("action");
- if (isStringEL(outcome)) {
+ // if no select options for "action" are defined in property file and
it is an EL expression
+ if (!hasSelectOptions("action") && isStringEL(outcome)) {
method = new ExpressionFactoryImpl().createMethodExpression(elContext,
outcome, String.class, new Class[0]);
return (String) method.invoke(elContext, null);
- } else {
- return outcome;
}
+
+ // if select options for "action" are defined in property file
+ if (hasSelectOptions("action")) {
+ method = new ExpressionFactoryImpl().createMethodExpression(elContext,
getMethodEL(outcome), String.class,
+ new Class[0]);
+ return (String) method.invoke(elContext, null);
+ }
+
+ return outcome;
+
}
/**
@@ -307,10 +372,78 @@
MethodExpression method = null;
String listener = (String) attributes.get("actionListener");
- if (isStringEL(listener)) {
+ // if no select options for "actionListener" are defined in property
file and it is an EL expression
+ if (!hasSelectOptions("actionListener") &&
isStringEL(listener)) {
method = new ExpressionFactoryImpl().createMethodExpression(elContext,
listener, void.class,
new Class[] { ActionEvent.class });
method.invoke(elContext, new Object[] { event });
}
+
+ // if select options for "actionListener" are defined in property file
+ if (hasSelectOptions("actionListener")) {
+ method = new ExpressionFactoryImpl().createMethodExpression(elContext,
getMethodEL(listener), void.class,
+ new Class[] { ActionEvent.class });
+ method.invoke(elContext, new Object[] { event });
+ }
}
+
+ /**
+ * Method used for creating EL expressions for methods.
+ *
+ * @param methodName
+ * name of the action or action listener, e.g. toUpperCaseAction
+ * @return string containing an expression for an action or action listener, e.g.
#{bean.toUpperCaseAction}
+ */
+ private String getMethodEL(String methodName) {
+ // get name of the managed bean
+ String el = beanClass.getAnnotation(ManagedBean.class).name();
+
+ if ("".equals(el)) {
+ // create name of a managed bean according to standard, i.e. MyBean ->
myBean
+ el = beanClass.getSimpleName().substring(0, 1).toLowerCase() +
beanClass.getSimpleName().substring(1);
+ }
+
+ StringBuilder methodEL = new StringBuilder("#{");
+ methodEL.append(el);
+ methodEL.append(".");
+ methodEL.append(methodName);
+ methodEL.append("}");
+
+ return methodEL.toString();
+ }
+
+ /**
+ * Decides whether given attribute is a boolean. If true, an checkbox should be
rendered on a page.
+ *
+ * @param attributeName
+ * name of a component attribute
+ * @return true if attribute is of type boolean, otherwise false
+ */
+ public boolean isBoolean(String attributeName) {
+ Class<?> clazz = attributesTypes.get(attributeName);
+ return (clazz == boolean.class || clazz == Boolean.class);
+ }
+
+ /**
+ * Decides if there are any select options for given attribute. If true, radio
buttons should be rendered on a page.
+ *
+ * @param attributeName
+ * name of a component attribute
+ * @return true if select options were defined, false otherwise
+ */
+ public boolean hasSelectOptions(String attributeName) {
+ return attributesSelectOptions.containsKey(attributeName);
+ }
+
+ /**
+ * Getter for select options of given attribute.
+ *
+ * @param attributeName
+ * name of a component attribute
+ * @return list of select items for given attribute
+ */
+ public List<SelectItem> getSelectOptions(String attributeName) {
+ return attributesSelectOptions.get(attributeName);
+ }
+
}
Modified:
root/tests/metamer/trunk/src/main/java/org/richfaces/testapp/bean/A4JCommandLinkBean.java
===================================================================
---
root/tests/metamer/trunk/src/main/java/org/richfaces/testapp/bean/A4JCommandLinkBean.java 2010-07-10
18:11:56 UTC (rev 17817)
+++
root/tests/metamer/trunk/src/main/java/org/richfaces/testapp/bean/A4JCommandLinkBean.java 2010-07-10
18:12:55 UTC (rev 17818)
@@ -65,8 +65,9 @@
attributes.put("value", "command link");
attributes.put("rendered", "true");
attributes.put("disabled", "false");
- attributes.put("action",
"#{a4jLinkBean.first6CharsAction}");
- attributes.put("actionListener",
"#{a4jLinkBean.toUpperCaseActionListener}");
+ attributes.putAttributeClass("disabled", Boolean.class);
+ attributes.put("action", "first6CharsAction");
+ attributes.put("actionListener",
"toUpperCaseActionListener");
attributes.put("render", "output1 output2 output3");
}
Modified:
root/tests/metamer/trunk/src/main/resources/org/richfaces/testapp/bean/A4JCommandLinkBean.properties
===================================================================
---
root/tests/metamer/trunk/src/main/resources/org/richfaces/testapp/bean/A4JCommandLinkBean.properties 2010-07-10
18:11:56 UTC (rev 17817)
+++
root/tests/metamer/trunk/src/main/resources/org/richfaces/testapp/bean/A4JCommandLinkBean.properties 2010-07-10
18:12:55 UTC (rev 17818)
@@ -1,4 +1,10 @@
-help.rendered=true or false
-help.disabled=true or false
-help.action=#{a4jLinkBean.first6CharsAction} #{a4jLinkBean.doubleStringAction}
#{a4jLinkBean.toUpperCaseAction}
-help.actionListener=#{a4jLinkBean.first6CharsActionListener}
#{a4jLinkBean.doubleStringActionListener} #{a4jLinkBean.toUpperCaseActionListener}
+#testapp.help.action=#{a4jLinkBean.first6CharsAction} #{a4jLinkBean.doubleStringAction}
#{a4jLinkBean.toUpperCaseAction}
+#testapp.help.actionListener=#{a4jLinkBean.first6CharsActionListener}
#{a4jLinkBean.doubleStringActionListener} #{a4jLinkBean.toUpperCaseActionListener}
+
+attr.action.first6CharsAction=first6CharsAction
+attr.action.doubleStringAction=doubleStringAction
+attr.action.toUpperCaseAction=toUpperCaseAction
+
+attr.actionListener.first6CharsActionListener=first6CharsActionListener
+attr.actionListener.doubleStringActionListener=doubleStringActionListener
+attr.actionListener.toUpperCaseActionListener=toUpperCaseActionListener
\ No newline at end of file
Modified: root/tests/metamer/trunk/src/main/webapp/components/a4jCommandLink/simple.xhtml
===================================================================
---
root/tests/metamer/trunk/src/main/webapp/components/a4jCommandLink/simple.xhtml 2010-07-10
18:11:56 UTC (rev 17817)
+++
root/tests/metamer/trunk/src/main/webapp/components/a4jCommandLink/simple.xhtml 2010-07-10
18:12:55 UTC (rev 17818)
@@ -5,6 +5,36 @@
<ui:composition template="/templates/template.xhtml">
+ <ui:define name="head">
+ <style>
+table.attributes {
+ border-width: 0px;
+ border-collapse: collapse;
+}
+
+.attributes-first-column {
+ border-width: 1px;
+ padding: 10px;
+ border-style: dotted;
+ border-color: blue;
+ border-right: none;
+}
+
+.attributes-second-column {
+ border-width: 1px;
+ padding: 10px;
+ padding-left: 0px;
+ border-style: dotted;
+ border-color: blue;
+ border-left: none;
+}
+
+.attributes-second-column table input {
+ margin-left: 0px;
+}
+</style>
+ </ui:define>
+
<ui:define name="viewParams">
<f:metadata>
<f:viewParam name="template"
value="#{templateBean.templateId}">
@@ -53,19 +83,39 @@
</ui:define>
<ui:define name="outOfTemplateAfter">
- <h:panelGrid id="attributes" columns="4"
style="">
+ <h:panelGrid id="attributes" columns="4"
styleClass="attributes" columnClasses="attributes-first-column,
attributes-second-column, attributes-first-column, attributes-second-column">
<c:forEach items="#{a4jLinkBean.attributes}"
var="entry">
- <h:outputLabel id="#{entry.key}Label"
value="#{entry.key}" />
<h:panelGroup layout="block">
- <h:inputText id="#{entry.key}Input"
value="#{a4jLinkBean.attributes[entry.key]}">
- <a4j:ajax event="blur" render="panel"
/>
- </h:inputText>
+ <h:outputLabel id="#{entry.key}Label"
value="#{entry.key}" style="margin-right: 5px;" />
<h:graphicImage value="/resources/images/help.png"
title="#{a4jLinkBean.attributes.getHelp(entry.key)}"
rendered="#{a4jLinkBean.attributes.getHelp(entry.key) !=
null}" height="28px;"
style="vertical-align: middle;" />
</h:panelGroup>
+
+ <c:choose>
+ <c:when
test="#{a4jLinkBean.attributes.isBoolean(entry.key)}">
+ <h:selectBooleanCheckbox id="#{entry.key}Input"
value="#{a4jLinkBean.attributes[entry.key]}">
+ <a4j:ajax event="change"
render="panel" />
+ </h:selectBooleanCheckbox>
+ </c:when>
+
+ <c:when
test="#{a4jLinkBean.attributes.hasSelectOptions(entry.key)}">
+ <h:selectOneRadio id="#{entry.key}Input"
value="#{a4jLinkBean.attributes[entry.key]}"
+ layout="pageDirection">
+ <f:selectItems
value="#{a4jLinkBean.attributes.getSelectOptions(entry.key)}" />
+ <a4j:ajax event="change"
render="panel" />
+ </h:selectOneRadio>
+ </c:when>
+
+ <c:otherwise>
+ <h:inputText id="#{entry.key}Input"
value="#{a4jLinkBean.attributes[entry.key]}" style="width:
200px;">
+ <a4j:ajax event="blur" render="panel"
/>
+ </h:inputText>
+ </c:otherwise>
+ </c:choose>
+
</c:forEach>
</h:panelGrid>
</ui:define>
Modified: root/tests/metamer/trunk/src/main/webapp/templates/template.xhtml
===================================================================
--- root/tests/metamer/trunk/src/main/webapp/templates/template.xhtml 2010-07-10 18:11:56
UTC (rev 17817)
+++ root/tests/metamer/trunk/src/main/webapp/templates/template.xhtml 2010-07-10 18:12:55
UTC (rev 17818)
@@ -6,10 +6,9 @@
<h:head>
<title><ui:insert name="pageTitle">Testing
Application</ui:insert></title>
<meta http-equiv="Content-Type" content="text/xhtml;
charset=UTF-8" />
- <!-- <h:outputStylesheet library="css" name="common.css"
/>-->
- <ui:insert name="viewParams">
-
- </ui:insert>
+<!-- <h:outputStylesheet library="css" name="common.css"
/>-->
+ <ui:insert name="viewParams"/>
+ <ui:insert name="head"/>
</h:head>
<h:body>