/**
* Copyright (c) 2014 by JP Moresmau
* This code is made available under the terms of the Eclipse Public License,
* version 1.0 (EPL). See http://www.eclipse.org/legal/epl-v10.html
*/
package net.sf.eclipsefp.haskell.ui.internal.views.worksheet;
import java.util.Iterator;
import net.sf.eclipsefp.haskell.ui.HaskellUIPlugin;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.ui.model.WorkbenchViewerComparator;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
/**
* A JSON Content provider, to show JSON content in a tree
* @author JP Moresmau
*
*/
public class JSONContentProvider implements ITreeContentProvider {
/**
*
*/
public JSONContentProvider() {
// noop
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.IContentProvider#dispose()
*/
@Override
public void dispose() {
// noop
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object)
*/
@Override
public void inputChanged( final Viewer viewer, final Object oldInput, final Object newInput ) {
// noop
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ITreeContentProvider#getElements(java.lang.Object)
*/
@Override
public Object[] getElements( final Object inputElement ) {
if (inputElement instanceof JSONObject){
JSONObject obj=(JSONObject)inputElement;
Object[] ret=new Object[obj.length()];
int a=0;
for (Iterator<String> it=obj.keys();it.hasNext();){
String name=it.next();
ret [a++]= new ObjectNode(obj,name);
}
return ret;
} else if (inputElement instanceof JSONArray){
JSONArray arr=(JSONArray)inputElement;
Object[] ret=new Object[arr.length()];
for (int a=0;a<arr.length();a++){
ret[a]=new ArrayNode( arr, a );
}
return ret;
}
return new Object[]{inputElement};
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java.lang.Object)
*/
@Override
public Object[] getChildren( final Object parentElement ) {
try {
if (parentElement instanceof ObjectNode){
ObjectNode on=(ObjectNode)parentElement;
return getElements( on.obj.get( on.name ) );
} else if (parentElement instanceof ArrayNode){
ArrayNode an=(ArrayNode)parentElement;
return getElements( an.arr.get( an.idx ) );
}
} catch (JSONException jsone){
HaskellUIPlugin.log( jsone );
}
return null;
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ITreeContentProvider#getParent(java.lang.Object)
*/
@Override
public Object getParent( final Object element ) {
return null;
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java.lang.Object)
*/
@Override
public boolean hasChildren( final Object element ) {
if (element instanceof JSONObject){
return ((JSONObject)element).length()>0;
} else if (element instanceof ObjectNode){
return true;
} else if (element instanceof JSONArray){
return ((JSONArray)element).length()>0;
}else if (element instanceof ArrayNode){
return true;
}
return false;
}
/**
* Wraps the JSONObject + name of key
* @author JP Moresmau
*
*/
private static class ObjectNode {
JSONObject obj;
String name;
public ObjectNode( final JSONObject obj, final String name ) {
super();
this.obj = obj;
this.name = name;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return name;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ( ( name == null ) ? 0 : name.hashCode() );
result = prime * result + ( ( obj == null ) ? 0 : obj.hashCode() );
return result;
}
/**
* we know that JSONObject doesn't implement equals, but that's fine, we want pointer equality on the JSON object
*/
@Override
public boolean equals( final Object obj ) {
if( this == obj ) {
return true;
}
if( obj == null ) {
return false;
}
if( getClass() != obj.getClass() ) {
return false;
}
ObjectNode other = ( ObjectNode )obj;
if( name == null ) {
if( other.name != null ) {
return false;
}
} else if( !name.equals( other.name ) ) {
return false;
}
if( this.obj == null ) {
if( other.obj != null ) {
return false;
}
} else if( !this.obj.equals( other.obj ) ) {
return false;
}
return true;
}
}
/**
* Wraps a JSONArray + index of value
* @author JP Moresmau
*
*/
private static class ArrayNode {
JSONArray arr;
int idx;
public ArrayNode( final JSONArray arr, final int idx ) {
super();
this.arr = arr;
this.idx = idx;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return String.valueOf( idx );
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ( ( arr == null ) ? 0 : arr.hashCode() );
result = prime * result + idx;
return result;
}
/**
* we know that JSONArray doesn't implement equals, but that's fine, we want pointer equality on the JSON array
*/
@Override
public boolean equals( final Object obj ) {
if( this == obj ) {
return true;
}
if( obj == null ) {
return false;
}
if( getClass() != obj.getClass() ) {
return false;
}
ArrayNode other = ( ArrayNode )obj;
if( arr == null ) {
if( other.arr != null ) {
return false;
}
} else if( !arr.equals( other.arr ) ) {
return false;
}
if( idx != other.idx ) {
return false;
}
return true;
}
}
/**
* Ensure JSON Array values are sorted properly by index
* @author JP Moresmau
*
*/
public static class JSONComparator extends WorkbenchViewerComparator {
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ViewerComparator#compare(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object)
*/
@Override
public int compare( final Viewer viewer, final Object e1, final Object e2 ) {
if (e1 instanceof ArrayNode && e2 instanceof ArrayNode){
ArrayNode an1=(ArrayNode)e1;
ArrayNode an2=(ArrayNode)e2;
return Integer.valueOf( an1.idx).compareTo(an2.idx);
}
return super.compare( viewer, e1, e2 );
}
}
}