/**
* Copyright 2010 Google Inc.
*
* 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.waveprotocol.wave.client.gadget.renderer;
import static org.waveprotocol.wave.model.gadget.GadgetConstants.CATEGORY_TAGNAME;
import static org.waveprotocol.wave.model.gadget.GadgetConstants.KEY_ATTRIBUTE;
import static org.waveprotocol.wave.model.gadget.GadgetConstants.PREF_TAGNAME;
import static org.waveprotocol.wave.model.gadget.GadgetConstants.STATE_TAGNAME;
import static org.waveprotocol.wave.model.gadget.GadgetConstants.TITLE_TAGNAME;
import static org.waveprotocol.wave.model.gadget.GadgetConstants.VALUE_ATTRIBUTE;
import org.waveprotocol.wave.client.editor.content.ContentElement;
import org.waveprotocol.wave.client.editor.content.ContentNode;
import org.waveprotocol.wave.model.document.util.XmlStringBuilder;
import org.waveprotocol.wave.model.util.CollectionUtils;
import org.waveprotocol.wave.model.util.StringMap;
/**
* Class to wrap gadget element children. Includes common methods to deal with
* data stored in the element nodes.
*
*/
public class GadgetElementChild {
/**
* Enumerates gadget child element types.
*/
public static enum Type {
/** Name element type. */
CATEGORIES(CATEGORY_TAGNAME),
/** Title element type. */
TITLE(TITLE_TAGNAME),
/** State element type. */
STATE(STATE_TAGNAME),
/** Preference element type. */
PREF(PREF_TAGNAME),
/** Unknown element type. */
UNKNOWN("?");
private final String tag;
private Type(String tag) {
this.tag = tag;
typeMap.put(tag, this);
}
@Override
public String toString() {
return tag;
}
}
/**
* Type map that has to be outside the Type class.
*/
// TODO(user): Use CollectionUtils.createStringMap() instead, less bug prone
// and easier to write unit tests for this class
private final static StringMap<Type> typeMap = CollectionUtils.createStringMap();
private final Type type;
private final ContentElement element;
private String value = "";
/**
* Returns initialized XML string builder for a gadget categories element.
*
* @param categories the categories.
* @return XML builder for the name element.
*/
public static XmlStringBuilder constructCategoriesXml(String categories) {
return XmlStringBuilder.createText("")
.wrap(CATEGORY_TAGNAME, KEY_ATTRIBUTE, categories);
}
/**
* Returns initialized XML string builder for a gadget title element.
*
* @param title the title value
* @return XML builder for the title element
*/
public static XmlStringBuilder constructTitleXml(String title) {
return XmlStringBuilder.createText("").wrap(TITLE_TAGNAME, VALUE_ATTRIBUTE, title);
}
/**
* Returns initialized XML string builder for a gadget element.
*
* @param tag element tag
* @param key the key
* @param value the value
* @return XML string builder for the state element
*/
public static XmlStringBuilder constructElementXml(String tag, String key, String value) {
return XmlStringBuilder.createText("").wrap(tag, KEY_ATTRIBUTE, key, VALUE_ATTRIBUTE, value);
}
/**
* Returns initialized XML string builder for a gadget state element.
*
* @param key the key
* @param value the value
* @return XML string builder for the state element
*/
public static XmlStringBuilder constructStateXml(String key, String value) {
return XmlStringBuilder.createText("").wrap(
STATE_TAGNAME, KEY_ATTRIBUTE, key, VALUE_ATTRIBUTE, value);
}
/**
* Returns initialized XML string builder for a gadget user pref element.
*
* @param key the key
* @param value the value
* @return XML string builder for the state element
*/
public static XmlStringBuilder constructPrefXml(String key, String value) {
return XmlStringBuilder.createText("").wrap(
PREF_TAGNAME, KEY_ATTRIBUTE, key, VALUE_ATTRIBUTE, value);
}
/**
* Returns element type based on the tag.
*
* @param tag tag to get the type for
* @return the type that corresponds to the tag
*/
private static Type getElementType(String tag) {
return typeMap.containsKey(tag) ? typeMap.get(tag) : Type.UNKNOWN;
}
/**
* Constructs a new wrapper object for the element.
*
* @param element element to wrap
*/
private GadgetElementChild(ContentElement element) {
this.element = element;
value = element.getAttribute(VALUE_ATTRIBUTE);
if (value == null) {
value = "";
}
type = getElementType(getTag());
}
/**
* Creates a new object to wrap the content node of the gadget element.
*
* @param node the node to be associated with the new object
* @return new object to wrap the node
*/
public static GadgetElementChild create(ContentNode node) {
if ((node == null) || !node.isElement()) {
return null;
} else {
ContentElement element = node.asElement();
return new GadgetElementChild(element);
}
}
/**
* Returns the current value (maybe different from the persistent value).
*
* @return the value
*/
public String getValue() {
return value;
}
/**
* Returns the element type.
*
* @return element type
*/
public Type getType() {
return type;
}
/**
* Returns the element tag.
*
* @return element tag
*/
public String getTag() {
return element.getTagName();
}
/**
* Returns the element.
*
* @return element
*/
public ContentElement getElement() {
return element;
}
/**
* Returns the name attribute of the element. The name attribute is the key in
* key-value pair elements such as state or pref.
*
* @return the key
*/
public String getKey() {
return element.getName();
}
/**
* Updates the current value to the one set in the element's text node and
* returns boolean that indicates whether the value has changed.
*
* @return true if the value changed, false otherwise
*/
public boolean updateValueFromElement() {
String persistentValue = element.getAttribute(VALUE_ATTRIBUTE);
if (persistentValue == null) {
persistentValue = "";
}
if (!persistentValue.equals(value)) {
value = persistentValue;
return true;
}
return false;
}
/**
* Sets the element text node to a new value.
*
* @param value new value
*/
public void setValue(String value) {
if (this.value.equals(value)) {
return;
}
element.getMutableDoc().setElementAttribute(element, VALUE_ATTRIBUTE, value);
}
/**
* Returns whether the given child is a duplicate (same type and key) of this
* object.
*
* @param child the child to check
* @return true if the child is duplicate, false otherwise
*/
public boolean isDuplicate(GadgetElementChild child) {
if ((child == null) || (child.getType() != getType())) {
return false;
}
String childKey = child.getKey();
return ((childKey == getKey()) || ((childKey != null) && childKey.equals(getKey())));
}
@Override
public String toString() {
String keyString = getKey() == null ? "" : ", key '" + getKey() + "'";
return "Gadget child " + type + keyString + ", value '" + getValue() + "'";
}
}