/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 org.apache.isis.viewer.wicket.ui.components.layout.bs3.col; import java.util.List; import javax.annotation.Nullable; import com.google.common.base.Function; import com.google.common.base.Predicate; import com.google.common.base.Predicates; import com.google.common.collect.FluentIterable; import com.google.common.collect.Lists; import org.apache.wicket.Component; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.isis.applib.layout.component.ActionLayoutData; import org.apache.isis.applib.layout.component.CollectionLayoutData; import org.apache.isis.applib.layout.component.DomainObjectLayoutData; import org.apache.isis.applib.layout.component.FieldSet; import org.apache.isis.applib.layout.grid.bootstrap3.BS3Col; import org.apache.isis.applib.layout.grid.bootstrap3.BS3Row; import org.apache.isis.applib.layout.grid.bootstrap3.BS3Tab; import org.apache.isis.applib.layout.grid.bootstrap3.BS3TabGroup; import org.apache.isis.core.metamodel.spec.feature.ObjectAction; import org.apache.isis.viewer.wicket.model.links.LinkAndLabel; import org.apache.isis.viewer.wicket.model.models.EntityModel; import org.apache.isis.viewer.wicket.ui.ComponentFactory; import org.apache.isis.viewer.wicket.ui.ComponentType; import org.apache.isis.viewer.wicket.ui.components.actionmenu.entityactions.AdditionalLinksPanel; import org.apache.isis.viewer.wicket.ui.components.actionmenu.entityactions.LinkAndLabelUtil; import org.apache.isis.viewer.wicket.ui.components.entity.fieldset.PropertyGroup; import org.apache.isis.viewer.wicket.ui.components.layout.bs3.Util; import org.apache.isis.viewer.wicket.ui.components.layout.bs3.row.Row; import org.apache.isis.viewer.wicket.ui.components.layout.bs3.tabs.TabGroupPanel; import org.apache.isis.viewer.wicket.ui.panels.HasDynamicallyVisibleContent; import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract; import org.apache.isis.viewer.wicket.ui.util.Components; import org.apache.isis.viewer.wicket.ui.util.CssClassAppender; public class Col extends PanelAbstract<EntityModel> implements HasDynamicallyVisibleContent { private static final long serialVersionUID = 1L; private static final String ID_COL = "col"; private static final String ID_ENTITY_HEADER_PANEL = "entityHeaderPanel"; private static final String ID_ROWS = "rows"; private static final String ID_TAB_GROUPS = "tabGroups"; private static final String ID_FIELD_SETS = "fieldSets"; private static final String ID_COLLECTIONS = "collections"; private final BS3Col bs3Col; public Col( final String id, final EntityModel entityModel, final BS3Col bs3Col) { super(id, entityModel); this.bs3Col = bs3Col; buildGui(); } private void buildGui() { setRenderBodyOnly(true); if(bs3Col.getSpan() == 0) { Components.permanentlyHide(this, ID_COL); return; } final WebMarkupContainer div = new WebMarkupContainer(ID_COL); CssClassAppender.appendCssClassTo(div, bs3Col.toCssClass()); Util.appendCssClass(div, bs3Col, ID_COL); // icon/title final DomainObjectLayoutData domainObject = bs3Col.getDomainObject(); final WebMarkupContainer actionOwner; final String actionIdToUse; final String actionIdToHide; if(domainObject != null) { final WebMarkupContainer entityHeaderPanel = new WebMarkupContainer(ID_ENTITY_HEADER_PANEL); div.add(entityHeaderPanel); final ComponentFactory componentFactory = getComponentFactoryRegistry().findComponentFactory(ComponentType.ENTITY_ICON_TITLE_AND_COPYLINK, getModel()); final Component component = componentFactory.createComponent(getModel()); entityHeaderPanel.addOrReplace(component); actionOwner = entityHeaderPanel; actionIdToUse = "entityActions"; actionIdToHide = "actions"; visible = true; } else { Components.permanentlyHide(div, ID_ENTITY_HEADER_PANEL); actionOwner = div; actionIdToUse = "actions"; actionIdToHide = null; } // actions // (rendering depends on whether also showing the icon/title) final List<ActionLayoutData> actionLayoutDatas = bs3Col.getActions(); final List<ObjectAction> visibleActions = FluentIterable.from(actionLayoutDatas) .filter(new Predicate<ActionLayoutData>() { @Override public boolean apply(final ActionLayoutData actionLayoutData) { return actionLayoutData.getMetadataError() == null; } }) .transform(new Function<ActionLayoutData, ObjectAction>() { @Nullable @Override public ObjectAction apply(@Nullable final ActionLayoutData actionLayoutData) { return getModel().getTypeOfSpecification().getObjectAction(actionLayoutData.getId()); } }) .filter(Predicates.<ObjectAction>notNull()) // // visibility needs to be determined at point of rendering, by ActionLink itself // //.filter(new Predicate<ObjectAction>() { // @Override public boolean apply(@Nullable final ObjectAction objectAction) { // final Consent visibility = objectAction // .isVisible(getModel().getObject(), InteractionInitiatedBy.USER, Where.OBJECT_FORMS); // return visibility.isAllowed(); // } //}) .toList(); final List<LinkAndLabel> entityActionLinks = LinkAndLabelUtil.asActionLinksForAdditionalLinksPanel(getModel(), visibleActions, null); if (!entityActionLinks.isEmpty()) { AdditionalLinksPanel.addAdditionalLinks(actionOwner, actionIdToUse, entityActionLinks, AdditionalLinksPanel.Style.INLINE_LIST); visible = true; } else { Components.permanentlyHide(actionOwner, actionIdToUse); } if(actionIdToHide != null) { Components.permanentlyHide(div, actionIdToHide); } // rows final List<BS3Row> rows = Lists.newArrayList(this.bs3Col.getRows()); if(!rows.isEmpty()) { final RepeatingViewWithDynamicallyVisibleContent rowsRv = buildRows(ID_ROWS, rows); div.add(rowsRv); visible = visible || rowsRv.isVisible(); } else { Components.permanentlyHide(div, ID_ROWS); } // tab groups final List<BS3TabGroup> tabGroupsWithNonEmptyTabs = FluentIterable.from(bs3Col.getTabGroups()) .filter(new Predicate<BS3TabGroup>() { @Override public boolean apply(@Nullable final BS3TabGroup bs3TabGroup) { final List<BS3Tab> bs3TabsWithRows = FluentIterable .from(bs3TabGroup.getTabs()) .filter(BS3Tab.Predicates.notEmpty()) .toList(); return !bs3TabsWithRows.isEmpty(); } }).toList(); if(!tabGroupsWithNonEmptyTabs.isEmpty()) { final RepeatingViewWithDynamicallyVisibleContent tabGroupRv = new RepeatingViewWithDynamicallyVisibleContent(ID_TAB_GROUPS); for (BS3TabGroup bs3TabGroup : tabGroupsWithNonEmptyTabs) { final String id = tabGroupRv.newChildId(); final List<BS3Tab> tabs = FluentIterable .from(bs3TabGroup.getTabs()) .filter(BS3Tab.Predicates.notEmpty()) .toList(); switch (tabs.size()) { case 0: // shouldn't occur; previously have filtered these out throw new IllegalStateException("Cannot render tabGroup with no tabs"); case 1: final BS3Tab bs3Tab = tabs.get(0); // render the rows of the one-and-only tab of this tab group. final List<BS3Row> tabRows = bs3Tab.getRows(); final RepeatingViewWithDynamicallyVisibleContent rowsRv = buildRows(id, tabRows); tabGroupRv.add(rowsRv); break; default: final WebMarkupContainer tabGroup = new TabGroupPanel(id, getModel(), bs3TabGroup); tabGroupRv.add(tabGroup); break; } } div.add(tabGroupRv); visible = visible || tabGroupRv.isVisible(); } else { Components.permanentlyHide(div, ID_TAB_GROUPS); } // fieldsets final List<FieldSet> fieldSetsWithProperties = FluentIterable.from(bs3Col.getFieldSets()) .filter(new Predicate<FieldSet>() { @Override public boolean apply(@Nullable final FieldSet fieldSet) { return !fieldSet.getProperties().isEmpty(); } }).toList(); if(!fieldSetsWithProperties.isEmpty()) { final RepeatingViewWithDynamicallyVisibleContent fieldSetRv = new RepeatingViewWithDynamicallyVisibleContent(ID_FIELD_SETS); for (FieldSet fieldSet : fieldSetsWithProperties) { final String id = fieldSetRv.newChildId(); final PropertyGroup propertyGroup = new PropertyGroup(id, getModel(), fieldSet); fieldSetRv.add(propertyGroup); } div.add(fieldSetRv); visible = visible || fieldSetRv.isVisible(); } else { Components.permanentlyHide(div, ID_FIELD_SETS); } // collections final List<CollectionLayoutData> collections = FluentIterable.from(bs3Col.getCollections()).filter( new Predicate<CollectionLayoutData>() { @Override public boolean apply(final CollectionLayoutData collectionLayoutData) { return collectionLayoutData.getMetadataError() == null; } }).toList(); if(!collections.isEmpty()) { final RepeatingViewWithDynamicallyVisibleContent collectionRv = new RepeatingViewWithDynamicallyVisibleContent(ID_COLLECTIONS); for (CollectionLayoutData collection : collections) { final String id = collectionRv.newChildId(); // we successively trample over the layout data; but that's ok, this is synchronous code anyway... final EntityModel entityModel = getModel(); entityModel.setCollectionLayoutData(collection); // the entityModel's getLayoutData() provides the hint as to which collection of the entity to render. final ComponentFactory componentFactory = getComponentFactoryRegistry().findComponentFactory( ComponentType.ENTITY_COLLECTION, entityModel); final Component collectionPanel = componentFactory.createComponent(id, entityModel); collectionRv.add(collectionPanel); } div.add(collectionRv); visible = visible || collectionRv.isVisible(); } else { Components.permanentlyHide(div, ID_COLLECTIONS); } final WebMarkupContainer panel = this; if(visible) { panel.add(div); } else { Components.permanentlyHide(panel, div.getId()); } } private RepeatingViewWithDynamicallyVisibleContent buildRows(final String owningId, final List<BS3Row> rows) { final RepeatingViewWithDynamicallyVisibleContent rowRv = new RepeatingViewWithDynamicallyVisibleContent(owningId); for(final BS3Row bs3Row: rows) { final String id = rowRv.newChildId(); final Row row = new Row(id, getModel(), bs3Row); rowRv.add(row); } return rowRv; } private boolean visible = false; @Override public boolean isVisible() { return visible; } }