blob: 5e50a2e53e0ff110fe9fcefba5f827b96de327d9 [file] [log] [blame]
// Copyright 2004, 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.contrib.inspector;
import java.util.Iterator;
import java.util.Map;
import org.apache.tapestry.BaseComponent;
import org.apache.tapestry.IComponent;
import org.apache.tapestry.IDirect;
import org.apache.tapestry.IMarkupWriter;
import org.apache.tapestry.IRender;
import org.apache.tapestry.IRequestCycle;
import org.apache.tapestry.engine.DirectServiceParameter;
import org.apache.tapestry.engine.IEngineService;
import org.apache.tapestry.engine.ILink;
import org.apache.tapestry.parse.CloseToken;
import org.apache.tapestry.parse.ComponentTemplate;
import org.apache.tapestry.parse.LocalizationToken;
import org.apache.tapestry.parse.OpenToken;
import org.apache.tapestry.parse.TemplateToken;
import org.apache.tapestry.parse.TextToken;
import org.apache.tapestry.parse.TokenType;
import org.apache.tapestry.services.TemplateSource;
/**
* Component of the {@link Inspector}page used to display the ids and types of all embedded
* components.
*
* @author Howard Lewis Ship
*/
public abstract class ShowTemplate extends BaseComponent implements IDirect
{
/** @since 4.0 */
public abstract TemplateSource getTemplateSource();
/** @since 4.1 */
public abstract IEngineService getDirectService();
public boolean getHasTemplate()
{
Inspector inspector;
inspector = (Inspector) getPage();
// Components that inherit from BaseComponent have templates,
// others do not.
return inspector.getInspectedComponent() instanceof BaseComponent;
}
public IRender getTemplateDelegate()
{
return new IRender()
{
public void render(IMarkupWriter writer, IRequestCycle cycle)
{
writeTemplate(writer, cycle);
}
};
}
/**
* Writes the HTML template for the component. When <jwc> tags are written, the id is made
* a link (that selects the named component). We use some magic to accomplish this, creating
* links as if we were a {@link DirectLink} component, and attributing those links to the
* captive {@link DirectLink} component embedded here.
*/
private void writeTemplate(IMarkupWriter writer, IRequestCycle cycle)
{
IComponent inspectedComponent = getInspectedComponent();
ComponentTemplate template = null;
try
{
template = getTemplateSource().getTemplate(cycle, inspectedComponent);
}
catch (Exception ex)
{
return;
}
writer.begin("pre");
int count = template.getTokenCount();
for (int i = 0; i < count; i++)
{
TemplateToken token = template.getToken(i);
TokenType type = token.getType();
if (type == TokenType.TEXT)
{
write(writer, (TextToken) token);
continue;
}
if (type == TokenType.CLOSE)
{
write(writer, (CloseToken) token);
continue;
}
if (token.getType() == TokenType.LOCALIZATION)
{
write(writer, (LocalizationToken) token);
continue;
}
if (token.getType() == TokenType.OPEN)
{
boolean nextIsClose = (i + 1 < count)
&& (template.getToken(i + 1).getType() == TokenType.CLOSE);
write(writer, nextIsClose, (OpenToken) token);
if (nextIsClose)
i++;
continue;
}
// That's all the types known at this time.
}
writer.end(); // <pre>
}
/** @since 3.0 * */
private IComponent getInspectedComponent()
{
Inspector page = (Inspector) getPage();
return page.getInspectedComponent();
}
/** @since 3.0 * */
private void write(IMarkupWriter writer, TextToken token)
{
// Print the section of the template ... print() will
// escape and invalid characters as HTML entities. Also,
// we show the full stretch of text, not the trimmed version.
writer.print(token.getTemplateDataAsString());
}
/** @since 3.0 * */
private void write(IMarkupWriter writer, CloseToken token)
{
writer.begin("span");
writer.attribute("class", "jwc-tag");
writer.print("</");
writer.print(token.getTag());
writer.print(">");
writer.end(); // <span>
}
/** @since 3.0 * */
private void write(IMarkupWriter writer, LocalizationToken token)
{
IComponent component = getInspectedComponent();
writer.begin("span");
writer.attribute("class", "jwc-tag");
writer.print("<span key=\"");
writer.print(token.getKey());
writer.print('"');
Map attributes = token.getAttributes();
if (attributes != null && !attributes.isEmpty())
{
Iterator it = attributes.entrySet().iterator();
while (it.hasNext())
{
Map.Entry entry = (Map.Entry) it.next();
String attributeName = (String) entry.getKey();
String attributeValue = (String) entry.getValue();
writer.print(' ');
writer.print(attributeName);
writer.print("=\"");
writer.print(attributeValue);
writer.print('"');
}
}
writer.print('>');
writer.begin("span");
writer.attribute("class", "localized-string");
writer.print(component.getMessages().getMessage(token.getKey()));
writer.end(); // <span>
writer.print("</span>");
writer.end(); // <span>
}
/** @since 3.0 * */
private void write(IMarkupWriter writer, boolean nextIsClose, OpenToken token)
{
IComponent component = getInspectedComponent();
IEngineService service = getDirectService();
// Each id references a component embedded in the inspected component.
// Get that component.
String id = token.getId();
IComponent embedded = component.getComponent(id);
Object[] serviceParameters = new Object[]
{ embedded.getIdPath() };
// Build a URL to select that component, as if by the captive
// component itself (it's a Direct).
DirectServiceParameter dsp = new DirectServiceParameter(this, serviceParameters);
ILink link = service.getLink(false, dsp);
writer.begin("span");
writer.attribute("class", "jwc-tag");
writer.print("<");
writer.print(token.getTag());
writer.print(" jwcid=\"");
writer.begin("span");
writer.attribute("class", "jwc-id");
writer.begin("a");
writer.attribute("href", link.getURL());
writer.print(id);
writer.end(); // <a>
writer.end(); // <span>
writer.print('"');
Map attributes = token.getAttributesMap();
if (attributes != null)
{
Iterator ii = attributes.entrySet().iterator();
while (ii.hasNext())
{
Map.Entry e = (Map.Entry) ii.next();
String value = (String) e.getValue();
writer.print(' ');
writer.print(e.getKey().toString());
writer.print("=\"");
writer.print(value);
writer.print('"');
}
}
// Collapse an open & close down to a single tag.
if (nextIsClose)
writer.print('/');
writer.print('>');
writer.end(); // <span>
}
/**
* Invoked when a component id is clicked.
*/
public void trigger(IRequestCycle cycle)
{
Inspector inspector = (Inspector) getPage();
String componentId = (String) cycle.getListenerParameters()[0];
inspector.selectComponent(componentId);
IComponent newComponent = inspector.getInspectedComponent();
// If the component is not a BaseComponent then it won't have
// a template, so switch to the specification view.
if (!(newComponent instanceof BaseComponent))
inspector.setView(View.SPECIFICATION);
}
/**
* Always returns true.
*
* @since 2.3
*/
public boolean isStateful()
{
return true;
}
}