/* * Copyright 2012 Amazon Technologies, 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://aws.amazon.com/apache2.0 * * This file 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.amazonaws.eclipse.cloudformation.templates.editor; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Map.Entry; import java.util.Set; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.ILabelProviderListener; import org.eclipse.jface.viewers.IOpenListener; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.OpenEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.TreeItem; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.views.contentoutline.ContentOutlinePage; import com.amazonaws.eclipse.cloudformation.templates.TemplateArrayNode; import com.amazonaws.eclipse.cloudformation.templates.TemplateNode; import com.amazonaws.eclipse.cloudformation.templates.TemplateObjectNode; import com.amazonaws.eclipse.cloudformation.templates.TemplateValueNode; import com.amazonaws.eclipse.cloudformation.templates.editor.TemplateEditor.TemplateDocument; import com.amazonaws.eclipse.cloudformation.templates.editor.TemplateEditor.TemplateDocumentListener; import com.fasterxml.jackson.core.JsonLocation; public class TemplateContentOutlinePage extends ContentOutlinePage implements TemplateDocumentListener { private final TemplateDocument document; public TemplateContentOutlinePage(TemplateDocument document) { this.document = document; } @Override public void dispose() { // TODO: Remove the document listener super.dispose(); } public void createControl(Composite parent) { super.createControl(parent); final TreeViewer viewer = getTreeViewer(); viewer.setContentProvider(new TemplateOutlineContentProvider()); viewer.setLabelProvider(new TemplateOutlineLabelProvider()); viewer.addSelectionChangedListener(this); viewer.setAutoExpandLevel(2); viewer.addOpenListener(new IOpenListener() { public void open(OpenEvent event) { TemplateOutlineNode selectedNode = (TemplateOutlineNode)((StructuredSelection)event.getSelection()).getFirstElement(); JsonLocation startLocation = selectedNode.getNode().getStartLocation(); JsonLocation endLocation = selectedNode.getNode().getEndLocation(); IEditorPart activeEditor = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor(); if (activeEditor != null) { TemplateEditor templateEditor = (TemplateEditor)activeEditor; templateEditor.setHighlightRange( (int)startLocation.getCharOffset(), (int)endLocation.getCharOffset() - (int)startLocation.getCharOffset(), true); } } }); document.addTemplateDocumentListener(this); updateContent(); } // TODO: move/rename me private Set<String> expandedPaths = new HashSet<String>(); private void updateContent() { TreeViewer viewer = getTreeViewer(); if (document.getModel() == null) return; expandedPaths = new HashSet<String>(); for (Object obj : viewer.getExpandedElements()) { TemplateOutlineNode expandedNode = (TemplateOutlineNode)obj; expandedPaths.add(expandedNode.getNode().getPath()); } viewer.setInput(new TemplateOutlineNode("ROOT", document.getModel())); for (TreeItem treeItem : viewer.getTree().getItems()) { expandTreeItems(treeItem, expandedPaths); } } private void expandTreeItems(TreeItem treeItem, Set<String> paths) { TemplateOutlineNode node = (TemplateOutlineNode)treeItem.getData(); if (node == null) return; if (paths.contains(node.getNode().getPath())) { getTreeViewer().setExpandedState(node, true); getTreeViewer().refresh(node, true); } for (TreeItem child : treeItem.getItems()) { expandTreeItems(child, paths); } } public class TemplateOutlineLabelProvider implements ILabelProvider { public void dispose() {} public void addListener(ILabelProviderListener listener) {} public void removeListener(ILabelProviderListener listener) {} public boolean isLabelProperty(Object element, String property) { return false; } public Image getImage(Object element) { return null; } public String getText(Object element) { if (element instanceof TemplateOutlineNode == false) return null; TemplateOutlineNode node = (TemplateOutlineNode)element; return node.getText(); } } public class TemplateOutlineNode { private final String text; private TemplateNode node; public TemplateOutlineNode(String text, TemplateNode node) { this.text = text; this.node = node; } @Override public boolean equals(Object arg0) { if (arg0 instanceof TemplateOutlineNode == false) return false; TemplateOutlineNode other = (TemplateOutlineNode)arg0; return (other.getNode().equals(node)); } public TemplateNode getNode() { return node; } @Override public int hashCode() { if (node == null) { return 0; } return node.hashCode(); } public String getText() { return text; } public TemplateOutlineNode[] getChildren() { if (node == null) return new TemplateOutlineNode[0]; List<TemplateOutlineNode> children = new ArrayList<TemplateOutlineNode>(); if (node.isObject()) { TemplateObjectNode object = (TemplateObjectNode)node; for (Entry<String, TemplateNode> entry : object.getFields()) { if (entry.getValue().isValue()) { children.add(new TemplateOutlineNode(entry.getKey() + ": " + ((TemplateValueNode)entry.getValue()).getText(), entry.getValue())); } else { children.add(new TemplateOutlineNode(entry.getKey(), entry.getValue())); } } } else if (node.isArray()) { TemplateArrayNode array = (TemplateArrayNode)node; for (TemplateNode node : array.getMembers()) { if (node.isObject()) children.add(new TemplateOutlineNode("{Object}", node)); if (node.isArray()) children.add(new TemplateOutlineNode("{Array}", node)); if (node.isValue()) children.add(new TemplateOutlineNode(((TemplateValueNode)node).getText(), node)); } } return children.toArray(new TemplateOutlineNode[0]); } } public class TemplateOutlineContentProvider implements ITreeContentProvider { public void dispose() {} private TemplateOutlineNode root; public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { if (newInput == null) { root = null; } else if (newInput instanceof TemplateOutlineNode) { root = (TemplateOutlineNode)newInput; } else if (newInput instanceof TemplateObjectNode) { root = new TemplateOutlineNode("ROOT/", (TemplateObjectNode)newInput); } else { throw new RuntimeException("Unexpected input!!!"); } } public Object[] getElements(Object inputElement) { return getChildren(inputElement); } public Object[] getChildren(Object parentElement) { if (root == null) return new Object[0]; if (parentElement instanceof TemplateOutlineNode) { return ((TemplateOutlineNode)parentElement).getChildren(); } return null; } public Object getParent(Object element) { return null; } public boolean hasChildren(Object element) { if (element instanceof TemplateOutlineNode) { return ((TemplateOutlineNode) element).getChildren().length > 0; } else { return false; } } } public void templateDocumentChanged() { updateContent(); } }