Skip to content
Snippets Groups Projects
Commit bd0fc10b authored by srosse's avatar srosse
Browse files

OO-3292, OO-3290: add copy and delete of curriculum element type, indent curriculum view

parent bff9a53f
No related merge requests found
Showing
with 237 additions and 28 deletions
......@@ -345,10 +345,10 @@ public class AssessmentHtmlBuilder {
this.attributesUri = uri;
}
public void addAttributes(Attributes attributes) {
for(int i=0; i<attributes.getLength(); i++) {
String name = attributes.getLocalName(i);
String value = attributes.getValue(i);
public void addAttributes(Attributes attrs) {
for(int i=0; i<attrs.getLength(); i++) {
String name = attrs.getLocalName(i);
String value = attrs.getValue(i);
addAttribute(name, value);
}
}
......
......@@ -37,6 +37,7 @@ public enum CurriculumElementTypeManagedFlag {
all,
identifier(all),
displayName(all),
cssClass(all),
description(all),
externalId(all),
subTypes(all),
......
......@@ -24,6 +24,7 @@ import java.util.List;
import org.olat.core.commons.persistence.DB;
import org.olat.modules.curriculum.CurriculumElementType;
import org.olat.modules.curriculum.CurriculumElementTypeRef;
import org.olat.modules.curriculum.model.CurriculumElementTypeImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
......@@ -52,6 +53,20 @@ public class CurriculumElementTypeDAO {
return type;
}
public CurriculumElementType cloneCurriculumElementType(CurriculumElementTypeRef typeRef) {
CurriculumElementType reloadedType = loadByKey(typeRef.getKey());
CurriculumElementTypeImpl clone = new CurriculumElementTypeImpl();
clone.setCreationDate(new Date());
clone.setLastModified(clone.getCreationDate());
clone.setIdentifier(reloadedType.getIdentifier() + " (Copy)");
clone.setDisplayName(reloadedType.getDisplayName());
clone.setDescription(reloadedType.getDescription());
clone.setCssClass(reloadedType.getCssClass());
dbInstance.getCurrentEntityManager().persist(clone);
return clone;
}
public CurriculumElementType loadByKey(Long key) {
List<CurriculumElementType> types = dbInstance.getCurrentEntityManager()
.createNamedQuery("loadCurriculumElementTypeByKey", CurriculumElementType.class)
......@@ -60,6 +75,17 @@ public class CurriculumElementTypeDAO {
return types == null || types.isEmpty() ? null : types.get(0);
}
public boolean hasElements(CurriculumElementTypeRef typeRef) {
String query = "select el.key from curriculumelement el where el.type.key=:typeKey";
List<Long> types = dbInstance.getCurrentEntityManager()
.createQuery(query, Long.class)
.setParameter("typeKey", typeRef.getKey())
.setFirstResult(0)
.setMaxResults(1)
.getResultList();
return types != null && !types.isEmpty() && types.get(0) != null && types.get(0).longValue() > 0;
}
public List<CurriculumElementType> load() {
return dbInstance.getCurrentEntityManager()
.createNamedQuery("loadCurriculumElementTypes", CurriculumElementType.class)
......@@ -70,5 +96,10 @@ public class CurriculumElementTypeDAO {
((CurriculumElementTypeImpl)type).setLastModified(new Date());
return dbInstance.getCurrentEntityManager().merge(type);
}
public void deleteCurriculumElementType(CurriculumElementTypeRef type) {
CurriculumElementType reloadedType = dbInstance.getCurrentEntityManager()
.getReference(CurriculumElementTypeImpl.class, type.getKey());
dbInstance.getCurrentEntityManager().remove(reloadedType);
}
}
......@@ -39,6 +39,7 @@ import org.olat.modules.curriculum.CurriculumElement;
import org.olat.modules.curriculum.CurriculumElementRef;
import org.olat.modules.curriculum.CurriculumElementType;
import org.olat.modules.curriculum.CurriculumElementTypeRef;
import org.olat.modules.curriculum.CurriculumElementTypeToType;
import org.olat.modules.curriculum.CurriculumRef;
import org.olat.modules.curriculum.CurriculumRoles;
import org.olat.modules.curriculum.CurriculumService;
......@@ -136,14 +137,25 @@ public class CurriculumServiceImpl implements CurriculumService {
}
@Override
public CurriculumElementType cloneCurriculumElementType(CurriculumElementTypeRef typeRef) {
// TODO Auto-generated method stub
return null;
public CurriculumElementType cloneCurriculumElementType(CurriculumElementTypeRef elementType) {
CurriculumElementType clonedType = curriculumElementTypeDao.cloneCurriculumElementType(elementType);
List<CurriculumElementTypeToType> allowSubTypesToTypes = curriculumElementTypeToTypeDao.getAllowedSubTypes(elementType);
if(allowSubTypesToTypes.size() > 0) {
for(CurriculumElementTypeToType allowSubTypeToType:allowSubTypesToTypes) {
curriculumElementTypeToTypeDao.addAllowedSubType(clonedType, allowSubTypeToType.getAllowedSubType());
}
}
return clonedType;
}
@Override
public boolean deleteCurriculumElementType(CurriculumElementTypeRef typeRef) {
return false;
public boolean deleteCurriculumElementType(CurriculumElementTypeRef elementType) {
if(curriculumElementTypeDao.hasElements(elementType)) {
return false;
}
curriculumElementTypeToTypeDao.deleteAllowedSubTypes(elementType);
curriculumElementTypeDao.deleteCurriculumElementType(elementType);
return true;
}
@Override
......
......@@ -23,7 +23,9 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import org.olat.NewControllerFactory;
import org.olat.core.gui.UserRequest;
......@@ -35,7 +37,9 @@ import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
import org.olat.core.gui.components.form.flexible.impl.FormEvent;
import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiColumnModel;
import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableCssDelegate;
import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableRendererType;
import org.olat.core.gui.components.link.Link;
import org.olat.core.gui.control.Controller;
import org.olat.core.gui.control.WindowControl;
......@@ -47,6 +51,8 @@ import org.olat.modules.curriculum.CurriculumService;
import org.olat.modules.curriculum.model.CurriculumElementRepositoryEntryViews;
import org.olat.modules.curriculum.ui.CurriculumElementDataModel.ElementCols;
import org.olat.modules.curriculum.ui.CurriculumElementWithViewsDataModel.ElementViewCols;
import org.olat.modules.curriculum.ui.component.CurriculumElementDepthComparator;
import org.olat.modules.curriculum.ui.component.CurriculumElementIndentRenderer;
import org.olat.repository.RepositoryEntry;
import org.olat.repository.RepositoryEntryMyView;
import org.olat.repository.RepositoryService;
......@@ -60,6 +66,8 @@ import org.olat.resource.accesscontrol.model.PriceMethodBundle;
import org.olat.resource.accesscontrol.ui.PriceFormat;
import org.springframework.beans.factory.annotation.Autowired;
import edu.emory.mathcs.backport.java.util.Collections;
/**
* This is a list of curriculum elements and repository entries
* aimed to participants. The repository entries permissions
......@@ -70,7 +78,7 @@ import org.springframework.beans.factory.annotation.Autowired;
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*
*/
public class CurriculumElementListController extends FormBasicController {
public class CurriculumElementListController extends FormBasicController implements FlexiTableCssDelegate {
private FlexiTableElement tableEl;
private CurriculumElementWithViewsDataModel tableModel;
......@@ -101,7 +109,7 @@ public class CurriculumElementListController extends FormBasicController {
protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, ElementCols.key));
columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ElementViewCols.elementDisplayName));
columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ElementViewCols.elementDisplayName, new CurriculumElementIndentRenderer()));
columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ElementViewCols.elementIdentifier));
columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ElementViewCols.entryDisplayName));
columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ElementViewCols.start));
......@@ -110,9 +118,30 @@ public class CurriculumElementListController extends FormBasicController {
tableEl = uifactory.addTableElement(getWindowControl(), "table", tableModel, 20, false, getTranslator(), formLayout);
tableEl.setCustomizeColumns(true);
tableEl.setEmtpyTableMessageKey("table.curriculum.empty");
tableEl.setCssDelegate(this);
tableEl.setAndLoadPersistedPreferences(ureq, "cur-curriculum-manage");
}
@Override
public String getWrapperCssClass(FlexiTableRendererType type) {
return null;
}
@Override
public String getTableCssClass(FlexiTableRendererType type) {
return null;
}
@Override
public String getRowCssClass(FlexiTableRendererType type, int pos) {
CurriculumElementWithViewsRow rowWithView = tableModel.getObject(pos);
int count = 0;
for(CurriculumElementWithViewsRow parent=rowWithView.getParent(); parent != null; parent=parent.getParent()) {
count++;
}
return "o_curriculum_element_l" + count;
}
private void loadModel(UserRequest ureq) {
Roles roles = ureq.getUserSession().getRoles();
List<CurriculumElementRepositoryEntryViews> elementsWithViews = curriculumService.getCurriculumElements(getIdentity(), roles, curriculum);
......@@ -137,19 +166,25 @@ public class CurriculumElementListController extends FormBasicController {
if(elementWithViews.getEntries() == null || elementWithViews.getEntries().isEmpty()) {
rows.add(new CurriculumElementWithViewsRow(element));
} else if(elementWithViews.getEntries().size() == 1) {
CurriculumElementWithViewsRow row = new CurriculumElementWithViewsRow(element, elementWithViews.getEntries().get(0));
CurriculumElementWithViewsRow row = new CurriculumElementWithViewsRow(element, elementWithViews.getEntries().get(0), true);
forge(row, repoKeys, resourcesWithOffer);
rows.add(row);
} else {
rows.add(new CurriculumElementWithViewsRow(element));
for(RepositoryEntryMyView entry:elementWithViews.getEntries()) {
CurriculumElementWithViewsRow row = new CurriculumElementWithViewsRow(element, entry);
CurriculumElementWithViewsRow row = new CurriculumElementWithViewsRow(element, entry, false);
forge(row, repoKeys, resourcesWithOffer);
rows.add(row);
}
}
}
Map<Long,CurriculumElementWithViewsRow> keyToRow = rows.stream()
.collect(Collectors.toMap(CurriculumElementWithViewsRow::getKey, row -> row, (row1, row2) -> row1));
rows.forEach(row -> row.setParent(keyToRow.get(row.getParentKey())));
Collections.sort(rows, new CurriculumElementDepthComparator());
tableModel.setObjects(rows);
tableEl.reset(true, true, true);
}
......
......@@ -40,9 +40,11 @@ public class CurriculumElementWithViewsRow implements CurriculumElementRef, Flex
private boolean hasChildren;
private CurriculumElementWithViewsRow parent;
private final Long parentKey;
private final CurriculumElement element;
private boolean singleEntry;
private Long repositoryEntryKey;
private String repositoryEntryName;
private OLATResource olatResource;
......@@ -57,11 +59,13 @@ public class CurriculumElementWithViewsRow implements CurriculumElementRef, Flex
public CurriculumElementWithViewsRow(CurriculumElement element) {
this.element = element;
singleEntry = false;
parentKey = element.getParent() == null ? null : element.getParent().getKey();
}
public CurriculumElementWithViewsRow(CurriculumElement element, RepositoryEntryMyView repositoryEntryView) {
public CurriculumElementWithViewsRow(CurriculumElement element, RepositoryEntryMyView repositoryEntryView, boolean alone) {
this.element = element;
singleEntry = alone;
parentKey = element.getParent() == null ? null : element.getParent().getKey();
isMembersOnly = repositoryEntryView.isMembersOnly();
......@@ -77,11 +81,19 @@ public class CurriculumElementWithViewsRow implements CurriculumElementRef, Flex
}
public String getCurriculumElementIdentifier() {
return element.getIdentifier();
return repositoryEntryName == null || singleEntry ? element.getIdentifier() : null;
}
public String getCurriculumElementDisplayName() {
return element.getDisplayName();
return repositoryEntryName == null || singleEntry ? element.getDisplayName() : null;
}
public String getMaterializedPathKeys() {
return element.getMaterializedPathKeys();
}
public boolean isSingleEntry() {
return singleEntry;
}
public int getAccess() {
......
......@@ -154,7 +154,7 @@ public class EditCurriculumElementController extends FormBasicController {
beginEl.setEnabled(!CurriculumElementManagedFlag.isManaged(element, CurriculumElementManagedFlag.dates));
Date end = element == null ? null : element.getEndDate();
endEl = uifactory.addDateChooser("start", "curriculum.element.end", end, formLayout);
endEl = uifactory.addDateChooser("end", "curriculum.element.end", end, formLayout);
endEl.setEnabled(!CurriculumElementManagedFlag.isManaged(element, CurriculumElementManagedFlag.dates));
String description = element == null ? "" : element.getDescription();
......
......@@ -50,6 +50,7 @@ import org.springframework.beans.factory.annotation.Autowired;
*/
public class EditCurriculumElementTypeController extends FormBasicController {
private TextElement cssClassEl;
private TextElement identifierEl;
private TextElement displayNameEl;
private RichTextElement descriptionEl;
......@@ -81,6 +82,10 @@ public class EditCurriculumElementTypeController extends FormBasicController {
displayNameEl.setEnabled(!CurriculumElementTypeManagedFlag.isManaged(curriculumElementType, CurriculumElementTypeManagedFlag.displayName));
displayNameEl.setMandatory(true);
String cssClass = curriculumElementType == null ? "" : curriculumElementType.getCssClass();
cssClassEl = uifactory.addTextElement("type.cssClass", "type.cssClass", 255, cssClass, formLayout);
cssClassEl.setEnabled(!CurriculumElementTypeManagedFlag.isManaged(curriculumElementType, CurriculumElementTypeManagedFlag.cssClass));
String description = curriculumElementType == null ? "" : curriculumElementType.getDescription();
descriptionEl = uifactory.addRichTextElementForStringDataMinimalistic("type.description", "type.description", description, 10, 60,
formLayout, getWindowControl());
......@@ -146,6 +151,7 @@ public class EditCurriculumElementTypeController extends FormBasicController {
curriculumElementType.setDisplayName(displayNameEl.getValue());
curriculumElementType.setDescription(descriptionEl.getValue());
}
curriculumElementType.setCssClass(cssClassEl.getValue());
Collection<String> selectedAllowedSubTypeKeys = allowedSubTypesEl.getSelectedKeys();
List<CurriculumElementType> allowedSubTypes = new ArrayList<>();
......
......@@ -57,6 +57,7 @@ table.header.repository.entry.displayName=Titel der Lernressource
table.header.start=Starten
table.type.empty=Es sind keine Typen vorhanden.
type.allowed.sub.types=Sub types
type.cssClass=CSS class
type.description=Beschreibung
type.displayname=Name
type.identifier=Bezeichnung
......
......@@ -56,6 +56,7 @@ table.header.start=Launch
table.header.username=Username
table.type.empty=There isn't any type available.
type.allowed.sub.types=Sub types
type.cssClass=CSS class
type.description=Description
type.displayname=Name
type.identifier=Identifier
......
/**
* <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.curriculum.ui.component;
import java.util.Comparator;
import org.olat.core.util.StringHelper;
import org.olat.modules.curriculum.ui.CurriculumElementWithViewsRow;
/**
*
* Initial date: 13 déc. 2017<br>
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*
*/
public class CurriculumElementDepthComparator implements Comparator<CurriculumElementWithViewsRow > {
@Override
public int compare(CurriculumElementWithViewsRow element1, CurriculumElementWithViewsRow element2) {
int l1 = getLevels(element1);
int l2 = getLevels(element2);
int c = Integer.compare(l1, l2);
if(c == 0) {
c = element1.getKey().compareTo(element2.getKey());
}
return c;
}
private final int getLevels(CurriculumElementWithViewsRow node) {
String materializedPath = node.getMaterializedPathKeys();
return StringHelper.count(materializedPath, '/');
}
}
\ 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.curriculum.ui.component;
import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiCellRenderer;
import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableComponent;
import org.olat.core.gui.render.Renderer;
import org.olat.core.gui.render.StringOutput;
import org.olat.core.gui.render.URLBuilder;
import org.olat.core.gui.translator.Translator;
import org.olat.core.util.StringHelper;
import org.olat.modules.curriculum.ui.CurriculumElementWithViewsRow;
/**
*
* Initial date: 31 mai 2018<br>
* @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
*
*/
public class CurriculumElementIndentRenderer implements FlexiCellRenderer {
@Override
public void render(Renderer renderer, StringOutput target, Object cellValue, int row, FlexiTableComponent source,
URLBuilder ubu, Translator translator) {
CurriculumElementWithViewsRow rowWithView = (CurriculumElementWithViewsRow)source.getFlexiTableElement().getTableDataModel().getObject(row);
indent(target, rowWithView);
if(cellValue instanceof String) {
target.append(StringHelper.escapeHtml((String)cellValue));
}
}
private void indent(StringOutput target, CurriculumElementWithViewsRow rowWithView) {
for(CurriculumElementWithViewsRow parent=rowWithView.getParent(); parent != null; parent=parent.getParent()) {
target.append("&nbsp;&nbsp;");
}
}
}
......@@ -54,6 +54,7 @@
@import "modules/repository";
@import "modules/course";
@import "modules/courseeditor";
@import "modules/curriculum";
@import "modules/qti";
@import "modules/qti21";
@import "modules/devel";
......
@for $i from 0 through 11 {
tr.o_curriculum_element_l#{$i} td {
padding: ($i * $o-tree-padding-steps-px);
}
}
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
source diff could not be displayed: it is too large. Options to address this: view the blob.
This diff is collapsed.
This diff is collapsed.
source diff could not be displayed: it is too large. Options to address this: view the blob.
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