// Copyright 2012 Google Inc. All Rights Reserved.
//
// 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 collide.client.filetree;
import collide.client.common.CommonResources;
import collide.client.treeview.NodeRenderer;
import collide.client.treeview.Tree;
import collide.client.treeview.TreeNodeElement;
import collide.client.treeview.TreeNodeMutator;
import collide.client.util.CssUtils;
import collide.client.util.Elements;
import com.google.collide.client.workspace.WorkspaceUtils;
import com.google.collide.dto.DirInfo;
import com.google.collide.json.client.JsoStringMap;
import elemental.dom.Element;
import elemental.events.Event;
import elemental.events.EventListener;
import elemental.events.MouseEvent;
import elemental.html.AnchorElement;
import elemental.html.SpanElement;
/**
* Renderer for nodes in the file tree.
*/
public class FileTreeNodeRenderer implements NodeRenderer<FileTreeNode> {
public static FileTreeNodeRenderer create(Resources res) {
return new FileTreeNodeRenderer(res);
}
public static interface Css extends TreeNodeMutator.Css {
String file();
String cssIcon();
String emptyFolder();
String emptyPackageIcon();
String folder();
String htmlIcon();
String jarIcon();
String javaIcon();
String javascriptIcon();
String xmlIcon();
String packageIcon();
String folderOpen();
String folderLoading();
String icon();
String label();
String root();
@Override
String nodeNameInput();
}
public static interface Resources extends CommonResources.BaseResources, Tree.Resources {
@Source({"FileTreeNodeRenderer.css", "collide/client/common/constants.css"})
Css workspaceNavigationFileTreeNodeRendererCss();
}
/**
* Renders the given information as a node.
* @param fileTypes
* @param b
*
* @param mouseDownListener an optional listener to be attached to the anchor. If not given, the
* label will not be an anchor.
*/
public static SpanElement renderNodeContents(
Css css, String name, boolean isFile, boolean isPackage, JsoStringMap<String> fileTypes, EventListener mouseDownListener, boolean renderIcon) {
SpanElement root = Elements.createSpanElement(css.root());
if (renderIcon) {
SpanElement icon = Elements.createSpanElement(css.icon());
if (isFile) {
String clsName = css.file();
int ind = name.lastIndexOf('.');
if (ind > -1) {
String type = name.substring(ind+1);
if (fileTypes.containsKey(type)) {
clsName = fileTypes.get(type);
}
}
icon.addClassName(clsName);
} else {
if (isPackage) {
icon.addClassName(css.packageIcon());
} else {
icon.addClassName(css.folder());
}
}
root.appendChild(icon);
}
final Element label;
if (mouseDownListener != null) {
label = Elements.createAnchorElement(css.label());
((AnchorElement) label).setHref("javascript:;");
label.addEventListener(Event.MOUSEDOWN, mouseDownListener, false);
} else {
label = Elements.createSpanElement(css.label());
}
label.setTextContent(name);
root.appendChild(label);
return root;
}
private final EventListener mouseDownListener = new EventListener() {
@Override
public void handleEvent(Event evt) {
MouseEvent event = (MouseEvent) evt;
AnchorElement anchor = (AnchorElement) evt.getTarget();
if (event.getButton() == MouseEvent.Button.AUXILIARY) {
Element parent = CssUtils.getAncestorOrSelfWithClassName(anchor, res.treeCss().treeNode());
if (parent != null) {
@SuppressWarnings("unchecked")
TreeNodeElement<FileTreeNode> fileNode = (TreeNodeElement<FileTreeNode>) parent;
anchor.setHref(
WorkspaceUtils.createDeepLinkToFile(fileNode.getData().getNodePath()));
}
}
}
};
private final Css css;
private final Resources res;
private final JsoStringMap<String> fileTypes;
private FileTreeNodeRenderer(Resources resources) {
this.res = resources;
this.css = res.workspaceNavigationFileTreeNodeRendererCss();
fileTypes = createFileTypeMap(css);
}
public static JsoStringMap<String> createFileTypeMap(Css css) {
JsoStringMap<String> fileTypes = JsoStringMap.create();
fileTypes.put("css", css.cssIcon());
fileTypes.put("html", css.htmlIcon());
fileTypes.put("jar", css.jarIcon());
fileTypes.put("java", css.javaIcon());
fileTypes.put("js", css.javascriptIcon());
fileTypes.put("xml", css.xmlIcon());
return fileTypes;
}
@Override
public Element getNodeKeyTextContainer(SpanElement treeNodeLabel) {
return (Element) treeNodeLabel.getChildNodes().item(1);
}
@Override
public SpanElement renderNodeContents(FileTreeNode data) {
if (data.isDirectory()) {
DirInfo dir = (DirInfo) data;
return renderNodeContents(css, data.getName(), data.isFile(), dir.isPackage(), fileTypes, mouseDownListener, true);
} else {
return renderNodeContents(css, data.getName(), data.isFile(), false, fileTypes, mouseDownListener, true);
}
}
@Override
public void updateNodeContents(TreeNodeElement<FileTreeNode> treeNode) {
if (treeNode.getData().isDirectory()) {
// Update folder icon based on icon state.
Element icon = treeNode.getNodeLabel().getFirstChildElement();
icon.setClassName(css.icon());
if (treeNode.getData().isLoading()) {
icon.addClassName(css.folderLoading());
} else if (((DirInfo)treeNode.getData()).isPackage()) {
icon.addClassName(css.packageIcon());
} else if (treeNode.isOpen()) {
icon.addClassName(css.folderOpen());
} else {
icon.addClassName(css.folder());
}
}
}
}