blob: 1d935d389f27a3fc29761a45d8983cbb4129297c [file] [log] [blame]
// Copyright 2005 The Apache Software Foundation
//
// 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 org.apache.tapestry.describe;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import org.apache.hivemind.util.Defense;
import org.apache.tapestry.IMarkupWriter;
/**
* Implementation of {@link org.apache.tapestry.describe.DescriptionReceiver}
* that produces HTML output using a {@link org.apache.tapestry.IMarkupWriter}.
* <p>
* TODO: Make {@link #describeAlternate(Object)} exclusive with the other
* methods {@link #title(String)}, {@link #property(String, Object)}, etc.
* </p>
*
* @author Howard M. Lewis Ship
* @since 4.0
*/
public class HTMLDescriptionReceiver implements RootDescriptionReciever
{
// Emitted for null values.
static final String NULL_VALUE = "<NULL>";
private final IMarkupWriter _writer;
private boolean _emitDefault = true;
private String _title;
private String _section;
private DescribableStrategy _strategy;
private HTMLDescriptionReceiverStyles _styles;
private boolean _even = true;
public HTMLDescriptionReceiver(IMarkupWriter writer,
DescribableStrategy adapter)
{
this(writer, adapter, new HTMLDescriptionReceiverStyles());
}
public HTMLDescriptionReceiver(IMarkupWriter writer,
DescribableStrategy strategy, HTMLDescriptionReceiverStyles styles)
{
Defense.notNull(writer, "writer");
Defense.notNull(strategy, "strategy");
Defense.notNull(styles, "styles");
_writer = writer;
_strategy = strategy;
_styles = styles;
}
/*
* (non-Javadoc)
*
* @see org.apache.tapestry.describe.RootDescriptionReciever#describe(java.lang.Object)
*/
public void describe(Object object)
{
if (object == null)
{
_writer.print(NULL_VALUE);
return;
}
_strategy.describeObject(object, this);
finishUp(object);
}
public void describeAlternate(Object alternate)
{
_strategy.describeObject(alternate, this);
}
public void finishUp()
{
// When false, a <table> was started, which must be closed.
if (!_emitDefault) _writer.end("table");
_writer.println();
_emitDefault = true;
_title = null;
_section = null;
_even = true;
}
void finishUp(Object object)
{
if (_emitDefault)
{
String value = _title != null ? _title : object.toString();
_writer.print(value);
}
finishUp();
}
public void title(String title)
{
Defense.notNull(title, "title");
if (_title != null)
throw new IllegalStateException(DescribeMessages.setTitleOnce());
_title = title;
}
public void section(String section)
{
Defense.notNull(section, "section");
if (_title == null)
throw new IllegalStateException(DescribeMessages
.mustSetTitleBeforeSection());
_section = section;
}
private void assertTitleSet()
{
if (_title == null)
throw new IllegalStateException(DescribeMessages
.mustSetTitleBeforeProperty());
}
/**
* Invoked to ensure that the section portion has been output, before any
* properties within the section are output.
*/
private void emitSection()
{
if (_emitDefault)
{
_emitDefault = false;
_writer.begin("div");
_writer.attribute("class", _styles.getHeaderClass());
_writer.print(_title);
_writer.end();
_writer.println();
_writer.begin("table");
_writer.attribute("class", _styles.getTableClass());
_writer.println();
_even = true;
}
if (_section != null)
{
_writer.begin("tr");
_writer.attribute("class", _styles.getSubheaderClass());
_writer.begin("th");
_writer.attribute("colspan", 2);
_writer.print(_section);
_writer.end("tr");
_writer.println();
_section = null;
_even = true;
}
}
private void pair(String key, String value)
{
assertTitleSet();
emitSection();
_writer.begin("tr");
writeRowClass();
_writer.begin("th");
_writer.print(key);
_writer.end();
_writer.begin("td");
_writer.print(value);
_writer.end("tr");
_writer.println();
}
private void writeRowClass()
{
_writer.attribute("class", _even ? "even" : "odd");
_even = !_even;
}
public void property(String key, Object value)
{
Defense.notNull(key, "key");
assertTitleSet();
emitSection();
_writer.begin("tr");
writeRowClass();
_writer.begin("th");
_writer.print(key);
_writer.end();
_writer.begin("td");
describeNested(value);
_writer.end("tr");
_writer.println();
}
private void describeNested(Object value)
{
if (value == null)
{
_writer.print(NULL_VALUE);
return;
}
new HTMLDescriptionReceiver(_writer, _strategy, _styles).describe(value);
}
public void property(String key, boolean value)
{
Defense.notNull(key, "key");
// toString is JDK 1.4 and above, so we'll provide our own.
pair(key, value ? "true" : "false");
}
public void property(String key, byte value)
{
Defense.notNull(key, "key");
pair(key, Byte.toString(value));
}
public void property(String key, short value)
{
Defense.notNull(key, "key");
pair(key, Short.toString(value));
}
public void property(String key, int value)
{
Defense.notNull(key, "key");
pair(key, Integer.toString(value));
}
public void property(String key, long value)
{
Defense.notNull(key, "key");
pair(key, Long.toString(value));
}
public void property(String key, float value)
{
Defense.notNull(key, "key");
pair(key, Float.toString(value));
}
public void property(String key, double value)
{
Defense.notNull(key, "key");
pair(key, Double.toString(value));
}
public void property(String key, char value)
{
Defense.notNull(key, "key");
pair(key, Character.toString(value));
}
public void array(String key, Object[] values)
{
Defense.notNull(key, "key");
assertTitleSet();
if (values == null || values.length == 0) return;
emitSection();
for(int i = 0; i < values.length; i++)
{
_writer.begin("tr");
writeRowClass();
_writer.begin("th");
if (i == 0) _writer.print(key);
_writer.end();
_writer.begin("td");
describeNested(values[i]);
_writer.end("tr");
_writer.println();
}
}
public void collection(String key, Collection values)
{
Defense.notNull(key, "key");
assertTitleSet();
if (values == null || values.isEmpty()) return;
emitSection();
Iterator i = new ArrayList(values).iterator();
boolean first = true;
while(i.hasNext())
{
_writer.begin("tr");
writeRowClass();
_writer.begin("th");
if (first)
_writer.print(key);
_writer.end();
_writer.begin("td");
describeNested(i.next());
_writer.end("tr");
_writer.println();
first = false;
}
}
}