echopointng.TemplatePanel Maven / Gradle / Ivy
Show all versions of ibis-echo2 Show documentation
package echopointng;
/*
* This file is part of the Echo Point Project. This project is a collection
* of Components that have extended the Echo Web Application Framework.
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*/
import java.util.HashMap;
import java.util.Map;
import nextapp.echo2.app.Component;
import nextapp.echo2.app.PaneContainer;
import echopointng.template.TemplateDataSource;
import echopointng.template.TemplateTextSubstitution;
/**
* TemplatePanel
is a container that uses a
* TemplateLayoutData
to render a template of content.
*
* This layout data can itself contained "named" Components and "named" Text
* Substitutions.
*
* A singleton TemplateDataSource
can be used for more than one
* TemplatePanel
and hence the memory footprint is reduced if
* used in this way.
*
*
Supplied Implementation
*
* The supplied template implementation reads XHTML template data from a number
* of different sources including Files, Strings, Resources and JSP pages.
*
* The markup :
*
*
*
*
* <component name="xxx" style="xxx" styleName="xxx"/>
*
*
*
*
* is used to indicate where in the template a named component will be placed.
*
* The style
attribute can contain a CSS statement for setting
* component properties.
*
* For example :
*
*
*
*
* <component name="xxx" style="background:red"/>
*
*
*
*
* will set the background of the inserted component to red. Under the covers a Style
object
* is created with these values and set into the component via setStyle().
*
* The styleName
attribute can contain a name ready for use with the Component.setStyleName()
* method.
*
* For example : * *
* <component name="xxx" styleName="useThisStyle"/>
*
*
* will end up having component.setStyleName('useThisStyle');
invoked.
* * The standard XHTML "controls" markup can also be used also to subsitute * components. * *
<input/>
<button/>
*
* and
*
* <select/>
*
* can all be used as component subsitution markers.
* * The markup : * *
<text name="xxx" />
*
* is used to indicate where text subsitutions will be placed.
* * Text subsitution can occur within components as well. *
* For example imagine the markup of the template looks a bit like this * *
... preceding markup <component name="button1">Button 1 Text
* Here</component> and so on ...
*
* If the isInvokeSetText() property is true and the component that maps to the
* name 'button1' has a public void setText(String s)
method,
* then the text inside the component marker, in this case "Button 1 Text Here",
* will be placed into the component via its setText() method.
* * This is only done once when the template is compiled and isStyleApplied() is * false. Of course the component in question must have a setText() method. * *
Custom Implementation
** The source template data need not be in XHTML format however you must compile * it into a XHTML DOM Element. For example you could write your own custom * XML/XSLT implementation that produced XHTML. *
* To do this you must provide a TemplateCompiler
to the
* rendering framework that takes the raw template data and converts it into a
* XHTML DOM element.
*
* TemplatePanel
is defined as an AbleComponent
* and as such has border, inset and mouse cursor support. However there is a
* caveat for to this. These properties only take affect if the top level tag in
* the the template data source does not provide a style="" attribute. if one is
* provided then it takes precedence over the AbleComponent properties
*
* TemplatePanel
also support the use of DisplayLayoutData
and
* ScrollableDisplayLayoutData
when used on child components. This allows
* the special "style" attributes to be placed within the template around the child component
* in question, perhaps to make it a certain size or position is aspecial place.
*
* @see echopointng.template.TemplateDataSource
* @see echopointng.template.TemplateTextSubstitution
* @see echopointng.layout.DisplayLayoutData
* @see echopointng.layout.ScrollableDisplayLayoutData
*/
public class TemplatePanel extends AbleComponent implements PaneContainer {
public static final String PROPERTY_EXCEPTION_ON_FAILURE = "exceptionOnFailure";
public static final String PROPERTY_INVOKE_SETTEXT = "invokeSetText";
public static final String PROPERTY_TEMPLATE_DATA_SOURCE = "templateDataSource";
public static final String PROPERTY_TEMPLATE_TEXT_SUBSTITUTION = "templateTextSubstition";
private Map componentNameMap = new HashMap();
private boolean styleApplied;
/**
* Constructs a TemplatePanel
with no template data as yet.
*/
public TemplatePanel() {
super();
}
/**
* Constructs a TemplatePanel
with the specified
* TemplateDataSource.
*
* @param tds -
* the source for the template data.
*/
public TemplatePanel(TemplateDataSource tds) {
super();
setTemplateDataSource(tds);
}
/**
* Adds a component to the TemplatePanel
with the associated
* name which can the be references from the template data.
*
* @param component
* the component to add
* @param componentName -
* the name to use when referencing this component in the
* template data.
*/
public void addNamedComponent(Component component, String componentName) {
if (component == null)
throw new IllegalArgumentException("component must be non null.");
if (componentName == null)
throw new IllegalArgumentException("componentName must be non null.");
componentNameMap.put(componentName, component);
add(component);
}
/**
* Returns the name associated with the component or null if it cant be
* found.
*
* @param component -
* the component associated with the name
* @return a name associated with component
*/
public String getComponentName(Component component) {
String componentNames[] = getNamedComponents();
for (int i = 0; i < componentNames.length; i++) {
Component c = getNamedComponent(componentNames[i]);
if (component == c) {
return componentNames[i];
}
}
return null;
}
/**
* Returns a component associated with the name or null if it cant be found.
*
* @param componentName -
* the name associated with the component
* @return a component associated with componentName
*/
public Component getNamedComponent(String componentName) {
return (Component) componentNameMap.get((componentName));
}
/**
* @return an array of all the component names in the
* TemplatePanel
.
*/
public String[] getNamedComponents() {
return (String[]) componentNameMap.keySet().toArray(new String[componentNameMap.keySet().size()]);
}
/**
* Returns the TemplateDataSource which contains the template data.
*
* @return the TemplateDataSource in place
*/
public TemplateDataSource getTemplateDataSource() {
return (TemplateDataSource) getProperty(PROPERTY_TEMPLATE_DATA_SOURCE);
}
/**
* Returns the TemplateTextSubstitution in place.
*
* @return Returns the textSubstitution in place.
*/
public TemplateTextSubstitution getTemplateTextSubstitution() {
return (TemplateTextSubstitution) getProperty(PROPERTY_TEMPLATE_TEXT_SUBSTITUTION);
}
/**
* The default value is false.
*
* @return - the exception failure value
*/
public boolean isExceptionOnFailure() {
return getProperty(PROPERTY_EXCEPTION_ON_FAILURE, false);
}
/**
* Returns true if the text of a component marker is the template is placed
* into the component via its setTextMethod.
*
* @return true if the text of a component marker is the template is placed
* into the component via its setTextMethod.
*/
public boolean isInvokeSetText() {
return getProperty(PROPERTY_INVOKE_SETTEXT, false);
}
/**
* Returns true if the style declarations from the template data have been
* applied. Typically not used outside the template rendering framework. The
* template rendering framework use this to keep track of when styles have
* been applied and to prevent them being unecessarity applied again.
*
* @return true if the the style declarations have been applied
*/
public boolean isStyleApplied() {
return styleApplied;
}
/**
* @see nextapp.echo2.app.Component#remove(nextapp.echo2.app.Component)
*/
public void remove(Component c) {
String componentName = getComponentName(c);
if (componentName != null) {
componentNameMap.remove(componentName);
}
super.remove(c);
}
/**
* Removes a named component from the TemplatePanel
that was
* previously added via the addNamedComponent()
method.
*
* @param componentName -
* the name of the component
*/
public void removeNamedComponent(String componentName) {
if (componentName == null)
throw new IllegalArgumentException("componentName must be non null.");
Component child = getNamedComponent(componentName);
componentNameMap.remove(componentName);
if (child != null) {
remove(child);
}
}
/**
* If set to true, then if the template data cannot be compiled, a a runtime
* exception will be thrown. If this is false, then a prominent error
* message will be returned as the template data but no exception will be
* thrown.
*
* Some people prefer exceptions and "defined" error behaviour. Others * prefer soft failures and the system to keep on running. * * @param newValue - * the new failure value */ public void setExceptionOnFailure(boolean newValue) { setProperty(PROPERTY_EXCEPTION_ON_FAILURE, newValue); } /** * Controls if the text of a component marker is the template is placed into * the component via its setTextMethod. *
* The markup of the template might look like this *
*
* ...
* preceding markup <component name="button1">Button 1 Text Here</component> and so on
* ...
*
*
* If this property is true and the component that maps to the name button1 * has a public void setText(String s) method, then the text inside the * component marker, in this case "Button 1 Text Here", will be placed into * the component via its setText() method. *
* This is only done once when the template is compiled and isStyleApplied()
* is false. Of course the component in question must have a setText()
* method.
*
* @param newValue -
* the new boolean value
*/
public void setInvokeSetText(boolean newValue) {
setProperty(PROPERTY_INVOKE_SETTEXT, newValue);
}
/**
* Controls whether style declarations in the template data have been
* applied or not. Typically you would not use this method. It is intended
* for use by the rendering framework
*
* @param styleApplied -
* The newValue to set.
*/
public void setStyleApplied(boolean styleApplied) {
this.styleApplied = styleApplied;
}
/**
* Sets the TemplateDataSource to be used
*
* @param templateDataSource
* the TemplateDataSource to be used
*/
public void setTemplateDataSource(TemplateDataSource templateDataSource) {
setProperty(PROPERTY_TEMPLATE_DATA_SOURCE, templateDataSource);
}
/**
* Sets the TemplateTextSubstitution to be used to substitute 'named' text
* into the template data
*
* @param textSubstitution -
* The newValue to set.
*/
public void setTemplateTextSubstitution(TemplateTextSubstitution textSubstitution) {
setProperty(PROPERTY_TEMPLATE_TEXT_SUBSTITUTION, textSubstitution);
}
/**
* @see nextapp.echo2.app.Component#validate()
*/
public void validate() {
super.validate();
String names[] = getNamedComponents();
for (int i = 0; i < names.length; i++) {
Component child = getNamedComponent(names[i]);
if (!this.isAncestorOf(child)) {
this.add(child);
}
}
}
}