From 0f820e6c33f437406ffc2d7dee9caf0aa7ee3258 Mon Sep 17 00:00:00 2001 From: ryounes Date: Tue, 12 Jul 2011 23:08:04 +0000 Subject: [PATCH] NIHVIVO-2729 Order subclass groupings in collated object properties by display rank rather than alphabetically. Introduce SubclassTemplateModel for a more flexible implementation. --- .../CollatedObjectPropertyTemplateModel.java | 151 +++++++++++------- .../ObjectPropertyTemplateModel.java | 1 - .../individual/SubclassTemplateModel.java | 92 +++++++++++ .../freemarker/lib/lib-properties.ftl | 14 +- 4 files changed, 196 insertions(+), 62 deletions(-) create mode 100644 webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/SubclassTemplateModel.java diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/CollatedObjectPropertyTemplateModel.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/CollatedObjectPropertyTemplateModel.java index 3c8ca4963..c1c4e2bbd 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/CollatedObjectPropertyTemplateModel.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/CollatedObjectPropertyTemplateModel.java @@ -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> subclasses; + private final List 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 list : subclasses.values()) { - postprocessStatementList(list); - } + for (SubclassTemplateModel subclass : subclasses) { + List list = subclass.getStatements(); + postprocessStatementList(list); + } + + Collections.sort(subclasses); + } else { log.debug("Object property " + getUri() + " is unpopulated."); - subclasses = new TreeMap>(); + subclasses = new ArrayList(); } } @@ -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> { - - private VClassDao vclassDao; - - SubclassComparator() { - this.vclassDao = vreq.getWebappDaoFactory().getVClassDao(); - } + private class DataComparatorBySubclass implements Comparator> { @Override public int compare(Map map1, Map map2) { @@ -188,64 +186,107 @@ public class CollatedObjectPropertyTemplateModel extends ObjectPropertyTemplateM } // Collate the statements by subclass. - private SortedMap> collate(String subjectUri, String propertyUri, + private List collate(String subjectUri, String propertyUri, List> statementData, EditingPolicyHelper policyHelper) { - - SortedMap> subclassMap = - new TreeMap>(); - + String objectKey = getObjectKey(); - Map subclassUrisToNames = new HashMap(); + List subclasses = new ArrayList(); for (Map map : statementData) { String subclassUri = map.get(SUBCLASS_VARIABLE_NAME); + + VClass vclass = vclassDao.getVClassByURI(subclassUri); - // Rows with no subclass are put into a subclass map with an empty name. - if (subclassUri == null) { - subclassUri = ""; - } - - // 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 listForThisSubclass = null; + + for (SubclassTemplateModel subclass : subclasses) { + VClass subclassVClass = subclass.getVClass(); + if ( ( vclass == null && subclassVClass == null ) || + ( vclass != null && vclass.equals(subclassVClass) ) ) { + listForThisSubclass = subclass.getStatements(); + break; + } } - List listForThisSubclass; - if ( subclassMap.containsKey(subclassName) ) { - listForThisSubclass = subclassMap.get(subclassName); - } else { - listForThisSubclass = new ArrayList(); - subclassMap.put(subclassName, listForThisSubclass); + if (listForThisSubclass == null) { + listForThisSubclass = new ArrayList(); + 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 { +// +// private List vclasses; +// +// SubclassComparatorByDisplayRank(List 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> getSubclasses() { + public List getSubclasses() { return subclasses; } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/ObjectPropertyTemplateModel.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/ObjectPropertyTemplateModel.java index 36ffa0383..4f9f1583a 100644 --- a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/ObjectPropertyTemplateModel.java +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/ObjectPropertyTemplateModel.java @@ -111,7 +111,6 @@ public abstract class ObjectPropertyTemplateModel extends PropertyTemplateModel objectKey = getQueryObjectVariableName(); - setAddAccess(policyHelper, op); } diff --git a/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/SubclassTemplateModel.java b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/SubclassTemplateModel.java new file mode 100644 index 000000000..16d677d29 --- /dev/null +++ b/webapp/src/edu/cornell/mannlib/vitro/webapp/web/templatemodels/individual/SubclassTemplateModel.java @@ -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 { + + private final VClass vclass; + private final List 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 statements) { + this(null, statements); + } + + SubclassTemplateModel(VClass vclass, List 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 getStatements() { + return statements; + } + +} diff --git a/webapp/web/templates/freemarker/lib/lib-properties.ftl b/webapp/web/templates/freemarker/lib/lib-properties.ftl index abb07ec56..66eae3158 100644 --- a/webapp/web/templates/freemarker/lib/lib-properties.ftl +++ b/webapp/web/templates/freemarker/lib/lib-properties.ftl @@ -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>
  • -

    ${subclass?lower_case}

    +

    ${subclassName?lower_case}

      - <@objectPropertyList property editable subclasses[subclass] template /> + <@objectPropertyList property editable subclass.statements template />
  • <#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/>