From 85e593fca18cfb0df4193b6d50351da7869e0f9c Mon Sep 17 00:00:00 2001 From: srosse <none@none> Date: Wed, 6 Jul 2016 16:22:13 +0200 Subject: [PATCH] OO-2057: search in media center --- .../BaseFullWebappWindowControl.java | 5 +- .../core/gui/control/LocalWindowControl.java | 5 +- .../olat/core/gui/control/WindowControl.java | 3 +- .../closablewrapper/CalloutSettings.java | 62 +++++++++++ .../CloseableCalloutWindowController.java | 40 ++++++- .../core/gui/control/guistack/GuiStack.java | 3 +- .../control/guistack/GuiStackNiceImpl.java | 14 ++- .../control/guistack/_content/callout.html | 90 ++++++++++----- .../context/StackedBusinessWindowControl.java | 5 +- .../tool/AssessedIdentityListController.java | 3 +- .../modules/portfolio/PortfolioService.java | 11 +- .../modules/portfolio/manager/MediaDAO.java | 26 ++++- .../modules/portfolio/manager/PageDAO.java | 31 ++++++ .../manager/PortfolioServiceImpl.java | 14 ++- .../modules/portfolio/model/MediaRow.java | 43 +++++++- .../portfolio/ui/BinderListController.java | 4 +- .../portfolio/ui/MediaCenterController.java | 82 ++++++++++---- .../modules/portfolio/ui/MediaDataModel.java | 103 ++++++++++++++++-- .../portfolio/ui/PageEditController.java | 4 +- .../portfolio/ui/PageListDataModel.java | 2 +- .../portfolio/ui/PageMetadataController.java | 19 ++++ .../portfolio/ui/_content/page_meta.html | 2 +- .../ui/_i18n/LocalStrings_de.properties | 11 +- .../ui/_i18n/LocalStrings_en.properties | 10 +- .../ui/editor/PageEditorController.java | 13 ++- .../ui/media/CollectImageMediaController.java | 4 +- .../ui/media/CollectTextMediaController.java | 4 +- .../ui/renderer/MediaTypeCellRenderer.java | 58 ++++++++++ .../ui/EPArtefactPoolRunController.java | 14 ++- .../portfolio/ui/_content/artefactsmain.html | 7 +- .../view/EPArtefactViewController.java | 4 +- .../ui/structel/EPAddElementsController.java | 2 +- .../restapi/support/ErrorWindowControl.java | 3 +- .../en/EnrollmentManagerConcurrentTest.java | 3 +- 34 files changed, 595 insertions(+), 109 deletions(-) create mode 100644 src/main/java/org/olat/core/gui/control/generic/closablewrapper/CalloutSettings.java create mode 100644 src/main/java/org/olat/modules/portfolio/ui/renderer/MediaTypeCellRenderer.java diff --git a/src/main/java/org/olat/core/commons/fullWebApp/BaseFullWebappWindowControl.java b/src/main/java/org/olat/core/commons/fullWebApp/BaseFullWebappWindowControl.java index 6d8d9324ead..2064ef73107 100644 --- a/src/main/java/org/olat/core/commons/fullWebApp/BaseFullWebappWindowControl.java +++ b/src/main/java/org/olat/core/commons/fullWebApp/BaseFullWebappWindowControl.java @@ -23,6 +23,7 @@ import org.olat.core.gui.components.Component; import org.olat.core.gui.control.WindowBackOffice; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.WindowControlInfoImpl; +import org.olat.core.gui.control.generic.closablewrapper.CalloutSettings; import org.olat.core.gui.control.info.WindowControlInfo; import org.olat.core.id.context.BusinessControl; import org.olat.core.id.context.BusinessControlFactory; @@ -61,8 +62,8 @@ class BaseFullWebappWindowControl implements WindowControl { } @Override - public void pushAsCallout(Component comp, String targetId) { - webappCtrl.getCurrentGuiStack().pushCallout(comp, targetId); + public void pushAsCallout(Component comp, String targetId, CalloutSettings settings) { + webappCtrl.getCurrentGuiStack().pushCallout(comp, targetId, settings); } /** diff --git a/src/main/java/org/olat/core/gui/control/LocalWindowControl.java b/src/main/java/org/olat/core/gui/control/LocalWindowControl.java index b0e65b9b6cf..c5e6c4f239c 100644 --- a/src/main/java/org/olat/core/gui/control/LocalWindowControl.java +++ b/src/main/java/org/olat/core/gui/control/LocalWindowControl.java @@ -27,6 +27,7 @@ package org.olat.core.gui.control; import org.olat.core.gui.components.Component; +import org.olat.core.gui.control.generic.closablewrapper.CalloutSettings; import org.olat.core.gui.control.info.WindowControlInfo; import org.olat.core.id.context.BusinessControl; import org.olat.core.logging.OLog; @@ -71,8 +72,8 @@ public class LocalWindowControl implements WindowControl { } @Override - public void pushAsCallout(Component comp, String targetId) { - origWControl.pushAsCallout(comp, targetId); + public void pushAsCallout(Component comp, String targetId, CalloutSettings settings) { + origWControl.pushAsCallout(comp, targetId, settings); localHeight++; } diff --git a/src/main/java/org/olat/core/gui/control/WindowControl.java b/src/main/java/org/olat/core/gui/control/WindowControl.java index f9002d0e4c3..4ecc320ac5e 100644 --- a/src/main/java/org/olat/core/gui/control/WindowControl.java +++ b/src/main/java/org/olat/core/gui/control/WindowControl.java @@ -27,6 +27,7 @@ package org.olat.core.gui.control; import org.olat.core.gui.components.Component; +import org.olat.core.gui.control.generic.closablewrapper.CalloutSettings; import org.olat.core.gui.control.info.WindowControlInfo; import org.olat.core.id.context.BusinessControl; @@ -61,7 +62,7 @@ public interface WindowControl { * @param comp * @param targetId */ - public void pushAsCallout(Component comp, String targetId); + public void pushAsCallout(Component comp, String targetId, CalloutSettings settings); /** diff --git a/src/main/java/org/olat/core/gui/control/generic/closablewrapper/CalloutSettings.java b/src/main/java/org/olat/core/gui/control/generic/closablewrapper/CalloutSettings.java new file mode 100644 index 00000000000..e5694600009 --- /dev/null +++ b/src/main/java/org/olat/core/gui/control/generic/closablewrapper/CalloutSettings.java @@ -0,0 +1,62 @@ +/** + * <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.core.gui.control.generic.closablewrapper; + +/** + * + * Initial date: 06.07.2016<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class CalloutSettings { + + private final boolean arrow; + private final CalloutOrientation orientation; + + public CalloutSettings() { + this(true, CalloutOrientation.bottom); + } + + public CalloutSettings(CalloutOrientation orientation) { + this(true, orientation); + } + + public CalloutSettings(boolean arrow) { + this(arrow, CalloutOrientation.bottom); + } + + public CalloutSettings(boolean arrow, CalloutOrientation orientation) { + this.orientation = orientation; + this.arrow = arrow; + } + + public boolean isArrow() { + return arrow; + } + + public CalloutOrientation getOrientation() { + return orientation; + } + + public enum CalloutOrientation { + top, + bottom + } +} diff --git a/src/main/java/org/olat/core/gui/control/generic/closablewrapper/CloseableCalloutWindowController.java b/src/main/java/org/olat/core/gui/control/generic/closablewrapper/CloseableCalloutWindowController.java index 1dfcc787f16..c63d92faab6 100644 --- a/src/main/java/org/olat/core/gui/control/generic/closablewrapper/CloseableCalloutWindowController.java +++ b/src/main/java/org/olat/core/gui/control/generic/closablewrapper/CloseableCalloutWindowController.java @@ -61,6 +61,7 @@ import org.olat.core.logging.OLATRuntimeException; public class CloseableCalloutWindowController extends BasicController { public static final Event CLOSE_WINDOW_EVENT = new Event("CLOSE_WINDOW_EVENT"); + private final CalloutSettings settings; private VelocityContainer calloutVC; private CloseableModalController cmc; @@ -92,8 +93,14 @@ public class CloseableCalloutWindowController extends BasicController { */ public CloseableCalloutWindowController(UserRequest ureq, WindowControl wControl, Component calloutWindowContent, String targetDomID, String title, boolean closable, String cssClasses) { + this(ureq, wControl, calloutWindowContent, targetDomID, title, closable, cssClasses, new CalloutSettings()); + } + + public CloseableCalloutWindowController(UserRequest ureq, WindowControl wControl, Component calloutWindowContent, + String targetDomID, String title, boolean closable, String cssClasses, CalloutSettings settings) { super(ureq, wControl); - + + this.settings = settings; boolean ajax = getWindowControl().getWindowBackOffice().getWindowManager().isAjaxEnabled(); if (ajax) { final Panel guiMsgPlace = new Panel("guimessage_place"); @@ -158,8 +165,7 @@ public class CloseableCalloutWindowController extends BasicController { * render the content of this controller your self with the * getInitialComponent() method. * - * @param ureq - * The user request + * @param ureq The user request * @param wControl * The window control * @param calloutWindowContent @@ -176,6 +182,32 @@ public class CloseableCalloutWindowController extends BasicController { + targetFormLink.getComponent().getDispatchID(), title, closable, cssClasses); } + /** + * Constructor for a closable callout window controller. After calling the + * constructor, the callout window will be visible immediately, there is no + * need to activate the window. In contrast to the modal dialogs you have to + * render the content of this controller your self with the + * getInitialComponent() method. + * + * @param ureq + * The user request + * @param wControl + * The window control + * @param calloutWindowContent + * The component that should be displayed in the callout window + * @param targetFormLink + * @param title + * @param closable + * @param cssClasses + * @param settings + */ + public CloseableCalloutWindowController(UserRequest ureq, + WindowControl wControl, Component calloutWindowContent, + FormLink targetFormLink, String title, boolean closable, String cssClasses, CalloutSettings settings) { + this(ureq, wControl, calloutWindowContent, "o_fi" + + targetFormLink.getComponent().getDispatchID(), title, closable, cssClasses, settings); + } + public String getDOMTarget() { if (calloutVC != null) { // Setting the new target makes this callout VC dirty which redraws @@ -281,7 +313,7 @@ public class CloseableCalloutWindowController extends BasicController { cmc.activate(); } else { // push to modal stack - getWindowControl().pushAsCallout(calloutVC, getDOMTarget()); + getWindowControl().pushAsCallout(calloutVC, getDOMTarget(), settings); } } diff --git a/src/main/java/org/olat/core/gui/control/guistack/GuiStack.java b/src/main/java/org/olat/core/gui/control/guistack/GuiStack.java index 749abb0d2b7..7b4022fe121 100644 --- a/src/main/java/org/olat/core/gui/control/guistack/GuiStack.java +++ b/src/main/java/org/olat/core/gui/control/guistack/GuiStack.java @@ -27,6 +27,7 @@ package org.olat.core.gui.control.guistack; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.panel.StackedPanel; +import org.olat.core.gui.control.generic.closablewrapper.CalloutSettings; /** * Description:<br> @@ -49,7 +50,7 @@ public interface GuiStack { * @param content The component to push as callout window * @param targetId The target element */ - public void pushCallout(Component content, String targetId); + public void pushCallout(Component content, String targetId, CalloutSettings settings); /** * @see org.olat.core.gui.control.GuiStackHandle#pushContent(org.olat.core.gui.components.Component) diff --git a/src/main/java/org/olat/core/gui/control/guistack/GuiStackNiceImpl.java b/src/main/java/org/olat/core/gui/control/guistack/GuiStackNiceImpl.java index db2ad0daed2..f589ca46ef2 100644 --- a/src/main/java/org/olat/core/gui/control/guistack/GuiStackNiceImpl.java +++ b/src/main/java/org/olat/core/gui/control/guistack/GuiStackNiceImpl.java @@ -30,10 +30,12 @@ import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.panel.LayeredPanel; import org.olat.core.gui.components.panel.Panel; -import org.olat.core.gui.components.panel.StackedPanel; import org.olat.core.gui.components.panel.SimpleStackedPanel; +import org.olat.core.gui.components.panel.StackedPanel; import org.olat.core.gui.components.velocity.VelocityContainer; import org.olat.core.gui.control.WindowBackOffice; +import org.olat.core.gui.control.generic.closablewrapper.CalloutSettings; +import org.olat.core.gui.control.generic.closablewrapper.CalloutSettings.CalloutOrientation; import org.olat.core.gui.control.util.ZIndexWrapper; import org.olat.core.gui.render.ValidationResult; import org.olat.core.util.Util; @@ -126,7 +128,7 @@ public class GuiStackNiceImpl implements GuiStack { @Override - public void pushCallout(Component content, String targetId) { + public void pushCallout(Component content, String targetId, CalloutSettings settings) { // wrap the component into a modal foreground dialog with alpha-blended-background final Panel guiMsgPlace = new Panel("guimsgplace_for_callout"); VelocityContainer inset = new VelocityContainer("inset", VELOCITY_ROOT + "/callout.html", null, null) { @@ -146,7 +148,13 @@ public class GuiStackNiceImpl implements GuiStack { inset.contextPut("zindexshim", zindex); inset.contextPut("zindexarea", zindex+5); inset.contextPut("zindexextwindows", zindex+50); - + if(settings != null) { + inset.contextPut("arrow", settings.isArrow()); + inset.contextPut("orientation", settings.getOrientation().name()); + } else { + inset.contextPut("arrow", Boolean.TRUE); + inset.contextPut("orientation", CalloutOrientation.bottom.name()); + } modalPanel.pushContent(inset); modalLayers++; } diff --git a/src/main/java/org/olat/core/gui/control/guistack/_content/callout.html b/src/main/java/org/olat/core/gui/control/guistack/_content/callout.html index ce9f444491a..35d0601c816 100644 --- a/src/main/java/org/olat/core/gui/control/guistack/_content/callout.html +++ b/src/main/java/org/olat/core/gui/control/guistack/_content/callout.html @@ -1,6 +1,7 @@ <div id="callout_$r.getCId()" class="popover in bottom" style="z-index:$zindexarea;"> - <div class="arrow"></div> + #if($arrow && $orientation == "bottom")<div class="arrow"></div>#end <div class="popover-content">$r.render("cont")</div> + #if($arrow && $orientation == "bottom")<div class="arrow"></div>#end </div> <div id="callout_overlay_$r.getCId()" class="o_callout_overlay" style="z-index:$zindexoverlay;"></div> <script type="text/javascript"> @@ -14,35 +15,70 @@ jQuery(function() { callout.css('display','block').css('z-index', o_info.zseed + 105); jQuery('#callout_overlay_$r.getCId()').css('z-index', o_info.zseed + 103); + var orientation = '${orientation}'; + var arrow = $arrow; var docWidth = jQuery(document).width(); - if(targetOffset.left >= 0 && callout.width() > 50 && targetOffset.left <= (callout.width() / 2)) { - ## left edge case: show at left border - ## add 15px for button size - ## add 10px for a bit space at left side - callout.offset({ - top: (targetOffset.top + targetEl.height() + 15) , - left: '10px' - }); - var percent = (targetOffset.left + targetEl.width()/2 + 15 + 10/2) / callout.width() * 100; - callout.find('.arrow').css({'left' : percent + '%'}); + if(orientation == 'top') { + if(targetOffset.left >= 0 && callout.width() > 50 && targetOffset.left <= (callout.width() / 2)) { + ## left edge case: show at left border + ## add 15px for button size + ## add 10px for a bit space at left side + callout.offset({ + top: (targetOffset.top - targetEl.height() - 25) , + left: '10px' + }); + var percent = (targetOffset.left + targetEl.width()/2 + 15 + 10/2) / callout.width() * 100; + callout.find('.arrow').css({'left' : percent + '%'}); + + } else if(targetOffset.left >= 0 && callout.width() > 50 && ((targetOffset.left + (callout.width() / 2)) >= docWidth)) { + ## right edge case: show at right border + ## add 15px for button size + ## add 10px for a bit space at right side + callout.offset({ + top: (targetOffset.top - targetEl.height() - 25) , + left: (docWidth - callout.width() - 10) + }); + var percent = (1 - ((docWidth - targetOffset.left - targetEl.width()/2 - 15 - 10/2 ) / callout.width() )) * 100; + callout.find('.arrow').css({'left' : percent + '%'}); + + } else { + ## standard case: show centered below element + callout.offset({ + top: (targetOffset.top - targetEl.height() - 25), + left: (targetOffset.left + targetEl.width()) - callout.width()/2 + }); + } - } else if(targetOffset.left >= 0 && callout.width() > 50 && ((targetOffset.left + (callout.width() / 2)) >= docWidth)) { - ## right edge case: show at right border - ## add 15px for button size - ## add 10px for a bit space at right side - callout.offset({ - top: (targetOffset.top + targetEl.height() + 15) , - left: (docWidth - callout.width() - 10) - }); - var percent = (1 - ((docWidth - targetOffset.left - targetEl.width()/2 - 15 - 10/2 ) / callout.width() )) * 100; - callout.find('.arrow').css({'left' : percent + '%'}); - } else { - ## standard case: show centered below element - callout.offset({ - top: (targetOffset.top + targetEl.height() + 25), - left: (targetOffset.left + targetEl.width()) - callout.width()/2 - }); + if(targetOffset.left >= 0 && callout.width() > 50 && targetOffset.left <= (callout.width() / 2)) { + ## left edge case: show at left border + ## add 15px for button size + ## add 10px for a bit space at left side + callout.offset({ + top: (targetOffset.top + targetEl.height() + 15) , + left: '10px' + }); + var percent = (targetOffset.left + targetEl.width()/2 + 15 + 10/2) / callout.width() * 100; + callout.find('.arrow').css({'left' : percent + '%'}); + + } else if(targetOffset.left >= 0 && callout.width() > 50 && ((targetOffset.left + (callout.width() / 2)) >= docWidth)) { + ## right edge case: show at right border + ## add 15px for button size + ## add 10px for a bit space at right side + callout.offset({ + top: (targetOffset.top + targetEl.height() + 15) , + left: (docWidth - callout.width() - 10) + }); + var percent = (1 - ((docWidth - targetOffset.left - targetEl.width()/2 - 15 - 10/2 ) / callout.width() )) * 100; + callout.find('.arrow').css({'left' : percent + '%'}); + + } else { + ## standard case: show centered below element + callout.offset({ + top: (targetOffset.top + targetEl.height() + (arrow ? 25 : 15)), + left: (targetOffset.left + targetEl.width()) - callout.width()/2 + }); + } } } }); diff --git a/src/main/java/org/olat/core/id/context/StackedBusinessWindowControl.java b/src/main/java/org/olat/core/id/context/StackedBusinessWindowControl.java index dc2b538e436..4e2da23ab61 100644 --- a/src/main/java/org/olat/core/id/context/StackedBusinessWindowControl.java +++ b/src/main/java/org/olat/core/id/context/StackedBusinessWindowControl.java @@ -31,6 +31,7 @@ package org.olat.core.id.context; import org.olat.core.gui.components.Component; import org.olat.core.gui.control.WindowBackOffice; import org.olat.core.gui.control.WindowControl; +import org.olat.core.gui.control.generic.closablewrapper.CalloutSettings; import org.olat.core.gui.control.info.WindowControlInfo; /** @@ -73,8 +74,8 @@ public class StackedBusinessWindowControl implements WindowControl { } @Override - public void pushAsCallout(Component comp, String targetId) { - origWControl.pushAsCallout(comp, targetId); + public void pushAsCallout(Component comp, String targetId, CalloutSettings settings) { + origWControl.pushAsCallout(comp, targetId, settings); } public void pushToMainArea(Component comp) { diff --git a/src/main/java/org/olat/course/assessment/ui/tool/AssessedIdentityListController.java b/src/main/java/org/olat/course/assessment/ui/tool/AssessedIdentityListController.java index adcf81ea638..10786123997 100644 --- a/src/main/java/org/olat/course/assessment/ui/tool/AssessedIdentityListController.java +++ b/src/main/java/org/olat/course/assessment/ui/tool/AssessedIdentityListController.java @@ -212,7 +212,8 @@ public class AssessedIdentityListController extends FormBasicController implemen stackPanel.pushController(fullname, userController); } - public static class AssessedUserTableModel extends DefaultFlexiTableDataModel<AssessedIdentityRow> implements SortableFlexiTableDataModel<AssessedIdentityRow> { + public static class AssessedUserTableModel extends DefaultFlexiTableDataModel<AssessedIdentityRow> + implements SortableFlexiTableDataModel<AssessedIdentityRow> { private ConcurrentMap<Long, CertificateLight> certificates; diff --git a/src/main/java/org/olat/modules/portfolio/PortfolioService.java b/src/main/java/org/olat/modules/portfolio/PortfolioService.java index 13cbddf96bf..ab0b731089d 100644 --- a/src/main/java/org/olat/modules/portfolio/PortfolioService.java +++ b/src/main/java/org/olat/modules/portfolio/PortfolioService.java @@ -152,6 +152,15 @@ public interface PortfolioService { */ public List<Identity> getMembers(BinderRef binder, String... roles); + /** + * The list of owners of the page and only of the specified page. + * + * @param page + * @param roles At least a role need to be specified + * @return + */ + public List<Identity> getMembers(Page page, String... roles); + public List<AccessRights> getAccessRights(Binder binder); public List<AccessRights> getAccessRights(Binder binder, Identity identity); @@ -318,7 +327,7 @@ public interface PortfolioService { public Media getMediaByKey(Long key); - public List<MediaLight> searchOwnedMedias(IdentityRef author); + public List<MediaLight> searchOwnedMedias(IdentityRef author, String searchString); public void updateCategories(Media media, List<String> categories); diff --git a/src/main/java/org/olat/modules/portfolio/manager/MediaDAO.java b/src/main/java/org/olat/modules/portfolio/manager/MediaDAO.java index 16ce28a5af7..c531cbba131 100644 --- a/src/main/java/org/olat/modules/portfolio/manager/MediaDAO.java +++ b/src/main/java/org/olat/modules/portfolio/manager/MediaDAO.java @@ -19,12 +19,18 @@ */ package org.olat.modules.portfolio.manager; +import static org.olat.core.commons.persistence.PersistenceHelper.appendFuzzyLike; +import static org.olat.core.commons.persistence.PersistenceHelper.makeFuzzyQueryString; + import java.util.Date; import java.util.List; +import javax.persistence.TypedQuery; + import org.olat.basesecurity.IdentityRef; import org.olat.core.commons.persistence.DB; import org.olat.core.id.Identity; +import org.olat.core.util.StringHelper; import org.olat.modules.portfolio.Media; import org.olat.modules.portfolio.MediaLight; import org.olat.modules.portfolio.model.MediaImpl; @@ -79,17 +85,27 @@ public class MediaDAO { return medias == null || medias.isEmpty() ? null : medias.get(0); } - public List<MediaLight> loadByAuthor(IdentityRef author) { + public List<MediaLight> searchByAuthor(IdentityRef author, String searchString) { StringBuilder sb = new StringBuilder(); sb.append("select media from pfmedia as media") .append(" inner join fetch media.author as author") .append(" where author.key=:authorKey"); + if(StringHelper.containsNonWhitespace(searchString)) { + searchString = makeFuzzyQueryString(searchString); + sb.append(" and ("); + appendFuzzyLike(sb, "media.title", "searchString", dbInstance.getDbVendor()); + sb.append(" or "); + appendFuzzyLike(sb, "media.description", "searchString", dbInstance.getDbVendor()); + sb.append(")"); + } - List<MediaLight> medias = dbInstance.getCurrentEntityManager() + TypedQuery<MediaLight> query = dbInstance.getCurrentEntityManager() .createQuery(sb.toString(), MediaLight.class) - .setParameter("authorKey", author.getKey()) - .getResultList(); - return medias; + .setParameter("authorKey", author.getKey()); + if(StringHelper.containsNonWhitespace(searchString)) { + query.setParameter("searchString", searchString.toLowerCase()); + } + return query.getResultList(); } } diff --git a/src/main/java/org/olat/modules/portfolio/manager/PageDAO.java b/src/main/java/org/olat/modules/portfolio/manager/PageDAO.java index 0290f73edcd..1d8f2491a0d 100644 --- a/src/main/java/org/olat/modules/portfolio/manager/PageDAO.java +++ b/src/main/java/org/olat/modules/portfolio/manager/PageDAO.java @@ -19,6 +19,8 @@ */ package org.olat.modules.portfolio.manager; +import java.util.ArrayList; +import java.util.Collections; import java.util.Date; import java.util.List; @@ -27,6 +29,8 @@ import org.olat.basesecurity.GroupRoles; import org.olat.basesecurity.IdentityRef; import org.olat.basesecurity.manager.GroupDAO; import org.olat.core.commons.persistence.DB; +import org.olat.core.id.Identity; +import org.olat.core.util.StringHelper; import org.olat.modules.portfolio.BinderRef; import org.olat.modules.portfolio.Page; import org.olat.modules.portfolio.PageBody; @@ -157,6 +161,33 @@ public class PageDAO { return pages; } + public List<Identity> getMembers(Page page, String... roles) { + if(page == null || roles == null || roles.length == 0 || roles[0] == null) { + return Collections.emptyList(); + } + + StringBuilder sb = new StringBuilder(); + sb.append("select membership.identity from pfpage as page") + .append(" inner join page.baseGroup as baseGroup") + .append(" inner join baseGroup.members as membership") + .append(" inner join membership.identity as ident") + .append(" inner join fetch ident.user as identUser") + .append(" where page.key=:pageKey and membership.role in (:roles)"); + + List<String> roleList = new ArrayList<>(roles.length); + for(String role:roles) { + if(StringHelper.containsNonWhitespace(role)) { + roleList.add(role); + } + } + + return dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), Identity.class) + .setParameter("pageKey", page.getKey()) + .setParameter("roles", roleList) + .getResultList(); + } + public Page loadByKey(Long key) { StringBuilder sb = new StringBuilder(); sb.append("select page from pfpage as page") diff --git a/src/main/java/org/olat/modules/portfolio/manager/PortfolioServiceImpl.java b/src/main/java/org/olat/modules/portfolio/manager/PortfolioServiceImpl.java index 1975b025bb4..53b0b496e18 100644 --- a/src/main/java/org/olat/modules/portfolio/manager/PortfolioServiceImpl.java +++ b/src/main/java/org/olat/modules/portfolio/manager/PortfolioServiceImpl.java @@ -267,6 +267,11 @@ public class PortfolioServiceImpl implements PortfolioService { return binderDao.getMembers(binder, roles); } + @Override + public List<Identity> getMembers(Page page, String... roles) { + return pageDao.getMembers(page, roles); + } + @Override public boolean isBinderVisible(Identity identity, Binder binder) { return true; @@ -589,8 +594,9 @@ public class PortfolioServiceImpl implements PortfolioService { } @Override - public PagePart updatePart(PagePart part) { - return pageDao.merge(part); + @SuppressWarnings("unchecked") + public <U extends PagePart> U updatePart(U part) { + return (U)pageDao.merge(part); } @Override @@ -617,8 +623,8 @@ public class PortfolioServiceImpl implements PortfolioService { } @Override - public List<MediaLight> searchOwnedMedias(IdentityRef author) { - return mediaDao.loadByAuthor(author); + public List<MediaLight> searchOwnedMedias(IdentityRef author, String searchString) { + return mediaDao.searchByAuthor(author, searchString); } @Override diff --git a/src/main/java/org/olat/modules/portfolio/model/MediaRow.java b/src/main/java/org/olat/modules/portfolio/model/MediaRow.java index e36cf7314e1..7d71b41caba 100644 --- a/src/main/java/org/olat/modules/portfolio/model/MediaRow.java +++ b/src/main/java/org/olat/modules/portfolio/model/MediaRow.java @@ -19,6 +19,8 @@ */ package org.olat.modules.portfolio.model; +import java.util.Date; + import org.olat.core.gui.components.form.flexible.elements.FormLink; import org.olat.core.util.vfs.VFSLeaf; import org.olat.modules.portfolio.MediaLight; @@ -29,7 +31,7 @@ import org.olat.modules.portfolio.MediaLight; * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public class MediaRow { +public class MediaRow implements MediaLight { private MediaLight media; @@ -42,14 +44,51 @@ public class MediaRow { this.openFormLink = openFormLink; } + @Override public Long getKey() { return media.getKey(); } + @Override + public Date getCreationDate() { + return media.getCreationDate(); + } + + @Override public String getTitle() { return media.getTitle(); } - + + @Override + public Date getCollectionDate() { + return media.getCollectionDate(); + } + + @Override + public String getType() { + return media.getType(); + } + + @Override + public String getStoragePath() { + return media.getStoragePath(); + } + + @Override + public String getRootFilename() { + return media.getRootFilename(); + } + + @Override + public String getDescription() { + return media.getDescription(); + } + + @Override + public String getBusinessPath() { + return media.getBusinessPath(); + } + public FormLink getOpenFormItem() { return openFormLink; } diff --git a/src/main/java/org/olat/modules/portfolio/ui/BinderListController.java b/src/main/java/org/olat/modules/portfolio/ui/BinderListController.java index e3348a9df93..73dd0bf9fe9 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/BinderListController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/BinderListController.java @@ -52,6 +52,7 @@ import org.olat.core.gui.components.velocity.VelocityContainer; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; +import org.olat.core.gui.control.generic.closablewrapper.CalloutSettings; import org.olat.core.gui.control.generic.closablewrapper.CloseableCalloutWindowController; import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController; import org.olat.core.gui.control.generic.dtabs.Activateable2; @@ -319,7 +320,8 @@ public class BinderListController extends FormBasicController listenTo(chooseNewBinderTypeCtrl); newBinderCalloutCtrl = new CloseableCalloutWindowController(ureq, getWindowControl(), - chooseNewBinderTypeCtrl.getInitialComponent(), newBinderDropdown.getFormDispatchId(), "", true, ""); + chooseNewBinderTypeCtrl.getInitialComponent(), newBinderDropdown.getFormDispatchId(), + "", true, "", new CalloutSettings(false)); listenTo(newBinderCalloutCtrl); newBinderCalloutCtrl.activate(); } diff --git a/src/main/java/org/olat/modules/portfolio/ui/MediaCenterController.java b/src/main/java/org/olat/modules/portfolio/ui/MediaCenterController.java index a0cb60c82a3..c54155fefa3 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/MediaCenterController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/MediaCenterController.java @@ -20,12 +20,13 @@ package org.olat.modules.portfolio.ui; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import javax.servlet.http.HttpServletRequest; +import org.olat.core.commons.persistence.SortKey; import org.olat.core.commons.services.image.Size; import org.olat.core.dispatcher.mapper.Mapper; import org.olat.core.gui.UserRequest; @@ -33,6 +34,9 @@ import org.olat.core.gui.components.Component; import org.olat.core.gui.components.form.flexible.FormItem; import org.olat.core.gui.components.form.flexible.FormItemContainer; import org.olat.core.gui.components.form.flexible.elements.FlexiTableElement; +import org.olat.core.gui.components.form.flexible.elements.FlexiTableFilter; +import org.olat.core.gui.components.form.flexible.elements.FlexiTableSort; +import org.olat.core.gui.components.form.flexible.elements.FlexiTableSortOptions; import org.olat.core.gui.components.form.flexible.elements.FormLink; import org.olat.core.gui.components.form.flexible.impl.FormBasicController; import org.olat.core.gui.components.form.flexible.impl.FormEvent; @@ -42,6 +46,7 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableComponentDelegate; 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.form.flexible.impl.elements.table.FlexiTableSearchEvent; import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent; import org.olat.core.gui.components.link.Link; import org.olat.core.gui.components.link.LinkFactory; @@ -65,14 +70,16 @@ import org.olat.modules.portfolio.MediaHandler; import org.olat.modules.portfolio.MediaLight; import org.olat.modules.portfolio.PortfolioService; import org.olat.modules.portfolio.model.MediaRow; -import org.olat.modules.portfolio.ui.BindersDataModel.PortfolioCols; +import org.olat.modules.portfolio.ui.MediaDataModel.MediaCols; import org.olat.modules.portfolio.ui.event.MediaSelectionEvent; import org.olat.modules.portfolio.ui.media.CollectFileMediaController; import org.olat.modules.portfolio.ui.media.CollectImageMediaController; import org.olat.modules.portfolio.ui.media.CollectTextMediaController; +import org.olat.modules.portfolio.ui.renderer.MediaTypeCellRenderer; import org.olat.portfolio.model.artefacts.AbstractArtefact; import org.olat.portfolio.ui.EPArtefactPoolRunController; import org.olat.portfolio.ui.artefacts.view.EPArtefactChoosenEvent; +import org.olat.repository.model.SearchMyRepositoryEntryViewParams.OrderBy; import org.springframework.beans.factory.annotation.Autowired; /** @@ -111,7 +118,7 @@ public class MediaCenterController extends FormBasicController this.select = true; initForm(ureq); - loadModel(); + loadModel(null); } public MediaCenterController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel) { @@ -120,7 +127,7 @@ public class MediaCenterController extends FormBasicController this.select = false; initForm(ureq); - loadModel(); + loadModel(null); } @Override @@ -145,11 +152,17 @@ public class MediaCenterController extends FormBasicController @Override protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) { FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel(); - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, PortfolioCols.key, "select")); - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(PortfolioCols.title, "select")); - columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(PortfolioCols.open)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, MediaCols.key, "select")); + + Map<String, MediaHandler> handlersMap = portfolioService.getMediaHandlers() + .stream().collect(Collectors.toMap (h -> h.getType(), h -> h)); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(MediaCols.type, + new MediaTypeCellRenderer(handlersMap))); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(MediaCols.title, "select")); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(MediaCols.collectionDate, "select")); + columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(MediaCols.open)); - model = new MediaDataModel(columnsModel); + model = new MediaDataModel(columnsModel, getLocale()); tableEl = uifactory.addTableElement(getWindowControl(), "table", model, 20, false, getTranslator(), formLayout); tableEl.setAvailableRendererTypes(FlexiTableRendererType.custom, FlexiTableRendererType.classic); tableEl.setRendererType(FlexiTableRendererType.custom); @@ -162,24 +175,47 @@ public class MediaCenterController extends FormBasicController tableEl.setRowRenderer(row, this); tableEl.setCssDelegate(new MediaCssDelegate()); tableEl.setAndLoadPersistedPreferences(ureq, "media-list"); + initSorters(tableEl); + initFilters(tableEl); mapperThumbnailUrl = registerCacheableMapper(ureq, "media-thumbnail", new ThumbnailMapper(model)); row.contextPut("mapperThumbnailUrl", mapperThumbnailUrl); } + + private void initSorters(FlexiTableElement tableElement) { + List<FlexiTableSort> sorters = new ArrayList<>(14); + sorters.add(new FlexiTableSort(translate(MediaCols.key.i18nHeaderKey()), MediaCols.key.name())); + sorters.add(new FlexiTableSort(translate(MediaCols.type.i18nHeaderKey()), MediaCols.type.name())); + sorters.add(new FlexiTableSort(translate(MediaCols.title.i18nHeaderKey()), MediaCols.title.name())); + sorters.add(new FlexiTableSort(translate(MediaCols.collectionDate.i18nHeaderKey()), MediaCols.collectionDate.name())); + sorters.add(FlexiTableSort.SPACER); + + FlexiTableSortOptions options = new FlexiTableSortOptions(sorters); + options.setDefaultOrderBy(new SortKey(OrderBy.title.name(), true)); + tableElement.setSortSettings(options); + } + + private void initFilters(FlexiTableElement tableElement) { + List<FlexiTableFilter> filters = new ArrayList<>(16); + filters.add(new FlexiTableFilter(translate("filter.show.all"), "showall")); + filters.add(FlexiTableFilter.SPACER); + List<MediaHandler> handlers = portfolioService.getMediaHandlers(); + for(MediaHandler handler:handlers) { + filters.add(new FlexiTableFilter(translate("artefact." + handler.getType()), handler.getType())); + } + tableElement.setFilters(null, filters); + } @Override public Iterable<Component> getComponents(int row, Object rowObject) { return null; } - private void loadModel() { - List<MediaRow> currentRows = model.getObjects(); - Map<Long,MediaRow> currentMap = new HashMap<>(); - for(MediaRow row:currentRows) { - currentMap.put(row.getKey(), row); - } - - List<MediaLight> medias = portfolioService.searchOwnedMedias(getIdentity()); + private void loadModel(String searchString) { + Map<Long,MediaRow> currentMap = model.getObjects() + .stream().collect(Collectors.toMap(r -> r.getKey(), r -> r)); + + List<MediaLight> medias = portfolioService.searchOwnedMedias(getIdentity(), searchString); List<MediaRow> rows = new ArrayList<>(medias.size()); for(MediaLight media:medias) { if(currentMap.containsKey(media.getKey())) { @@ -194,6 +230,7 @@ public class MediaCenterController extends FormBasicController } } model.setObjects(rows); + model.filter(tableEl.getSelectedFilterKey()); } @Override @@ -223,6 +260,9 @@ public class MediaCenterController extends FormBasicController } } } + } else if(event instanceof FlexiTableSearchEvent) { + FlexiTableSearchEvent se = (FlexiTableSearchEvent)event; + loadModel(se.getSearch()); } } else if(source instanceof FormLink) { FormLink link = (FormLink)source; @@ -246,21 +286,21 @@ public class MediaCenterController extends FormBasicController public void event(UserRequest ureq, Controller source, Event event) { if(imageUploadCtrl == source) { if(event == Event.DONE_EVENT) { - loadModel(); + loadModel(null); tableEl.reloadData(); } cmc.deactivate(); cleanUp(); } else if(fileUploadCtrl == source) { if(event == Event.DONE_EVENT) { - loadModel(); + loadModel(null); tableEl.reloadData(); } cmc.deactivate(); cleanUp(); } else if(textUploadCtrl == source) { if(event == Event.DONE_EVENT) { - loadModel(); + loadModel(null); tableEl.reloadData(); } cmc.deactivate(); @@ -269,7 +309,7 @@ public class MediaCenterController extends FormBasicController if(event instanceof EPArtefactChoosenEvent) { EPArtefactChoosenEvent cEvent = (EPArtefactChoosenEvent)event; doImportArtefactV1(cEvent.getArtefact()); - loadModel(); + loadModel(null); tableEl.reloadData(); } cmc.deactivate(); @@ -369,7 +409,7 @@ public class MediaCenterController extends FormBasicController private void doChooseArtefactV1(UserRequest ureq) { if(importArtefactv1Ctrl != null) return; - importArtefactv1Ctrl = new EPArtefactPoolRunController(ureq, this.getWindowControl(), true); + importArtefactv1Ctrl = new EPArtefactPoolRunController(ureq, this.getWindowControl(), true, false); listenTo(importArtefactv1Ctrl); String title = translate("import.artefactV1"); diff --git a/src/main/java/org/olat/modules/portfolio/ui/MediaDataModel.java b/src/main/java/org/olat/modules/portfolio/ui/MediaDataModel.java index 2dc2685a354..44937d51b97 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/MediaDataModel.java +++ b/src/main/java/org/olat/modules/portfolio/ui/MediaDataModel.java @@ -19,9 +19,20 @@ */ package org.olat.modules.portfolio.ui; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.Locale; + +import org.olat.core.commons.persistence.SortKey; import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTableDataModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.FilterableFlexiTableModel; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiSortableColumnDef; import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableDataModel; +import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableModelDelegate; +import org.olat.core.util.StringHelper; import org.olat.modules.portfolio.model.MediaRow; /** @@ -30,31 +41,76 @@ import org.olat.modules.portfolio.model.MediaRow; * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ -public class MediaDataModel extends DefaultFlexiTableDataModel<MediaRow> { +public class MediaDataModel extends DefaultFlexiTableDataModel<MediaRow> + implements SortableFlexiTableDataModel<MediaRow>, FilterableFlexiTableModel { + + private final Locale locale; + private List<MediaRow> backups; - public MediaDataModel(FlexiTableColumnModel columnsModel) { + public MediaDataModel(FlexiTableColumnModel columnsModel, Locale locale) { super(columnsModel); + this.locale = locale; + } + + @Override + public void filter(String key) { + if(StringHelper.containsNonWhitespace(key) && !"showall".equals(key)) { + List<MediaRow> filteredRows = new ArrayList<>(); + for(MediaRow row:backups) { + if(key.equals(row.getType())) { + filteredRows.add(row); + } + } + super.setObjects(filteredRows); + } else { + super.setObjects(backups); + } + } + + @Override + public void sort(SortKey orderBy) { + if(orderBy != null) { + List<MediaRow> views = new MediaDataModelSorterDelegate(orderBy, this, locale).sort(); + super.setObjects(views); + } } @Override public Object getValueAt(int row, int col) { - MediaRow page = getObject(row); + MediaRow media = getObject(row); + return getValueAt(media, col); + } + + @Override + public Object getValueAt(MediaRow media, int col) { switch(MediaCols.values()[col]) { - case key: return page.getKey(); - case title: return page.getTitle(); - case open: return page.getOpenFormItem(); + case key: return media.getKey(); + case title: return media.getTitle(); + case collectionDate: return media.getCollectionDate(); + case type: return media; + case open: return media.getOpenFormItem(); } return null; } + + + @Override + public void setObjects(List<MediaRow> objects) { + backups = objects; + super.setObjects(objects); + } + @Override public DefaultFlexiTableDataModel<MediaRow> createCopyWithEmptyList() { - return new MediaDataModel(getTableColumnModel()); + return new MediaDataModel(getTableColumnModel(), locale); } public enum MediaCols implements FlexiSortableColumnDef { key("table.header.key"), title("table.header.title"), + collectionDate("table.header.collection.date"), + type("table.header.type"), open("table.header.open"); private final String i18nKey; @@ -78,4 +134,37 @@ public class MediaDataModel extends DefaultFlexiTableDataModel<MediaRow> { return name(); } } + + public static class MediaDataModelSorterDelegate extends SortableFlexiTableModelDelegate<MediaRow> { + + public MediaDataModelSorterDelegate(SortKey orderBy, MediaDataModel model, Locale locale) { + super(orderBy, model, locale); + } + + @Override + protected void sort(List<MediaRow> rows) { + int columnIndex = getColumnIndex(); + MediaCols column = MediaCols.values()[columnIndex]; + switch(column) { + case type: Collections.sort(rows, new TypeComparator()); break; + default: { + super.sort(rows); + } + } + } + + private class TypeComparator implements Comparator<MediaRow> { + @Override + public int compare(MediaRow t1, MediaRow t2) { + String r1 = t1.getType(); + String r2 = t2.getType(); + + int compare = compareString(r1, r2); + if(compare == 0) { + compare = compareString(t1.getTitle(), t2.getTitle()); + } + return compare; + } + } + } } diff --git a/src/main/java/org/olat/modules/portfolio/ui/PageEditController.java b/src/main/java/org/olat/modules/portfolio/ui/PageEditController.java index 0dec547508d..52233f6abf7 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/PageEditController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/PageEditController.java @@ -230,12 +230,12 @@ public class PageEditController extends BasicController { return mediaPart; } - @Autowired + @Override public AddElementInfos getUserObject() { return userObject; } - @Autowired + @Override public void setUserObject(AddElementInfos userObject) { this.userObject = userObject; } diff --git a/src/main/java/org/olat/modules/portfolio/ui/PageListDataModel.java b/src/main/java/org/olat/modules/portfolio/ui/PageListDataModel.java index c58239921df..2e78790a2c6 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/PageListDataModel.java +++ b/src/main/java/org/olat/modules/portfolio/ui/PageListDataModel.java @@ -36,7 +36,7 @@ import org.olat.modules.portfolio.model.PageRow; * */ public class PageListDataModel extends DefaultFlexiTableDataModel<PageRow> - implements SortableFlexiTableDataModel<PageRow>{ + implements SortableFlexiTableDataModel<PageRow> { public PageListDataModel(FlexiTableColumnModel columnModel) { super(columnModel); diff --git a/src/main/java/org/olat/modules/portfolio/ui/PageMetadataController.java b/src/main/java/org/olat/modules/portfolio/ui/PageMetadataController.java index f780d13be71..9420474f4e5 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/PageMetadataController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/PageMetadataController.java @@ -21,8 +21,11 @@ package org.olat.modules.portfolio.ui; import java.util.ArrayList; import java.util.Date; +import java.util.HashSet; import java.util.List; +import java.util.Set; +import org.olat.basesecurity.GroupRoles; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; import org.olat.core.gui.components.link.Link; @@ -31,11 +34,13 @@ import org.olat.core.gui.components.velocity.VelocityContainer; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; +import org.olat.core.id.Identity; import org.olat.modules.portfolio.BinderSecurityCallback; import org.olat.modules.portfolio.Category; import org.olat.modules.portfolio.Page; import org.olat.modules.portfolio.PortfolioService; import org.olat.modules.portfolio.ui.event.PublishEvent; +import org.olat.user.UserManager; import org.springframework.beans.factory.annotation.Autowired; /** @@ -48,6 +53,8 @@ public class PageMetadataController extends BasicController { private Link publishButton; + @Autowired + private UserManager userManager; @Autowired private PortfolioService portfolioService; @@ -59,6 +66,18 @@ public class PageMetadataController extends BasicController { publishButton = LinkFactory.createButton("publish", mainVC, this); } + Set<Identity> owners = new HashSet<>(); + if(page.getSection() != null && page.getSection().getBinder() != null) { + owners.addAll(portfolioService.getMembers(page.getSection().getBinder(), GroupRoles.owner.name())); + } + owners.addAll(portfolioService.getMembers(page, GroupRoles.owner.name())); + + StringBuilder ownerSb = new StringBuilder(); + for(Identity owner:owners) { + if(ownerSb.length() > 0) ownerSb.append(", "); + ownerSb.append(userManager.getUserDisplayName(owner)); + } + mainVC.contextPut("owners", ownerSb.toString()); mainVC.contextPut("pageTitle", page.getTitle()); mainVC.contextPut("pageSummary", page.getSummary()); mainVC.contextPut("status", page.getPageStatus()); diff --git a/src/main/java/org/olat/modules/portfolio/ui/_content/page_meta.html b/src/main/java/org/olat/modules/portfolio/ui/_content/page_meta.html index 1d5fc4f3b2d..64e31104928 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/_content/page_meta.html +++ b/src/main/java/org/olat/modules/portfolio/ui/_content/page_meta.html @@ -1,5 +1,5 @@ <div class="o_header_with_buttons"> - <h1>$r.escapeHtml($pageTitle)</h1> + <h2>$r.escapeHtml($pageTitle) <small>$r.translate("binder.by",$owners)</small></h2> #if($r.available("publish")) <div class="o_button_group o_button_group_right"> $r.render("publish") diff --git a/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_de.properties index 945f0711030..43e76ad86c8 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_de.properties @@ -23,7 +23,14 @@ artefact.descr=Beschreibung artefact.file=Datei artefact.source=Quelle artefact.title=Titel -artefatct.text=Text +artefact.text=Text +artefact.image=Bild +artefact.bc=Datei +artefact.Forum=Forum Eintrag +artefact.FileResource.BLOG=Blog Eintrag +artefact.FileResource.WIKI=Wikiseite +artefact.EfficiencyStatement=Leistungnachweis +filter.show.all=Alle anzeigen author=Autor begin.date=Beginn binder.by=von {0} @@ -148,6 +155,7 @@ table.grading.passed.points=<span class\="o_state o_passed"><i class\="o_icon o_ table.grading.points={0} Punkt(e) table.header.change.status=Status table.header.course=Kurs +table.header.collection.date=Sammelt am table.header.date=Datum table.header.grading=Bewertung table.header.key=ID @@ -157,6 +165,7 @@ table.header.open=Start table.header.passed=Bestanden table.header.score=Punkte table.header.section=Bereich +table.header.type=Typ table.header.title=Titel table.of.contents=Inhaltsverzeichnis table.user.login=Benutzername diff --git a/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_en.properties index 9100d32c5fe..87c4d244090 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/modules/portfolio/ui/_i18n/LocalStrings_en.properties @@ -24,7 +24,13 @@ artefact.file=File artefact.source=Source artefact.text=Text artefact.title=Title -artefatct.text=Text +artefact.image=Image +artefact.bc=File +artefact.Forum=Forum post +artefact.FileResource.BLOG=Blog entry +artefact.FileResource.WIKI=Wiki page +artefact.EfficiencyStatement=Efficiency statement +filter.show.all=Show all author=Author begin.date=Begin binder.by=by {0} @@ -149,6 +155,7 @@ table.grading.passed.points=<span class\="o_state o_passed"><i class\="o_icon o_ table.grading.points={0} Point(s) table.header.change.status=Status table.header.course=Course +table.header.collection.date=Collected at table.header.date=Date table.header.grading=Grading table.header.key=ID @@ -158,6 +165,7 @@ table.header.open=Start table.header.passed=Passed table.header.score=Points table.header.section=Section +table.header.type=Type table.header.title=Title table.of.contents=Table of contents {0} table.user.login=User name diff --git a/src/main/java/org/olat/modules/portfolio/ui/editor/PageEditorController.java b/src/main/java/org/olat/modules/portfolio/ui/editor/PageEditorController.java index 6f392393f2b..1484439ddf4 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/editor/PageEditorController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/editor/PageEditorController.java @@ -33,6 +33,8 @@ import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; +import org.olat.core.gui.control.generic.closablewrapper.CalloutSettings; +import org.olat.core.gui.control.generic.closablewrapper.CalloutSettings.CalloutOrientation; import org.olat.core.gui.control.generic.closablewrapper.CloseableCalloutWindowController; import org.olat.core.gui.control.generic.closablewrapper.CloseableModalController; import org.olat.core.util.Util; @@ -251,10 +253,15 @@ public class PageEditorController extends BasicController { addElementsCtrl = new AddElementsController(ureq, getWindowControl(), provider, referenceFragment, target); listenTo(addElementsCtrl); - // data-placement="top" - + CalloutSettings calloutSettings; + if(target == PageElementTarget.above) { + calloutSettings = new CalloutSettings(true, CalloutOrientation.top); + } else { + calloutSettings = new CalloutSettings(false); + } addCalloutCtrl = new CloseableCalloutWindowController(ureq, getWindowControl(), - addElementsCtrl.getInitialComponent(), link.getDispatchID(), "", true, ""); + addElementsCtrl.getInitialComponent(), link.getDispatchID(), + "", true, "", calloutSettings); listenTo(addCalloutCtrl); addCalloutCtrl.activate(); } diff --git a/src/main/java/org/olat/modules/portfolio/ui/media/CollectImageMediaController.java b/src/main/java/org/olat/modules/portfolio/ui/media/CollectImageMediaController.java index 20938486bb3..0abbaed0222 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/media/CollectImageMediaController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/media/CollectImageMediaController.java @@ -86,12 +86,12 @@ public class CollectImageMediaController extends FormBasicController implements return mediaReference; } - @Autowired + @Override public AddElementInfos getUserObject() { return userObject; } - @Autowired + @Override public void setUserObject(AddElementInfos userObject) { this.userObject = userObject; } diff --git a/src/main/java/org/olat/modules/portfolio/ui/media/CollectTextMediaController.java b/src/main/java/org/olat/modules/portfolio/ui/media/CollectTextMediaController.java index 1ef98aa8629..92def2ca975 100644 --- a/src/main/java/org/olat/modules/portfolio/ui/media/CollectTextMediaController.java +++ b/src/main/java/org/olat/modules/portfolio/ui/media/CollectTextMediaController.java @@ -82,12 +82,12 @@ public class CollectTextMediaController extends FormBasicController implements P return mediaReference; } - @Autowired + @Override public AddElementInfos getUserObject() { return userObject; } - @Autowired + @Override public void setUserObject(AddElementInfos userObject) { this.userObject = userObject; } diff --git a/src/main/java/org/olat/modules/portfolio/ui/renderer/MediaTypeCellRenderer.java b/src/main/java/org/olat/modules/portfolio/ui/renderer/MediaTypeCellRenderer.java new file mode 100644 index 00000000000..d42772ec94f --- /dev/null +++ b/src/main/java/org/olat/modules/portfolio/ui/renderer/MediaTypeCellRenderer.java @@ -0,0 +1,58 @@ +/** + * <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.portfolio.ui.renderer; + +import java.util.Map; + +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.modules.portfolio.MediaHandler; +import org.olat.modules.portfolio.model.MediaRow; + +/** + * + * Initial date: 06.07.2016<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class MediaTypeCellRenderer implements FlexiCellRenderer { + + private Map<String,MediaHandler> handlersMap; + + public MediaTypeCellRenderer(Map<String,MediaHandler> handlersMap) { + this.handlersMap = handlersMap; + } + + @Override + public void render(Renderer renderer, StringOutput target, Object cellValue, + int row, FlexiTableComponent source, URLBuilder ubu, Translator translator) { + if(cellValue instanceof MediaRow) { + MediaRow mRow = (MediaRow)cellValue; + MediaHandler handler = handlersMap.get(mRow.getType()); + if(handler != null) { + target.append("<i class='o_icon o_icon-lg ").append(handler.getIconCssClass(mRow)).append("'> </i>"); + } + } + } +} diff --git a/src/main/java/org/olat/portfolio/ui/EPArtefactPoolRunController.java b/src/main/java/org/olat/portfolio/ui/EPArtefactPoolRunController.java index 58bed1e4197..4330b5271e6 100755 --- a/src/main/java/org/olat/portfolio/ui/EPArtefactPoolRunController.java +++ b/src/main/java/org/olat/portfolio/ui/EPArtefactPoolRunController.java @@ -72,6 +72,7 @@ public class EPArtefactPoolRunController extends BasicController implements Acti private EPFilterSettings filterSettings = new EPFilterSettings(); private EPAddArtefactController addArtefactCtrl; private boolean artefactChooseMode; + private boolean canAddArtefacts; private SegmentViewComponent segmentView; private Link artefactsLink, browseLink, searchLink; private Controller filterSelectCtrl; @@ -89,11 +90,12 @@ public class EPArtefactPoolRunController extends BasicController implements Acti private PortfolioStructure preSelectedStruct; public EPArtefactPoolRunController(UserRequest ureq, WindowControl wControl) { - this(ureq, wControl, false); + this(ureq, wControl, false, true); } - public EPArtefactPoolRunController(UserRequest ureq, WindowControl wControl, boolean artefactChooseMode) { + public EPArtefactPoolRunController(UserRequest ureq, WindowControl wControl, boolean artefactChooseMode, boolean canAddArtefacts) { super(ureq, wControl); + this.canAddArtefacts = canAddArtefacts; this.artefactChooseMode = artefactChooseMode; Component viewComp = new Panel("empty"); Component filterPanel = new Panel("filter"); @@ -136,9 +138,11 @@ public class EPArtefactPoolRunController extends BasicController implements Acti searchLink = LinkFactory.createLink("viewTab.search", vC, this); segmentView.addSegment(searchLink, false); - addArtefactCtrl = new EPAddArtefactController(ureq, getWindowControl()); - listenTo(addArtefactCtrl); - vC.put("addArtefactCtrl", addArtefactCtrl.getInitialComponent()); + if(canAddArtefacts) { + addArtefactCtrl = new EPAddArtefactController(ureq, getWindowControl()); + listenTo(addArtefactCtrl); + vC.put("addArtefactCtrl", addArtefactCtrl.getInitialComponent()); + } } /** diff --git a/src/main/java/org/olat/portfolio/ui/_content/artefactsmain.html b/src/main/java/org/olat/portfolio/ui/_content/artefactsmain.html index c6bc767c206..f67543d74f5 100644 --- a/src/main/java/org/olat/portfolio/ui/_content/artefactsmain.html +++ b/src/main/java/org/olat/portfolio/ui/_content/artefactsmain.html @@ -1,11 +1,14 @@ <div class="o_eportfolio o_artefacts"> - #if (!$artefactChooseMode) + + #if(!$artefactChooseMode && $r.available("addArtefactCtrl")) <div class="o_ep_add_artefact pull-right"> $r.render("addArtefactCtrl") </div><br /><br /> #else $r.translate("choose.artefact.intro") - <p>$r.render("addArtefactCtrl")</p> + #if($r.available("addArtefactCtrl")) + <p>$r.render("addArtefactCtrl")</p> + #end #end <div class="o_ep_content"> diff --git a/src/main/java/org/olat/portfolio/ui/artefacts/view/EPArtefactViewController.java b/src/main/java/org/olat/portfolio/ui/artefacts/view/EPArtefactViewController.java index 3ef80b8ebd5..e51c91fa5de 100644 --- a/src/main/java/org/olat/portfolio/ui/artefacts/view/EPArtefactViewController.java +++ b/src/main/java/org/olat/portfolio/ui/artefacts/view/EPArtefactViewController.java @@ -204,8 +204,8 @@ public class EPArtefactViewController extends FormBasicController { List<FormLink> selectMapNames = new ArrayList<FormLink>(linkedMaps.size()); int count = 0; for (PortfolioStructure ePMap : linkedMaps) { - String title = StringHelper.escapeHtml(ePMap.getTitle()); - FormLink selectMap = uifactory.addFormLink("map-" + count++, "map", title, null, formLayout, Link.NONTRANSLATED); + String mapTitle = StringHelper.escapeHtml(ePMap.getTitle()); + FormLink selectMap = uifactory.addFormLink("map-" + count++, "map", mapTitle, null, formLayout, Link.NONTRANSLATED); selectMap.setUserObject(ePMap.getOlatResource()); selectMap.setEnabled(!viewOnlyMode && !artefactChooseMode); selectMapNames.add(selectMap); diff --git a/src/main/java/org/olat/portfolio/ui/structel/EPAddElementsController.java b/src/main/java/org/olat/portfolio/ui/structel/EPAddElementsController.java index 882cbe9bd65..a6a4a4f4707 100644 --- a/src/main/java/org/olat/portfolio/ui/structel/EPAddElementsController.java +++ b/src/main/java/org/olat/portfolio/ui/structel/EPAddElementsController.java @@ -196,7 +196,7 @@ public class EPAddElementsController extends BasicController { private void popUpAddArtefactBox(UserRequest ureq) { if (artefactPoolCtrl == null) { - artefactPoolCtrl = new EPArtefactPoolRunController(ureq, getWindowControl(), true); + artefactPoolCtrl = new EPArtefactPoolRunController(ureq, getWindowControl(), true, true); listenTo(artefactPoolCtrl); } artefactBox = new CloseableModalController(getWindowControl(),"close",artefactPoolCtrl.getInitialComponent(),true, translate("choose.artefact.title")); diff --git a/src/main/java/org/olat/restapi/support/ErrorWindowControl.java b/src/main/java/org/olat/restapi/support/ErrorWindowControl.java index 9a35746f1ab..2b33897877a 100644 --- a/src/main/java/org/olat/restapi/support/ErrorWindowControl.java +++ b/src/main/java/org/olat/restapi/support/ErrorWindowControl.java @@ -22,6 +22,7 @@ package org.olat.restapi.support; import org.olat.core.gui.components.Component; import org.olat.core.gui.control.WindowBackOffice; import org.olat.core.gui.control.WindowControl; +import org.olat.core.gui.control.generic.closablewrapper.CalloutSettings; import org.olat.core.gui.control.info.WindowControlInfo; import org.olat.core.id.context.BusinessControl; @@ -50,7 +51,7 @@ public class ErrorWindowControl implements WindowControl { public void pushAsModalDialog(Component comp) {/* */} @Override - public void pushAsCallout(Component comp, String targetId) {/* */} + public void pushAsCallout(Component comp, String targetId, CalloutSettings settings) {/* */} @Override public void pop() {/* */} diff --git a/src/test/java/org/olat/course/nodes/en/EnrollmentManagerConcurrentTest.java b/src/test/java/org/olat/course/nodes/en/EnrollmentManagerConcurrentTest.java index 0272c99fd09..0bc285744fa 100644 --- a/src/test/java/org/olat/course/nodes/en/EnrollmentManagerConcurrentTest.java +++ b/src/test/java/org/olat/course/nodes/en/EnrollmentManagerConcurrentTest.java @@ -47,6 +47,7 @@ import org.olat.core.commons.persistence.DBFactory; import org.olat.core.gui.components.Component; import org.olat.core.gui.control.WindowBackOffice; import org.olat.core.gui.control.WindowControl; +import org.olat.core.gui.control.generic.closablewrapper.CalloutSettings; import org.olat.core.gui.control.generic.dtabs.DTabs; import org.olat.core.gui.control.info.WindowControlInfo; import org.olat.core.gui.translator.Translator; @@ -326,7 +327,7 @@ public class EnrollmentManagerConcurrentTest extends OlatTestCase implements Win public void pushToMainArea(Component comp){} public void pushAsModalDialog(Component comp){} @Override - public void pushAsCallout(Component comp, String targetId){} + public void pushAsCallout(Component comp, String targetId, CalloutSettings settings){} public void pop(){} public void setInfo(String string){} public void setError(String string){} -- GitLab