NIHVIVO-2729 Order subclass groupings in collated object properties by display rank rather than alphabetically. Introduce SubclassTemplateModel for a more flexible implementation.

This commit is contained in:
ryounes 2011-07-12 23:08:04 +00:00
parent e8528fa101
commit 0f820e6c33
4 changed files with 196 additions and 62 deletions

View file

@ -5,13 +5,10 @@ package edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -38,7 +35,8 @@ public class CollatedObjectPropertyTemplateModel extends ObjectPropertyTemplateM
private static final Pattern ORDER_BY_SUBCLASS_PATTERN =
Pattern.compile("ORDER\\s+BY\\s+(DESC\\s*\\(\\s*)?\\?" + SUBCLASS_VARIABLE_NAME, Pattern.CASE_INSENSITIVE);
private final SortedMap<String, List<ObjectPropertyStatementTemplateModel>> subclasses;
private final List<SubclassTemplateModel> subclasses;
private final VClassDao vclassDao;
CollatedObjectPropertyTemplateModel(ObjectProperty op, Individual subject,
VitroRequest vreq, EditingPolicyHelper policyHelper,
@ -47,6 +45,8 @@ public class CollatedObjectPropertyTemplateModel extends ObjectPropertyTemplateM
super(op, subject, vreq, policyHelper);
vclassDao = vreq.getWebappDaoFactory().getVClassDao();
if (populatedObjectPropertyList.contains(op)) {
log.debug("Getting data for populated object property " + op.getURI());
@ -59,12 +59,16 @@ public class CollatedObjectPropertyTemplateModel extends ObjectPropertyTemplateM
/* Collate the data */
subclasses = collate(subjectUri, propertyUri, statementData, policyHelper);
for (List<ObjectPropertyStatementTemplateModel> list : subclasses.values()) {
for (SubclassTemplateModel subclass : subclasses) {
List<ObjectPropertyStatementTemplateModel> list = subclass.getStatements();
postprocessStatementList(list);
}
Collections.sort(subclasses);
} else {
log.debug("Object property " + getUri() + " is unpopulated.");
subclasses = new TreeMap<String, List<ObjectPropertyStatementTemplateModel>>();
subclasses = new ArrayList<SubclassTemplateModel>();
}
}
@ -131,7 +135,7 @@ public class CollatedObjectPropertyTemplateModel extends ObjectPropertyTemplateM
}
}
// Sort the data for this object from most to least specific subclass, with nulls at end
Collections.sort(dataForThisObject, new SubclassComparator());
Collections.sort(dataForThisObject, new DataComparatorBySubclass());
filteredList.add(dataForThisObject.get(0));
}
@ -143,13 +147,7 @@ public class CollatedObjectPropertyTemplateModel extends ObjectPropertyTemplateM
}
}
private class SubclassComparator implements Comparator<Map<String, String>> {
private VClassDao vclassDao;
SubclassComparator() {
this.vclassDao = vreq.getWebappDaoFactory().getVClassDao();
}
private class DataComparatorBySubclass implements Comparator<Map<String, String>> {
@Override
public int compare(Map<String, String> map1, Map<String, String> map2) {
@ -188,64 +186,107 @@ public class CollatedObjectPropertyTemplateModel extends ObjectPropertyTemplateM
}
// Collate the statements by subclass.
private SortedMap<String, List<ObjectPropertyStatementTemplateModel>> collate(String subjectUri, String propertyUri,
private List<SubclassTemplateModel> collate(String subjectUri, String propertyUri,
List<Map<String, String>> statementData, EditingPolicyHelper policyHelper) {
SortedMap<String, List<ObjectPropertyStatementTemplateModel>> subclassMap =
new TreeMap<String, List<ObjectPropertyStatementTemplateModel>>();
String objectKey = getObjectKey();
Map<String, String> subclassUrisToNames = new HashMap<String, String>();
List<SubclassTemplateModel> subclasses = new ArrayList<SubclassTemplateModel>();
for (Map<String, String> map : statementData) {
String subclassUri = map.get(SUBCLASS_VARIABLE_NAME);
// Rows with no subclass are put into a subclass map with an empty name.
if (subclassUri == null) {
subclassUri = "";
VClass vclass = vclassDao.getVClassByURI(subclassUri);
List<ObjectPropertyStatementTemplateModel> listForThisSubclass = null;
for (SubclassTemplateModel subclass : subclasses) {
VClass subclassVClass = subclass.getVClass();
if ( ( vclass == null && subclassVClass == null ) ||
( vclass != null && vclass.equals(subclassVClass) ) ) {
listForThisSubclass = subclass.getStatements();
break;
}
}
// Keep a map of subclass uris to subclass names, so we don't have
// to keep recomputing from the dao each time we hit the same subclass.
String subclassName;
if (subclassUri.isEmpty()) {
subclassName = "";
} else if ( subclassUrisToNames.containsKey(subclassUri) ) {
subclassName = subclassUrisToNames.get(subclassUri);
} else {
subclassName = getSubclassName(subclassUri, vreq);
subclassUrisToNames.put(subclassUri, subclassName);
}
List<ObjectPropertyStatementTemplateModel> listForThisSubclass;
if ( subclassMap.containsKey(subclassName) ) {
listForThisSubclass = subclassMap.get(subclassName);
} else {
if (listForThisSubclass == null) {
listForThisSubclass = new ArrayList<ObjectPropertyStatementTemplateModel>();
subclassMap.put(subclassName, listForThisSubclass);
subclasses.add(new SubclassTemplateModel(vclass, listForThisSubclass));
}
listForThisSubclass.add(new ObjectPropertyStatementTemplateModel(subjectUri,
propertyUri, objectKey, map, policyHelper, getTemplateName(), vreq));
}
return subclassMap;
return subclasses;
}
private String getSubclassName(String subclassUri, VitroRequest vreq) {
if (subclassUri.isEmpty()) {
return "";
}
VClassDao vclassDao = vreq.getWebappDaoFactory().getVClassDao();
VClass vclass = vclassDao.getVClassByURI(subclassUri);
return vclass != null ? vclass.getName() : "";
}
// class SubclassComparatorByDisplayRank implements Comparator<String> {
//
// private List<VClass> vclasses;
//
// SubclassComparatorByDisplayRank(List<VClass> vclasses) {
// this.vclasses = vclasses;
// }
//
// @Override
// public int compare(String nameLeft, String nameRight) {
//
// if (StringUtils.isBlank(uriLeft)) {
// return StringUtils.isBlank(uriRight) ? 0 : 1;
// }
//
// VClass vclassLeft = vclassDao.getVClassByURI(uriLeft);
// VClass vclassRight = vclassDao.getVClassByURI(uriRight);
//
// if (vclassLeft == null) {
// return vclassRight == null ? 0 : 1;
// }
//
// int rankLeft = vclassLeft.getDisplayRank();
// int rankRight = vclassRight.getDisplayRank();
//
// int intCompare = 0;
//
// // Values < 1 are undefined and go at end, not beginning
// if (rankLeft < 1) {
// intCompare = rankRight < 1 ? 0 : 1;
// } else if (rankRight < 1) {
// intCompare = -1;
// } else {
// intCompare = ((Integer)rankLeft).compareTo(rankRight);
// }
//
// if (intCompare != 0) {
// return intCompare;
// }
//
// // If display ranks are equal, sort by name
// if (nameLeft == null) {
// return nameRight == null ? 0 : 1;
// }
// if (nameRight == null) {
// return -1;
// }
// return nameLeft.compareToIgnoreCase(nameRight);
//
// }
// }
// private String getSubclassName(String subclassUri) {
// if (subclassUri.isEmpty()) {
// return "";
// }
// VClass vclass = vclassDao.getVClassByURI(subclassUri);
// return vclass != null ? vclass.getName() : "";
// }
/* Access methods for templates */
public Map<String, List<ObjectPropertyStatementTemplateModel>> getSubclasses() {
public List<SubclassTemplateModel> getSubclasses() {
return subclasses;
}

View file

@ -111,7 +111,6 @@ public abstract class ObjectPropertyTemplateModel extends PropertyTemplateModel
objectKey = getQueryObjectVariableName();
setAddAccess(policyHelper, op);
}

View file

@ -0,0 +1,92 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.webapp.web.templatemodels.individual;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import edu.cornell.mannlib.vitro.webapp.beans.ObjectPropertyStatement;
import edu.cornell.mannlib.vitro.webapp.beans.VClass;
import edu.cornell.mannlib.vitro.webapp.web.templatemodels.BaseTemplateModel;
public class SubclassTemplateModel extends BaseTemplateModel implements Comparable<SubclassTemplateModel> {
private final VClass vclass;
private final List<ObjectPropertyStatementTemplateModel> statements;
/* A dummy SubclassTemplateModel object is created for statements not belonging to any
* real subclass. The template will recognize it because getName() returns an empty string.
* This parallels the dummy PropertyGroupTemplateModel created for properties not
* belonging to any real group.
*/
SubclassTemplateModel(List<ObjectPropertyStatementTemplateModel> statements) {
this(null, statements);
}
SubclassTemplateModel(VClass vclass, List<ObjectPropertyStatementTemplateModel> statements) {
this.vclass = vclass;
this.statements = statements;
}
@Override
public int compareTo(SubclassTemplateModel other) {
if (other == null) {
return -1;
}
VClass vclassOther = other.getVClass();
if (vclass == null) {
return vclassOther == null ? 0 : 1;
}
if (vclassOther == null) {
return -1;
}
int rank = vclass.getDisplayRank();
int rankOther = vclassOther.getDisplayRank();
int intCompare = 0;
// Values < 1 are undefined and go at end, not beginning
if (rank < 1) {
intCompare = rankOther < 1 ? 0 : 1;
} else if (rankOther < 1) {
intCompare = -1;
} else {
intCompare = ((Integer)rank).compareTo(rankOther);
}
if (intCompare != 0) {
return intCompare;
}
// If display ranks are equal, sort by name
String name = getName();
String nameOther = vclassOther.getName();
if (name == null) {
return nameOther == null ? 0 : 1;
}
if (nameOther == null) {
return -1;
}
return name.compareToIgnoreCase(nameOther);
}
protected VClass getVClass() {
return vclass;
}
/* Accessor methods for templates */
public String getName() {
return vclass == null ? "" : vclass.getName();
}
public List<ObjectPropertyStatementTemplateModel> getStatements() {
return statements;
}
}

View file

@ -55,17 +55,19 @@
<#macro collatedObjectPropertyList property editable template=property.template >
<#assign subclasses = property.subclasses>
<#list subclasses?keys as subclass>
<#if subclass?has_content>
<#list subclasses as subclass>
<#local subclassName = subclass.name!>
<#if subclassName?has_content>
<li class="subclass" role="listitem">
<h3>${subclass?lower_case}</h3>
<h3>${subclassName?lower_case}</h3>
<ul class="subclass-property-list">
<@objectPropertyList property editable subclasses[subclass] template />
<@objectPropertyList property editable subclass.statements template />
</ul>
</li>
<#else>
<#-- If not in a subclass, list the statements in the top level ul, not nested -->
<@objectPropertyList property editable subclasses[subclass] template/>
<#-- If not in a real subclass, the statements are in a dummy subclass with an
empty name. List them in the top level ul, not nested. -->
<@objectPropertyList property editable subclass.statements template/>
</#if>
</#list>
</#macro>