/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates.
*
* 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 org.uberfire.ext.widgets.common.client.breadcrumbs;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import javax.enterprise.event.Observes;
import javax.inject.Inject;
import com.google.gwt.user.client.ui.HasWidgets;
import org.jboss.errai.common.client.dom.Element;
import org.jboss.errai.ioc.client.api.AfterInitialization;
import org.jboss.errai.ioc.client.api.EntryPoint;
import org.jboss.errai.ioc.client.api.ManagedInstance;
import org.uberfire.client.mvp.PlaceManager;
import org.uberfire.client.mvp.UberElement;
import org.uberfire.client.workbench.events.PerspectiveChange;
import org.uberfire.ext.widgets.common.client.breadcrumbs.header.UberfireBreadcrumbsContainer;
import org.uberfire.ext.widgets.common.client.breadcrumbs.widget.BreadcrumbsPresenter;
import org.uberfire.mvp.Command;
import org.uberfire.mvp.PlaceRequest;
/**
* A container for breadcrumbs and a toolbar area.
* Allows the applications to add breadcrumbs to
* any displayable thing: a {@link WorkbenchPerspective},
* a {@link WorkbenchScreen} a {@link WorkbenchEditor},
* or the editor associated with a VFS file located at a
* particular {@link Path} through a {@link PathPlaceRequest}.
* Also has a toolbar area, placed in the right side of bread, that allows
* applications to add {@link Element} to Uberfire Breadcrumbs.
*/
@EntryPoint
public class UberfireBreadcrumbs {
final Map<String, List<BreadcrumbsPresenter>> breadcrumbsPerPerspective = new HashMap<>();
final Map<String, Element> breadcrumbsToolBarPerPerspective = new HashMap<>();
private final UberfireBreadcrumbsContainer uberfireBreadcrumbsContainer;
private final View view;
String currentPerspective;
private ManagedInstance<BreadcrumbsPresenter> breadcrumbsPresenters;
private PlaceManager placeManager;
@Inject
public UberfireBreadcrumbs(UberfireBreadcrumbsContainer uberfireBreadcrumbsContainer,
ManagedInstance<BreadcrumbsPresenter> breadcrumbsPresenters,
PlaceManager placeManager,
View view) {
this.uberfireBreadcrumbsContainer = uberfireBreadcrumbsContainer;
this.breadcrumbsPresenters = breadcrumbsPresenters;
this.placeManager = placeManager;
this.view = view;
}
void perspectiveChangeEvent(@Observes PerspectiveChange perspectiveChange) {
currentPerspective = perspectiveChange.getIdentifier();
updateView();
}
@AfterInitialization
public void createBreadcrumbs() {
uberfireBreadcrumbsContainer.init(getView().getElement());
}
/**
* Clears the breadcrumbs associated with a perspective.
* @param associatedPerspective perspective associated with the breadcrumb
*/
public void clearBreadcrumbs(final String associatedPerspective) {
breadcrumbsPerPerspective.put(associatedPerspective,
new ArrayList<>());
}
/**
* Clears the breadcrumbs and toolbars associated with a perspective.
* @param associatedPerspective perspective associated with the breadcrumb
*/
public void clearBreadcrumbsAndToolBars(final String associatedPerspective) {
breadcrumbsPerPerspective.put(associatedPerspective,
new ArrayList<>());
breadcrumbsToolBarPerPerspective.remove(associatedPerspective);
}
/**
* Creates a breadcrumb associated with a perspective.
* @param associatedPerspective perspective associated with the breadcrumb
* @param breadCrumbLabel label of the breadcrumb
* @param command command to be executed after the associated place request is accessed
*/
public void addBreadCrumb(final String associatedPerspective,
final String breadCrumbLabel,
final Command command) {
addBreadCrumb(associatedPerspective,
breadCrumbLabel,
null,
null,
command);
}
/**
* Creates a breadcrumb associated with a perspective
* and Place Request.
* @param associatedPerspective perspective associated with the breadcrumb
* @param breadCrumbLabel label of the breadcrumb
* @param associatedPlaceRequest place request associated with the breadcrumb
*/
public void addBreadCrumb(final String associatedPerspective,
final String breadCrumbLabel,
final PlaceRequest associatedPlaceRequest) {
addBreadCrumb(associatedPerspective,
breadCrumbLabel,
associatedPlaceRequest,
null,
null);
}
/**
* Creates a breadcrumb associated with a perspective
* a Place Request and a target panel.
* @param associatedPerspective perspective associated with the breadcrumb
* @param breadCrumbLabel label of the breadcrumb
* @param associatedPlaceRequest place request associated with the breadcrumb
* @param addTo target content panel of the place request
*/
public void addBreadCrumb(final String associatedPerspective,
final String breadCrumbLabel,
final PlaceRequest associatedPlaceRequest,
final HasWidgets addTo) {
addBreadCrumb(associatedPerspective,
breadCrumbLabel,
associatedPlaceRequest,
addTo,
null);
}
/**
* Creates a breadcrumb associated with a perspective
* and Place Request.
* @param associatedPerspective perspective associated with the breadcrumb
* @param breadCrumbLabel label of the breadcrumb
* @param associatedPlaceRequest place request associated with the breadcrumb
* @param command command to be executed after the associated place request is accessed
*/
public void addBreadCrumb(final String associatedPerspective,
final String breadCrumbLabel,
final PlaceRequest associatedPlaceRequest,
final Command command) {
addBreadCrumb(associatedPerspective,
breadCrumbLabel,
associatedPlaceRequest,
null,
command);
}
/**
* Creates a breadcrumb associated with a perspective
* a Place Request and a target panel.
* @param associatedPerspective perspective associated with the breadcrumb
* @param breadCrumbLabel label of the breadcrumb
* @param associatedPlaceRequest place request associated with the breadcrumb
* @param addTo target content panel of the place request
* @param command command to be executed after the associated place request is accessed
*/
public void addBreadCrumb(final String associatedPerspective,
final String breadCrumbLabel,
final PlaceRequest associatedPlaceRequest,
final HasWidgets addTo,
final Command command) {
List<BreadcrumbsPresenter> breadcrumbs = getBreadcrumbs(associatedPerspective);
deactivateLastBreadcrumb(breadcrumbs);
breadcrumbs.add(createBreadCrumb(associatedPerspective,
breadCrumbLabel,
associatedPlaceRequest,
addTo,
command));
breadcrumbsPerPerspective.put(associatedPerspective,
breadcrumbs);
if (currentPerspective == associatedPerspective) {
updateView();
}
}
/**
* Adds a toolbar to a perspective.
* Toolbar is placed in the right side of the breadcrumbs area.
* @param associatedPerspective perspective associated with the toolbar
* @param toolbar toolbar that will be added
*/
public void addToolbar(final String associatedPerspective,
final Element toolbar) {
breadcrumbsToolBarPerPerspective.put(associatedPerspective,
toolbar);
if (currentPerspective == associatedPerspective) {
updateView();
}
}
private List<BreadcrumbsPresenter> getBreadcrumbs(final String perspective) {
List<BreadcrumbsPresenter> breadcrumbs = breadcrumbsPerPerspective.get(perspective);
if (breadcrumbs == null) {
breadcrumbs = new ArrayList<>();
}
return breadcrumbs;
}
private void deactivateLastBreadcrumb(final List<BreadcrumbsPresenter> breadcrumbs) {
if (!breadcrumbs.isEmpty()) {
breadcrumbs.get(breadcrumbs.size() - 1).deactivate();
}
}
private BreadcrumbsPresenter createBreadCrumb(final String perspective,
final String label,
final PlaceRequest placeRequest,
final HasWidgets addTo,
final Command command) {
BreadcrumbsPresenter breadCrumb = breadcrumbsPresenters.get();
breadCrumb.setup(label,
placeRequest,
generateBreadCrumbSelectCommand(perspective,
breadCrumb,
placeRequest,
addTo,
command));
breadCrumb.activate();
return breadCrumb;
}
Command generateBreadCrumbSelectCommand(final String perspective,
final BreadcrumbsPresenter breadCrumb,
final PlaceRequest placeRequest,
final HasWidgets addTo,
final Command command) {
return () -> {
removeDeepLevelBreadcrumbs(perspective,
breadCrumb);
breadCrumb.activate();
if (placeRequest != null) {
goToBreadCrumb(placeRequest,
addTo);
}
updateView();
if (command != null) {
command.execute();
}
};
}
private void goToBreadCrumb(final PlaceRequest placeRequest,
final HasWidgets addTo) {
if (addTo != null) {
placeManager.goTo(placeRequest,
addTo);
} else {
placeManager.goTo(placeRequest);
}
}
void removeDeepLevelBreadcrumbs(final String perspective,
final BreadcrumbsPresenter breadCrumb) {
List<BreadcrumbsPresenter> breadcrumbs = breadcrumbsPerPerspective.get(perspective);
if (breadcrumbs != null) {
Predicate<BreadcrumbsPresenter> toRemovePredicate = current ->
breadcrumbs.indexOf(current) > breadcrumbs.indexOf(breadCrumb);
breadcrumbs.removeIf(toRemovePredicate);
}
}
private void updateView() {
getView();
}
View getView() {
view.clear();
updateBreadcrumbsContainer();
updateBreadcrumbs();
return view;
}
private void updateBreadcrumbs() {
if (thereIsBreadcrumbsFor(currentPerspective)) {
breadcrumbsPerPerspective.get(currentPerspective)
.stream()
.forEach(p -> view.addBreadcrumb(p.getView()));
}
if (thereIsBreadcrumbToolbarFor(currentPerspective)) {
view.addBreadcrumbToolbar(breadcrumbsToolBarPerPerspective.get(currentPerspective));
}
}
void updateBreadcrumbsContainer() {
if (thereIsContentOnBreadcrumbs()) {
uberfireBreadcrumbsContainer.enable();
} else {
uberfireBreadcrumbsContainer.disable();
}
}
private boolean thereIsContentOnBreadcrumbs() {
return thereIsBreadcrumbsFor(currentPerspective) || thereIsBreadcrumbToolbarFor(currentPerspective);
}
private boolean thereIsBreadcrumbsFor(final String perspective) {
return breadcrumbsPerPerspective.containsKey(perspective);
}
private boolean thereIsBreadcrumbToolbarFor(final String perspective) {
return breadcrumbsToolBarPerPerspective.containsKey(perspective);
}
public interface View extends UberElement<UberfireBreadcrumbs> {
void clear();
void addBreadcrumb(UberElement<BreadcrumbsPresenter> view);
void addBreadcrumbToolbar(Element uberElement);
}
}