/*
* Copyright (c) 2012 Data Harmonisation Panel
*
* All rights reserved. This program and the accompanying materials are made
* available under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution. If not, see <http://www.gnu.org/licenses/>.
*
* Contributors:
* HUMBOLDT EU Integrated Project #030962
* Data Harmonisation Panel <http://www.dhpanel.eu>
*/
package eu.esdihumboldt.hale.ui.instancevalidation.report;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javax.xml.namespace.QName;
import org.eclipse.jface.viewers.ITreePathContentProvider;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.ui.PlatformUI;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import eu.esdihumboldt.hale.common.instance.extension.validation.report.InstanceValidationMessage;
import eu.esdihumboldt.hale.common.schema.SchemaSpaceID;
import eu.esdihumboldt.hale.common.schema.model.ChildDefinition;
import eu.esdihumboldt.hale.common.schema.model.Definition;
import eu.esdihumboldt.hale.common.schema.model.DefinitionUtil;
import eu.esdihumboldt.hale.common.schema.model.TypeDefinition;
import eu.esdihumboldt.hale.ui.service.schema.SchemaService;
/**
* Content provider for the instance validation report details page.
*
* @author Kai Schwierczek
*/
public class InstanceValidationReportDetailsContentProvider implements ITreePathContentProvider {
/**
* Maximum number of messages shown for one path/category.
*/
public static final int LIMIT = 5;
private final Map<TreePath, Set<Object>> childCache = new HashMap<TreePath, Set<Object>>();
private final Multimap<TreePath, InstanceValidationMessage> messages = ArrayListMultimap
.create();
private final Set<TreePath> limitedPaths = new HashSet<TreePath>();
/**
* @see ITreePathContentProvider#dispose()
*/
@Override
public void dispose() {
childCache.clear();
messages.clear();
limitedPaths.clear();
}
/**
* @see ITreePathContentProvider#inputChanged(Viewer, Object, Object)
*/
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
childCache.clear();
messages.clear();
limitedPaths.clear();
if (newInput instanceof Collection<?>) {
SchemaService ss = PlatformUI.getWorkbench().getService(SchemaService.class);
TreePath emptyPath = new TreePath(new Object[0]);
for (Object o : (Collection<?>) newInput) {
if (o instanceof InstanceValidationMessage) {
InstanceValidationMessage message = ((InstanceValidationMessage) o);
Set<Object> baseTypes = childCache.get(emptyPath);
if (baseTypes == null) {
baseTypes = new HashSet<Object>();
childCache.put(emptyPath, baseTypes);
}
// XXX maybe expand messages with SSID?
TypeDefinition typeDef = ss.getSchemas(SchemaSpaceID.TARGET)
.getType(message.getType());
// use typeDef if available, QName otherwise
Object use = typeDef == null ? message.getType() : typeDef;
if (use == null) {
// fall-back to generic category
use = "General";
}
baseTypes.add(use);
messages.put(new TreePath(new Object[] { use }), message);
}
}
}
}
/**
* @see ITreePathContentProvider#getElements(Object)
*/
@Override
public Object[] getElements(Object inputElement) {
Set<Object> baseTypes = childCache.get(new TreePath(new Object[0]));
if (baseTypes == null)
return new Object[0];
return baseTypes.toArray();
}
/**
* @see ITreePathContentProvider#getChildren(TreePath)
*/
@Override
public Object[] getChildren(TreePath parentPath) {
Set<Object> children = childCache.get(parentPath);
if (children == null) {
Collection<InstanceValidationMessage> ivms = messages.get(parentPath);
if (!ivms.isEmpty()) {
children = new HashSet<Object>();
// count of added messages
int messageCount = 0;
for (InstanceValidationMessage message : ivms) {
if (message.getPath().size() > parentPath.getSegmentCount() - 1) {
// path not done, add next segment
QName name = message.getPath().get(parentPath.getSegmentCount() - 1);
Object child = name;
Object parent = parentPath.getLastSegment();
if (parent instanceof Definition<?>) {
ChildDefinition<?> childDef = DefinitionUtil
.getChild((Definition<?>) parent, name);
if (childDef != null)
child = childDef;
}
children.add(child);
messages.put(parentPath.createChildPath(child), message);
}
else if (message.getPath().size() == parentPath.getSegmentCount() - 1) {
// path done, go by category
String category = message.getCategory();
children.add(category);
messages.put(parentPath.createChildPath(category), message);
}
else {
// all done, add as child
if (messageCount < LIMIT) {
children.add(message);
messageCount++;
}
else {
limitedPaths.add(parentPath);
}
}
}
}
else
children = Collections.emptySet();
childCache.put(parentPath, children);
}
return children.toArray();
}
/**
* Returns the number of messages that are children of the given path.
*
* @param path the path
* @return the number of messages that are children of the given path
*/
public int getMessageCount(TreePath path) {
return messages.get(path).size();
}
/**
* Returns whether the given path has more instances available than those
* which are shown.
*
* @see #LIMIT
* @param path the path
* @return whether the given path has more instances available than those
* which are shown
*/
public boolean isLimited(TreePath path) {
getChildren(path); // get children so limitedPaths is updated
return limitedPaths.contains(path);
}
/**
* Returns all messages that are children of the given path.
*
* @param path the path
* @return all messages that are children of the given path
*/
public Collection<InstanceValidationMessage> getMessages(TreePath path) {
return messages.get(path);
}
/**
* @see ITreePathContentProvider#hasChildren(TreePath)
*/
@Override
public boolean hasChildren(TreePath path) {
return !messages.get(path).isEmpty();
}
/**
* @see ITreePathContentProvider#getParents(Object)
*/
@Override
public TreePath[] getParents(Object element) {
return new TreePath[0]; // only possible for messages
}
}