package tk.eclipse.plugin.dtdeditor.editors;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import jp.aonir.fuzzyxml.internal.FuzzyXMLUtil;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
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.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.views.contentoutline.ContentOutlinePage;
import tk.eclipse.plugin.htmleditor.HTMLPlugin;
import tk.eclipse.plugin.htmleditor.editors.IHTMLOutlinePage;
/**
* IContentOutlinePage implementation for DTDEditor.
*
* @author Naoki Takezoe
* @see tk.eclipse.plugin.dtdeditor.editors.DTDEditor
*/
public class DTDOutlinePage extends ContentOutlinePage implements IHTMLOutlinePage {
private DTDEditor editor;
private DTDRootNode root;
public DTDOutlinePage(DTDEditor editor){
this.editor = editor;
}
@Override
public void createControl(Composite parent) {
super.createControl(parent);
TreeViewer viewer = getTreeViewer();
if(root==null){
root = new DTDRootNode();
}
viewer.setContentProvider(new DTDContentProvider());
viewer.setLabelProvider(new DTDLabelProvider());
viewer.setInput(root);
viewer.addSelectionChangedListener(new DTDSelectionChangedListener());
update();
}
public void update() {
String source = editor.getDocumentProvider().getDocument(editor.getEditorInput()).get();
source = FuzzyXMLUtil.comment2space(source, true);
if(root==null){
root = new DTDRootNode();
}
root.clear();
int index = 0;
int last = 0;
Map<String, List<DTDNode>> attrMap = new HashMap<String, List<DTDNode>>();
Map<String, DTDNode> elementMap = new HashMap<String, DTDNode>();
while((index = source.indexOf("<!", last))>=0){
if(source.startsWith("<!ELEMENT",index)){
String text = source.substring(index, source.indexOf(">", index)+1);
text = text.replaceAll("\\s+"," ");
String[] dim = text.split(" ");
DTDNode node = new DTDNode(index, text, HTMLPlugin.ICON_ELEMENT);
elementMap.put(dim[1], node);
root.add(node);
}
else if(source.startsWith("<!ATTLIST",index)){
String text = source.substring(index, source.indexOf(">", index)+1);
text = text.replaceAll("\\s+"," ");
String[] dim = text.split(" ");
List<DTDNode> list = attrMap.get(dim[1]);
if(list==null){
list = new ArrayList<DTDNode>();
attrMap.put(dim[1], list);
}
list.add(new DTDNode(index, text, HTMLPlugin.ICON_ATTLIST));
}
else if(source.startsWith("<!ENTITY",index)){
String text = source.substring(index, source.indexOf(">", index)+1);
text = text.replaceAll("\\s+"," ");
root.add(new DTDNode(index, text, HTMLPlugin.ICON_ENTITY));
}
else if(source.startsWith("<!NOTATION",index)){
String text = source.substring(index, source.indexOf(">", index)+1);
text = text.replaceAll("\\s+"," ");
root.add(new DTDNode(index, text, HTMLPlugin.ICON_NOTATE));
}
// else if(source.startsWith("<!--", index)){
// root.add(new DTDNode(index, "#comment", HTMLPlugin.ICON_COMMENT));
// }
last = index + 2;
}
// put ATTLIST to ELEMENT
for(Iterator<Map.Entry<String, List<DTDNode>>> ite = attrMap.entrySet().iterator(); ite.hasNext();){
Map.Entry<String, List<DTDNode>> entry = ite.next();
String key = entry.getKey();
List attrs = entry.getValue();
DTDNode element = elementMap.get(key);
for(int i=0;i<attrs.size();i++){
DTDNode attr = (DTDNode)attrs.get(i);
if(element==null){
root.add(attr);
} else {
element.addChild(attr);
}
}
}
TreeViewer viewer = getTreeViewer();
if(viewer!=null){
viewer.refresh();
}
}
/** The root node of this outline page. */
private class DTDRootNode {
private List<DTDNode> children = new ArrayList<DTDNode>();
public void add(DTDNode node){
children.add(node);
}
public DTDNode[] getChildren(){
return this.children.toArray(new DTDNode[this.children.size()]);
}
public void clear(){
this.children.clear();
}
}
/** The node class for DTD elements. */
private class DTDNode {
private int position;
private String text;
private String image;
private List<DTDNode> children = new ArrayList<DTDNode>();
private DTDNode parent;
public DTDNode(int position, String text, String image){
this.position = position;
this.text = text;
this.image = image;
}
public int getPosition(){
return this.position;
}
public void addChild(DTDNode node){
this.children.add(node);
}
public DTDNode[] getChildren(){
return this.children.toArray(new DTDNode[this.children.size()]);
}
public void setParent(DTDNode parent){
this.parent = parent;
}
public DTDNode getParent(){
return this.parent;
}
@Override
public String toString(){
return this.text;
}
public String getImage(){
return this.image;
}
}
/** ContentProvider of HTMLOutlinePage. */
private class DTDContentProvider implements ITreeContentProvider {
public Object[] getChildren(Object parentElement) {
if(parentElement instanceof DTDRootNode){
return ((DTDRootNode)parentElement).getChildren();
} else if(parentElement instanceof DTDNode){
return ((DTDNode)parentElement).getChildren();
}
return new Object[0];
}
public Object getParent(Object element) {
if(element instanceof DTDNode){
DTDNode parent = ((DTDNode)element).getParent();
if(parent==null){
return root;
} else {
return parent;
}
}
return null;
}
public boolean hasChildren(Object element) {
if(getChildren(element).length==0){
return false;
} else {
return true;
}
}
public Object[] getElements(Object inputElement) {
return getChildren(inputElement);
}
public void dispose() {
}
public void inputChanged(Viewer viewer, Object oldInput,Object newInput) {
}
}
/** LabelProvider of HTMLOutlinePage */
private class DTDLabelProvider extends LabelProvider {
@Override
public Image getImage(Object element) {
if(element instanceof DTDNode){
return HTMLPlugin.getDefault().getImageRegistry().get(((DTDNode)element).getImage());
}
return null;
}
}
/** This listener is called when selection of TreeViewer is changed. */
private class DTDSelectionChangedListener implements ISelectionChangedListener {
public void selectionChanged(SelectionChangedEvent event) {
IStructuredSelection sel = (IStructuredSelection)event.getSelection();
Object element = sel.getFirstElement();
if(element instanceof DTDNode){
int offset = ((DTDNode)element).getPosition();
IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
IEditorPart editorPart = page.getActiveEditor();
if(editorPart instanceof DTDEditor){
((DTDEditor)editorPart).selectAndReveal(offset, 0);
}
}
}
}
}