Skip to content
Snippets Groups Projects
Commit ff3a8d93 authored by uhensler's avatar uhensler
Browse files

OO-3304: Save the presentation of an analysis under a particular name

parent 40bbc8e0
No related branches found
No related tags found
No related merge requests found
Showing
with 1038 additions and 98 deletions
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
*/ */
package org.olat.modules.quality; package org.olat.modules.quality;
import org.olat.basesecurity.OrganisationRoles;
import org.olat.modules.quality.analysis.AnalysisPresentation;
import org.olat.modules.quality.generator.QualityGenerator; import org.olat.modules.quality.generator.QualityGenerator;
/** /**
...@@ -80,5 +82,13 @@ public interface QualitySecurityCallback { ...@@ -80,5 +82,13 @@ public interface QualitySecurityCallback {
public boolean canDeleteGenerator(long numberDataCollections); public boolean canDeleteGenerator(long numberDataCollections);
public boolean canViewAnalysis(); public boolean canViewAnalysis();
public OrganisationRoles[] getAnalysisViewRoles();
public OrganisationRoles[] getPresentationViewRoles();
public boolean canEditPresentations();
public boolean canDeletePresentation(AnalysisPresentation presentation);
} }
/**
* <a href="http://www.openolat.org">
* OpenOLAT - Online Learning and Training</a><br>
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at the
* <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS, <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Initial code contributed and copyrighted by<br>
* frentix GmbH, http://www.frentix.com
* <p>
*/
package org.olat.modules.quality.analysis;
import org.olat.core.id.CreateInfo;
import org.olat.core.id.ModifiedInfo;
import org.olat.core.id.OLATResourceable;
import org.olat.repository.RepositoryEntry;
/**
*
* Initial date: 28.09.2018<br>
* @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
*
*/
public interface AnalysisPresentation extends AnalysisPresentationRef, OLATResourceable, CreateInfo, ModifiedInfo {
public String RESOURCEABLE_TYPE = "presentation";
public String getName();
public void setName(String name);
public AnalysisSegment getAnalysisSegment();
public void setAnalysisSegment(AnalysisSegment segment);
public AnalysisSearchParameter getSearchParams();
public void setSearchParams(AnalysisSearchParameter searchParams);
public MultiGroupBy getHeatMapGrouping();
public void setHeatMapGrouping(MultiGroupBy groupBy);
public Boolean getHeatMapInsufficientOnly();
public void setHeatMapInsufficientOnly(Boolean insufficientOnly);
public RepositoryEntry getFormEntry();
}
/**
* <a href="http://www.openolat.org">
* OpenOLAT - Online Learning and Training</a><br>
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at the
* <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS, <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Initial code contributed and copyrighted by<br>
* frentix GmbH, http://www.frentix.com
* <p>
*/
package org.olat.modules.quality.analysis;
/**
*
* Initial date: 01.10.2018<br>
* @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
*
*/
public interface AnalysisPresentationRef {
Long getKey();
}
\ No newline at end of file
/**
* <a href="http://www.openolat.org">
* OpenOLAT - Online Learning and Training</a><br>
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at the
* <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS, <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Initial code contributed and copyrighted by<br>
* frentix GmbH, http://www.frentix.com
* <p>
*/
package org.olat.modules.quality.analysis;
import java.util.Collection;
import org.olat.core.id.OrganisationRef;
/**
*
* Initial date: 02.10.2018<br>
* @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
*
*/
public class AnalysisPresentationSearchParameter {
private Collection<? extends OrganisationRef> organisationRefs;
public Collection<? extends OrganisationRef> getOrganisationRefs() {
return organisationRefs;
}
public void setOrganisationRefs(Collection<? extends OrganisationRef> organisationRefs) {
this.organisationRefs = organisationRefs;
}
}
...@@ -30,6 +30,7 @@ import org.olat.modules.curriculum.CurriculumElementRef; ...@@ -30,6 +30,7 @@ import org.olat.modules.curriculum.CurriculumElementRef;
import org.olat.modules.curriculum.CurriculumRef; import org.olat.modules.curriculum.CurriculumRef;
import org.olat.modules.taxonomy.TaxonomyLevelRef; import org.olat.modules.taxonomy.TaxonomyLevelRef;
import org.olat.repository.RepositoryEntryRef; import org.olat.repository.RepositoryEntryRef;
import org.olat.repository.model.RepositoryEntryRefImpl;
/** /**
* *
...@@ -59,7 +60,8 @@ public class AnalysisSearchParameter { ...@@ -59,7 +60,8 @@ public class AnalysisSearchParameter {
} }
public void setFormEntryRef(RepositoryEntryRef formEntryRef) { public void setFormEntryRef(RepositoryEntryRef formEntryRef) {
this.formEntryRef = formEntryRef; // Make sure to have a plain RepositoryEntryRef for XStream.
this.formEntryRef = new RepositoryEntryRefImpl(formEntryRef.getKey());
} }
public Date getDateRangeFrom() { public Date getDateRangeFrom() {
......
/**
* <a href="http://www.openolat.org">
* OpenOLAT - Online Learning and Training</a><br>
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at the
* <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS, <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Initial code contributed and copyrighted by<br>
* frentix GmbH, http://www.frentix.com
* <p>
*/
package org.olat.modules.quality.analysis;
/**
*
* Initial date: 28.09.2018<br>
* @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
*
*/
public enum AnalysisSegment {
OVERVIEW,
HEAT_MAP,
TREND;
}
...@@ -22,6 +22,7 @@ package org.olat.modules.quality.analysis; ...@@ -22,6 +22,7 @@ package org.olat.modules.quality.analysis;
import java.util.Date; import java.util.Date;
import org.olat.core.id.OLATResourceable; import org.olat.core.id.OLATResourceable;
import org.olat.repository.RepositoryEntry;
/** /**
* *
...@@ -33,17 +34,13 @@ public interface EvaluationFormView extends OLATResourceable { ...@@ -33,17 +34,13 @@ public interface EvaluationFormView extends OLATResourceable {
public String RESOURCEABLE_TYPE = "form"; public String RESOURCEABLE_TYPE = "form";
public Long getFormEntryKey(); public RepositoryEntry getFormEntry();
public Date getFormCreatedDate();
public String getFormTitle();
public Long getNumberDataCollections(); public Long getNumberDataCollections();
public Date getSoonestDataCollectionDate(); public Date getSoonestDataCollectionDate();
public Date getLatestDataCollectionDate(); public Date getLatestDataCollectionFinishedDate();
public Long getNumberParticipationsDone(); public Long getNumberParticipationsDone();
......
...@@ -69,4 +69,32 @@ public class MultiGroupBy { ...@@ -69,4 +69,32 @@ public class MultiGroupBy {
return groupBy1 == null && groupBy2 == null && groupBy3 == null; return groupBy1 == null && groupBy2 == null && groupBy3 == null;
} }
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((groupBy1 == null) ? 0 : groupBy1.hashCode());
result = prime * result + ((groupBy2 == null) ? 0 : groupBy2.hashCode());
result = prime * result + ((groupBy3 == null) ? 0 : groupBy3.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
MultiGroupBy other = (MultiGroupBy) obj;
if (groupBy1 != other.groupBy1)
return false;
if (groupBy2 != other.groupBy2)
return false;
if (groupBy3 != other.groupBy3)
return false;
return true;
}
} }
...@@ -38,9 +38,21 @@ import org.olat.repository.RepositoryEntry; ...@@ -38,9 +38,21 @@ import org.olat.repository.RepositoryEntry;
* *
*/ */
public interface QualityAnalysisService { public interface QualityAnalysisService {
public List<EvaluationFormView> loadEvaluationForms(EvaluationFormViewSearchParams searchParams); public List<EvaluationFormView> loadEvaluationForms(EvaluationFormViewSearchParams searchParams);
public AnalysisPresentation createPresentation(RepositoryEntry formEntry);
public AnalysisPresentation clonePresentation(AnalysisPresentation presentation);
public AnalysisPresentation savePresentation(AnalysisPresentation presentation);
public List<AnalysisPresentation> loadPresentations(AnalysisPresentationSearchParameter searchParams);
public AnalysisPresentation loadPresentationByKey(AnalysisPresentationRef presentationRef);
public void deletePresentation(AnalysisPresentationRef presentationRef);
public AvailableAttributes getAvailableAttributes(AnalysisSearchParameter searchParams); public AvailableAttributes getAvailableAttributes(AnalysisSearchParameter searchParams);
public Long loadFilterDataCollectionCount(AnalysisSearchParameter searchParams); public Long loadFilterDataCollectionCount(AnalysisSearchParameter searchParams);
......
/**
* <a href="http://www.openolat.org">
* OpenOLAT - Online Learning and Training</a><br>
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at the
* <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS, <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Initial code contributed and copyrighted by<br>
* frentix GmbH, http://www.frentix.com
* <p>
*/
package org.olat.modules.quality.analysis.manager;
import static java.util.stream.Collectors.toList;
import java.util.Date;
import java.util.List;
import javax.persistence.TypedQuery;
import org.olat.core.commons.persistence.DB;
import org.olat.core.commons.persistence.QueryBuilder;
import org.olat.core.id.OrganisationRef;
import org.olat.modules.quality.QualityDataCollectionLight;
import org.olat.modules.quality.analysis.AnalysisPresentation;
import org.olat.modules.quality.analysis.AnalysisPresentationRef;
import org.olat.modules.quality.analysis.AnalysisPresentationSearchParameter;
import org.olat.modules.quality.analysis.AnalysisSearchParameter;
import org.olat.modules.quality.analysis.AnalysisSegment;
import org.olat.modules.quality.analysis.MultiGroupBy;
import org.olat.modules.quality.analysis.model.AnalysisPresentationImpl;
import org.olat.repository.RepositoryEntry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
*
* Initial date: 01.10.2018<br>
* @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
*
*/
@Service
class AnalysisPresentationDAO {
@Autowired
private DB dbInstance;
AnalysisPresentation create(RepositoryEntry formEntry) {
AnalysisPresentationImpl presentation = new AnalysisPresentationImpl();
presentation.setCreationDate(new Date());
presentation.setLastModified(presentation.getCreationDate());
presentation.setFormEntry(formEntry);
presentation.setAnalysisSegment(AnalysisSegment.OVERVIEW);
AnalysisSearchParameter searchParams = new AnalysisSearchParameter();
searchParams.setFormEntryRef(formEntry);
presentation.setSearchParams(searchParams);
presentation.setHeatMapGrouping(MultiGroupBy.noGroupBy());
presentation.setHeatMapInsufficientOnly(Boolean.FALSE);
return presentation;
}
AnalysisPresentation save(AnalysisPresentation presentation) {
toXMLs(presentation);
if (presentation.getKey() == null) {
return saveNew(presentation);
}
return saveExisting(presentation);
}
private AnalysisPresentation saveNew(AnalysisPresentation presentation) {
dbInstance.getCurrentEntityManager().persist(presentation);
return presentation;
}
private AnalysisPresentation saveExisting(AnalysisPresentation presentation) {
presentation.setLastModified(new Date());
AnalysisPresentation savedPresentation = dbInstance.getCurrentEntityManager().merge(presentation);
// Hibernate does not deliver transient attributes in merged objects
savedPresentation.setHeatMapGrouping(presentation.getHeatMapGrouping());
savedPresentation.setSearchParams(presentation.getSearchParams());
return savedPresentation;
}
AnalysisPresentation loadByKey(AnalysisPresentationRef presentationRef) {
if (presentationRef == null || presentationRef.getKey() == null) return null;
StringBuilder sb = new StringBuilder(256);
sb.append("select presentation");
sb.append(" from qualityanalysispresentation as presentation");
sb.append(" inner join fetch presentation.formEntry");
sb.append(" where presentation.key = :presentationRef");
List<AnalysisPresentation> presentations = dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), AnalysisPresentation.class)
.setParameter("presentationRef", presentationRef.getKey())
.getResultList();
AnalysisPresentation presentation = presentations.isEmpty() ? null : presentations.get(0);
fromXMLs(presentation);
return presentation;
}
List<AnalysisPresentation> load(AnalysisPresentationSearchParameter searchParams) {
QueryBuilder sb = new QueryBuilder(256);
sb.append("select presentation");
sb.append(" from qualityanalysispresentation as presentation");
sb.append(" inner join presentation.formEntry as formEntry");
appendWhere(sb, searchParams);
TypedQuery<AnalysisPresentation> query = dbInstance.getCurrentEntityManager()
.createQuery(sb.toString(), AnalysisPresentation.class);
appendParameters(query, searchParams);
List<AnalysisPresentation> presentations = query.getResultList();
for (AnalysisPresentation presentation : presentations) {
fromXMLs(presentation);
}
return presentations;
}
private void appendWhere(QueryBuilder sb, AnalysisPresentationSearchParameter searchParams) {
if (searchParams.getOrganisationRefs() != null && !searchParams.getOrganisationRefs().isEmpty()) {
sb.and();
sb.append("formEntry.key in (");
sb.append("select survey.formEntry.key");
sb.append(" from qualitydatacollectiontoorganisation dcToOrg");
sb.append(" join dcToOrg.dataCollection as collection");
sb.append(" join evaluationformsurvey survey on survey.resName = '").append(QualityDataCollectionLight.RESOURCEABLE_TYPE_NAME).append("'");
sb.append(" and survey.resId = collection.key");
sb.append(" where dcToOrg.organisation.key in :organisationKeys");
sb.append(")");
}
}
private void appendParameters(TypedQuery<AnalysisPresentation> query,
AnalysisPresentationSearchParameter searchParams) {
if (searchParams.getOrganisationRefs() != null && !searchParams.getOrganisationRefs().isEmpty()) {
List<Long> keys = searchParams.getOrganisationRefs().stream().map(OrganisationRef::getKey).collect(toList());
query.setParameter("organisationKeys", keys);
}
}
private void toXMLs(AnalysisPresentation presentation) {
if (presentation instanceof AnalysisPresentationImpl) {
AnalysisPresentationImpl presentationImpl = (AnalysisPresentationImpl) presentation;
String searchParamsXml = AnalysisPresentationXStream.toXml(presentation.getSearchParams());
presentationImpl.setSearchParamsXml(searchParamsXml);
String heatMapGroupingXml = AnalysisPresentationXStream.toXml(presentation.getHeatMapGrouping());
presentationImpl.setHeatMapGroupingXml(heatMapGroupingXml);
}
}
private void fromXMLs(AnalysisPresentation presentation) {
if (presentation instanceof AnalysisPresentationImpl) {
AnalysisPresentationImpl presentationImpl = (AnalysisPresentationImpl) presentation;
AnalysisSearchParameter searchParams = AnalysisPresentationXStream
.fromXml(presentationImpl.getSearchParamsXml(), AnalysisSearchParameter.class);
presentation.setSearchParams(searchParams);
MultiGroupBy groupBy = AnalysisPresentationXStream
.fromXml(presentationImpl.getHeatMapGroupingXml(), MultiGroupBy.class);
presentation.setHeatMapGrouping(groupBy);
}
}
void delete(AnalysisPresentationRef presentationRef) {
if (presentationRef == null || presentationRef.getKey() == null) return;
QueryBuilder sb = new QueryBuilder(256);
sb.append("delete from qualityanalysispresentation as presentation");
sb.append(" where presentation.key = :presentationKey");
dbInstance.getCurrentEntityManager()
.createQuery(sb.toString())
.setParameter("presentationKey", presentationRef.getKey())
.executeUpdate();
}
}
/**
* <a href="http://www.openolat.org">
* OpenOLAT - Online Learning and Training</a><br>
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at the
* <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS, <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Initial code contributed and copyrighted by<br>
* frentix GmbH, http://www.frentix.com
* <p>
*/
package org.olat.modules.quality.analysis.manager;
import org.olat.basesecurity.model.IdentityRefImpl;
import org.olat.basesecurity.model.OrganisationRefImpl;
import org.olat.core.logging.OLog;
import org.olat.core.logging.Tracing;
import org.olat.core.util.StringHelper;
import org.olat.core.util.xml.XStreamHelper;
import org.olat.modules.curriculum.model.CurriculumElementRefImpl;
import org.olat.modules.curriculum.model.CurriculumRefImpl;
import org.olat.modules.quality.analysis.AnalysisSearchParameter;
import org.olat.modules.quality.analysis.GroupBy;
import org.olat.modules.quality.analysis.MultiGroupBy;
import org.olat.modules.taxonomy.model.TaxonomyLevelRefImpl;
import org.olat.repository.model.RepositoryEntryRefImpl;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.security.ExplicitTypePermission;
/**
*
* Initial date: 01.10.2018<br>
* @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
*
*/
public class AnalysisPresentationXStream {
private static final OLog log = Tracing.createLoggerFor(AnalysisPresentationXStream.class);
private static final XStream xstream = XStreamHelper.createXStreamInstance();
static {
XStream.setupDefaultSecurity(xstream);
Class<?>[] types = new Class[] {
MultiGroupBy.class, GroupBy.class, AnalysisSearchParameter.class, RepositoryEntryRefImpl.class,
IdentityRefImpl.class, OrganisationRefImpl.class, CurriculumRefImpl.class,
CurriculumElementRefImpl.class, TaxonomyLevelRefImpl.class };
xstream.addPermission(new ExplicitTypePermission(types));
xstream.alias("multiGroupBy", MultiGroupBy.class);
xstream.alias("groupBy", GroupBy.class);
xstream.alias("AnalysisSearchParameter", AnalysisSearchParameter.class);
xstream.alias("RepositoryEntryRef", RepositoryEntryRefImpl.class);
xstream.alias("IdentityRef", IdentityRefImpl.class);
xstream.alias("OrganisationRef", OrganisationRefImpl.class);
xstream.alias("CurriculumRef", CurriculumRefImpl.class);
xstream.alias("CurriculumElementRef", CurriculumElementRefImpl.class);
xstream.alias("TaxonomyLevelRef", TaxonomyLevelRefImpl.class);
}
static String toXml(Object obj) {
if (obj == null) return null;
return xstream.toXML(obj);
}
@SuppressWarnings("unchecked")
public static <U> U fromXml(String xml, @SuppressWarnings("unused") Class<U> cl) {
if(StringHelper.containsNonWhitespace(xml)) {
try {
Object obj = xstream.fromXML(xml);
return (U)obj;
} catch (Exception e) {
log.error("", e);
}
}
return null;
}
}
...@@ -50,9 +50,7 @@ public class EvaluationFormDAO { ...@@ -50,9 +50,7 @@ public class EvaluationFormDAO {
List<EvaluationFormView> load(EvaluationFormViewSearchParams searchParams) { List<EvaluationFormView> load(EvaluationFormViewSearchParams searchParams) {
QueryBuilder sb = new QueryBuilder(); QueryBuilder sb = new QueryBuilder();
sb.append("select new org.olat.modules.quality.analysis.model.EvaluationFormViewImpl("); sb.append("select new org.olat.modules.quality.analysis.model.EvaluationFormViewImpl(");
sb.append(" form.key as formEntryKey"); sb.append(" form as formEntry");
sb.append(" , form.creationDate as formCreationDate");
sb.append(" , form.displayname as formTitle");
sb.append(" , count(distinct collection) as numberDataCollections"); sb.append(" , count(distinct collection) as numberDataCollections");
sb.append(" , min(collection.start) as soonestDataCollectionDate"); sb.append(" , min(collection.start) as soonestDataCollectionDate");
sb.append(" , max(collection.deadline) as latestDataCollectionDate"); sb.append(" , max(collection.deadline) as latestDataCollectionDate");
......
...@@ -40,6 +40,9 @@ import org.olat.modules.forms.EvaluationFormManager; ...@@ -40,6 +40,9 @@ import org.olat.modules.forms.EvaluationFormManager;
import org.olat.modules.forms.RubricRating; import org.olat.modules.forms.RubricRating;
import org.olat.modules.forms.SessionFilter; import org.olat.modules.forms.SessionFilter;
import org.olat.modules.forms.model.xml.Rubric; import org.olat.modules.forms.model.xml.Rubric;
import org.olat.modules.quality.analysis.AnalysisPresentation;
import org.olat.modules.quality.analysis.AnalysisPresentationRef;
import org.olat.modules.quality.analysis.AnalysisPresentationSearchParameter;
import org.olat.modules.quality.analysis.AnalysisSearchParameter; import org.olat.modules.quality.analysis.AnalysisSearchParameter;
import org.olat.modules.quality.analysis.AvailableAttributes; import org.olat.modules.quality.analysis.AvailableAttributes;
import org.olat.modules.quality.analysis.EvaluationFormView; import org.olat.modules.quality.analysis.EvaluationFormView;
...@@ -64,13 +67,15 @@ import org.springframework.stereotype.Service; ...@@ -64,13 +67,15 @@ import org.springframework.stereotype.Service;
@Service @Service
public class QualityAnalysisServiceImpl implements QualityAnalysisService { public class QualityAnalysisServiceImpl implements QualityAnalysisService {
@Autowired
private EvaluationFormDAO evaluationFromDao;
@Autowired
private AnalysisPresentationDAO presentationDAO;
@Autowired @Autowired
private AnalysisFilterDAO filterDao; private AnalysisFilterDAO filterDao;
@Autowired @Autowired
private StatisticsCalculator statisticsCalculator; private StatisticsCalculator statisticsCalculator;
@Autowired @Autowired
private EvaluationFormDAO evaluationFromDao;
@Autowired
private EvaluationFormManager evaluationFormManager; private EvaluationFormManager evaluationFormManager;
@Autowired @Autowired
private OrganisationService organisationService; private OrganisationService organisationService;
...@@ -88,6 +93,42 @@ public class QualityAnalysisServiceImpl implements QualityAnalysisService { ...@@ -88,6 +93,42 @@ public class QualityAnalysisServiceImpl implements QualityAnalysisService {
return evaluationFromDao.load(searchParams); return evaluationFromDao.load(searchParams);
} }
@Override
public AnalysisPresentation createPresentation(RepositoryEntry formEntry) {
return presentationDAO.create(formEntry);
}
@Override
public AnalysisPresentation clonePresentation(AnalysisPresentation presentation) {
AnalysisPresentation clone = presentationDAO.create(presentation.getFormEntry());
clone.setAnalysisSegment(presentation.getAnalysisSegment());
clone.setHeatMapGrouping(presentation.getHeatMapGrouping());
clone.setHeatMapInsufficientOnly(presentation.getHeatMapInsufficientOnly());
clone.setName(presentation.getName());
clone.setSearchParams(presentation.getSearchParams().clone());
return clone;
}
@Override
public AnalysisPresentation savePresentation(AnalysisPresentation presentation) {
return presentationDAO.save(presentation);
}
@Override
public List<AnalysisPresentation> loadPresentations(AnalysisPresentationSearchParameter searchParams) {
return presentationDAO.load(searchParams);
}
@Override
public AnalysisPresentation loadPresentationByKey(AnalysisPresentationRef presentationRef) {
return presentationDAO.loadByKey(presentationRef);
}
@Override
public void deletePresentation(AnalysisPresentationRef presentationRef) {
presentationDAO.delete(presentationRef);
}
@Override @Override
public AvailableAttributes getAvailableAttributes(AnalysisSearchParameter searchParams) { public AvailableAttributes getAvailableAttributes(AnalysisSearchParameter searchParams) {
return filterDao.getAvailableAttributes(searchParams); return filterDao.getAvailableAttributes(searchParams);
...@@ -228,4 +269,5 @@ public class QualityAnalysisServiceImpl implements QualityAnalysisService { ...@@ -228,4 +269,5 @@ public class QualityAnalysisServiceImpl implements QualityAnalysisService {
} }
return false; return false;
} }
} }
/**
* <a href="http://www.openolat.org">
* OpenOLAT - Online Learning and Training</a><br>
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at the
* <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS, <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Initial code contributed and copyrighted by<br>
* frentix GmbH, http://www.frentix.com
* <p>
*/
package org.olat.modules.quality.analysis.model;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
import org.olat.core.id.Persistable;
import org.olat.modules.quality.analysis.AnalysisPresentation;
import org.olat.modules.quality.analysis.AnalysisSearchParameter;
import org.olat.modules.quality.analysis.AnalysisSegment;
import org.olat.modules.quality.analysis.MultiGroupBy;
import org.olat.repository.RepositoryEntry;
/**
*
* Initial date: 28.09.2018<br>
* @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
*
*/
@Entity(name="qualityanalysispresentation")
@Table(name="o_qual_analysis_presentation")
public class AnalysisPresentationImpl implements AnalysisPresentation, Persistable {
private static final long serialVersionUID = 1061934209099333284L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name="id", nullable=false, unique=true, insertable=true, updatable=false)
private Long key;
@Temporal(TemporalType.TIMESTAMP)
@Column(name="creationdate", nullable=false, insertable=true, updatable=false)
private Date creationDate;
@Temporal(TemporalType.TIMESTAMP)
@Column(name="lastmodified", nullable=false, insertable=true, updatable=true)
private Date lastModified;
@Column(name="q_name", nullable=true, insertable=true, updatable=true)
private String name;
@Enumerated(EnumType.STRING)
@Column(name="q_analysis_segment", nullable=true, insertable=true, updatable=true)
private AnalysisSegment analysisSegment;
@Column(name="q_search_params", nullable=true, insertable=true, updatable=true)
private String searchParamsXml;
@Transient
private AnalysisSearchParameter searchParams;
@Column(name="q_heatmap_grouping", nullable=true, insertable=true, updatable=true)
private String heatMapGroupingXml;
@Transient
private MultiGroupBy heatMapGrouping;
@Column(name="q_heatmap_insufficient_only", nullable=true, insertable=true, updatable=true)
private Boolean heatMapInsufficientOnly;
@ManyToOne(targetEntity=RepositoryEntry.class,fetch=FetchType.LAZY,optional=false)
@JoinColumn(name="fk_form_entry", nullable=false, insertable=true, updatable=false)
private RepositoryEntry formEntry;
@Override
public Long getKey() {
return key;
}
public void setKey(Long key) {
this.key = key;
}
@Override
public String getResourceableTypeName() {
return AnalysisPresentation.RESOURCEABLE_TYPE;
}
@Override
public Long getResourceableId() {
return key;
}
@Override
public Date getCreationDate() {
return creationDate;
}
public void setCreationDate(Date creationDate) {
this.creationDate = creationDate;
}
@Override
public Date getLastModified() {
return lastModified;
}
@Override
public void setLastModified(Date lastModified) {
this.lastModified = lastModified;
}
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public AnalysisSegment getAnalysisSegment() {
return analysisSegment;
}
@Override
public void setAnalysisSegment(AnalysisSegment analysisSegment) {
this.analysisSegment = analysisSegment;
}
@Override
public AnalysisSearchParameter getSearchParams() {
return searchParams;
}
@Override
public void setSearchParams(AnalysisSearchParameter searchParams) {
this.searchParams = searchParams;
}
public String getSearchParamsXml() {
return searchParamsXml;
}
public void setSearchParamsXml(String searchParamsXml) {
this.searchParamsXml = searchParamsXml;
}
@Override
public MultiGroupBy getHeatMapGrouping() {
return heatMapGrouping;
}
@Override
public void setHeatMapGrouping(MultiGroupBy heatMapGrouping) {
this.heatMapGrouping = heatMapGrouping;
}
public String getHeatMapGroupingXml() {
return heatMapGroupingXml;
}
public void setHeatMapGroupingXml(String heatMapGroupingXml) {
this.heatMapGroupingXml = heatMapGroupingXml;
}
@Override
public Boolean getHeatMapInsufficientOnly() {
return heatMapInsufficientOnly;
}
@Override
public void setHeatMapInsufficientOnly(Boolean heatMapInsufficientOnly) {
this.heatMapInsufficientOnly = heatMapInsufficientOnly;
}
@Override
public RepositoryEntry getFormEntry() {
return formEntry;
}
public void setFormEntry(RepositoryEntry formEntry) {
this.formEntry = formEntry;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((key == null) ? 0 : key.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
AnalysisPresentationImpl other = (AnalysisPresentationImpl) obj;
if (key == null) {
if (other.key != null)
return false;
} else if (!key.equals(other.key))
return false;
return true;
}
@Override
public boolean equalsByPersistableKey(Persistable persistable) {
return equals(persistable);
}
}
...@@ -22,6 +22,7 @@ package org.olat.modules.quality.analysis.model; ...@@ -22,6 +22,7 @@ package org.olat.modules.quality.analysis.model;
import java.util.Date; import java.util.Date;
import org.olat.modules.quality.analysis.EvaluationFormView; import org.olat.modules.quality.analysis.EvaluationFormView;
import org.olat.repository.RepositoryEntry;
/** /**
* *
...@@ -31,22 +32,18 @@ import org.olat.modules.quality.analysis.EvaluationFormView; ...@@ -31,22 +32,18 @@ import org.olat.modules.quality.analysis.EvaluationFormView;
*/ */
public class EvaluationFormViewImpl implements EvaluationFormView { public class EvaluationFormViewImpl implements EvaluationFormView {
private final Long formEntryKey; private final RepositoryEntry formEntry;
private final Date formCreatedDate;
private final String formTitle;
private final Long numberDataCollections; private final Long numberDataCollections;
private final Date soonestDataCollectionDate; private final Date soonestDataCollectionDate;
private final Date latestDataCollectionDate; private final Date latestDataCollectionFinishedDate;
private final Long numberParticipationsDone; private final Long numberParticipationsDone;
public EvaluationFormViewImpl(Long formEntryKey, Date formCreatedDate, String formTitle, Long numberDataCollections, public EvaluationFormViewImpl(RepositoryEntry formEntry, Long numberDataCollections, Date soonestDataCollectionDate,
Date soonestDataCollectionDate, Date latestDataCollectionDate, Long numberParticipationsDone) { Date latestDataCollectionFinishedDate, Long numberParticipationsDone) {
this.formEntryKey = formEntryKey; this.formEntry = formEntry;
this.formCreatedDate = formCreatedDate;
this.formTitle = formTitle;
this.numberDataCollections = numberDataCollections; this.numberDataCollections = numberDataCollections;
this.soonestDataCollectionDate = soonestDataCollectionDate; this.soonestDataCollectionDate = soonestDataCollectionDate;
this.latestDataCollectionDate = latestDataCollectionDate; this.latestDataCollectionFinishedDate = latestDataCollectionFinishedDate;
this.numberParticipationsDone = numberParticipationsDone; this.numberParticipationsDone = numberParticipationsDone;
} }
...@@ -57,22 +54,12 @@ public class EvaluationFormViewImpl implements EvaluationFormView { ...@@ -57,22 +54,12 @@ public class EvaluationFormViewImpl implements EvaluationFormView {
@Override @Override
public Long getResourceableId() { public Long getResourceableId() {
return formEntryKey; return formEntry.getKey();
}
@Override
public Long getFormEntryKey() {
return formEntryKey;
}
@Override
public Date getFormCreatedDate() {
return formCreatedDate;
} }
@Override @Override
public String getFormTitle() { public RepositoryEntry getFormEntry() {
return formTitle; return formEntry;
} }
@Override @Override
...@@ -86,8 +73,8 @@ public class EvaluationFormViewImpl implements EvaluationFormView { ...@@ -86,8 +73,8 @@ public class EvaluationFormViewImpl implements EvaluationFormView {
} }
@Override @Override
public Date getLatestDataCollectionDate() { public Date getLatestDataCollectionFinishedDate() {
return latestDataCollectionDate; return latestDataCollectionFinishedDate;
} }
@Override @Override
......
...@@ -32,18 +32,19 @@ import org.olat.core.gui.control.Controller; ...@@ -32,18 +32,19 @@ import org.olat.core.gui.control.Controller;
import org.olat.core.gui.control.Event; import org.olat.core.gui.control.Event;
import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.WindowControl;
import org.olat.core.gui.control.controller.BasicController; import org.olat.core.gui.control.controller.BasicController;
import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController;
import org.olat.modules.forms.EvaluationFormManager; import org.olat.modules.forms.EvaluationFormManager;
import org.olat.modules.forms.model.xml.Form; import org.olat.modules.forms.model.xml.Form;
import org.olat.modules.forms.ui.ReportSegment; import org.olat.modules.forms.ui.ReportSegment;
import org.olat.modules.forms.ui.ReportSegmentEvent; import org.olat.modules.forms.ui.ReportSegmentEvent;
import org.olat.modules.quality.QualitySecurityCallback; import org.olat.modules.quality.QualitySecurityCallback;
import org.olat.modules.quality.analysis.AnalysisPresentation;
import org.olat.modules.quality.analysis.AnalysisSearchParameter; import org.olat.modules.quality.analysis.AnalysisSearchParameter;
import org.olat.modules.quality.analysis.AnalysisSegment;
import org.olat.modules.quality.analysis.AvailableAttributes; import org.olat.modules.quality.analysis.AvailableAttributes;
import org.olat.modules.quality.analysis.EvaluationFormView;
import org.olat.modules.quality.analysis.MultiGroupBy; import org.olat.modules.quality.analysis.MultiGroupBy;
import org.olat.modules.quality.analysis.QualityAnalysisService; import org.olat.modules.quality.analysis.QualityAnalysisService;
import org.olat.repository.RepositoryEntry; import org.olat.modules.quality.analysis.ui.PresentationEvent.Action;
import org.olat.repository.RepositoryService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
/** /**
...@@ -54,53 +55,69 @@ import org.springframework.beans.factory.annotation.Autowired; ...@@ -54,53 +55,69 @@ import org.springframework.beans.factory.annotation.Autowired;
*/ */
public class AnalysisController extends BasicController implements TooledController { public class AnalysisController extends BasicController implements TooledController {
enum Presentation {REPORT, HEAT_MAP}; private Link editPresentationLink;
private Link deletePresentationLink;
private Link showFilterLink; private Link showFilterLink;
private Link hideFilterLink; private Link hideFilterLink;
private VelocityContainer mainVC; private VelocityContainer mainVC;
private Controller filterCtrl; private Controller filterCtrl;
private FilterableController presentationCtrl; private FilterableController filterableCtrl;
private CloseableModalController cmc;
private PresentationController presentationCtrl;
private PresentationDeleteConfirmationController presentationDeleteCtrl;
private final QualitySecurityCallback secCallback; private final QualitySecurityCallback secCallback;
private final TooledStackedPanel stackPanel; private final TooledStackedPanel stackPanel;
private final EvaluationFormView formView;
private final Form form; private final Form form;
private final AvailableAttributes availableAttributes; private final AvailableAttributes availableAttributes;
private AnalysisSearchParameter searchParams; private AnalysisPresentation presentation;
private MultiGroupBy multiGroupBy = MultiGroupBy.noGroupBy(); private ReportSegment currentReportSegment;
private ReportSegment currentSegment;
@Autowired
private EvaluationFormManager evaluationFormManager;
@Autowired
private RepositoryService repositoryService;
@Autowired @Autowired
private QualityAnalysisService analysisService; private QualityAnalysisService analysisService;
@Autowired
private EvaluationFormManager evaluationFormManager;
protected AnalysisController(UserRequest ureq, WindowControl wControl, QualitySecurityCallback secCallback, protected AnalysisController(UserRequest ureq, WindowControl wControl, QualitySecurityCallback secCallback,
TooledStackedPanel stackPanel, EvaluationFormView formView) { TooledStackedPanel stackPanel, AnalysisPresentation presentation) {
super(ureq, wControl); super(ureq, wControl);
this.secCallback = secCallback; this.secCallback = secCallback;
this.stackPanel = stackPanel; this.stackPanel = stackPanel;
stackPanel.addListener(this); stackPanel.addListener(this);
this.formView = formView; this.presentation = presentation;
RepositoryEntry formEntry = repositoryService.loadByKey(formView.getFormEntryKey()); this.form = evaluationFormManager.loadForm(presentation.getFormEntry());
this.form = evaluationFormManager.loadForm(formEntry);
mainVC = createVelocityContainer("analysis"); mainVC = createVelocityContainer("analysis");
putInitialPanel(mainVC); putInitialPanel(mainVC);
searchParams = new AnalysisSearchParameter(); availableAttributes = analysisService.getAvailableAttributes(presentation.getSearchParams());
searchParams.setFormEntryRef(() -> formView.getFormEntryKey()); filterCtrl= new FilterController(ureq, wControl, form, presentation.getSearchParams(), availableAttributes);
availableAttributes = analysisService.getAvailableAttributes(searchParams);
filterCtrl= new FilterController(ureq, wControl, form, searchParams, availableAttributes);
listenTo(filterCtrl); listenTo(filterCtrl);
mainVC.put("filter", filterCtrl.getInitialComponent()); mainVC.put("filter", filterCtrl.getInitialComponent());
} }
@Override @Override
public void initTools() { public void initTools() {
initPresentationTools();
initFilterTools();
}
private void initPresentationTools() {
stackPanel.removeTool(editPresentationLink);
if (secCallback.canEditPresentations()) {
editPresentationLink = LinkFactory.createToolLink("presentation.edit", translate("presentation.edit"), this);
editPresentationLink.setIconLeftCSS("o_icon o_icon-fw o_icon_qual_ana_pres_edit");
stackPanel.addTool(editPresentationLink, Align.left);
}
stackPanel.removeTool(deletePresentationLink);
if (secCallback.canDeletePresentation(presentation)) {
deletePresentationLink = LinkFactory.createToolLink("presentation.delete", translate("presentation.delete"), this);
deletePresentationLink.setIconLeftCSS("o_icon o_icon-fw o_icon_qual_ana_pres_delete");
stackPanel.addTool(deletePresentationLink, Align.left);
}
}
private void initFilterTools() {
showFilterLink = LinkFactory.createToolLink("filter.show", translate("filter.show"), this); showFilterLink = LinkFactory.createToolLink("filter.show", translate("filter.show"), this);
showFilterLink.setIconLeftCSS("o_icon o_icon-fw o_icon_qual_ana_show_filter"); showFilterLink.setIconLeftCSS("o_icon o_icon-fw o_icon_qual_ana_show_filter");
hideFilterLink = LinkFactory.createToolLink("filter.hide", translate("filter.hide"), this); hideFilterLink = LinkFactory.createToolLink("filter.hide", translate("filter.hide"), this);
...@@ -110,7 +127,11 @@ public class AnalysisController extends BasicController implements TooledControl ...@@ -110,7 +127,11 @@ public class AnalysisController extends BasicController implements TooledControl
@Override @Override
protected void event(UserRequest ureq, Component source, Event event) { protected void event(UserRequest ureq, Component source, Event event) {
if (source == showFilterLink) { if (source == editPresentationLink) {
doEditPresentation(ureq);
} else if (source == deletePresentationLink) {
doConfirmDeletePresentation(ureq);
} else if (source == showFilterLink) {
doShowFilter(); doShowFilter();
} else if (source == hideFilterLink) { } else if (source == hideFilterLink) {
doHideFilter(); doHideFilter();
...@@ -119,7 +140,7 @@ public class AnalysisController extends BasicController implements TooledControl ...@@ -119,7 +140,7 @@ public class AnalysisController extends BasicController implements TooledControl
if (popEvent.isClose()) { if (popEvent.isClose()) {
stackPanel.popController(this); stackPanel.popController(this);
} else { } else {
setPresentation(ureq, Presentation.REPORT); setSegment(ureq, AnalysisSegment.OVERVIEW);
} }
} }
} }
...@@ -128,20 +149,56 @@ public class AnalysisController extends BasicController implements TooledControl ...@@ -128,20 +149,56 @@ public class AnalysisController extends BasicController implements TooledControl
protected void event(UserRequest ureq, Controller source, Event event) { protected void event(UserRequest ureq, Controller source, Event event) {
if (source == filterCtrl && event instanceof AnalysisFilterEvent) { if (source == filterCtrl && event instanceof AnalysisFilterEvent) {
AnalysisFilterEvent filterEvent = (AnalysisFilterEvent) event; AnalysisFilterEvent filterEvent = (AnalysisFilterEvent) event;
searchParams = filterEvent.getSearchParams(); AnalysisSearchParameter searchParams = filterEvent.getSearchParams();
presentationCtrl.onFilter(ureq, searchParams); presentation.setSearchParams(searchParams);
} else if (source == presentationCtrl) { filterableCtrl.onFilter(ureq, searchParams);
} else if (source == filterableCtrl) {
if (event instanceof ReportSegmentEvent) { if (event instanceof ReportSegmentEvent) {
// Save current segment between analysis segment changes // Save current segment between analysis segment changes
ReportSegmentEvent rsEvent = (ReportSegmentEvent) event; ReportSegmentEvent rsEvent = (ReportSegmentEvent) event;
currentSegment = rsEvent.getSegment(); currentReportSegment = rsEvent.getSegment();
} else if (event instanceof AnalysisGroupingEvent) { } else if (event instanceof AnalysisGroupingEvent) {
AnalysisGroupingEvent groupingEvent = (AnalysisGroupingEvent) event; AnalysisGroupingEvent groupingEvent = (AnalysisGroupingEvent) event;
multiGroupBy = groupingEvent.getMultiGroupBy(); MultiGroupBy multiGroupBy = groupingEvent.getMultiGroupBy();
presentation.setHeatMapGrouping(multiGroupBy);
} else if (event instanceof AnalysisInsufficientOnlyEvent) {
AnalysisInsufficientOnlyEvent iEvent = (AnalysisInsufficientOnlyEvent) event;
Boolean insufficientOnly = iEvent.getInsufficientOnly();
presentation.setHeatMapInsufficientOnly(insufficientOnly);
} }
} else if (source == presentationCtrl) {
if (event instanceof PresentationEvent) {
PresentationEvent apEvent = (PresentationEvent) event;
AnalysisPresentation editetPresentation = apEvent.getPresentation();
Action action = apEvent.getAction();
if (Action.SAVE.equals(action)) {
doSavePresentation(editetPresentation);
} else if (Action.CLONE.equals(action)) {
doClonePresentation(editetPresentation);
}
}
cmc.deactivate();
cleanUp();
} else if (source == presentationDeleteCtrl) {
if (Event.DONE_EVENT.equals(event)) {
doDeletePresentation();
}
cmc.deactivate();
cleanUp();
} else if (source == cmc) {
cleanUp();
} }
super.event(ureq, source, event); super.event(ureq, source, event);
} }
private void cleanUp() {
removeAsListenerAndDispose(presentationDeleteCtrl);
removeAsListenerAndDispose(presentationCtrl);
removeAsListenerAndDispose(cmc);
presentationDeleteCtrl = null;
presentationCtrl = null;
cmc = null;
}
@Override @Override
protected void doDispose() { protected void doDispose() {
...@@ -150,29 +207,71 @@ public class AnalysisController extends BasicController implements TooledControl ...@@ -150,29 +207,71 @@ public class AnalysisController extends BasicController implements TooledControl
} }
} }
public void setPresentation(UserRequest ureq, Presentation presentation) { public void setSegment(UserRequest ureq, AnalysisSegment segment) {
removeAsListenerAndDispose(presentationCtrl); removeAsListenerAndDispose(filterableCtrl);
presentationCtrl = null; filterableCtrl = null;
switch (presentation) { presentation.setAnalysisSegment(segment);
case REPORT: switch (segment) {
presentationCtrl = new AnalysisReportController(ureq, getWindowControl(), form, formView.getFormTitle(), case OVERVIEW:
currentSegment); filterableCtrl = new AnalysisReportController(ureq, getWindowControl(), form,
presentation.getFormEntry().getDisplayname(), currentReportSegment);
break; break;
case HEAT_MAP: case HEAT_MAP:
presentationCtrl = new HeatMapController(ureq, getWindowControl(), form, availableAttributes, multiGroupBy); filterableCtrl = new HeatMapController(ureq, getWindowControl(), form, availableAttributes,
presentation.getHeatMapGrouping(), presentation.getHeatMapInsufficientOnly());
break; break;
default: default:
presentationCtrl = new AnalysisReportController(ureq, getWindowControl(), form, formView.getFormTitle(), filterableCtrl = new AnalysisReportController(ureq, getWindowControl(), form,
currentSegment); presentation.getFormEntry().getDisplayname(), currentReportSegment);
break; break;
} }
listenTo(presentationCtrl); listenTo(filterableCtrl);
presentationCtrl.onFilter(ureq, searchParams); filterableCtrl.onFilter(ureq, presentation.getSearchParams());
mainVC.put("presentation", presentationCtrl.getInitialComponent()); mainVC.put("presentation", filterableCtrl.getInitialComponent());
mainVC.setDirty(true); mainVC.setDirty(true);
} }
private void doEditPresentation(UserRequest ureq) {
presentationCtrl = new PresentationController(ureq, getWindowControl(), presentation);
listenTo(presentationCtrl);
cmc = new CloseableModalController(getWindowControl(), translate("close"),
presentationCtrl.getInitialComponent(), true, translate("presentation.edit.title"));
cmc.activate();
listenTo(cmc);
}
private void doSavePresentation(AnalysisPresentation editetPresentation) {
presentation = analysisService.savePresentation(editetPresentation);
// refresh to avoid LazyInitializationException if access formEntry
presentation = analysisService.loadPresentationByKey(presentation);
initPresentationTools();
}
private void doClonePresentation(AnalysisPresentation editetPresentation) {
presentation = analysisService.clonePresentation(editetPresentation);
doSavePresentation(presentation);
}
private void doConfirmDeletePresentation(UserRequest ureq) {
presentationDeleteCtrl = new PresentationDeleteConfirmationController(ureq, getWindowControl(), presentation);
listenTo(presentationDeleteCtrl);
cmc = new CloseableModalController(getWindowControl(), translate("close"),
presentationDeleteCtrl.getInitialComponent(), true, translate("presentation.delete.title"));
cmc.activate();
listenTo(cmc);
}
private void doDeletePresentation() {
AnalysisPresentation clone = analysisService.clonePresentation(presentation);
clone.setName(null);
analysisService.deletePresentation(presentation);
presentation = clone;
initPresentationTools();
}
private void doShowFilter() { private void doShowFilter() {
stackPanel.addTool(hideFilterLink, Align.right); stackPanel.addTool(hideFilterLink, Align.right);
stackPanel.removeTool(showFilterLink); stackPanel.removeTool(showFilterLink);
......
...@@ -45,6 +45,16 @@ class AnalysisDataModel extends DefaultFlexiTableDataModel<AnalysisRow> ...@@ -45,6 +45,16 @@ class AnalysisDataModel extends DefaultFlexiTableDataModel<AnalysisRow>
this.locale = locale; this.locale = locale;
} }
public AnalysisRow getObjectByFormEntryKey(Long key) {
List<AnalysisRow> rows = getObjects();
for (AnalysisRow row: rows) {
if (row != null && row.getFormEntry().getKey().equals(key)) {
return row;
}
}
return null;
}
@Override @Override
public void sort(SortKey orderBy) { public void sort(SortKey orderBy) {
List<AnalysisRow> rows = new SortableFlexiTableModelDelegate<>(orderBy, this, locale).sort(); List<AnalysisRow> rows = new SortableFlexiTableModelDelegate<>(orderBy, this, locale).sort();
...@@ -64,7 +74,7 @@ class AnalysisDataModel extends DefaultFlexiTableDataModel<AnalysisRow> ...@@ -64,7 +74,7 @@ class AnalysisDataModel extends DefaultFlexiTableDataModel<AnalysisRow>
case formCreated: return row.getFormCreatedDate(); case formCreated: return row.getFormCreatedDate();
case numberDataCollections: return row.getNumberDataCollections(); case numberDataCollections: return row.getNumberDataCollections();
case soonest: return row.getSoonestDataCollectionDate(); case soonest: return row.getSoonestDataCollectionDate();
case latest: return row.getLatestDataCollectionDate(); case latest: return row.getLatestDataCollectionFinishedDate();
case numberParticipations: return row.getNumberParticipationsDone(); case numberParticipations: return row.getNumberParticipationsDone();
default: return null; default: return null;
} }
......
/**
* <a href="http://www.openolat.org">
* OpenOLAT - Online Learning and Training</a><br>
* <p>
* Licensed under the Apache License, Version 2.0 (the "License"); <br>
* you may not use this file except in compliance with the License.<br>
* You may obtain a copy of the License at the
* <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
* <p>
* Unless required by applicable law or agreed to in writing,<br>
* software distributed under the License is distributed on an "AS IS" BASIS, <br>
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
* See the License for the specific language governing permissions and <br>
* limitations under the License.
* <p>
* Initial code contributed and copyrighted by<br>
* frentix GmbH, http://www.frentix.com
* <p>
*/
package org.olat.modules.quality.analysis.ui;
import org.olat.core.gui.control.Event;
/**
*
* Initial date: 03.10.2018<br>
* @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
*
*/
public class AnalysisInsufficientOnlyEvent extends Event {
private static final long serialVersionUID = 2527721368026609367L;
private final Boolean insufficientOnly;
public AnalysisInsufficientOnlyEvent(boolean insufficientOnly) {
super("analysis-insufficient-only-event");
this.insufficientOnly = Boolean.valueOf(insufficientOnly);
}
public Boolean getInsufficientOnly() {
return insufficientOnly;
}
}
...@@ -23,7 +23,6 @@ import java.util.ArrayList; ...@@ -23,7 +23,6 @@ import java.util.ArrayList;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import org.olat.basesecurity.OrganisationRoles;
import org.olat.basesecurity.OrganisationService; import org.olat.basesecurity.OrganisationService;
import org.olat.core.gui.UserRequest; import org.olat.core.gui.UserRequest;
import org.olat.core.gui.components.Component; import org.olat.core.gui.components.Component;
...@@ -48,8 +47,12 @@ import org.olat.core.gui.components.velocity.VelocityContainer; ...@@ -48,8 +47,12 @@ import org.olat.core.gui.components.velocity.VelocityContainer;
import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.Controller;
import org.olat.core.gui.control.Event; import org.olat.core.gui.control.Event;
import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.WindowControl;
import org.olat.core.gui.control.generic.dtabs.Activateable2;
import org.olat.core.id.Organisation; import org.olat.core.id.Organisation;
import org.olat.core.id.context.ContextEntry;
import org.olat.core.id.context.StateEntry;
import org.olat.modules.quality.QualitySecurityCallback; import org.olat.modules.quality.QualitySecurityCallback;
import org.olat.modules.quality.analysis.AnalysisPresentation;
import org.olat.modules.quality.analysis.EvaluationFormView; import org.olat.modules.quality.analysis.EvaluationFormView;
import org.olat.modules.quality.analysis.EvaluationFormViewSearchParams; import org.olat.modules.quality.analysis.EvaluationFormViewSearchParams;
import org.olat.modules.quality.analysis.QualityAnalysisService; import org.olat.modules.quality.analysis.QualityAnalysisService;
...@@ -62,11 +65,11 @@ import org.springframework.beans.factory.annotation.Autowired; ...@@ -62,11 +65,11 @@ import org.springframework.beans.factory.annotation.Autowired;
* @author uhensler, urs.hensler@frentix.com, http://www.frentix.com * @author uhensler, urs.hensler@frentix.com, http://www.frentix.com
* *
*/ */
public class AnalysisListController extends FormBasicController implements FlexiTableComponentDelegate { public class AnalysisListController extends FormBasicController implements FlexiTableComponentDelegate, Activateable2 {
private static final String CMD_OPEN = "open"; private static final String CMD_OPEN = "open";
private static final Comparator<? super EvaluationFormView> CREATED_DESC = private static final Comparator<? super EvaluationFormView> CREATED_DESC =
(f1, f2) -> f2.getFormCreatedDate().compareTo(f1.getFormCreatedDate()); (f1, f2) -> f2.getLatestDataCollectionFinishedDate().compareTo(f1.getLatestDataCollectionFinishedDate());
private final TooledStackedPanel stackPanel; private final TooledStackedPanel stackPanel;
private final QualitySecurityCallback secCallback; private final QualitySecurityCallback secCallback;
...@@ -76,7 +79,7 @@ public class AnalysisListController extends FormBasicController implements Flexi ...@@ -76,7 +79,7 @@ public class AnalysisListController extends FormBasicController implements Flexi
private AnalysisSegmentsController analysisCtrl; private AnalysisSegmentsController analysisCtrl;
private final List<Organisation> organisations; private final List<Organisation> organisations;
private int counter; private int counter = 0;
private EvaluationFormView currentFormView; private EvaluationFormView currentFormView;
@Autowired @Autowired
...@@ -91,7 +94,7 @@ public class AnalysisListController extends FormBasicController implements Flexi ...@@ -91,7 +94,7 @@ public class AnalysisListController extends FormBasicController implements Flexi
stackPanel.addListener(this); stackPanel.addListener(this);
this.secCallback = secCallback; this.secCallback = secCallback;
this.organisations = organisationService.getOrganisations(getIdentity(), ureq.getUserSession().getRoles(), this.organisations = organisationService.getOrganisations(getIdentity(), ureq.getUserSession().getRoles(),
OrganisationRoles.administrator, OrganisationRoles.qualitymanager); secCallback.getAnalysisViewRoles());
initForm(ureq); initForm(ureq);
} }
...@@ -165,6 +168,24 @@ public class AnalysisListController extends FormBasicController implements Flexi ...@@ -165,6 +168,24 @@ public class AnalysisListController extends FormBasicController implements Flexi
return components; return components;
} }
@Override
public void activate(UserRequest ureq, List<ContextEntry> entries, StateEntry state) {
if(entries == null || entries.isEmpty()) return;
String type = entries.get(0).getOLATResourceable().getResourceableTypeName();
if (EvaluationFormView.RESOURCEABLE_TYPE.equalsIgnoreCase(type)) {
Long formEntryKey = entries.get(0).getOLATResourceable().getResourceableId();
AnalysisRow row = dataModel.getObjectByFormEntryKey(formEntryKey);
if (row != null) {
currentFormView = row;
doOpenAnalysis(ureq);
}
} else if (AnalysisPresentation.RESOURCEABLE_TYPE.equalsIgnoreCase(type)) {
Long presentationKey = entries.get(0).getOLATResourceable().getResourceableId();
doOpenPresentation(ureq, presentationKey);
}
}
@Override @Override
public void event(UserRequest ureq, Component source, Event event) { public void event(UserRequest ureq, Component source, Event event) {
if (stackPanel == source && stackPanel.getLastController() == analysisCtrl && event instanceof PopEvent) { if (stackPanel == source && stackPanel.getLastController() == analysisCtrl && event instanceof PopEvent) {
...@@ -198,10 +219,21 @@ public class AnalysisListController extends FormBasicController implements Flexi ...@@ -198,10 +219,21 @@ public class AnalysisListController extends FormBasicController implements Flexi
} }
private void doOpenAnalysis(UserRequest ureq) { private void doOpenAnalysis(UserRequest ureq) {
AnalysisPresentation presentation = analysisService.createPresentation(currentFormView.getFormEntry());
WindowControl bwControl = addToHistory(ureq, currentFormView, null); WindowControl bwControl = addToHistory(ureq, currentFormView, null);
analysisCtrl = new AnalysisSegmentsController(ureq, bwControl, secCallback, stackPanel, currentFormView); doOpenAnalysis(ureq, bwControl, presentation);
}
private void doOpenPresentation(UserRequest ureq, Long presentationKey) {
AnalysisPresentation presentation = analysisService.loadPresentationByKey(() -> presentationKey);
WindowControl bwControl = addToHistory(ureq, presentation, null);
doOpenAnalysis(ureq, bwControl, presentation);
}
private void doOpenAnalysis(UserRequest ureq, WindowControl wControl, AnalysisPresentation presentation) {
analysisCtrl = new AnalysisSegmentsController(ureq, wControl, secCallback, stackPanel, presentation);
listenTo(analysisCtrl); listenTo(analysisCtrl);
String title = currentFormView.getFormTitle(); String title = presentation.getFormEntry().getDisplayname();
stackPanel.pushController(title, analysisCtrl); stackPanel.pushController(title, analysisCtrl);
analysisCtrl.activate(ureq, null, null); analysisCtrl.activate(ureq, null, null);
} }
......
...@@ -23,6 +23,7 @@ import java.util.Date; ...@@ -23,6 +23,7 @@ import java.util.Date;
import org.olat.core.gui.components.form.flexible.elements.FormLink; import org.olat.core.gui.components.form.flexible.elements.FormLink;
import org.olat.modules.quality.analysis.EvaluationFormView; import org.olat.modules.quality.analysis.EvaluationFormView;
import org.olat.repository.RepositoryEntry;
/** /**
* *
...@@ -51,18 +52,16 @@ public class AnalysisRow implements EvaluationFormView { ...@@ -51,18 +52,16 @@ public class AnalysisRow implements EvaluationFormView {
} }
@Override @Override
public Long getFormEntryKey() { public RepositoryEntry getFormEntry() {
return formView.getFormEntryKey(); return formView.getFormEntry();
} }
@Override
public Date getFormCreatedDate() { public Date getFormCreatedDate() {
return formView.getFormCreatedDate(); return formView.getFormEntry().getCreationDate();
} }
@Override
public String getFormTitle() { public String getFormTitle() {
return formView.getFormTitle(); return formView.getFormEntry().getDisplayname();
} }
@Override @Override
...@@ -76,8 +75,8 @@ public class AnalysisRow implements EvaluationFormView { ...@@ -76,8 +75,8 @@ public class AnalysisRow implements EvaluationFormView {
} }
@Override @Override
public Date getLatestDataCollectionDate() { public Date getLatestDataCollectionFinishedDate() {
return formView.getLatestDataCollectionDate(); return formView.getLatestDataCollectionFinishedDate();
} }
@Override @Override
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment