/******************************************************************************* * Copyright (c) 2009 Fraunhofer IWU 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: * Fraunhofer IWU - initial API and implementation *******************************************************************************/ package net.enilink.komma.edit.ui.properties.internal.parts; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import net.enilink.commons.iterator.IExtendedIterator; import net.enilink.commons.iterator.UniqueExtendedIterator; import net.enilink.commons.iterator.WrappedIterator; import net.enilink.komma.core.IStatement; import net.enilink.komma.core.Statement; import net.enilink.komma.em.concepts.IProperty; import net.enilink.komma.em.concepts.IResource; import net.enilink.vocab.rdf.RDF; /** * Tree node that represents the values of a given property for a given resource * as its children. */ public class PropertyNode extends StatementNode { private static Options DEFAULT_OPTIONS = new Options(); public static class Options { public boolean includeInferred; } private boolean createNewStatementOnEdit; private Boolean hasMultipleStatements; private Options options; private IStatement statement; private IProperty property; private IResource resource; private List<PropertyStatementNode> children; IStatement[] statements; public PropertyNode(IResource resource, IProperty property, boolean inverse, Options options) { super(inverse); this.resource = resource; this.property = property; this.options = options != null ? options : DEFAULT_OPTIONS; } /** * Returns the list of all statements for the corresponding * <code>resource</code> and <code>property</code>. * * @return The list of all statements */ public Collection<? extends StatementNode> getChildren() { if (children == null) { statement = null; IStatement[] stmtAry = getStatementIterator().toList().toArray( new IStatement[0]); // reorder first two items in case the first is rdf:type=owl:Thing // and the second is not inferred // this way, the expanded view is consistent with the collapsed one if (stmtAry.length > 1 && RDF.PROPERTY_TYPE.equals(stmtAry[0].getPredicate()) && net.enilink.vocab.owl.OWL.TYPE_THING.equals(stmtAry[0] .getObject()) && !stmtAry[1].isInferred()) { IStatement typeThingStmt = stmtAry[0]; stmtAry[0] = stmtAry[1]; stmtAry[1] = typeThingStmt; } statements = stmtAry; children = new ArrayList<PropertyStatementNode>(statements.length); for (int i = 0; i < statements.length; i++) { children.add(new PropertyStatementNode(this, i, inverse)); } hasMultipleStatements = children.size() > 1; } return children != null ? children : Collections .<StatementNode> emptyList(); } /** * Returns the first statement for the corresponding <code>resource</code> * and <code>property</code>. This method does not initialize the list all * statements if it was not loaded before. * * @return The first statement */ public IStatement getStatement() { if (hasMultipleStatements == null) { if (children != null) { children = null; getChildren(); } else { IExtendedIterator<IStatement> stmtIt = getStatementIterator(); if (!stmtIt.hasNext()) { statement = inverse ? new Statement(null, property, resource) : new Statement(resource, property, null); hasMultipleStatements = false; return statement; } statement = stmtIt.next(); hasMultipleStatements = stmtIt.hasNext(); // skip first statement if it's rdf:type=owl:Thing and if there // are // more non-inferred statements // this way, the collapsed view does not show owl:Thing as the // type if (hasMultipleStatements && RDF.PROPERTY_TYPE.equals(statement.getPredicate()) && net.enilink.vocab.owl.OWL.TYPE_THING .equals(statement.getObject())) { IStatement secondStatement = stmtIt.next(); if (!secondStatement.isInferred()) { statement = secondStatement; } } stmtIt.close(); } } return children != null && children.size() > 0 ? children.get(0) .getStatement() : statement; } public IProperty getProperty() { return property; } public IResource getResource() { return resource; } protected IExtendedIterator<IStatement> getStatementIterator() { if (property == null) { return WrappedIterator.<IStatement> create(Collections .<IStatement> emptyList().iterator()); } return UniqueExtendedIterator.create(inverse ? resource .getInversePropertyStatements(property, true, options.includeInferred) : resource .getPropertyStatements(property, options.includeInferred)); } /** * Returns <code>true</code> if there are multiple statements for the * corresponding <code>resource</code> and <code>property</code>, else * <code>false</code>. * * @return <code>true</code> if multiple statements exist, else * <code>false</code> */ public boolean hasMultipleStatements() { if (hasMultipleStatements == null) { getStatement(); } return hasMultipleStatements; } public boolean isCreateNewStatementOnEdit() { return createNewStatementOnEdit; } public boolean isIncomplete() { return property == null || (inverse && getStatement().getSubject() == null) || (!inverse && getStatement().getObject() == null); } public boolean isInitialized() { return hasMultipleStatements != null; } /** * Removes all cached statements of this property node. */ public void refreshChildren() { statement = null; if (children != null) { // required to mark statements as already loaded, // that next reload fetches all statements and not only the first // one children = Collections.emptyList(); } hasMultipleStatements = null; } public void setCreateNewStatementOnEdit(boolean createNewStatementOnEdit) { this.createNewStatementOnEdit = createNewStatementOnEdit; } public void setProperty(IProperty property) { if (isIncomplete()) { this.property = property; this.statement = inverse ? new Statement(null, property, resource) : new Statement(resource, property, null); } else { throw new IllegalArgumentException( "Changing the property is only allowed for incomplete statements."); } } public void setResource(IResource resource) { this.resource = resource; refreshChildren(); } }