/* * Copyright (c) 2010-2016 Evolveum * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.evolveum.midpoint.web.component.assignment; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import com.evolveum.midpoint.gui.api.page.PageBase; import com.evolveum.midpoint.gui.api.util.WebModelServiceUtils; import com.evolveum.midpoint.prism.PrismObject; import com.evolveum.midpoint.prism.query.*; import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.web.component.util.ListDataProvider; import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour; import com.evolveum.midpoint.web.page.admin.users.dto.UserDtoStatus; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import org.apache.commons.collections.IteratorUtils; import org.apache.commons.lang.StringUtils; import org.apache.wicket.AttributeModifier; import org.apache.wicket.Component; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.markup.html.AjaxLink; import org.apache.wicket.behavior.AttributeAppender; import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator; import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn; import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn; import org.apache.wicket.markup.ComponentTag; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.markup.repeater.Item; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; import com.evolveum.midpoint.gui.api.component.BasePanel; import com.evolveum.midpoint.gui.api.component.ObjectBrowserPanel; import com.evolveum.midpoint.gui.api.model.LoadableModel; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.web.component.data.BaseSortableDataProvider; import com.evolveum.midpoint.web.component.data.BoxedTablePanel; import com.evolveum.midpoint.web.component.data.ObjectDataProvider; import com.evolveum.midpoint.web.component.search.Search; import com.evolveum.midpoint.web.component.search.SearchFactory; import com.evolveum.midpoint.web.component.search.SearchPanel; import com.evolveum.midpoint.web.component.util.SelectableBean; import com.evolveum.midpoint.web.session.UserProfileStorage; import javax.xml.namespace.QName; /** * Creates a panel with the list of focus type items * with the possibility to filter by user (show only * assigned to the specified user items), to search * through the list and to reset the list to the * initial state * * @author Kate Honchar */ public class MultipleAssignmentSelector<F extends FocusType, H extends FocusType> extends BasePanel<List<AssignmentEditorDto>> { private static final long serialVersionUID = 1L; private static final Trace LOGGER = TraceManager.getTrace(MultipleAssignmentSelector.class); private static final String DOT_CLASS = MultipleAssignmentSelector.class.getName() + "."; private static final String OPERATION_LOAD_FILTER_OBJECT = DOT_CLASS + "loadFilterObject"; private static final String ID_TABLE = "table"; private static final String ID_FILTER_BUTTON_CONTAINER = "filterButtonContainer"; private static final String ID_SEARCH_FORM = "searchForm"; private static final String ID_SEARCH = "search"; private static final int ITEMS_PER_PAGE = 10; private static final String ID_FILTER_BY_USER_BUTTON = "filterByUserButton"; private static final String ID_LABEL = "label"; private static final String ID_DELETE_BUTTON = "deleteButton"; private boolean showDialog = true; private IModel<Search> searchModel; private BaseSortableDataProvider provider; private Class type; private Class<H> targetFocusClass; private String labelValue =""; private IModel<ObjectFilter> filterModel = null; private ObjectQuery searchQuery = null; private PrismObject<F> focus; private H filterObject = null; private boolean filterObjectIsAdded = false; public MultipleAssignmentSelector(String id, IModel<List<AssignmentEditorDto>> selectorModel, Class<H> targetFocusClass, Class type, PrismObject<F> focus, IModel<ObjectFilter> filterModel, PageBase pageBase) { super(id, selectorModel); this.focus=focus; this.filterModel = filterModel; this.type = type; this.targetFocusClass = targetFocusClass; searchModel = new LoadableModel<Search>(false) { @Override public Search load() { Search search = SearchFactory.createSearch(RoleType.class, getPageBase().getPrismContext(), getPageBase().getModelInteractionService()); return search; } }; if (focus == null){ provider = getListDataProvider(null); } else { provider = getAvailableAssignmentsDataProvider(); } initLayout(pageBase); } private void initLayout(PageBase pageBase) { setOutputMarkupId(true); WebMarkupContainer filterButtonContainer = new WebMarkupContainer(ID_FILTER_BUTTON_CONTAINER); AjaxLink<String> filterByUserButton = new AjaxLink<String>(ID_FILTER_BY_USER_BUTTON) { @Override public void onClick(AjaxRequestTarget target) { if (showDialog) { labelValue = createStringResource("MultipleAssignmentSelector.filterByUser").getString(); initUserDialog(createStringResource("MultipleAssignmentSelector.filterByUser"), target); } showDialog = true; } }; filterButtonContainer.add(filterByUserButton); labelValue = pageBase.createStringResource("MultipleAssignmentSelector.filterByUser").getString(); Label label = new Label(ID_LABEL, createLabelModel()); label.setRenderBodyOnly(true); filterByUserButton.add(label); AjaxLink deleteButton = new AjaxLink(ID_DELETE_BUTTON) { @Override public void onClick(AjaxRequestTarget target) { labelValue = createStringResource("MultipleAssignmentSelector.filterByUser").getString(); showDialog = false; deleteFilterPerformed(target); } }; filterByUserButton.add(deleteButton); add(filterButtonContainer); initSearchPanel(); add(initTablePanel()); } private Component createRowLink(String id, final IModel<SelectableBean<AssignmentEditorDto>> rowModel) { AjaxLink<SelectableBean<AssignmentEditorDto>> button = new AjaxLink<SelectableBean<AssignmentEditorDto>>(id, rowModel) { @Override public IModel<?> getBody() { AssignmentEditorDto dto =(AssignmentEditorDto) rowModel.getObject(); String name = StringUtils.isNotEmpty(dto.getNameForTargetObject()) ? dto.getNameForTargetObject() : dto.getName(); return new Model<>(name); } @Override public void onClick(AjaxRequestTarget target) { LOGGER.trace("{} CLICK: {}", this, rowModel.getObject()); toggleRow(rowModel); target.add(this); } @Override protected void onComponentTag(ComponentTag tag) { super.onComponentTag(tag); if (rowModel.getObject().isSelected()) { tag.put("class", "list-group-item active"); tag.put("style", "background-color: #eee; border-color: #d6d6d6; color: #000;"); } else { tag.put("class", "list-group-item"); } String description = ((AssignmentEditorDto) rowModel.getObject()).getDescription(); if (description != null) { tag.put("title", description); } } }; button.add(new VisibleEnableBehaviour(){ @Override public boolean isVisible(){ return ((AssignmentEditorDto)rowModel.getObject()).getStatus() != UserDtoStatus.DELETE; } }); button.setOutputMarkupId(true); return button; } private List<IColumn<SelectableBean<AssignmentEditorDto>, String>> initColumns() { List<IColumn<SelectableBean<AssignmentEditorDto>, String>> columns = new ArrayList<>(); columns.add(new AbstractColumn<SelectableBean<AssignmentEditorDto>, String>(new Model()) { public void populateItem(Item<ICellPopulator<SelectableBean<AssignmentEditorDto>>> cellItem, String componentId, IModel<SelectableBean<AssignmentEditorDto>> rowModel) { cellItem.add(createRowLink(componentId, rowModel)); } }); return columns; } private void updateBoxedTablePanelStyles(BoxedTablePanel panel) { panel.getDataTableContainer().add(new AttributeAppender("class", " multiple-assignment-selector-table-container")); panel.getDataTable().add(new AttributeModifier("class", "multiple-assignment-selector-table")); panel.getFooterPaging().getParent().add(new AttributeModifier("class", "multiple-assignment-selector-table-footer")); } public BaseSortableDataProvider getProvider() { return provider; } private void toggleRow(IModel<SelectableBean<AssignmentEditorDto>> rowModel){ rowModel.getObject().setSelected(!rowModel.getObject().isSelected()); List<AssignmentEditorDto> providerList = ((BaseSortableDataProvider) getProvider()).getAvailableData(); for (AssignmentEditorDto dto : providerList){ if (dto.equals(rowModel.getObject())){ dto.setSelected(rowModel.getObject().isSelected()); break; } } } private void initSearchPanel(){ final Form searchForm = new Form(ID_SEARCH_FORM); add(searchForm); searchForm.setOutputMarkupId(true); SearchPanel search = new SearchPanel(ID_SEARCH, (IModel) searchModel, false) { @Override public void searchPerformed(ObjectQuery query, AjaxRequestTarget target) { MultipleAssignmentSelector.this.searchPerformed(query, target); } }; searchForm.add(search); } private void searchPerformed(ObjectQuery query, AjaxRequestTarget target) { MultipleAssignmentSelector.this.searchQuery = query; if (filterModel != null && filterModel.getObject() != null) { if (query == null){ query = new ObjectQuery(); } query.addFilter(filterModel.getObject()); filterObjectIsAdded = true; } BoxedTablePanel panel = getTable(); panel.setCurrentPage(null); provider.setQuery(query); target.add(panel); } public BoxedTablePanel getTable() { return (BoxedTablePanel) get(ID_TABLE); } private BoxedTablePanel initTablePanel(){ List<IColumn<SelectableBean<AssignmentEditorDto>, String>> columns = initColumns(); BoxedTablePanel table = new BoxedTablePanel(ID_TABLE, provider, columns, UserProfileStorage.TableId.TABLE_ROLES, ITEMS_PER_PAGE); updateBoxedTablePanelStyles(table); //hide footer menu table.getFooterMenu().setVisible(false); //hide footer count label table.getFooterCountLabel().setVisible(false); table.setOutputMarkupId(true); return table; } private void initUserDialog(IModel<String> title, AjaxRequestTarget target) { List<QName> supportedTypes = new ArrayList<>(); supportedTypes.add(getPageBase().getPrismContext().getSchemaRegistry() .findObjectDefinitionByCompileTimeClass(targetFocusClass).getTypeName()); ObjectBrowserPanel<H> focusBrowser = new ObjectBrowserPanel<H>(getPageBase().getMainPopupBodyId(), targetFocusClass, supportedTypes, false, getPageBase()) { @Override protected void onSelectPerformed(AjaxRequestTarget target, H filterUser) { super.onSelectPerformed(target, filterUser); filterObject = filterUser; filterByUserPerformed(); replaceTable(target); labelValue += " " + filterUser.getName().toString(); target.add(getFilterButton()); } }; getPageBase().showMainPopup(focusBrowser, target); } private void filterByUserPerformed(){ //we need to load filter object (e.g. user) totally because we //need to know its assignments' tenantRef data (name) //and orgRef data (name) Task task = getPageBase().createSimpleTask(OPERATION_LOAD_FILTER_OBJECT); OperationResult result = task.getResult(); PrismObject<H> loadedObject = WebModelServiceUtils.loadObject(targetFocusClass, filterObject.getOid(), null, getPageBase(), task, result); provider = getListDataProvider(loadedObject != null ? loadedObject.asObjectable() : filterObject); } private void deleteFilterPerformed(AjaxRequestTarget target){ filterObject = null; provider = getAvailableAssignmentsDataProvider(); provider.setQuery(searchQuery); replaceTable(target); } private void replaceTable(AjaxRequestTarget target){ BoxedTablePanel table = initTablePanel(); MultipleAssignmentSelector.this.replace(table); target.add(MultipleAssignmentSelector.this); } public void setFilterButtonVisibility(boolean isVisible){ getFilterButton().setVisible(isVisible); } private IModel<String> createLabelModel(){ return new IModel<String>() { @Override public String getObject() { return labelValue; } @Override public void setObject(String s) { } @Override public void detach() { } }; } private Component getFilterButton(){ return get(createComponentPath(ID_FILTER_BUTTON_CONTAINER, ID_FILTER_BY_USER_BUTTON)); } public <T extends FocusType> BaseSortableDataProvider getListDataProvider(final FocusType focus) { BaseSortableDataProvider provider; provider = new ListDataProvider<AssignmentEditorDto>(this, new IModel<List<AssignmentEditorDto>>() { @Override public List<AssignmentEditorDto> getObject() { return getAvailableAssignmentsDataList(focus); } @Override public void setObject(List<AssignmentEditorDto> list) { } @Override public void detach() { } }); return provider; } private <T extends FocusType> List<AssignmentEditorDto> getAvailableAssignmentsDataList(FocusType focus){ ObjectQuery query = provider.getQuery() == null ? (searchQuery == null ? new ObjectQuery() : searchQuery) : provider.getQuery(); List<AssignmentEditorDto> assignmentsList = getListProviderDataList(); if (assignmentsList == null) { if (focus != null) { assignmentsList = getAssignmentEditorDtoList(focus.getAssignment()); } else { assignmentsList = getModelObject(); } } List<AssignmentEditorDto> currentAssignments = getAssignmentsByType(assignmentsList); if (!filterObjectIsAdded && filterModel != null && filterModel.getObject() != null && query.getFilter() == null) { query.setFilter(filterModel.getObject()); List<String> oidsList = getAssignmentOids(currentAssignments); if (oidsList != null && oidsList.size() > 0) { InOidFilter oidsFilter = InOidFilter.createInOid(oidsList); query.addFilter(oidsFilter); } } filterObjectIsAdded = false; if (currentAssignments != null && currentAssignments.size() > 0) { return applyQueryToListProvider(query, currentAssignments); } else { return new ArrayList<AssignmentEditorDto>(); } } private List<String> getAssignmentOids(List<AssignmentEditorDto> assignments){ List<String> oidsList = new ArrayList<>(); if (assignments != null && assignments.size() > 0){ for (AssignmentEditorDto assignment : assignments){ if (assignment.getTargetRef() != null) { oidsList.add(assignment.getTargetRef().getOid()); } } } return oidsList; } protected List<AssignmentEditorDto> getListProviderDataList(){ return null; } private List<AssignmentEditorDto> getAssignmentsByType(List<AssignmentEditorDto> assignmentsList) { List<AssignmentEditorDto> currentUsersAssignments = new ArrayList<>(); for (AssignmentEditorDto dto : assignmentsList) { if (dto.getType().equals(AssignmentEditorDtoType.getType(type)) && !dto.getStatus().equals(UserDtoStatus.DELETE)) { currentUsersAssignments.add(dto); } } return currentUsersAssignments; } private List<AssignmentEditorDto> applyQueryToListProvider(ObjectQuery query, List<AssignmentEditorDto> providerList){ ObjectDataProvider temporaryProvider = new ObjectDataProvider(MultipleAssignmentSelector.this, type); List<AssignmentEditorDto> displayAssignmentsList = new ArrayList<>(); temporaryProvider.setQuery(query); Iterator it = temporaryProvider.internalIterator(0, temporaryProvider.size()); List<SelectableBean<F>> providerDataList = IteratorUtils.toList(it); for (AssignmentEditorDto dto : providerList) { for (SelectableBean<F> providerDataDto : providerDataList){ F object = providerDataDto.getValue(); if (object != null && object.getOid().equals(dto.getTargetRef().getOid())) { displayAssignmentsList.add(dto); break; } } } return displayAssignmentsList; } private List<AssignmentEditorDto> getAssignmentEditorDtoList(List<AssignmentType> assignmentTypeList){ List<AssignmentEditorDto> assignmentEditorDtoList = new ArrayList<>(); for (AssignmentType assignmentType : assignmentTypeList){ AssignmentEditorDto assignmentEditorDto = new AssignmentEditorDto(UserDtoStatus.MODIFY, assignmentType, getPageBase()); assignmentEditorDtoList.add(assignmentEditorDto); } return assignmentEditorDtoList; } public ObjectDataProvider getAvailableAssignmentsDataProvider() { ObjectDataProvider<AssignmentEditorDto, F> provider = new ObjectDataProvider<AssignmentEditorDto, F>(this, type) { @Override public AssignmentEditorDto createDataObjectWrapper(PrismObject<F> obj) { return AssignmentEditorDto.createDtoFromObject(obj.asObjectable(), UserDtoStatus.MODIFY, getPageBase()); } @Override public void setQuery(ObjectQuery query) { super.setQuery(query); searchQuery = query; } @Override public ObjectQuery getQuery() { if (searchQuery == null){ searchQuery = new ObjectQuery(); if (filterModel != null && filterModel.getObject() != null) { searchQuery.addFilter(filterModel.getObject()); } } return searchQuery; } }; return provider; } }