/*
* 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.collection.selector;
import java.util.List;
import org.apache.wicket.AttributeModifier;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.event.Broadcast;
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.link.AbstractLink;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.isis.applib.services.bookmark.Bookmark;
import org.apache.isis.core.commons.lang.StringExtensions;
import org.apache.isis.viewer.wicket.model.hints.IsisSelectorEvent;
import org.apache.isis.viewer.wicket.model.models.EntityCollectionModel;
import org.apache.isis.viewer.wicket.model.models.EntityModel;
import org.apache.isis.viewer.wicket.model.util.ComponentHintKey;
import org.apache.isis.viewer.wicket.ui.CollectionContentsAsFactory;
import org.apache.isis.viewer.wicket.ui.ComponentFactory;
import org.apache.isis.viewer.wicket.ui.panels.PanelAbstract;
import org.apache.isis.viewer.wicket.ui.util.CssClassAppender;
import de.agilecoders.wicket.core.markup.html.bootstrap.button.Buttons;
/**
* Provides a list of links for selecting other views that support
* {@link org.apache.isis.viewer.wicket.ui.ComponentType#COLLECTION_CONTENTS} with a backing
* {@link org.apache.isis.viewer.wicket.model.models.EntityCollectionModel}.
*/
public class CollectionSelectorPanel extends PanelAbstract<EntityCollectionModel> {
private static final long serialVersionUID = 1L;
private static final String ID_VIEWS = "views";
private static final String ID_VIEW_LIST = "viewList";
private static final String ID_VIEW_LINK = "viewLink";
private static final String ID_VIEW_ITEM = "viewItem";
private static final String ID_VIEW_ITEM_TITLE = "viewItemTitle";
private static final String ID_VIEW_ITEM_ICON = "viewItemIcon";
private static final String ID_VIEW_BUTTON_TITLE = "viewButtonTitle";
private static final String ID_VIEW_BUTTON_ICON = "viewButtonIcon";
private final CollectionSelectorHelper selectorHelper;
private final ComponentHintKey componentHintKey;
private ComponentFactory selectedComponentFactory;
public CollectionSelectorPanel(
final String id,
final EntityCollectionModel model) {
this(id, model, ComponentHintKey.<String>noop());
}
public CollectionSelectorPanel(
final String id,
final EntityCollectionModel model,
final ComponentHintKey componentHintKey) {
super(id, model);
this.componentHintKey = componentHintKey;
selectorHelper = new CollectionSelectorHelper(
model, getComponentFactoryRegistry(), componentHintKey);
}
/**
* Build UI only after added to parent.
*/
public void onInitialize() {
super.onInitialize();
addDropdown();
}
private void addDropdown() {
final List<ComponentFactory> componentFactories = selectorHelper.getComponentFactories();
final String selected = selectorHelper.honourViewHintElseDefault(this);
// selector
if (componentFactories.size() <= 1) {
permanentlyHide(ID_VIEWS);
} else {
final Model<ComponentFactory> componentFactoryModel = new Model<>();
this.selectedComponentFactory = selectorHelper.find(selected);
componentFactoryModel.setObject(this.selectedComponentFactory);
final WebMarkupContainer views = new WebMarkupContainer(ID_VIEWS);
final Label viewButtonTitle = new Label(ID_VIEW_BUTTON_TITLE, "Hidden");
views.addOrReplace(viewButtonTitle);
final Label viewButtonIcon = new Label(ID_VIEW_BUTTON_ICON, "");
views.addOrReplace(viewButtonIcon);
final WebMarkupContainer container = new WebMarkupContainer(ID_VIEW_LIST);
views.addOrReplace(container);
views.setOutputMarkupId(true);
this.setOutputMarkupId(true);
final ListView<ComponentFactory> listView = new ListView<ComponentFactory>(ID_VIEW_ITEM, componentFactories) {
private static final long serialVersionUID = 1L;
@Override
protected void populateItem(ListItem<ComponentFactory> item) {
final ComponentFactory componentFactory = item.getModelObject();
final AbstractLink link = new AjaxLink<Void>(ID_VIEW_LINK) {
private static final long serialVersionUID = 1L;
@Override
public void onClick(AjaxRequestTarget target) {
CollectionSelectorPanel linksSelectorPanel = CollectionSelectorPanel.this;
linksSelectorPanel.setViewHintAndBroadcast(componentFactory.getName(), target);
linksSelectorPanel.selectedComponentFactory = componentFactory;
componentHintKey.set(domainObjectBookmarkIfAny(), componentFactory.getName());
target.add(linksSelectorPanel, views);
}
Bookmark domainObjectBookmarkIfAny() {
final EntityCollectionModel entityCollectionModel = CollectionSelectorPanel.this.getModel();
final EntityModel entityModel = entityCollectionModel.getEntityModel();
return entityModel != null
? entityModel.getObjectAdapterMemento().asHintingBookmark()
: null;
}
@Override
protected void onComponentTag(ComponentTag tag) {
super.onComponentTag(tag);
Buttons.fixDisabledState(this, tag);
}
};
IModel<String> title = nameFor(componentFactory);
Label viewItemTitleLabel = new Label(ID_VIEW_ITEM_TITLE, title);
link.add(viewItemTitleLabel);
Label viewItemIcon = new Label(ID_VIEW_ITEM_ICON, "");
link.add(viewItemIcon);
final boolean selected = componentFactory == CollectionSelectorPanel.this.selectedComponentFactory;
if (selected) {
viewButtonTitle.setDefaultModel(title);
IModel<String> cssClass = cssClassFor(componentFactory, viewButtonIcon);
viewButtonIcon.add(AttributeModifier.replace("class", "ViewLinkItem " + cssClass.getObject()));
link.setVisible(false);
} else {
IModel<String> cssClass = cssClassFor(componentFactory, viewItemIcon);
viewItemIcon.add(new CssClassAppender(cssClass));
}
item.add(link);
}
private IModel<String> cssClassFor(final ComponentFactory componentFactory, Label viewIcon) {
IModel<String> cssClass = null;
if (componentFactory instanceof CollectionContentsAsFactory) {
CollectionContentsAsFactory collectionContentsAsFactory = (CollectionContentsAsFactory) componentFactory;
cssClass = collectionContentsAsFactory.getCssClass();
viewIcon.setDefaultModelObject("");
viewIcon.setEscapeModelStrings(true);
}
if (cssClass == null) {
String name = componentFactory.getName();
cssClass = Model.of(StringExtensions.asLowerDashed(name));
// Small hack: if there is no specific CSS class then we assume that background-image is used
// the span.ViewItemLink should have some content to show it
// FIX: find a way to do this with CSS (width and height don't seems to help)
viewIcon.setDefaultModelObject(" ");
viewIcon.setEscapeModelStrings(false);
}
return cssClass;
}
private IModel<String> nameFor(final ComponentFactory componentFactory) {
IModel<String> name = null;
if (componentFactory instanceof CollectionContentsAsFactory) {
CollectionContentsAsFactory collectionContentsAsFactory = (CollectionContentsAsFactory) componentFactory;
name = collectionContentsAsFactory.getTitleLabel();
}
if (name == null) {
name = Model.of(componentFactory.getName());
}
return name;
}
};
container.add(listView);
addOrReplace(views);
}
}
protected void setViewHintAndBroadcast(String viewName, AjaxRequestTarget target) {
final CollectionSelectorPanel component = CollectionSelectorPanel.this;
final IsisSelectorEvent selectorEvent =
new IsisSelectorEvent(component, CollectionSelectorHelper.UIHINT_EVENT_VIEW_KEY, viewName, target);
send(getPage(), Broadcast.EXACT, selectorEvent);
}
}