/*
* Copyright 2008 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 com.google.gwt.topspin.desktop.client;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.SpanElement;
import com.google.gwt.dom.client.UListElement;
import com.google.gwt.events.client.Event;
import com.google.gwt.events.client.EventListener;
import com.google.gwt.topspin.ui.client.ClickEvent;
import com.google.gwt.topspin.ui.client.Container;
import com.google.gwt.topspin.ui.client.DefaultContainerImpl;
import com.google.gwt.topspin.ui.client.Widget;
/**
* A standard hierarchical tree widget. The tree contains a hierarchy of
* {@link Tree.Item tree items} that the user can open, close, and select.
*
* TODO(jgw): There's still a lot of missing functionality here, most notably
* keyboard support.
*/
public class Tree extends Widget {
/**
* A widget representing a single item within the tree.
*
* TODO(jgw): Item should not have the setText() or setHtml() methods.
* Instead, we should create an 'html item' and a 'container item' that can
* handle widgets. Having these two things conflated in the original GWT Tree
* is an unnecessary source of complexity.
*/
public static class Item extends Widget {
private Item parent;
private Tree tree;
private SpanElement contentSpan;
private UListElement childList;
private Container defaultContainer;
/**
* Creates a new Item as a child of an existing item.
*
* @param parent the item's parent
*/
public Item(Item parent) {
this(parent.ensureContainer());
this.parent = parent;
this.tree = parent.tree;
sinkEvents();
}
/**
* Creates a new Item at the root of a {@link Tree}.
*
* @param tree the item's tree
*/
public Item(Tree tree) {
this(tree.defaultContainer);
this.tree = tree;
sinkEvents();
}
private Item(Container container) {
super(container.getDocument().createLIElement(), container);
contentSpan = container.getDocument().createSpanElement();
getElement().appendChild(contentSpan);
getElement().setClassName("gwt-TreeItem");
getElement().getStyle().setPropertyPx("paddingLeft", 16);
getElement().getStyle().setProperty("listStyleType", "none");
}
/**
* Gets this item's parent item.
*
* @return the item's parent, or <code>null</code> if it is a root item
*/
public Item getParent() {
return parent;
}
/**
* Gets whether this item is currently open or closed.
*
* @return <code>true</code> if the item is open
*/
public boolean isOpen() {
if (childList == null) {
return false;
}
return !"none".equals(childList.getStyle().getProperty("display"));
}
/**
* Sets whether this item is open or closed.
*
* @param open <code>true</code> to open the item, <code>false</code> to
* close it
*/
public void setOpen(boolean open) {
if (childList != null) {
childList.getStyle().setProperty("display", open ? "" : "none");
}
}
/**
* Sets the item's text contents.
*
* @param text the text contents
* @deprecated this method will be replaced with two tab subclasses, as
* described in the comment above.
*/
public void setText(String text) {
contentSpan.setInnerText(text);
}
private void ensureChildList() {
if (childList == null) {
childList = getElement().getOwnerDocument().createULElement();
childList.getStyle().setPropertyPx("paddingLeft", 0);
getElement().appendChild(childList);
}
}
private Container ensureContainer() {
if (defaultContainer == null) {
ensureChildList();
defaultContainer = new DefaultContainerImpl(getElement());
}
return defaultContainer;
}
private void sinkEvents() {
EventListener listener = new EventListener() {
public void handleEvent(Event event) {
Element srcElement = event.getTarget();
if (srcElement.equals(contentSpan)) {
// TODO: selection
} else {
setOpen(!isOpen());
}
event.cancelBubble(true);
}
};
Event.addEventListener(ClickEvent.NAME, getElement(), listener);
Event.addEventListener(ClickEvent.NAME, contentSpan, listener);
}
}
private final Container defaultContainer = new DefaultContainerImpl(
getElement());
/**
* Creates a new Tree widget in the given container.
*
* @param container the container in which the widget will be created
*/
public Tree(Container container) {
super(container.getDocument().createULElement(), container);
getElement().getStyle().setPropertyPx("paddingLeft", 0);
}
}