/* * 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.gui.api.component; import java.util.*; import com.evolveum.midpoint.xml.ns._public.common.common_3.*; import org.apache.commons.lang3.StringUtils; import org.apache.wicket.Component; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn; import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.form.Form; import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model; import org.apache.wicket.model.StringResourceModel; import com.evolveum.midpoint.gui.api.model.LoadableModel; import com.evolveum.midpoint.gui.api.page.PageBase; import com.evolveum.midpoint.gui.api.util.WebComponentUtil; import com.evolveum.midpoint.prism.query.ObjectPaging; import com.evolveum.midpoint.prism.query.ObjectQuery; import com.evolveum.midpoint.schema.GetOperationOptions; import com.evolveum.midpoint.schema.SelectorOptions; 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.SelectableBeanObjectDataProvider; import com.evolveum.midpoint.web.component.data.Table; import com.evolveum.midpoint.web.component.data.column.CheckBoxHeaderColumn; import com.evolveum.midpoint.web.component.data.column.ColumnUtils; import com.evolveum.midpoint.web.component.menu.cog.InlineMenuItem; import com.evolveum.midpoint.web.component.search.Search; import com.evolveum.midpoint.web.component.search.SearchFactory; import com.evolveum.midpoint.web.component.search.SearchFormPanel; import com.evolveum.midpoint.web.component.util.ListDataProvider2; import com.evolveum.midpoint.web.component.util.SelectableBean; import com.evolveum.midpoint.web.session.PageStorage; import com.evolveum.midpoint.web.session.UserProfileStorage.TableId; /** * @author katkav */ public abstract class ObjectListPanel<O extends ObjectType> extends BasePanel<O> { private static final long serialVersionUID = 1L; private static final String ID_MAIN_FORM = "mainForm"; private static final String ID_TABLE = "table"; private static final Trace LOGGER = TraceManager.getTrace(ObjectListPanel.class); private Class<? extends O> type; private PageBase parentPage; private LoadableModel<Search> searchModel; private Collection<SelectorOptions<GetOperationOptions>> options; private boolean multiselect; private TableId tableId; protected List<O> selectedObjects = null; private String addutionalBoxCssClasses; public Class<? extends O> getType() { return type; } /** * @param defaultType specifies type of the object that will be selected by default. It can be changed. */ public ObjectListPanel(String id, Class<? extends O> defaultType, TableId tableId, Collection<SelectorOptions<GetOperationOptions>> options, PageBase parentPage) { super(id); this.type = defaultType; this.parentPage = parentPage; this.options = options; this.tableId = tableId; initLayout(); } /** * @param defaultType specifies type of the object that will be selected by default. It can be changed. */ ObjectListPanel(String id, Class<? extends O> defaultType, boolean multiselect, PageBase parentPage) { super(id); this.type = defaultType; this.parentPage = parentPage; this.multiselect = multiselect; initLayout(); } public ObjectListPanel(String id, Class<? extends O> defaultType, boolean multiselect, PageBase parentPage, List<O> selectedObjectsList) { super(id); this.type = defaultType; this.parentPage = parentPage; this.multiselect = multiselect; this.selectedObjects = selectedObjectsList; initLayout(); } public boolean isMultiselect() { return multiselect; } public int getSelectedObjectsCount(){ List<O> selectedList = getSelectedObjects(); return selectedList == null ? 0 : selectedList.size(); } @SuppressWarnings("unchecked") public List<O> getSelectedObjects() { BaseSortableDataProvider<SelectableBean<O>> dataProvider = getDataProvider(); if (dataProvider instanceof SelectableBeanObjectDataProvider) { return ((SelectableBeanObjectDataProvider<O>) dataProvider).getSelectedData(); } else if (dataProvider instanceof ListDataProvider2) { return ((ListDataProvider2) dataProvider).getSelectedObjects(); } return new ArrayList<>(); } private void initLayout() { Form<O> mainForm = new Form<O>(ID_MAIN_FORM); add(mainForm); searchModel = initSearchModel(); BoxedTablePanel<SelectableBean<O>> table = createTable(); mainForm.add(table); } private LoadableModel<Search> initSearchModel(){ return new LoadableModel<Search>(false) { private static final long serialVersionUID = 1L; @Override public Search load() { String storageKey = getStorageKey(); Search search = null; if (StringUtils.isNotEmpty(storageKey)) { PageStorage storage = getPageStorage(storageKey); if (storage != null) { search = storage.getSearch(); } } if (search == null) { search = createSearch(); } return search; } }; } protected Search createSearch() { return SearchFactory.createSearch(type, parentPage.getPrismContext(), parentPage.getModelInteractionService()); } private BoxedTablePanel<SelectableBean<O>> createTable() { List<IColumn<SelectableBean<O>, String>> columns; if (isCustomColumnsListConfigured()){ columns = initCustomColumns(); } else { columns = initColumns(); } BaseSortableDataProvider<SelectableBean<O>> provider = initProvider(); BoxedTablePanel<SelectableBean<O>> table = new BoxedTablePanel<SelectableBean<O>>(ID_TABLE, provider, columns, tableId, tableId == null ? 10 : parentPage.getSessionStorage().getUserProfile().getPagingSize(tableId)) { private static final long serialVersionUID = 1L; @Override protected WebMarkupContainer createHeader(String headerId) { return initSearch(headerId); } @Override public String getAdditionalBoxCssClasses() { return ObjectListPanel.this.getAdditionalBoxCssClasses(); } @Override protected WebMarkupContainer createButtonToolbar(String id) { WebMarkupContainer bar = ObjectListPanel.this.createTableButtonToolbar(id); return bar != null ? bar : super.createButtonToolbar(id); } }; table.setOutputMarkupId(true); String storageKey = getStorageKey(); if (StringUtils.isNotEmpty(storageKey)) { PageStorage storage = getPageStorage(storageKey); if (storage != null) { table.setCurrentPage(storage.getPaging()); } } return table; } protected List<IColumn<SelectableBean<O>, String>> initCustomColumns() { LOGGER.trace("Start to init custom columns for table of type {}", type); List<IColumn<SelectableBean<O>, String>> columns = new ArrayList<IColumn<SelectableBean<O>, String>>(); List<GuiObjectColumnType> customColumns = getGuiObjectColumnTypeList(); if (customColumns == null){ return columns; } CheckBoxHeaderColumn<SelectableBean<O>> checkboxColumn = (CheckBoxHeaderColumn<SelectableBean<O>>) createCheckboxColumn(); if (checkboxColumn != null) { columns.add(checkboxColumn); } IColumn<SelectableBean<O>, String> iconColumn = ColumnUtils.createIconColumn(type); columns.add(iconColumn); columns.addAll(getCustomColumnsTransformed(customColumns)); IColumn<SelectableBean<O>, String> actionsColumn = createActionsColumn(); if (actionsColumn != null){ columns.add(actionsColumn); } LOGGER.trace("Finished to init custom columns, created columns {}", columns); return columns; } protected List<IColumn<SelectableBean<O>, String>> getCustomColumnsTransformed(List<GuiObjectColumnType> customColumns){ List<IColumn<SelectableBean<O>, String>> columns = new ArrayList<IColumn<SelectableBean<O>, String>>(); if (customColumns == null || customColumns.size() == 0){ return columns; } IColumn<SelectableBean<O>, String> column; for (GuiObjectColumnType customColumn : customColumns){ if (WebComponentUtil.getElementVisibility(customColumn.getVisibility())) { if (customColumns.indexOf(customColumn) == 0) { column = createNameColumn(customColumn.getDisplay() != null && customColumn.getDisplay().getLabel() != null ? Model.of(customColumn.getDisplay().getLabel()) : createStringResource(getItemDisplayName(customColumn)), customColumn.getPath().toString()); } else { column = new PropertyColumn(customColumn.getDisplay() != null && customColumn.getDisplay().getLabel() != null ? Model.of(customColumn.getDisplay().getLabel()) : createStringResource(getItemDisplayName(customColumn)), null, SelectableBean.F_VALUE + "." + customColumn.getPath()); } columns.add(column); } } return columns; } protected List<IColumn<SelectableBean<O>, String>> initColumns() { LOGGER.trace("Start to init columns for table of type {}", type); List<IColumn<SelectableBean<O>, String>> columns = new ArrayList<IColumn<SelectableBean<O>, String>>(); CheckBoxHeaderColumn<SelectableBean<O>> checkboxColumn = (CheckBoxHeaderColumn<SelectableBean<O>>) createCheckboxColumn(); if (checkboxColumn != null) { columns.add(checkboxColumn); } IColumn<SelectableBean<O>, String> iconColumn = ColumnUtils.createIconColumn(type); columns.add(iconColumn); IColumn<SelectableBean<O>, String> nameColumn = createNameColumn(null, null); columns.add(nameColumn); List<IColumn<SelectableBean<O>, String>> others = createColumns(); columns.addAll(others); IColumn<SelectableBean<O>, String> actionsColumn = createActionsColumn(); if (actionsColumn != null) { columns.add(createActionsColumn()); } LOGGER.trace("Finished to init columns, created columns {}", columns); return columns; } protected BaseSortableDataProvider<SelectableBean<O>> initProvider() { Set<O> selectedObjectsSet = selectedObjects == null ? null : new HashSet<O>(selectedObjects); SelectableBeanObjectDataProvider<O> provider = new SelectableBeanObjectDataProvider<O>( parentPage, type, selectedObjectsSet) { private static final long serialVersionUID = 1L; @Override protected void saveProviderPaging(ObjectQuery query, ObjectPaging paging) { String storageKey = getStorageKey(); if (StringUtils.isNotEmpty(storageKey)) { PageStorage storage = getPageStorage(storageKey); if (storage != null) { storage.setPaging(paging); } } } @Override public SelectableBean<O> createDataObjectWrapper(O obj) { SelectableBean<O> bean = super.createDataObjectWrapper(obj); List<InlineMenuItem> inlineMenu = createInlineMenu(); if (inlineMenu != null) { bean.getMenuItems().addAll(inlineMenu); } return bean; } }; if (options == null){ if (ResourceType.class.equals(type)) { options = SelectorOptions.createCollection(GetOperationOptions.createNoFetch()); } } else { if (ResourceType.class.equals(type)) { GetOperationOptions root = SelectorOptions.findRootOptions(options); root.setNoFetch(Boolean.TRUE); } provider.setOptions(options); } provider.setQuery(getQuery()); return provider; } private SearchFormPanel initSearch(String headerId) { SearchFormPanel searchPanel = new SearchFormPanel(headerId, searchModel) { private static final long serialVersionUID = 1L; @Override protected void searchPerformed(ObjectQuery query, AjaxRequestTarget target) { ObjectListPanel.this.searchPerformed(query, target); } }; return searchPanel; } public String getAdditionalBoxCssClasses() { return addutionalBoxCssClasses; } public void setAdditionalBoxCssClasses(String boxCssClasses) { this.addutionalBoxCssClasses = boxCssClasses; } /** * there's no way to do it properly... */ @Deprecated protected WebMarkupContainer createTableButtonToolbar(String id) { return null; } private String getStorageKey() { String storageKey = WebComponentUtil.getStorageKeyForPage(parentPage.getClass()); if (storageKey == null) { storageKey = WebComponentUtil.getStorageKeyForTableId(tableId); } return storageKey; } private PageStorage getPageStorage(String storageKey){ PageStorage storage = getSession().getSessionStorage().getPageStorageMap().get(storageKey); if (storage == null) { storage = getSession().getSessionStorage().initPageStorage(storageKey); } return storage; } @SuppressWarnings("unchecked") protected BaseSortableDataProvider<SelectableBean<O>> getDataProvider() { BoxedTablePanel<SelectableBean<O>> table = getTable(); BaseSortableDataProvider<SelectableBean<O>> provider = (BaseSortableDataProvider<SelectableBean<O>>) table .getDataTable().getDataProvider(); return provider; } @SuppressWarnings("unchecked") protected BoxedTablePanel<SelectableBean<O>> getTable() { return (BoxedTablePanel<SelectableBean<O>>) get(createComponentPath(ID_MAIN_FORM, ID_TABLE)); } @SuppressWarnings("deprecation") private void searchPerformed(ObjectQuery query, AjaxRequestTarget target) { BaseSortableDataProvider<SelectableBean<O>> provider = getDataProvider(); // note: we ignore 'query' parameter, as the 'customQuery' already contains its content (MID-3271) ObjectQuery customQuery = getQuery(); // if (customQuery == null){ // customQuery = query; // } else { // if (query != null){ // customQuery.addFilter(query.getFilter()); // } // } provider.setQuery(customQuery); String storageKey = getStorageKey(); if (StringUtils.isNotEmpty(storageKey)) { PageStorage storage = getPageStorage(storageKey); if (storage != null) { storage.setSearch(searchModel.getObject()); storage.setPaging(null); } } Table table = getTable(); table.setCurrentPage(null); target.add((Component) table); target.add(parentPage.getFeedbackPanel()); } public void refreshTable(Class<O> newType, AjaxRequestTarget target) { BaseSortableDataProvider<SelectableBean<O>> provider = getDataProvider(); provider.setQuery(getQuery()); if (newType != null && provider instanceof SelectableBeanObjectDataProvider) { ((SelectableBeanObjectDataProvider<O>) provider).setType(newType); } if (newType != null && !this.type.equals(newType)) { this.type = newType; searchModel.reset(); } else { saveSearchModel(); } BoxedTablePanel<SelectableBean<O>> table = getTable(); ((WebMarkupContainer) table.get("box")).addOrReplace(initSearch("header")); table.setCurrentPage(null); target.add((Component) table); target.add(parentPage.getFeedbackPanel()); } private void saveSearchModel() { String storageKey = getStorageKey(); if (StringUtils.isNotEmpty(storageKey)) { PageStorage storage = getPageStorage(storageKey); if (storage != null) { storage.setSearch(searchModel.getObject()); storage.setPaging(null); } } } public void clearCache() { BaseSortableDataProvider<SelectableBean<O>> provider = getDataProvider(); provider.clearCache(); if (provider instanceof SelectableBeanObjectDataProvider) { ((SelectableBeanObjectDataProvider<O>) provider).clearSelectedObjects(); } } public ObjectQuery getQuery() { ObjectQuery customQuery = createContentQuery(); return customQuery; } protected ObjectQuery createContentQuery() { Search search = searchModel.getObject(); ObjectQuery query = search.createObjectQuery(parentPage.getPrismContext()); query = addFilterToContentQuery(query); return query; } protected ObjectQuery addFilterToContentQuery(ObjectQuery query) { return query; } public StringResourceModel createStringResource(String resourceKey, Object... objects) { return PageBase.createStringResourceStatic(this, resourceKey, objects); } protected abstract IColumn<SelectableBean<O>, String> createCheckboxColumn(); protected abstract IColumn<SelectableBean<O>, String> createNameColumn(IModel<String> columnNameModel, String itemPath); protected abstract List<IColumn<SelectableBean<O>, String>> createColumns(); protected IColumn<SelectableBean<O>, String> createActionsColumn(){ return null; } protected abstract List<InlineMenuItem> createInlineMenu(); public void addPerformed(AjaxRequestTarget target, List<O> selected) { parentPage.hideMainPopup(target); } private List<GuiObjectColumnType> getGuiObjectColumnTypeList(){ AdminGuiConfigurationType adminGuiConfig = parentPage.getPrincipal().getAdminGuiConfiguration(); if (adminGuiConfig != null && adminGuiConfig.getObjectLists() != null && adminGuiConfig.getObjectLists().getObjectList() != null){ for (GuiObjectListType object : adminGuiConfig.getObjectLists().getObjectList()){ if (object.getType() != null && !type.getSimpleName().equals(object.getType().getLocalPart())){ continue; } return object.getColumn(); } } return null; } private boolean isCustomColumnsListConfigured(){ return getGuiObjectColumnTypeList() != null; } private String getItemDisplayName(GuiObjectColumnType column){ return parentPage.getPrismContext().getSchemaRegistry() .findObjectDefinitionByCompileTimeClass(type).findItemDefinition(column.getPath().getItemPath()).getDisplayName(); } }