[Jguiraffe-developers] SF.net SVN: jguiraffe:[202] trunk/core/src
Brought to you by:
oheger
|
From: <oh...@us...> - 2011-07-16 20:22:33
|
Revision: 202
http://jguiraffe.svn.sourceforge.net/jguiraffe/?rev=202&view=rev
Author: oheger
Date: 2011-07-16 20:22:27 +0000 (Sat, 16 Jul 2011)
Log Message:
-----------
[3368763] Added a new transformer which creates StaticTextData objects.
Modified Paths:
--------------
trunk/core/src/changes/changes.xml
trunk/core/src/site/xdoc/userguide/formbuilder.xml
Added Paths:
-----------
trunk/core/src/main/java/net/sf/jguiraffe/gui/builder/components/tags/StaticTextDataTransformer.java
trunk/core/src/test/java/net/sf/jguiraffe/gui/builder/components/tags/TestStaticTextDataTransformer.java
Modified: trunk/core/src/changes/changes.xml
===================================================================
--- trunk/core/src/changes/changes.xml 2011-07-16 14:52:47 UTC (rev 201)
+++ trunk/core/src/changes/changes.xml 2011-07-16 20:22:27 UTC (rev 202)
@@ -27,6 +27,10 @@
</properties>
<body>
<release version="1.1" date="in SVN" description="TBD">
+ <action dev="oheger" issue="3368763" type="fix">
+ Added a transformer to StaticTextData objects which simpliefies usage
+ of static text controls in forms.
+ </action>
<action dev="oheger" issue="3368750" type="fix">
Builders could throw an undocumented LocatorException. Such exceptions
are now caught and re-thrown as BuilderException exceptions.
Added: trunk/core/src/main/java/net/sf/jguiraffe/gui/builder/components/tags/StaticTextDataTransformer.java
===================================================================
--- trunk/core/src/main/java/net/sf/jguiraffe/gui/builder/components/tags/StaticTextDataTransformer.java (rev 0)
+++ trunk/core/src/main/java/net/sf/jguiraffe/gui/builder/components/tags/StaticTextDataTransformer.java 2011-07-16 20:22:27 UTC (rev 202)
@@ -0,0 +1,277 @@
+/*
+ * Copyright 2006-2011 The JGUIraffe Team.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License")
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.sf.jguiraffe.gui.builder.components.tags;
+
+import java.util.Locale;
+import java.util.Map;
+
+import net.sf.jguiraffe.gui.builder.components.model.StaticTextData;
+import net.sf.jguiraffe.gui.builder.components.model.TextIconAlignment;
+import net.sf.jguiraffe.transform.Transformer;
+import net.sf.jguiraffe.transform.TransformerContext;
+
+/**
+ * <p>
+ * A special implementation of the {@code Transformer} interface for converting
+ * data to {@code StaticTextData} objects.
+ * </p>
+ * <p>
+ * This transformer class is useful if {@link StaticTextTag} is used to produce
+ * labels in forms which should display some data. The data is to be provided as
+ * part of the form's model. If only textual data is involved, it is pretty
+ * inconvenient to expose properties of type {@code StaticTextData} in the model
+ * bean. Rather, this class can be assigned as {@code Transformer} to the static
+ * text fields. It creates {@code StaticTextData} objects and populates them
+ * from the object passed to the {@link #transform(Object, TransformerContext)}
+ * method. The following objects can be handled:
+ * <ul>
+ * <li>Objects implementing the {@code CharSequence} interface become the text
+ * of the {@code StaticTextData} object.</li>
+ * <li>Objects of type {@link TextIconAlignment} are passed to the
+ * {@code alignment} property.</li>
+ * <li>If the object passed to {@code transform()} is already of type
+ * {@code StaticTextData}, it is returned without changes.</li>
+ * <li>Other objects are interpreted as icons and stored in the {@code icon}
+ * property.</li>
+ * </ul>
+ * </p>
+ * <p>
+ * An instance defines properties for all elements of a {@code StaticTextData}
+ * object. If set, the corresponding values are written in the newly created
+ * objects. For instance, if the {@code icon} property is set and a
+ * {@code CharSequence} object is passed to {@code transform()}, the resulting
+ * object will have this icon and the text of the {@code CharSequence}. These
+ * properties can be overridden by properties in the {@code TransformerContext}.
+ * Here the following properties are supported:
+ * <table border="1">
+ * <tr>
+ * <th>Property</th>
+ * <th>Description</th>
+ * <th>Default</th>
+ * </tr>
+ * <tr>
+ * <td valign="top">text</td>
+ * <td>The text to be written into the {@code StaticTextData} object.</td>
+ * <td valign="top">undefined</td>
+ * </tr>
+ * <tr>
+ * <td valign="top">icon</td>
+ * <td>The icon to be written into the {@code StaticTextData} object.</td>
+ * <td valign="top">undefined</td>
+ * </tr>
+ * <tr>
+ * <td valign="top">alignment</td>
+ * <td>The alignment for the {@code StaticTextData} object.</td>
+ * <td valign="top">undefined</td>
+ * </tr>
+ * </table>
+ * </p>
+ *
+ * @author Oliver Heger
+ * @version $Id$
+ */
+public class StaticTextDataTransformer implements Transformer
+{
+ /** Constant for the name of the property with the default text. */
+ private static final String PROP_TEXT = "text";
+
+ /** Constant for the name of the property with the default icon. */
+ private static final String PROP_ICON = "icon";
+
+ /** Constant for the name of the property with the default alignment. */
+ private static final String PROP_ALIGNMENT = "alignment";
+
+ /** The default text. */
+ private String text;
+
+ /** The default icon. */
+ private Object icon;
+
+ /** The default alignment. */
+ private TextIconAlignment alignment;
+
+ /**
+ * Returns the default text for the newly created {@code StaticTextData}
+ * objects.
+ *
+ * @return the default text
+ */
+ public String getText()
+ {
+ return text;
+ }
+
+ /**
+ * Sets the default text for the newly created {@code StaticTextData}
+ * objects.
+ *
+ * @param text the default text
+ */
+ public void setText(String text)
+ {
+ this.text = text;
+ }
+
+ /**
+ * Returns the default icon for the newly created {@code StaticTextData}
+ * objects.
+ *
+ * @return the default icon
+ */
+ public Object getIcon()
+ {
+ return icon;
+ }
+
+ /**
+ * Sets the default icon for the newly created {@code StaticTextData}
+ * objects.
+ *
+ * @param icon the default icon
+ */
+ public void setIcon(Object icon)
+ {
+ this.icon = icon;
+ }
+
+ /**
+ * Returns the default {@code TextIconAlignment}.
+ *
+ * @return the default alignment
+ */
+ public TextIconAlignment getAlignment()
+ {
+ return alignment;
+ }
+
+ /**
+ * Sets the default {@code TextIconAlignment}.
+ *
+ * @param alignment the default alignment
+ */
+ public void setAlignment(TextIconAlignment alignment)
+ {
+ this.alignment = alignment;
+ }
+
+ /**
+ * {@inheritDoc} Performs the transformation as described in the class
+ * comment.
+ */
+ public Object transform(Object o, TransformerContext ctx) throws Exception
+ {
+ if (o == null)
+ {
+ return null;
+ }
+ if (o instanceof StaticTextData)
+ {
+ return o;
+ }
+
+ StaticTextDataImpl result = new StaticTextDataImpl();
+ populate(result, ctx);
+ convertProperty(o, result, ctx);
+ return result;
+ }
+
+ /**
+ * Fills the specified data object with default values. This method is
+ * called by {@code transform()} to write default values into the result
+ * object. It evaluates the properties in the context and the member fields
+ * of this instance.
+ *
+ * @param data the data object to be filled
+ * @param ctx the {@code TransformerContext}
+ */
+ protected void populate(StaticTextDataImpl data, TransformerContext ctx)
+ {
+ Map<String, Object> props = ctx.properties();
+ data.setText(fetchValue((String) props.get(PROP_TEXT), getText()));
+ data.setIcon(fetchValue(props.get(PROP_ICON), getIcon()));
+ TextIconAlignment align =
+ fetchValue(convertAlignment(props.get(PROP_ALIGNMENT)),
+ getAlignment());
+ if (align != null)
+ {
+ data.setAlignment(align);
+ }
+ }
+
+ /**
+ * Performs the transformation if the object to be converted must be set as
+ * a property of a {@code StaticTextData} object. This method is called by
+ * {@code transform()} if the passed in object is not <b>null</b> and not a
+ * {@code StaticTextData} object. The base implementation sets the
+ * corresponding property in the passed in data object based on the class of
+ * the object to be converted.
+ *
+ * @param o the object to be converted
+ * @param data the data object to be filled
+ * @param ctx the {@code TransformerContext}
+ * @throws Exception if an error occurs
+ */
+ protected void convertProperty(Object o, StaticTextDataImpl data,
+ TransformerContext ctx) throws Exception
+ {
+ if (o instanceof CharSequence)
+ {
+ data.setText(((CharSequence) o).toString());
+ }
+ else if (o instanceof TextIconAlignment)
+ {
+ data.setAlignment((TextIconAlignment) o);
+ }
+ else
+ {
+ data.setIcon(o);
+ }
+ }
+
+ /**
+ * Helper method for converting an alignment value. This method can handle
+ * strings which are converted to alignment constants.
+ *
+ * @param value the value to be converted
+ * @return the converted value (can be <b>null</b>)
+ */
+ private static TextIconAlignment convertAlignment(Object value)
+ {
+ if (value instanceof TextIconAlignment)
+ {
+ return (TextIconAlignment) value;
+ }
+ if (value == null)
+ {
+ return null;
+ }
+ return TextIconAlignment.valueOf(value.toString().toUpperCase(
+ Locale.ENGLISH));
+ }
+
+ /**
+ * Helper method for obtaining a property value. If the value is defined, it
+ * is casted and returned. Otherwise the default value is used.
+ *
+ * @param value the value as object
+ * @param defValue the default value
+ * @return the final value
+ */
+ private static <T> T fetchValue(T value, T defValue)
+ {
+ return (value != null) ? value : defValue;
+ }
+}
Property changes on: trunk/core/src/main/java/net/sf/jguiraffe/gui/builder/components/tags/StaticTextDataTransformer.java
___________________________________________________________________
Added: svn:mime-type
+ text/plain
Added: svn:keywords
+ Date Author Id Revision HeadURL
Added: svn:eol-style
+ native
Modified: trunk/core/src/site/xdoc/userguide/formbuilder.xml
===================================================================
--- trunk/core/src/site/xdoc/userguide/formbuilder.xml 2011-07-16 14:52:47 UTC (rev 201)
+++ trunk/core/src/site/xdoc/userguide/formbuilder.xml 2011-07-16 20:22:27 UTC (rev 202)
@@ -995,10 +995,40 @@
<p>
The following rule of thumb can be used to determine whether a plain label
or a static text element should be used: If the element is not changed
- during the runtime of the application, use a label. Otherwise take a static
+ during the life time of the application, use a label. Otherwise take a static
text and manipulate it accordingly.
</p>
<p>
+ Although there exists a <code>ComponentHandler</code> for each static text
+ element, the handlers are not added to the form object constructed for the
+ UI per default. This is typically not desired because these elements are not
+ used to gather user input and therefore do not need a corresponding
+ property in the model object of the form. However, the default behavior can
+ be changed by setting the <code>noField</code> attribute of the
+ <code><statictext></code> tag to <strong>false</strong>. The tag
+ should then also be given a name. Then it is possible to write data from
+ the model object of the form into the UI elements.
+ </p>
+ <p>
+ There is one problem however:
+ <code><a href="../apidocs/net/sf/jguiraffe/gui/builder/components/model/StaticTextHandler.html">
+ StaticTextHandler</a></code> expects that it is passed data as
+ <code><a href="../apidocs/net/sf/jguiraffe/gui/builder/components/model/StaticTextData.html">
+ StaticTextData</a></code> objects; therefore the properties of the form's
+ model bound to static text elements must be of this type. This is
+ inconvenient for instance if the elements are used to display mutable text
+ only. In order to simplify this use case, <em>JGUIraffe</em> provides a
+ special <a href="validators.html">transformer</a> implementation which can
+ convert data to <code>StaticTextData</code> objects:
+ <code><a href="../apidocs/net/sf/jguiraffe/gui/builder/components/tags/StaticTextDataTransromer.html">
+ StaticTextDataTransromer</a></code>. Among other things, this class is able
+ to transform a plain text string into a <code>StaticTextData</code> object
+ which can then be used to initialize the static text element. So if this
+ transformer is applied, properties of the form's model object can be
+ simple types. We will see in a moment how transformers are assigned to UI
+ elements.
+ </p>
+ <p>
<a name="transformers"/><strong>Transformers</strong>
</p>
<p>
Added: trunk/core/src/test/java/net/sf/jguiraffe/gui/builder/components/tags/TestStaticTextDataTransformer.java
===================================================================
--- trunk/core/src/test/java/net/sf/jguiraffe/gui/builder/components/tags/TestStaticTextDataTransformer.java (rev 0)
+++ trunk/core/src/test/java/net/sf/jguiraffe/gui/builder/components/tags/TestStaticTextDataTransformer.java 2011-07-16 20:22:27 UTC (rev 202)
@@ -0,0 +1,283 @@
+/*
+ * Copyright 2006-2011 The JGUIraffe Team.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License")
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package net.sf.jguiraffe.gui.builder.components.tags;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import net.sf.jguiraffe.gui.builder.components.model.StaticTextData;
+import net.sf.jguiraffe.gui.builder.components.model.TextIconAlignment;
+import net.sf.jguiraffe.transform.TransformerContext;
+
+import org.easymock.EasyMock;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * Test class for {@code StaticTextDataTransformer}.
+ *
+ * @author Oliver Heger
+ * @version $Id$
+ */
+public class TestStaticTextDataTransformer
+{
+ /** A mock for the transformer context. */
+ private TransformerContext ctx;
+
+ /** The transformer to be tested. */
+ private StaticTextDataTransformerTestImpl transformer;
+
+ @Before
+ public void setUp() throws Exception
+ {
+ ctx = EasyMock.createMock(TransformerContext.class);
+ transformer = new StaticTextDataTransformerTestImpl();
+ }
+
+ /**
+ * Tests a newly created instance.
+ */
+ @Test
+ public void testInit()
+ {
+ assertNull("Got a default text", transformer.getText());
+ assertNull("Got a default icon", transformer.getIcon());
+ assertNull("Got a default alignment", transformer.getAlignment());
+ }
+
+ /**
+ * Tests whether null objects are handled.
+ */
+ @Test
+ public void testTransformNull() throws Exception
+ {
+ EasyMock.replay(ctx);
+ assertNull("Wrong result", transformer.transform(null, ctx));
+ EasyMock.verify(ctx);
+ }
+
+ /**
+ * Tests transform() if a static text data object is passed in.
+ */
+ @Test
+ public void testTransformStaticTextData() throws Exception
+ {
+ StaticTextData data = EasyMock.createMock(StaticTextData.class);
+ EasyMock.replay(ctx, data);
+ assertSame("Wrong result", data, transformer.transform(data, ctx));
+ EasyMock.verify(ctx, data);
+ }
+
+ /**
+ * Tests populate() if there are no default properties.
+ */
+ @Test
+ public void testPopulateNoProperties()
+ {
+ EasyMock.expect(ctx.properties()).andReturn(
+ new HashMap<String, Object>());
+ EasyMock.replay(ctx);
+ StaticTextDataImpl data = new StaticTextDataImpl();
+ transformer.populate(data, ctx);
+ assertNull("Got a text", data.getText());
+ assertNull("Got an icon", data.getIcon());
+ assertEquals("No default alginment",
+ new StaticTextDataImpl().getAlignment(), data.getAlignment());
+ EasyMock.verify(ctx);
+ }
+
+ /**
+ * Tests whether properties of the context are used for populating the data
+ * object.
+ */
+ @Test
+ public void testPopulateFromContext()
+ {
+ Map<String, Object> props = new HashMap<String, Object>();
+ props.put("text", "MyText");
+ props.put("icon", this);
+ props.put("alignment", TextIconAlignment.RIGHT);
+ transformer.setText("other Text");
+ transformer.setIcon(new Object());
+ transformer.setAlignment(TextIconAlignment.CENTER);
+ EasyMock.expect(ctx.properties()).andReturn(
+ Collections.unmodifiableMap(props));
+ EasyMock.replay(ctx);
+ StaticTextDataImpl data = new StaticTextDataImpl();
+ transformer.populate(data, ctx);
+ assertEquals("Wrong text", props.get("text"), data.getText());
+ assertEquals("Wrong icon", this, data.getIcon());
+ assertEquals("Wrong alignment", TextIconAlignment.RIGHT,
+ data.getAlignment());
+ EasyMock.verify(ctx);
+ }
+
+ /**
+ * Tests whether the alignment enumeration is converted when data from the
+ * context is read.
+ */
+ @Test
+ public void testPopulateFromContextConvertEnum()
+ {
+ Map<String, Object> props = new HashMap<String, Object>();
+ props.put("alignment", "right");
+ EasyMock.expect(ctx.properties()).andReturn(
+ Collections.unmodifiableMap(props));
+ EasyMock.replay(ctx);
+ StaticTextDataImpl data = new StaticTextDataImpl();
+ transformer.populate(data, ctx);
+ assertEquals("Wrong alignment", TextIconAlignment.RIGHT,
+ data.getAlignment());
+ EasyMock.verify(ctx);
+ }
+
+ /**
+ * Tests whether properties of the transformer are used to populate the data
+ * object.
+ */
+ @Test
+ public void testPopulateFromProperties()
+ {
+ Map<String, Object> props = Collections.emptyMap();
+ EasyMock.expect(ctx.properties()).andReturn(props);
+ EasyMock.replay(ctx);
+ transformer.setText("text");
+ transformer.setIcon(this);
+ transformer.setAlignment(TextIconAlignment.CENTER);
+ StaticTextDataImpl data = new StaticTextDataImpl();
+ transformer.populate(data, ctx);
+ assertEquals("Wrong text", "text", data.getText());
+ assertEquals("Wrong icon", this, data.getIcon());
+ assertEquals("Wrong alignment", TextIconAlignment.CENTER,
+ data.getAlignment());
+ EasyMock.verify(ctx);
+ }
+
+ /**
+ * Tests whether a text object is correctly handled by transform().
+ */
+ @Test
+ public void testTransformCharSequence() throws Exception
+ {
+ transformer.setMockPopulate(true);
+ final String text = "This is a test text!";
+ StaticTextData data =
+ (StaticTextData) transformer.transform(new StringBuilder(text),
+ ctx);
+ assertEquals("Wrong text", text, data.getText());
+ transformer.verify(data);
+ }
+
+ /**
+ * Tests whether an icon object is correctly handled by transform().
+ */
+ @Test
+ public void testTransformIcon() throws Exception
+ {
+ transformer.setMockPopulate(true);
+ final Object icon = new Object();
+ StaticTextData data = (StaticTextData) transformer.transform(icon, ctx);
+ assertEquals("Wrong icon", icon, data.getIcon());
+ transformer.verify(data);
+ }
+
+ /**
+ * Tests whether an alignment object is correctly handled by transform().
+ */
+ @Test
+ public void testTransformAlignment() throws Exception
+ {
+ transformer.setMockPopulate(true);
+ StaticTextData data =
+ (StaticTextData) transformer.transform(TextIconAlignment.LEFT,
+ ctx);
+ assertEquals("Wrong alignment", TextIconAlignment.LEFT,
+ data.getAlignment());
+ transformer.verify(data);
+ }
+
+ /**
+ * A special transformer implementation which allows mocking the population
+ * of the data object.
+ */
+ private class StaticTextDataTransformerTestImpl extends
+ StaticTextDataTransformer
+ {
+ /** The number of invocations of populate(). */
+ private int populateCount;
+
+ /** The data object passed to populate(). */
+ private StaticTextDataImpl populateData;
+
+ /** A flag whether the populate() method is to be mocked. */
+ private boolean mockPopulate;
+
+ /**
+ * Returns a flag whether populate() is to be mocked.
+ *
+ * @return the mock populate() flag
+ */
+ public boolean isMockPopulate()
+ {
+ return mockPopulate;
+ }
+
+ /**
+ * Sets a flag whether populate() is to be mocked.
+ *
+ * @param mockPopulate the mock flag
+ */
+ public void setMockPopulate(boolean mockPopulate)
+ {
+ this.mockPopulate = mockPopulate;
+ }
+
+ /**
+ * Verifies whether a transformation was done correctly.
+ *
+ * @param data the data object returned by transform()
+ */
+ public void verify(StaticTextData data)
+ {
+ assertEquals("Wrong number of populate() calls", 1, populateCount);
+ assertSame("Wrong data object", populateData, data);
+ }
+
+ /**
+ * Either mocks this method and records the invocation or calls the
+ * super method.
+ */
+ @Override
+ protected void populate(StaticTextDataImpl data, TransformerContext tctx)
+ {
+ if (isMockPopulate())
+ {
+ populateCount++;
+ populateData = data;
+ assertSame("Wrong context", ctx, tctx);
+ }
+ else
+ {
+ super.populate(data, tctx);
+ }
+ }
+ }
+}
Property changes on: trunk/core/src/test/java/net/sf/jguiraffe/gui/builder/components/tags/TestStaticTextDataTransformer.java
___________________________________________________________________
Added: svn:mime-type
+ text/plain
Added: svn:keywords
+ Date Author Id Revision HeadURL
Added: svn:eol-style
+ native
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|