blob: 65a8c13deece5faba8789c1a147512ea58a9c890 [file] [log] [blame]
// Copyright 2004 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.Tapestry;
import org.apache.tapestry.engine.IEngineService;
import org.apache.tapestry.engine.ILink;
import org.apache.tapestry.engine.ITemplateSource;
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.TemplateAttribute;
import org.apache.tapestry.parse.TemplateToken;
import org.apache.tapestry.parse.TextToken;
import org.apache.tapestry.parse.TokenType;
/**
* Component of the {@link Inspector} page used to display
* the ids and types of all embedded components.
*
*
* @version $Id$
* @author Howard Lewis Ship
*
**/
public class ShowTemplate extends BaseComponent implements IDirect
{
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;
ITemplateSource source = getPage().getEngine().getTemplateSource();
try
{
template = source.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)
{
int start = token.getStartIndex();
int end = token.getEndIndex();
// 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.getTemplateData(), start, end - start + 1);
}
/** @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 = getPage().getEngine().getService(Tapestry.DIRECT_SERVICE);
String[] context = new String[1];
// Each id references a component embedded in the inspected component.
// Get that component.
String id = token.getId();
IComponent embedded = component.getComponent(id);
context[0] = embedded.getIdPath();
// Build a URL to select that component, as if by the captive
// component itself (it's a Direct).
ILink link = service.getLink(getPage().getRequestCycle(), this, context);
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();
TemplateAttribute attribute = (TemplateAttribute)e.getValue();
writer.print(' ');
writer.print(e.getKey().toString());
writer.print("=\"");
// TODO: Fix this to output something appropriate for each type
// of attribute (literal, expression, string).
writer.print(attribute.getValue());
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();
Object[] parameters = cycle.getServiceParameters();
inspector.selectComponent((String) parameters[0]);
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;
}
}