blob: 08d4fd27b0aa1c7f9dcb01d9eabcc7e88df963a4 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.wst.xml.ui.internal.views.contentmodel;
import java.util.ArrayList;
import java.util.EmptyStackException;
import java.util.List;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.ui.model.IWorkbenchAdapter;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.eclipse.wst.xml.core.internal.contentmodel.CMAttributeDeclaration;
import org.eclipse.wst.xml.core.internal.contentmodel.CMDataType;
import org.eclipse.wst.xml.core.internal.contentmodel.CMElementDeclaration;
import org.eclipse.wst.xml.core.internal.contentmodel.CMGroup;
import org.eclipse.wst.xml.core.internal.contentmodel.CMNamedNodeMap;
import org.eclipse.wst.xml.core.internal.contentmodel.CMNode;
import org.eclipse.wst.xml.core.internal.contentmodel.util.CMVisitor;
import org.eclipse.wst.xml.ui.internal.XMLUIPlugin;
import org.eclipse.wst.xml.ui.internal.editor.XMLEditorPluginImages;
public class CMListWorkbenchAdapter extends CMVisitor implements IWorkbenchAdapter {
private CMElementDeclaration fDeclaration;
private String text;
private ImageDescriptor image;
private GroupStack fGroupStack;
private CMDescriber fRoot;
public CMListWorkbenchAdapter(CMElementDeclaration decl) {
text = getFormattedLabel(decl.getNodeName(), decl.getMinOccur(), decl.getMaxOccur(), decl.getDataType());
fDeclaration = decl;
image = AbstractUIPlugin.imageDescriptorFromPlugin(XMLUIPlugin.ID, XMLEditorPluginImages.IMG_OBJ_ELEMENT);
fGroupStack = new GroupStack();
fRoot = new CMDescriber(decl);
}
public Object[] getChildren(Object o) {
/* TODO Use the CMElementDeclaration and ModelQuery to get the available children of the root element */
return fRoot.getChildren(o);
}
public ImageDescriptor getImageDescriptor(Object object) {
return image;
}
public String getLabel(Object o) {
return text;
}
public Object getParent(Object o) {
return fDeclaration;
}
/**
* Formats the label for an element declaration. The format will be: <b>name</b> [<i>min</i>..<i>max</i>], where <i>max</i> when unbounded is represented by <b>*</b>
* @param name The name of the element declaration
* @param min The minimum number of occurrences of the element
* @param max The maximum number of occurrences of the element
* @return The formatted label String
*/
static String getFormattedLabel(String name, int min, int max, CMDataType dataType) {
StringBuffer buffer = new StringBuffer(name);
buffer.append('[');
buffer.append(min);
buffer.append(".."); //$NON-NLS-1$
buffer.append((max >= 0 ? Integer.toString(max) : "*")); //$NON-NLS-1$
buffer.append(']');
if (dataType != null) {
buffer.append(" {"); //$NON-NLS-1$
buffer.append(dataType.getDataTypeName());
buffer.append('}');
}
return buffer.toString();
}
/**
* Workbench adapter that describes its CMNode. It calculates its children lazily using the CMVisitor
* to identify immediate children (i.e., the content of child nodes is not visited).
*
*/
private class CMDescriber extends CMVisitor implements IWorkbenchAdapter {
List fChildren = null;
ImageDescriptor fImage;
String label;
CMNode root;
public CMDescriber(CMNode node) {
root = node;
}
public Object[] getChildren(Object o) {
if (fChildren == null) {
fChildren = new ArrayList();
if (root.getNodeType() == CMNode.ELEMENT_DECLARATION) {
CMElementDeclaration ed = (CMElementDeclaration) root;
CMNamedNodeMap nodeMap = ed.getAttributes();
int size = nodeMap.getLength();
for (int i = 0; i < size; i++) {
visitCMNode(nodeMap.item(i));
}
visitCMNode(ed.getContent());
}
}
return fChildren.toArray();
}
public ImageDescriptor getImageDescriptor(Object object) {
return fImage;
}
public void setImage(String path) {
fImage = AbstractUIPlugin.imageDescriptorFromPlugin(XMLUIPlugin.ID, path);
}
public String getLabel(Object o) {
return label;
}
public Object getParent(Object o) {
return root;
}
public void visitCMGroup(CMGroup e) {
fGroupStack.push(e.getMaxOccur());
super.visitCMGroup(e);
fGroupStack.pop();
}
public void visitCMAttributeDeclaration(CMAttributeDeclaration ad) {
CMDescriber describer = new CMDescriber(ad);
describer.label = ad.getNodeName();
describer.setImage(XMLEditorPluginImages.IMG_OBJ_ATTRIBUTE);
fChildren.add(describer);
}
public void visitCMElementDeclaration(CMElementDeclaration ed) {
CMDescriber describer = new CMDescriber(ed);
// If the parent group stack containing this element declaration is unbounded, the element within is unbounded as well
describer.label = getFormattedLabel(ed.getNodeName(), ed.getMinOccur(), (!fGroupStack.isEmpty() && fGroupStack.peek() < 0) ? -1 : ed.getMaxOccur(), ed.getDataType());
describer.setImage(XMLEditorPluginImages.IMG_OBJ_ELEMENT);
fChildren.add(describer);
}
}
/**
* A stack of integers used to determine if an element declaration is unbounded
*
*/
private static class GroupStack {
int[] stack;
int size;
public GroupStack() {
stack = new int[5];
}
public void push(int i) {
if (size >= stack.length) {
int[] tmp = stack;
stack = new int[stack.length * 2];
System.arraycopy(tmp, 0, stack, 0, tmp.length);
}
stack[size++] = i;
}
public int pop() {
if (isEmpty())
throw new EmptyStackException();
return stack[--size];
}
public boolean isEmpty() {
return size == 0;
}
public int peek() {
if (isEmpty())
throw new EmptyStackException();
return stack[size - 1];
}
}
}