Hello,
my english is not the best, I hope you understand me
My problem is I need a Tree who display HTML-Code not as Plainetext.
I think I have approximately the same problem as this user
click me
I created a ITree and a IVTree like in the other thread compiled that without problems, but if I created a new ITree this object would be allways “null”.
This are my classes:
ITree
/*
@ITMillApache2LicenseForJavaFiles@
*/
package components;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import java.util.StringTokenizer;
import uebersicht.widgetset.client.ui.VITree;
import com.vaadin.data.Container;
import com.vaadin.data.Item;
import com.vaadin.data.Property;
import com.vaadin.data.util.ContainerHierarchicalWrapper;
import com.vaadin.data.util.IndexedContainer;
import com.vaadin.event.Action;
import com.vaadin.event.ItemClickEvent;
import com.vaadin.event.ItemClickEvent.ItemClickListener;
import com.vaadin.event.ItemClickEvent.ItemClickSource;
import com.vaadin.terminal.KeyMapper;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.Resource;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
import com.vaadin.ui.AbstractSelect;
import com.vaadin.ui.Component;
/**
* Tree component. A Tree can be used to select an item (or multiple items) from
* a hierarchical set of items.
*
* @author IT Mill Ltd.
* @version
* @VERSION@
* @since 3.0
*/
@SuppressWarnings("serial")
@com.vaadin.ui.ClientWidget(uebersicht.widgetset.client.ui.VITree.class)
public class ITree extends AbstractSelect implements Container.Hierarchical,
Action.Container, ItemClickSource {
private static final Method EXPAND_METHOD;
private static final Method COLLAPSE_METHOD;
static {
try {
EXPAND_METHOD = ExpandListener.class.getDeclaredMethod(
"nodeExpand", new Class[] { ExpandEvent.class });
COLLAPSE_METHOD = CollapseListener.class.getDeclaredMethod(
"nodeCollapse", new Class[] { CollapseEvent.class });
} catch (final java.lang.NoSuchMethodException e) {
// This should never happen
throw new java.lang.RuntimeException(
"Internal error finding methods in ITree");
}
}
/* Private members */
/**
* Set of expanded nodes.
*/
private final HashSet expanded = new HashSet();
/**
* List of action handlers.
*/
private LinkedList<Action.Handler> actionHandlers = null;
/**
* Action mapper.
*/
private KeyMapper actionMapper = null;
/**
* Is the ITree selectable on the client side.
*/
private boolean selectable = true;
/**
* Flag to indicate sub-ITree loading
*/
private boolean partialUpdate = false;
/**
* Holds a itemId which was recently expanded
*/
private Object expandedItemId;
/**
* a flag which indicates initial paint. After this flag set true partial
* updates are allowed.
*/
private boolean initialPaint = true;
/* ITree constructors */
/**
* Creates a new empty ITree.
*/
public ITree() {
}
/**
* Creates a new empty ITree with caption.
*
* @param caption
*/
public ITree(String caption) {
setCaption(caption);
}
/**
* Creates a new ITree with caption and connect it to a Container.
*
* @param caption
* @param dataSource
*/
public ITree(String caption, Container dataSource) {
setCaption(caption);
setContainerDataSource(dataSource);
}
/* Expanding and collapsing */
/**
* Check is an item is expanded
*
* @param itemId
* the item id.
* @return true iff the item is expanded.
*/
public boolean isExpanded(Object itemId) {
return expanded.contains(itemId);
}
/**
* Expands an item.
*
* @param itemId
* the item id.
* @return True iff the expand operation succeeded
*/
public boolean expandItem(Object itemId) {
boolean success = expandItem(itemId, true);
requestRepaint();
return success;
}
/**
* Expands an item.
*
* @param itemId
* the item id.
* @param sendChildTree
* flag to indicate if client needs subITree or not (may be
* cached)
* @return True iff the expand operation succeeded
*/
private boolean expandItem(Object itemId, boolean sendChildTree) {
// Succeeds if the node is already expanded
if (isExpanded(itemId)) {
return true;
}
// Nodes that can not have children are not expandable
if (!areChildrenAllowed(itemId)) {
return false;
}
// Expands
expanded.add(itemId);
expandedItemId = itemId;
if (initialPaint) {
requestRepaint();
} else if (sendChildTree) {
requestPartialRepaint();
}
fireExpandEvent(itemId);
return true;
}
@Override
public void requestRepaint() {
super.requestRepaint();
partialUpdate = false;
}
private void requestPartialRepaint() {
super.requestRepaint();
partialUpdate = true;
}
/**
* Expands the items recursively
*
* Expands all the children recursively starting from an item. Operation
* succeeds only if all expandable items are expanded.
*
* @param startItemId
* @return True iff the expand operation succeeded
*/
public boolean expandItemsRecursively(Object startItemId) {
boolean result = true;
// Initial stack
final Stack todo = new Stack();
todo.add(startItemId);
// Expands recursively
while (!todo.isEmpty()) {
final Object id = todo.pop();
if (areChildrenAllowed(id) && !expandItem(id, false)) {
result = false;
}
if (hasChildren(id)) {
todo.addAll(getChildren(id));
}
}
requestRepaint();
return result;
}
/**
* Collapses an item.
*
* @param itemId
* the item id.
* @return True iff the collapse operation succeeded
*/
public boolean collapseItem(Object itemId) {
// Succeeds if the node is already collapsed
if (!isExpanded(itemId)) {
return true;
}
// Collapse
expanded.remove(itemId);
requestRepaint();
fireCollapseEvent(itemId);
return true;
}
/**
* Collapses the items recursively.
*
* Collapse all the children recursively starting from an item. Operation
* succeeds only if all expandable items are collapsed.
*
* @param startItemId
* @return True iff the collapse operation succeeded
*/
public boolean collapseItemsRecursively(Object startItemId) {
boolean result = true;
// Initial stack
final Stack todo = new Stack();
todo.add(startItemId);
// Collapse recursively
while (!todo.isEmpty()) {
final Object id = todo.pop();
if (areChildrenAllowed(id) && !collapseItem(id)) {
result = false;
}
if (hasChildren(id)) {
todo.addAll(getChildren(id));
}
}
return result;
}
/**
* Returns the current selectable state. Selectable determines if the a node
* can be selected on the client side. Selectable does not affect
* {@link #setValue(Object)} or {@link #select(Object)}.
*
* <p>
* The ITree is selectable by default.
* </p>
*
* @return the current selectable state.
*/
public boolean isSelectable() {
return selectable;
}
/**
* Sets the selectable state. Selectable determines if the a node can be
* selected on the client side. Selectable does not affect
* {@link #setValue(Object)} or {@link #select(Object)}.
*
* <p>
* The ITree is selectable by default.
* </p>
*
* @param selectable
* The new selectable state.
*/
public void setSelectable(boolean selectable) {
if (this.selectable != selectable) {
this.selectable = selectable;
requestRepaint();
}
}
/* Component API */
/*
* (non-Javadoc)
*
* @see com.vaadin.ui.AbstractSelect#changeVariables(java.lang.Object,
* java.util.Map)
*/
@Override
public void changeVariables(Object source, Map variables) {
if (variables.containsKey("clickedKey")) {
String key = (String) variables.get("clickedKey");
Object id = itemIdMapper.get(key);
MouseEventDetails details = MouseEventDetails
.deSerialize((String) variables.get("clickEvent"));
Item item = getItem(id);
if (item != null) {
fireEvent(new ItemClickEvent(this, item, id, null, details));
}
}
if (!isSelectable() && variables.containsKey("selected")) {
// Not-selectable is a special case, AbstractSelect does not support
// TODO could be optimized.
variables = new HashMap(variables);
variables.remove("selected");
}
// Collapses the nodes
if (variables.containsKey("collapse")) {
final String[] keys = (String[]
) variables.get("collapse");
for (int i = 0; i < keys.length; i++) {
final Object id = itemIdMapper.get(keys[i]
);
if (id != null && isExpanded(id)) {
expanded.remove(id);
fireCollapseEvent(id);
}
}
}
// Expands the nodes
if (variables.containsKey("expand")) {
boolean sendChildTree = false;
if (variables.containsKey("requestChildTree")) {
sendChildTree = true;
}
final String[] keys = (String[]
) variables.get("expand");
for (int i = 0; i < keys.length; i++) {
final Object id = itemIdMapper.get(keys[i]
);
if (id != null) {
expandItem(id, sendChildTree);
}
}
}
// Selections are handled by the select component
super.changeVariables(source, variables);
// Actions
if (variables.containsKey("action")) {
final StringTokenizer st = new StringTokenizer((String) variables
.get("action"), ",");
if (st.countTokens() == 2) {
final Object itemId = itemIdMapper.get(st.nextToken());
final Action action = (Action) actionMapper.get(st.nextToken());
if (action != null && containsId(itemId)
&& actionHandlers != null) {
for (final Iterator<Action.Handler> i = actionHandlers
.iterator(); i.hasNext();) {
i.next().handleAction(action, this, itemId);
}
}
}
}
}
/**
* Paints any needed component-specific things to the given UIDL stream.
*
* @see com.vaadin.ui.AbstractComponent#paintContent(PaintTarget)
*/
@Override
public void paintContent(PaintTarget target) throws PaintException {
initialPaint = false;
if (partialUpdate) {
target.addAttribute("partialUpdate", true);
target.addAttribute("rootKey", itemIdMapper.key(expandedItemId));
} else {
getCaptionChangeListener().clear();
// The tab ordering number
if (getTabIndex() > 0) {
target.addAttribute("tabindex", getTabIndex());
}
// Paint ITree attributes
if (isSelectable()) {
target.addAttribute("selectmode", (isMultiSelect() ? "multi"
: "single"));
} else {
target.addAttribute("selectmode", "none");
}
if (isNewItemsAllowed()) {
target.addAttribute("allownewitem", true);
}
if (isNullSelectionAllowed()) {
target.addAttribute("nullselect", true);
}
}
// Initialize variables
final Set<Action> actionSet = new LinkedHashSet<Action>();
// rendered selectedKeys
LinkedList<String> selectedKeys = new LinkedList<String>();
final LinkedList<String> expandedKeys = new LinkedList<String>();
// Iterates through hierarchical ITree using a stack of iterators
final Stack<Iterator> iteratorStack = new Stack<Iterator>();
Collection ids;
if (partialUpdate) {
ids = getChildren(expandedItemId);
} else {
ids = rootItemIds();
}
if (ids != null) {
iteratorStack.push(ids.iterator());
}
while (!iteratorStack.isEmpty()) {
// Gets the iterator for current ITree level
final Iterator i = iteratorStack.peek();
// If the level is finished, back to previous ITree level
if (!i.hasNext()) {
// Removes used iterator from the stack
iteratorStack.pop();
// Closes node
if (!iteratorStack.isEmpty()) {
target.endTag("node");
}
}
// Adds the item on current level
else {
final Object itemId = i.next();
// Starts the item / node
final boolean isNode = areChildrenAllowed(itemId);
if (isNode) {
target.startTag("node");
} else {
target.startTag("leaf");
}
if (itemStyleGenerator != null) {
String stylename = itemStyleGenerator.getStyle(itemId);
if (stylename != null) {
target.addAttribute("style", stylename);
}
}
// Adds the attributes
target.addAttribute("caption", getItemCaption(itemId));
final Resource icon = getItemIcon(itemId);
if (icon != null) {
target.addAttribute("icon", getItemIcon(itemId));
}
final String key = itemIdMapper.key(itemId);
target.addAttribute("key", key);
if (isSelected(itemId)) {
target.addAttribute("selected", true);
selectedKeys.add(key);
}
if (areChildrenAllowed(itemId) && isExpanded(itemId)) {
target.addAttribute("expanded", true);
expandedKeys.add(key);
}
// Add caption change listener
getCaptionChangeListener().addNotifierForItem(itemId);
// Actions
if (actionHandlers != null) {
final ArrayList<String> keys = new ArrayList<String>();
final Iterator<Action.Handler> ahi = actionHandlers
.iterator();
while (ahi.hasNext()) {
final Action[] aa = ahi.next().getActions(itemId, this);
if (aa != null) {
for (int ai = 0; ai < aa.length; ai++) {
final String akey = actionMapper.key(aa[ai]
);
actionSet.add(aa[ai]
);
keys.add(akey);
}
}
}
target.addAttribute("al", keys.toArray());
}
// Adds the children if expanded, or close the tag
if (isExpanded(itemId) && hasChildren(itemId)
&& areChildrenAllowed(itemId)) {
iteratorStack.push(getChildren(itemId).iterator());
} else {
if (isNode) {
target.endTag("node");
} else {
target.endTag("leaf");
}
}
}
}
// Actions
if (!actionSet.isEmpty()) {
target.addVariable(this, "action", "");
target.startTag("actions");
final Iterator<Action> i = actionSet.iterator();
while (i.hasNext()) {
final Action a = i.next();
target.startTag("action");
if (a.getCaption() != null) {
target.addAttribute("caption", a.getCaption());
}
if (a.getIcon() != null) {
target.addAttribute("icon", a.getIcon());
}
target.addAttribute("key", actionMapper.key(a));
target.endTag("action");
}
target.endTag("actions");
}
if (partialUpdate) {
partialUpdate = false;
} else {
// Selected
target.addVariable(this, "selected", selectedKeys
.toArray(new String[selectedKeys.size()]
));
// Expand and collapse
target.addVariable(this, "expand", new String[] {});
target.addVariable(this, "collapse", new String[] {});
// New items
target.addVariable(this, "newitem", new String[] {});
}
}
/* Container.Hierarchical API */
/**
* Tests if the Item with given ID can have any children.
*
* @see com.vaadin.data.Container.Hierarchical#areChildrenAllowed(Object)
*/
public boolean areChildrenAllowed(Object itemId) {
return ((Container.Hierarchical) items).areChildrenAllowed(itemId);
}
/**
* Gets the IDs of all Items that are children of the specified Item.
*
* @see com.vaadin.data.Container.Hierarchical#getChildren(Object)
*/
public Collection getChildren(Object itemId) {
return ((Container.Hierarchical) items).getChildren(itemId);
}
/**
* Gets the ID of the parent Item of the specified Item.
*
* @see com.vaadin.data.Container.Hierarchical#getParent(Object)
*/
public Object getParent(Object itemId) {
return ((Container.Hierarchical) items).getParent(itemId);
}
/**
* Tests if the Item specified with <code>itemId</code> has child Items.
*
* @see com.vaadin.data.Container.Hierarchical#hasChildren(Object)
*/
public boolean hasChildren(Object itemId) {
return ((Container.Hierarchical) items).hasChildren(itemId);
}
/**
* Tests if the Item specified with <code>itemId</code> is a root Item.
*
* @see com.vaadin.data.Container.Hierarchical#isRoot(Object)
*/
public boolean isRoot(Object itemId) {
return ((Container.Hierarchical) items).isRoot(itemId);
}
/**
* Gets the IDs of all Items in the container that don't have a parent.
*
* @see com.vaadin.data.Container.Hierarchical#rootItemIds()
*/
public Collection rootItemIds() {
return ((Container.Hierarchical) items).rootItemIds();
}
/**
* Sets the given Item's capability to have children.
*
* @see com.vaadin.data.Container.Hierarchical#setChildrenAllowed(Object,
* boolean)
*/
public boolean setChildrenAllowed(Object itemId, boolean areChildrenAllowed) {
final boolean success = ((Container.Hierarchical) items)
.setChildrenAllowed(itemId, areChildrenAllowed);
if (success) {
fireValueChange(false);
}
return success;
}
/*
* (non-Javadoc)
*
* @see com.vaadin.data.Container.Hierarchical#setParent(java.lang.Object ,
* java.lang.Object)
*/
public boolean setParent(Object itemId, Object newParentId) {
final boolean success = ((Container.Hierarchical) items).setParent(
itemId, newParentId);
if (success) {
requestRepaint();
}
return success;
}
/* Overriding select behavior */
/**
* Sets the Container that serves as the data source of the viewer.
*
* @see com.vaadin.data.Container.Viewer#setContainerDataSource(Container)
*/
@Override
public void setContainerDataSource(Container newDataSource) {
if (newDataSource == null) {
// Note: using wrapped IndexedContainer to match constructor (super
// creates an IndexedContainer, which is then wrapped).
newDataSource = new ContainerHierarchicalWrapper(
new IndexedContainer());
}
// Assure that the data source is ordered by making unordered
// containers ordered by wrapping them
if (Container.Hierarchical.class.isAssignableFrom(newDataSource
.getClass())) {
super.setContainerDataSource(newDataSource);
} else {
super.setContainerDataSource(new ContainerHierarchicalWrapper(
newDataSource));
}
}
/* Expand event and listener */
/**
* Event to fired when a node is expanded. ExapandEvent is fired when a node
* is to be expanded. it can me used to dynamically fill the sub-nodes of
* the node.
*
* @author IT Mill Ltd.
* @version
* @VERSION@
* @since 3.0
*/
public class ExpandEvent extends Component.Event {
private final Object expandedItemId;
/**
* New instance of options change event
*
* @param iTree
* the Source of the event.
* @param expandedItemId
*/
public ExpandEvent(ITree iTree, Object expandedItemId) {
super(iTree);
this.expandedItemId = expandedItemId;
}
/**
* Node where the event occurred.
*
* @return the Source of the event.
*/
public Object getItemId() {
return expandedItemId;
}
}
/**
* Expand event listener.
*
* @author IT Mill Ltd.
* @version
* @VERSION@
* @since 3.0
*/
public interface ExpandListener extends Serializable {
/**
* A node has been expanded.
*
* @param event
* the Expand event.
*/
public void nodeExpand(ExpandEvent event);
}
/**
* Adds the expand listener.
*
* @param listener
* the Listener to be added.
*/
public void addListener(ExpandListener listener) {
addListener(ExpandEvent.class, listener, EXPAND_METHOD);
}
/**
* Removes the expand listener.
*
* @param listener
* the Listener to be removed.
*/
public void removeListener(ExpandListener listener) {
removeListener(ExpandEvent.class, listener, EXPAND_METHOD);
}
/**
* Emits the expand event.
*
* @param itemId
* the item id.
*/
protected void fireExpandEvent(Object itemId) {
fireEvent(new ExpandEvent(this, itemId));
}
/* Collapse event */
/**
* Collapse event
*
* @author IT Mill Ltd.
* @version
* @VERSION@
* @since 3.0
*/
public class CollapseEvent extends Component.Event {
private final Object collapsedItemId;
/**
* New instance of options change event.
*
* @param iTree
* the Source of the event.
* @param collapsedItemId
*/
public CollapseEvent(ITree iTree, Object collapsedItemId) {
super(iTree);
this.collapsedItemId = collapsedItemId;
}
/**
* Gets tge Collapsed Item id.
*
* @return the collapsed item id.
*/
public Object getItemId() {
return collapsedItemId;
}
}
/**
* Collapse event listener.
*
* @author IT Mill Ltd.
* @version
* @VERSION@
* @since 3.0
*/
public interface CollapseListener extends Serializable {
/**
* A node has been collapsed.
*
* @param event
* the Collapse event.
*/
public void nodeCollapse(CollapseEvent event);
}
/**
* Adds the collapse listener.
*
* @param listener
* the Listener to be added.
*/
public void addListener(CollapseListener listener) {
addListener(CollapseEvent.class, listener, COLLAPSE_METHOD);
}
/**
* Removes the collapse listener.
*
* @param listener
* the Listener to be removed.
*/
public void removeListener(CollapseListener listener) {
removeListener(CollapseEvent.class, listener, COLLAPSE_METHOD);
}
/**
* Emits collapse event.
*
* @param itemId
* the item id.
*/
protected void fireCollapseEvent(Object itemId) {
fireEvent(new CollapseEvent(this, itemId));
}
/* Action container */
/**
* Adds an action handler.
*
* @see com.vaadin.event.Action.Container#addActionHandler(com.vaadin.event.Action.Handler)
*/
public void addActionHandler(Action.Handler actionHandler) {
if (actionHandler != null) {
if (actionHandlers == null) {
actionHandlers = new LinkedList<Action.Handler>();
actionMapper = new KeyMapper();
}
if (!actionHandlers.contains(actionHandler)) {
actionHandlers.add(actionHandler);
requestRepaint();
}
}
}
/**
* Removes an action handler.
*
* @see com.vaadin.event.Action.Container#removeActionHandler(Action.Handler)
*/
public void removeActionHandler(Action.Handler actionHandler) {
if (actionHandlers != null && actionHandlers.contains(actionHandler)) {
actionHandlers.remove(actionHandler);
if (actionHandlers.isEmpty()) {
actionHandlers = null;
actionMapper = null;
}
requestRepaint();
}
}
/**
* Removes all action handlers
*/
public void removeAllActionHandlers() {
actionHandlers = null;
actionMapper = null;
requestRepaint();
}
/**
* Gets the visible item ids.
*
* @see com.vaadin.ui.Select#getVisibleItemIds()
*/
@Override
public Collection getVisibleItemIds() {
final LinkedList visible = new LinkedList();
// Iterates trough hierarchical ITree using a stack of iterators
final Stack<Iterator> iteratorStack = new Stack<Iterator>();
final Collection ids = rootItemIds();
if (ids != null) {
iteratorStack.push(ids.iterator());
}
while (!iteratorStack.isEmpty()) {
// Gets the iterator for current ITree level
final Iterator i = iteratorStack.peek();
// If the level is finished, back to previous ITree level
if (!i.hasNext()) {
// Removes used iterator from the stack
iteratorStack.pop();
}
// Adds the item on current level
else {
final Object itemId = i.next();
visible.add(itemId);
// Adds children if expanded, or close the tag
if (isExpanded(itemId) && hasChildren(itemId)) {
iteratorStack.push(getChildren(itemId).iterator());
}
}
}
return visible;
}
/**
* ITree does not support <code>setNullSelectionItemId</code>.
*
* @see com.vaadin.ui.AbstractSelect#setNullSelectionItemId(java.lang.Object)
*/
@Override
public void setNullSelectionItemId(Object nullSelectionItemId)
throws UnsupportedOperationException {
if (nullSelectionItemId != null) {
throw new UnsupportedOperationException();
}
}
/**
* Adding new items is not supported.
*
* @throws UnsupportedOperationException
* if set to true.
* @see com.vaadin.ui.Select#setNewItemsAllowed(boolean)
*/
@Override
public void setNewItemsAllowed(boolean allowNewOptions)
throws UnsupportedOperationException {
if (allowNewOptions) {
throw new UnsupportedOperationException();
}
}
/**
* Focusing to this component is not supported.
*
* @throws UnsupportedOperationException
* if invoked.
* @see com.vaadin.ui.AbstractField#focus()
*/
@Override
public void focus() throws UnsupportedOperationException {
throw new UnsupportedOperationException();
}
/**
* ITree does not support lazy options loading mode. Setting this true will
* throw UnsupportedOperationException.
*
* @see com.vaadin.ui.Select#setLazyLoading(boolean)
*/
public void setLazyLoading(boolean useLazyLoading) {
if (useLazyLoading) {
throw new UnsupportedOperationException(
"Lazy options loading is not supported by ITree.");
}
}
private ItemStyleGenerator itemStyleGenerator;
public void addListener(ItemClickListener listener) {
addListener(VITree.ITEM_CLICK_EVENT_ID, ItemClickEvent.class, listener,
ItemClickEvent.ITEM_CLICK_METHOD);
}
public void removeListener(ItemClickListener listener) {
removeListener(VITree.ITEM_CLICK_EVENT_ID, ItemClickEvent.class,
listener);
}
/**
* Sets the {@link ItemStyleGenerator} to be used with this ITree.
*
* @param itemStyleGenerator
* item style generator or null to remove generator
*/
public void setItemStyleGenerator(ItemStyleGenerator itemStyleGenerator) {
if (this.itemStyleGenerator != itemStyleGenerator) {
this.itemStyleGenerator = itemStyleGenerator;
requestRepaint();
}
}
/**
* @return the current {@link ItemStyleGenerator} for this ITree. Null if
* {@link ItemStyleGenerator} is not set.
*/
public ItemStyleGenerator getItemStyleGenerator() {
return itemStyleGenerator;
}
/**
* ItemStyleGenerator can be used to add custom styles to ITree items. The
* CSS class name that will be added to the cell content is
* <tt>v-ITree-node-[style name]
</tt>.
*/
public interface ItemStyleGenerator extends Serializable {
/**
* Called by ITree when an item is painted.
*
* @param itemId
* The itemId of the item to be painted
* @return The style name to add to this item. (the CSS class name will
* be v-ITree-node-[style name]
*/
public abstract String getStyle(Object itemId);
}
@Override
public boolean addContainerProperty(Object propertyId, Class<?> type,
Object defaultValue) throws UnsupportedOperationException {
// TODO Auto-generated method stub
return false;
}
@Override
public Object addItem() throws UnsupportedOperationException {
// TODO Auto-generated method stub
return null;
}
@Override
public Item addItem(Object itemId) throws UnsupportedOperationException {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean containsId(Object itemId) {
// TODO Auto-generated method stub
return false;
}
@Override
public Property getContainerProperty(Object itemId, Object propertyId) {
// TODO Auto-generated method stub
return null;
}
@Override
public Collection<?> getContainerPropertyIds() {
// TODO Auto-generated method stub
return null;
}
@Override
public Item getItem(Object itemId) {
// TODO Auto-generated method stub
return null;
}
@Override
public Collection<?> getItemIds() {
// TODO Auto-generated method stub
return null;
}
@Override
public Class<?> getType(Object propertyId) {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean removeAllItems() throws UnsupportedOperationException {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean removeContainerProperty(Object propertyId)
throws UnsupportedOperationException {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean removeItem(Object itemId)
throws UnsupportedOperationException {
// TODO Auto-generated method stub
return false;
}
@Override
public int size() {
// TODO Auto-generated method stub
return 0;
}
}
VITree:
/*
@ITMillApache2LicenseForJavaFiles@
*/
package uebersicht.widgetset.client.ui;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.Widget;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.BrowserInfo;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
import com.vaadin.terminal.gwt.client.Paintable;
import com.vaadin.terminal.gwt.client.UIDL;
import com.vaadin.terminal.gwt.client.Util;
import com.vaadin.terminal.gwt.client.ui.Action;
import com.vaadin.terminal.gwt.client.ui.ActionOwner;
import com.vaadin.terminal.gwt.client.ui.Icon;
import com.vaadin.terminal.gwt.client.ui.TreeAction;
/**
*
*/
public class VITree extends FlowPanel implements Paintable {
public static final String CLASSNAME = "v-tree";
public static final String ITEM_CLICK_EVENT_ID = "itemClick";
private Set<String> selectedIds = new HashSet<String>();
private ApplicationConnection client;
private String paintableId;
private boolean selectable;
private boolean isMultiselect;
private final HashMap<String, TreeNode> keyToNode = new HashMap<String, TreeNode>();
/**
* This map contains captions and icon urls for actions like: * "33_c" ->
* "Edit" * "33_i" -> "http://dom.com/edit.png"
*/
private final HashMap<String, String> actionMap = new HashMap<String, String>();
private boolean immediate;
private boolean isNullSelectionAllowed = true;
private boolean disabled = false;
private boolean readonly;
private boolean rendering;
public VITree() {
super();
setStyleName(CLASSNAME);
}
private void updateActionMap(UIDL c) {
final Iterator it = c.getChildIterator();
while (it.hasNext()) {
final UIDL action = (UIDL) it.next();
final String key = action.getStringAttribute("key");
final String caption = action.getStringAttribute("caption");
actionMap.put(key + "_c", caption);
if (action.hasAttribute("icon")) {
// TODO need some uri handling ??
actionMap.put(key + "_i", client.translateVaadinUri(action
.getStringAttribute("icon")));
}
}
}
public String getActionCaption(String actionKey) {
return actionMap.get(actionKey + "_c");
}
public String getActionIcon(String actionKey) {
return actionMap.get(actionKey + "_i");
}
public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
// Ensure correct implementation and let container manage caption
if (client.updateComponent(this, uidl, true)) {
return;
}
rendering = true;
this.client = client;
if (uidl.hasAttribute("partialUpdate")) {
handleUpdate(uidl);
rendering = false;
return;
}
paintableId = uidl.getId();
immediate = uidl.hasAttribute("immediate");
disabled = uidl.getBooleanAttribute("disabled");
readonly = uidl.getBooleanAttribute("readonly");
isNullSelectionAllowed = uidl.getBooleanAttribute("nullselect");
clear();
for (final Iterator i = uidl.getChildIterator(); i.hasNext();) {
final UIDL childUidl = (UIDL) i.next();
if ("actions".equals(childUidl.getTag())) {
updateActionMap(childUidl);
continue;
}
final TreeNode childTree = new TreeNode();
if (childTree.ie6compatnode != null) {
this.add(childTree);
}
childTree.updateFromUIDL(childUidl, client);
if (childTree.ie6compatnode == null) {
this.add(childTree);
}
}
final String selectMode = uidl.getStringAttribute("selectmode");
selectable = !"none".equals(selectMode);
isMultiselect = "multi".equals(selectMode);
selectedIds = uidl.getStringArrayVariableAsSet("selected");
rendering = false;
}
private void handleUpdate(UIDL uidl) {
final TreeNode rootNode = keyToNode.get(uidl
.getStringAttribute("rootKey"));
if (rootNode != null) {
if (!rootNode.getState()) {
// expanding node happened server side
rootNode.setState(true, false);
}
rootNode.renderChildNodes(uidl.getChildIterator());
}
}
public void setSelected(TreeNode treeNode, boolean selected) {
if (selected) {
if (!isMultiselect) {
while (selectedIds.size() > 0) {
final String id = selectedIds.iterator().next();
final TreeNode oldSelection = keyToNode.get(id);
if (oldSelection != null) {
// can be null if the node is not visible (parent
// collapsed)
oldSelection.setSelected(false);
}
selectedIds.remove(id);
}
}
treeNode.setSelected(true);
selectedIds.add(treeNode.key);
} else {
if (!isNullSelectionAllowed) {
if (!isMultiselect || selectedIds.size() == 1) {
return;
}
}
selectedIds.remove(treeNode.key);
treeNode.setSelected(false);
}
client.updateVariable(paintableId, "selected", selectedIds
.toArray(new String[selectedIds.size()]
), immediate);
}
public boolean isSelected(TreeNode treeNode) {
return selectedIds.contains(treeNode.key);
}
protected class TreeNode extends SimplePanel implements ActionOwner {
public static final String CLASSNAME = "v-tree-node";
String key;
private String[] actionKeys = null;
private boolean childrenLoaded;
private Element nodeCaptionDiv;
protected Element nodeCaptionSpan;
private FlowPanel childNodeContainer;
private boolean open;
private Icon icon;
private Element ie6compatnode;
public TreeNode() {
constructDom();
sinkEvents(Event.ONCLICK | Event.ONDBLCLICK | Event.ONMOUSEUP
| Event.ONCONTEXTMENU);
}
@Override
public void onBrowserEvent(Event event) {
super.onBrowserEvent(event);
if (disabled) {
return;
}
final int type = DOM.eventGetType(event);
final Element target = DOM.eventGetTarget(event);
if (client.hasEventListeners(VITree.this, ITEM_CLICK_EVENT_ID)
&& target == nodeCaptionSpan
&& (type == Event.ONDBLCLICK || type == Event.ONMOUSEUP)) {
fireClick(event);
}
if (type == Event.ONCLICK) {
if (getElement() == target || ie6compatnode == target) {
// state change
toggleState();
} else if (!readonly && target == nodeCaptionSpan) {
// caption click = selection change && possible click event
toggleSelection();
}
DOM.eventCancelBubble(event, true);
} else if (type == Event.ONCONTEXTMENU) {
showContextMenu(event);
}
}
private void fireClick(Event evt) {
// non-immediate iff an immediate select event is going to happen
boolean imm = !immediate
|| !selectable
|| (!isNullSelectionAllowed && isSelected() && selectedIds
.size() == 1);
MouseEventDetails details = new MouseEventDetails(evt);
client.updateVariable(paintableId, "clickedKey", key, false);
client.updateVariable(paintableId, "clickEvent",
details.toString(), imm);
}
private void toggleSelection() {
if (selectable) {
VITree.this.setSelected(this, !isSelected());
}
}
private void toggleState() {
setState(!getState(), true);
}
protected void constructDom() {
// workaround for a very weird IE6 issue #1245
if (BrowserInfo.get().isIE6()) {
ie6compatnode = DOM.createDiv();
setStyleName(ie6compatnode, CLASSNAME + "-ie6compatnode");
DOM.setInnerHTML(ie6compatnode, " ");
DOM.appendChild(getElement(), ie6compatnode);
DOM.sinkEvents(ie6compatnode, Event.ONCLICK);
}
nodeCaptionDiv = DOM.createDiv();
DOM.setElementProperty(nodeCaptionDiv, "className", CLASSNAME
+ "-caption");
Element wrapper = DOM.createDiv();
nodeCaptionSpan = DOM.createSpan();
DOM.appendChild(getElement(), nodeCaptionDiv);
DOM.appendChild(nodeCaptionDiv, wrapper);
DOM.appendChild(wrapper, nodeCaptionSpan);
childNodeContainer = new FlowPanel();
childNodeContainer.setStylePrimaryName(CLASSNAME + "-children");
setWidget(childNodeContainer);
}
public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
setText(uidl.getStringAttribute("caption"));
key = uidl.getStringAttribute("key");
keyToNode.put(key, this);
if (uidl.hasAttribute("al")) {
actionKeys = uidl.getStringArrayAttribute("al");
}
if (uidl.getTag().equals("node")) {
if (uidl.getChildCount() == 0) {
childNodeContainer.setVisible(false);
} else {
renderChildNodes(uidl.getChildIterator());
childrenLoaded = true;
}
} else {
addStyleName(CLASSNAME + "-leaf");
}
addStyleName(CLASSNAME);
if (uidl.hasAttribute("style")) {
addStyleName(CLASSNAME + "-" + uidl.getStringAttribute("style"));
Widget.setStyleName(nodeCaptionDiv, CLASSNAME + "-caption-"
+ uidl.getStringAttribute("style"), true);
childNodeContainer.addStyleName(CLASSNAME + "-children-"
+ uidl.getStringAttribute("style"));
}
if (uidl.getBooleanAttribute("expanded") && !getState()) {
setState(true, false);
}
if (uidl.getBooleanAttribute("selected")) {
setSelected(true);
// ensure that identifier is in selectedIds array (this may be a
// partial update)
selectedIds.add(key);
}
if (uidl.hasAttribute("icon")) {
if (icon == null) {
icon = new Icon(client);
DOM.insertBefore(DOM.getFirstChild(nodeCaptionDiv), icon
.getElement(), nodeCaptionSpan);
}
icon.setUri(uidl.getStringAttribute("icon"));
} else {
if (icon != null) {
DOM.removeChild(DOM.getFirstChild(nodeCaptionDiv), icon
.getElement());
icon = null;
}
}
if (BrowserInfo.get().isIE6() && isAttached()) {
fixWidth();
}
}
private void setState(boolean state, boolean notifyServer) {
if (open == state) {
return;
}
if (state) {
if (!childrenLoaded && notifyServer) {
client.updateVariable(paintableId, "requestChildTree",
true, false);
}
if (notifyServer) {
client.updateVariable(paintableId, "expand",
new String[] { key }, true);
}
addStyleName(CLASSNAME + "-expanded");
childNodeContainer.setVisible(true);
} else {
removeStyleName(CLASSNAME + "-expanded");
childNodeContainer.setVisible(false);
if (notifyServer) {
client.updateVariable(paintableId, "collapse",
new String[] { key }, true);
}
}
open = state;
if (!rendering) {
Util.notifyParentOfSizeChange(VITree.this, false);
}
}
private boolean getState() {
return open;
}
private void setText(String text) {
DOM.setInnerHTML(nodeCaptionSpan, text);
}
private void renderChildNodes(Iterator i) {
childNodeContainer.clear();
childNodeContainer.setVisible(true);
while (i.hasNext()) {
final UIDL childUidl = (UIDL) i.next();
// actions are in bit weird place, don't mix them with children,
// but current node's actions
if ("actions".equals(childUidl.getTag())) {
updateActionMap(childUidl);
continue;
}
final TreeNode childTree = new TreeNode();
if (ie6compatnode != null) {
childNodeContainer.add(childTree);
}
childTree.updateFromUIDL(childUidl, client);
if (ie6compatnode == null) {
childNodeContainer.add(childTree);
}
}
childrenLoaded = true;
}
public boolean isChildrenLoaded() {
return childrenLoaded;
}
public Action[] getActions() {
if (actionKeys == null) {
return new Action[] {};
}
final Action[] actions = new Action[actionKeys.length]
;
for (int i = 0; i < actions.length; i++) {
final String actionKey = actionKeys[i]
;
final TreeAction a = new TreeAction(this, String.valueOf(key),
actionKey);
a.setCaption(getActionCaption(actionKey));
a.setIconUrl(getActionIcon(actionKey));
actions[i]
= a;
}
return actions;
}
public ApplicationConnection getClient() {
return client;
}
public String getPaintableId() {
return paintableId;
}
/**
* Adds/removes Vaadin specific style name. This method ought to be
* called only from VITree.
*
* @param selected
*/
protected void setSelected(boolean selected) {
// add style name to caption dom structure only, not to subtree
setStyleName(nodeCaptionDiv, "v-tree-node-selected", selected);
}
protected boolean isSelected() {
return VITree.this.isSelected(this);
}
public void showContextMenu(Event event) {
if (!readonly && !disabled) {
if (actionKeys != null) {
int left = event.getClientX();
int top = event.getClientY();
top += Window.getScrollTop();
left += Window.getScrollLeft();
client.getContextMenu().showAt(this, left, top);
}
event.cancelBubble(true);
event.preventDefault();
}
}
/*
* We need to fix the width of TreeNodes so that the float in
* ie6compatNode does not wrap (see ticket #1245)
*/
private void fixWidth() {
nodeCaptionDiv.getStyle().setProperty("styleFloat", "left");
nodeCaptionDiv.getStyle().setProperty("display", "inline");
nodeCaptionDiv.getStyle().setProperty("marginLeft", "0");
final int captionWidth = ie6compatnode.getOffsetWidth()
+ nodeCaptionDiv.getOffsetWidth();
setWidth(captionWidth + "px");
}
@Override
public void onAttach() {
super.onAttach();
if (ie6compatnode != null) {
fixWidth();
}
}
}
}
I hope anyone can help me.